From 65f7c3f7761c860b075cebd0037b34047e546cda Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Mon, 24 Jun 2024 11:56:51 +0200 Subject: [PATCH 01/28] refactor(app-aco): use FTA in app-aco - folder entity --- packages/app-aco/package.json | 1 + .../app-aco/src/Domain/Caches/FoldersCache.ts | 39 ++++++++++ .../src/Domain/Caches/FoldersCacheFactory.ts | 19 +++++ packages/app-aco/src/Domain/Caches/ICache.ts | 7 ++ packages/app-aco/src/Domain/Caches/index.ts | 3 + .../src/Domain/Models/Folder/Folder.ts | 62 ++++++++++++++++ .../src/Domain/Models/Folder/FolderMapper.ts | 25 +++++++ .../src/Domain/Models/Folder/IFolderMapper.ts | 5 ++ .../app-aco/src/Domain/Models/Folder/index.ts | 3 + packages/app-aco/src/Domain/Models/index.ts | 1 + .../CreateFolder/CreateFolderRepository.ts | 19 +++++ .../CreateFolderRepositoryWithLoading.ts | 26 +++++++ .../CreateFolder/ICreateFolderRepository.ts | 5 ++ .../Folders/CreateFolder/index.ts | 3 + .../DeleteFolder/DeleteFolderRepository.ts | 19 +++++ .../DeleteFolderRepositoryWithLoading.ts | 26 +++++++ .../DeleteFolder/IDeleteFolderRepository.ts | 5 ++ .../Folders/DeleteFolder/index.ts | 3 + .../Folders/GetFolder/GetFolderRepository.ts | 19 +++++ .../GetFolderRepositoryWithLoading.ts | 22 ++++++ .../Folders/GetFolder/IGetFolderRepository.ts | 3 + .../Repositories/Folders/GetFolder/index.ts | 3 + .../ListFolders/IListFoldersRepository.ts | 3 + .../ListFolders/ListFoldersRepository.ts | 21 ++++++ .../ListFoldersRepositoryWithLoading.ts | 25 +++++++ .../Repositories/Folders/ListFolders/index.ts | 3 + .../UpdateFolder/IUpdateFolderRepository.ts | 5 ++ .../UpdateFolder/UpdateFolderRepository.ts | 19 +++++ .../UpdateFolderRepositoryWithLoading.ts | 26 +++++++ .../Folders/UpdateFolder/index.ts | 3 + .../src/Domain/Repositories/Folders/index.ts | 5 ++ .../app-aco/src/Domain/Repositories/index.ts | 1 + .../CreateFolderGraphQLGateway.ts | 37 ++++++++++ .../CreateFolder/ICreateFolderGateway.ts | 5 ++ .../Gateways/Folders/CreateFolder/index.ts | 2 + .../DeleteFolderGraphQLGateway.ts | 36 ++++++++++ .../DeleteFolder/IDeleteFolderGateway.ts | 3 + .../Gateways/Folders/DeleteFolder/index.ts | 2 + .../GetFolder/GetFolderGraphQLGateway.ts | 39 ++++++++++ .../Folders/GetFolder/IGetFolderGateway.ts | 5 ++ .../src/Gateways/Folders/GetFolder/index.ts | 2 + .../ListFolders/IListFoldersGateway.ts | 5 ++ .../ListFolders/ListFoldersGraphQLGateway.ts | 68 ++++++++++++++++++ .../src/Gateways/Folders/ListFolders/index.ts | 2 + .../UpdateFolder/IUpdateFolderGateway.ts | 5 ++ .../UpdateFolderGraphQLGateway.ts | 45 ++++++++++++ .../Gateways/Folders/UpdateFolder/index.ts | 2 + .../app-aco/src/Gateways/Folders/index.ts | 5 ++ packages/app-aco/src/Gateways/index.ts | 1 + packages/app-aco/src/types.ts | 71 +++++++++++++++++++ packages/app-aco/tsconfig.build.json | 1 + packages/app-aco/tsconfig.json | 3 + yarn.lock | 1 + 53 files changed, 769 insertions(+) create mode 100644 packages/app-aco/src/Domain/Caches/FoldersCache.ts create mode 100644 packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts create mode 100644 packages/app-aco/src/Domain/Caches/ICache.ts create mode 100644 packages/app-aco/src/Domain/Caches/index.ts create mode 100644 packages/app-aco/src/Domain/Models/Folder/Folder.ts create mode 100644 packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts create mode 100644 packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts create mode 100644 packages/app-aco/src/Domain/Models/Folder/index.ts create mode 100644 packages/app-aco/src/Domain/Models/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetFolder/IGetFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetFolder/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/ListFolders/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/index.ts create mode 100644 packages/app-aco/src/Domain/Repositories/index.ts create mode 100644 packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts create mode 100644 packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/DeleteFolder/IDeleteFolderGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/DeleteFolder/index.ts create mode 100644 packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/GetFolder/index.ts create mode 100644 packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/ListFolders/index.ts create mode 100644 packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts create mode 100644 packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts create mode 100644 packages/app-aco/src/Gateways/Folders/index.ts create mode 100644 packages/app-aco/src/Gateways/index.ts diff --git a/packages/app-aco/package.json b/packages/app-aco/package.json index e0e400a63a7..eba2bb2cb35 100644 --- a/packages/app-aco/package.json +++ b/packages/app-aco/package.json @@ -21,6 +21,7 @@ "@webiny/app-admin": "0.0.0", "@webiny/app-headless-cms-common": "0.0.0", "@webiny/app-security": "0.0.0", + "@webiny/app-utils": "0.0.0", "@webiny/app-wcp": "0.0.0", "@webiny/form": "0.0.0", "@webiny/plugins": "0.0.0", diff --git a/packages/app-aco/src/Domain/Caches/FoldersCache.ts b/packages/app-aco/src/Domain/Caches/FoldersCache.ts new file mode 100644 index 00000000000..7375b112669 --- /dev/null +++ b/packages/app-aco/src/Domain/Caches/FoldersCache.ts @@ -0,0 +1,39 @@ +import { makeAutoObservable } from "mobx"; +import { ICache } from "./ICache"; +import { Folder } from "~/Domain/Models"; + +export class FoldersCache implements ICache { + private folders: Folder[]; + + constructor() { + this.folders = []; + makeAutoObservable(this); + } + + async get(): Promise { + return this.folders; + } + + async set(item: Folder): Promise { + this.folders.push(item); + } + + async setMultiple(items: Folder[]): Promise { + this.folders = items; + } + + async update(id: string, item: Folder): Promise { + const folderIndex = this.folders.findIndex(f => f.id === id); + + if (folderIndex > -1) { + this.folders[folderIndex] = { + ...this.folders[folderIndex], + ...item + }; + } + } + + async remove(id: string): Promise { + this.folders = this.folders.filter(folder => folder.id !== id); + } +} diff --git a/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts b/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts new file mode 100644 index 00000000000..9388c451ca9 --- /dev/null +++ b/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts @@ -0,0 +1,19 @@ +import { FoldersCache } from "~/Domain/Caches/FoldersCache"; + +export class FoldersCacheFactory { + private cache: Map = new Map(); + + getCache(namespace: string) { + const cacheKey = this.getCacheKey(namespace); + + if (!this.cache.has(cacheKey)) { + this.cache.set(cacheKey, new FoldersCache()); + } + + return this.cache.get(cacheKey) as FoldersCache; + } + + private getCacheKey(namespace: string) { + return namespace; + } +} diff --git a/packages/app-aco/src/Domain/Caches/ICache.ts b/packages/app-aco/src/Domain/Caches/ICache.ts new file mode 100644 index 00000000000..32d538438fc --- /dev/null +++ b/packages/app-aco/src/Domain/Caches/ICache.ts @@ -0,0 +1,7 @@ +export interface ICache { + get: () => Promise; + set: (item: TItem) => Promise; + setMultiple: (items: TItem[]) => Promise; + update: (id: string, item: TItem) => Promise; + remove: (id: string) => Promise; +} diff --git a/packages/app-aco/src/Domain/Caches/index.ts b/packages/app-aco/src/Domain/Caches/index.ts new file mode 100644 index 00000000000..84d81e89572 --- /dev/null +++ b/packages/app-aco/src/Domain/Caches/index.ts @@ -0,0 +1,3 @@ +export * from "./ICache"; +export * from "./FoldersCache"; +export * from "./FoldersCacheFactory"; diff --git a/packages/app-aco/src/Domain/Models/Folder/Folder.ts b/packages/app-aco/src/Domain/Models/Folder/Folder.ts new file mode 100644 index 00000000000..972bf27b6ba --- /dev/null +++ b/packages/app-aco/src/Domain/Models/Folder/Folder.ts @@ -0,0 +1,62 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderDTO { + id: string; + title: string; + slug: string; + type: string; + parentId: string; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity | null; + modifiedOn: string | null; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; +} + +export class Folder { + public id: string; + public title: string; + public slug: string; + public type: string; + public parentId: string | null; + public createdBy: CmsIdentity; + public createdOn: string; + public savedBy: CmsIdentity; + public savedOn: string; + public modifiedBy: CmsIdentity | null; + public modifiedOn: string | null; + public permissions: FolderPermission[]; + public hasNonInheritedPermissions: boolean; + public canManagePermissions: boolean; + public canManageStructure: boolean; + public canManageContent: boolean; + + protected constructor(folder: FolderDTO) { + this.id = folder.id; + this.title = folder.title; + this.slug = folder.slug; + this.type = folder.type; + this.parentId = folder.parentId; + this.createdBy = folder.createdBy; + this.createdOn = folder.createdOn; + this.savedBy = folder.savedBy; + this.savedOn = folder.savedOn; + this.modifiedBy = folder.modifiedBy; + this.modifiedOn = folder.modifiedOn; + this.permissions = folder.permissions; + this.hasNonInheritedPermissions = folder.hasNonInheritedPermissions; + this.canManagePermissions = folder.canManagePermissions; + this.canManageStructure = folder.canManageStructure; + this.canManageContent = folder.canManageContent; + } + + static create(folder: FolderDTO) { + return new Folder(folder); + } +} diff --git a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts new file mode 100644 index 00000000000..f7c214024af --- /dev/null +++ b/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts @@ -0,0 +1,25 @@ +import { Folder } from "./Folder"; +import { IFolderMapper } from "./IFolderMapper"; + +export class FolderMapper implements IFolderMapper { + toDTO(folder: Folder) { + return { + id: folder.id, + title: folder.title, + slug: folder.slug, + type: folder.type, + parentId: folder.parentId || "root", + createdBy: folder.createdBy, + createdOn: folder.createdOn, + savedBy: folder.savedBy, + savedOn: folder.savedOn, + modifiedBy: folder.modifiedBy, + modifiedOn: folder.modifiedOn, + permissions: folder.permissions, + hasNonInheritedPermissions: folder.hasNonInheritedPermissions, + canManagePermissions: folder.canManagePermissions, + canManageStructure: folder.canManageStructure, + canManageContent: folder.canManageContent + }; + } +} diff --git a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts new file mode 100644 index 00000000000..93c15538b0e --- /dev/null +++ b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts @@ -0,0 +1,5 @@ +import { Folder, FolderDTO } from "./Folder"; + +export interface IFolderMapper { + toDTO: (folder: Folder | FolderDTO) => FolderDTO; +} diff --git a/packages/app-aco/src/Domain/Models/Folder/index.ts b/packages/app-aco/src/Domain/Models/Folder/index.ts new file mode 100644 index 00000000000..efb55b7bcdb --- /dev/null +++ b/packages/app-aco/src/Domain/Models/Folder/index.ts @@ -0,0 +1,3 @@ +export * from "./Folder"; +export * from "./FolderMapper"; +export * from "./IFolderMapper"; diff --git a/packages/app-aco/src/Domain/Models/index.ts b/packages/app-aco/src/Domain/Models/index.ts new file mode 100644 index 00000000000..b6ab82d77ce --- /dev/null +++ b/packages/app-aco/src/Domain/Models/index.ts @@ -0,0 +1 @@ +export * from "./Folder"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts new file mode 100644 index 00000000000..c741a0ecce9 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts @@ -0,0 +1,19 @@ +import { ICreateFolderRepository } from "./ICreateFolderRepository"; +import { ICreateFolderGateway } from "~/Gateways"; +import { Folder, FolderDTO } from "~/Domain/Models"; +import { FoldersCache } from "~/Domain/Caches"; + +export class CreateFolderRepository implements ICreateFolderRepository { + private cache: FoldersCache; + private gateway: ICreateFolderGateway; + + constructor(cache: FoldersCache, gateway: ICreateFolderGateway) { + this.cache = cache; + this.gateway = gateway; + } + + async execute(folder: FolderDTO) { + const response = await this.gateway.execute(folder); + await this.cache.set(Folder.create(response)); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts new file mode 100644 index 00000000000..d64928b843f --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts @@ -0,0 +1,26 @@ +import { makeAutoObservable } from "mobx"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { ICreateFolderRepository } from "~/Domain/Repositories"; +import { FolderDTO } from "~/Domain/Models"; +import { LoadingActionsEnum } from "~/types"; + +export class CreateFolderRepositoryWithLoading implements ICreateFolderRepository { + private loadingRepository: ILoadingRepository; + private createFolderRepository: ICreateFolderRepository; + + constructor( + loadingRepository: ILoadingRepository, + createFolderRepository: ICreateFolderRepository + ) { + this.loadingRepository = loadingRepository; + this.createFolderRepository = createFolderRepository; + makeAutoObservable(this); + } + + async execute(folder: FolderDTO) { + await this.loadingRepository.runCallBack( + this.createFolderRepository.execute(folder), + LoadingActionsEnum.create + ); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts new file mode 100644 index 00000000000..f839161f067 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface ICreateFolderRepository { + execute: (folder: FolderDTO) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/index.ts new file mode 100644 index 00000000000..f68097987bb --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/index.ts @@ -0,0 +1,3 @@ +export * from "./CreateFolderRepository"; +export * from "./CreateFolderRepositoryWithLoading"; +export * from "./ICreateFolderRepository"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts new file mode 100644 index 00000000000..f051b34a528 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts @@ -0,0 +1,19 @@ +import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; +import { IDeleteFolderGateway } from "~/Gateways"; +import { FolderDTO } from "~/Domain/Models"; +import { FoldersCache } from "~/Domain/Caches"; + +export class DeleteFolderRepository implements IDeleteFolderRepository { + private cache: FoldersCache; + private gateway: IDeleteFolderGateway; + + constructor(cache: FoldersCache, gateway: IDeleteFolderGateway) { + this.cache = cache; + this.gateway = gateway; + } + + async execute(folder: FolderDTO) { + await this.gateway.execute(folder.id); + await this.cache.remove(folder.id); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts new file mode 100644 index 00000000000..ccaf380ef2b --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts @@ -0,0 +1,26 @@ +import { makeAutoObservable } from "mobx"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { IDeleteFolderRepository } from "~/Domain/Repositories"; +import { FolderDTO } from "~/Domain/Models"; +import { LoadingActionsEnum } from "~/types"; + +export class DeleteFolderRepositoryWithLoading implements IDeleteFolderRepository { + private loadingRepository: ILoadingRepository; + private deleteFolderRepository: IDeleteFolderRepository; + + constructor( + loadingRepository: ILoadingRepository, + deleteFolderRepository: IDeleteFolderRepository + ) { + this.loadingRepository = loadingRepository; + this.deleteFolderRepository = deleteFolderRepository; + makeAutoObservable(this); + } + + async execute(folder: FolderDTO) { + await this.loadingRepository.runCallBack( + this.deleteFolderRepository.execute(folder), + LoadingActionsEnum.delete + ); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts new file mode 100644 index 00000000000..28513cbe890 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface IDeleteFolderRepository { + execute: (folder: FolderDTO) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/index.ts new file mode 100644 index 00000000000..85d104dcfcb --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/index.ts @@ -0,0 +1,3 @@ +export * from "./DeleteFolderRepository"; +export * from "./DeleteFolderRepositoryWithLoading"; +export * from "./IDeleteFolderRepository"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts new file mode 100644 index 00000000000..dd723c6f5be --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts @@ -0,0 +1,19 @@ +import { IGetFolderRepository } from "./IGetFolderRepository"; +import { IGetFolderGateway } from "~/Gateways"; +import { FoldersCache } from "~/Domain/Caches"; +import { Folder } from "~/Domain/Models"; + +export class GetFolderRepository implements IGetFolderRepository { + private cache: FoldersCache; + private gateway: IGetFolderGateway; + + constructor(cache: FoldersCache, gateway: IGetFolderGateway) { + this.cache = cache; + this.gateway = gateway; + } + + async execute(id: string) { + const response = await this.gateway.execute(id); + await this.cache.set(Folder.create(response)); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts new file mode 100644 index 00000000000..2c7bbabdb3f --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts @@ -0,0 +1,22 @@ +import { makeAutoObservable } from "mobx"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { IGetFolderRepository } from "~/Domain/Repositories"; +import { LoadingActionsEnum } from "~/types"; + +export class GetFolderRepositoryWithLoading implements IGetFolderRepository { + private loadingRepository: ILoadingRepository; + private getFolderRepository: IGetFolderRepository; + + constructor(loadingRepository: ILoadingRepository, getFolderRepository: IGetFolderRepository) { + this.loadingRepository = loadingRepository; + this.getFolderRepository = getFolderRepository; + makeAutoObservable(this); + } + + async execute(id: string) { + await this.loadingRepository.runCallBack( + this.getFolderRepository.execute(id), + LoadingActionsEnum.get + ); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/IGetFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/IGetFolderRepository.ts new file mode 100644 index 00000000000..48bcaf7f250 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/IGetFolderRepository.ts @@ -0,0 +1,3 @@ +export interface IGetFolderRepository { + execute: (id: string) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/index.ts new file mode 100644 index 00000000000..87f4a5be0b7 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/index.ts @@ -0,0 +1,3 @@ +export * from "./GetFolderRepository"; +export * from "./GetFolderRepositoryWithLoading"; +export * from "./IGetFolderRepository"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts new file mode 100644 index 00000000000..f9aedf93d50 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts @@ -0,0 +1,3 @@ +export interface IListFoldersRepository { + execute: () => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts new file mode 100644 index 00000000000..1e2421b559a --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts @@ -0,0 +1,21 @@ +import { IListFoldersRepository } from "./IListFoldersRepository"; +import { IListFoldersGateway } from "~/Gateways"; +import { FoldersCache } from "~/Domain/Caches"; +import { Folder } from "~/Domain/Models"; + +export class ListFoldersRepository implements IListFoldersRepository { + private readonly type: string; + private cache: FoldersCache; + private gateway: IListFoldersGateway; + + constructor(type: string, cache: FoldersCache, gateway: IListFoldersGateway) { + this.type = type; + this.cache = cache; + this.gateway = gateway; + } + + async execute() { + const items = await this.gateway.execute(this.type); + await this.cache.setMultiple(items.map(item => Folder.create(item))); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts new file mode 100644 index 00000000000..0bdb6c94e9c --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts @@ -0,0 +1,25 @@ +import { makeAutoObservable } from "mobx"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { IListFoldersRepository } from "~/Domain/Repositories"; +import { LoadingActionsEnum } from "~/types"; + +export class ListFoldersRepositoryWithLoading implements IListFoldersRepository { + private loadingRepository: ILoadingRepository; + private listFoldersRepository: IListFoldersRepository; + + constructor( + loadingRepository: ILoadingRepository, + listFoldersRepository: IListFoldersRepository + ) { + this.loadingRepository = loadingRepository; + this.listFoldersRepository = listFoldersRepository; + makeAutoObservable(this); + } + + async execute() { + await this.loadingRepository.runCallBack( + this.listFoldersRepository.execute(), + LoadingActionsEnum.list + ); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/index.ts new file mode 100644 index 00000000000..888cf6c98f5 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/index.ts @@ -0,0 +1,3 @@ +export * from "./ListFoldersRepository"; +export * from "./ListFoldersRepositoryWithLoading"; +export * from "./IListFoldersRepository"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts new file mode 100644 index 00000000000..d303f4c07b7 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface IUpdateFolderRepository { + execute: (folder: FolderDTO) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts new file mode 100644 index 00000000000..99297f67102 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts @@ -0,0 +1,19 @@ +import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; +import { IUpdateFolderGateway } from "~/Gateways"; +import { Folder, FolderDTO } from "~/Domain/Models"; +import { FoldersCache } from "~/Domain/Caches"; + +export class UpdateFolderRepository implements IUpdateFolderRepository { + private cache: FoldersCache; + private gateway: IUpdateFolderGateway; + + constructor(cache: FoldersCache, gateway: IUpdateFolderGateway) { + this.cache = cache; + this.gateway = gateway; + } + + async execute(folder: FolderDTO) { + const item = await this.gateway.execute(folder); + await this.cache.update(item.id, Folder.create(item)); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts new file mode 100644 index 00000000000..ca176a4c396 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts @@ -0,0 +1,26 @@ +import { makeAutoObservable } from "mobx"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { IUpdateFolderRepository } from "~/Domain/Repositories"; +import { LoadingActionsEnum } from "~/types"; +import { FolderDTO } from "~/Domain/Models"; + +export class UpdateFolderRepositoryWithLoading implements IUpdateFolderRepository { + private loadingRepository: ILoadingRepository; + private updateFolderRepository: IUpdateFolderRepository; + + constructor( + loadingRepository: ILoadingRepository, + updateFolderRepository: IUpdateFolderRepository + ) { + this.loadingRepository = loadingRepository; + this.updateFolderRepository = updateFolderRepository; + makeAutoObservable(this); + } + + async execute(folder: FolderDTO) { + await this.loadingRepository.runCallBack( + this.updateFolderRepository.execute(folder), + LoadingActionsEnum.update + ); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/index.ts new file mode 100644 index 00000000000..e2ff5740d81 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/index.ts @@ -0,0 +1,3 @@ +export * from "./UpdateFolderRepository"; +export * from "./UpdateFolderRepositoryWithLoading"; +export * from "./IUpdateFolderRepository"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/index.ts new file mode 100644 index 00000000000..4e48864c20f --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/index.ts @@ -0,0 +1,5 @@ +export * from "./CreateFolder"; +export * from "./DeleteFolder"; +export * from "./GetFolder"; +export * from "./ListFolders"; +export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/Domain/Repositories/index.ts b/packages/app-aco/src/Domain/Repositories/index.ts new file mode 100644 index 00000000000..3d7438e1836 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/index.ts @@ -0,0 +1 @@ +export * from "./Folders"; diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts new file mode 100644 index 00000000000..71159b5ce8a --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts @@ -0,0 +1,37 @@ +import { ApolloClient } from "apollo-client"; +import { ICreateFolderGateway } from "./ICreateFolderGateway"; +import { CreateFolderFtaResponse, CreateFolderFtaVariables } from "~/types"; +import { CREATE_FOLDER } from "~/graphql/folders.gql"; +import { FolderDTO } from "~/Domain/Models"; + +export class CreateFolderGraphQLGateway implements ICreateFolderGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(folder: FolderDTO) { + const { data: response } = await this.client.mutate< + CreateFolderFtaResponse, + CreateFolderFtaVariables + >({ + mutation: CREATE_FOLDER, + variables: { + data: folder + } + }); + + if (!response) { + throw new Error("Network error while creating folder."); + } + + const { data, error } = response.aco.createFolder; + + if (!data) { + throw new Error(error?.message || "Could not create folder"); + } + + return data; + } +} diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts new file mode 100644 index 00000000000..58ac43c9737 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface ICreateFolderGateway { + execute: (folder: FolderDTO) => Promise; +} diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts new file mode 100644 index 00000000000..f2607ede986 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./CreateFolderGraphQLGateway"; +export * from "./ICreateFolderGateway"; diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts new file mode 100644 index 00000000000..96f3e4567f7 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts @@ -0,0 +1,36 @@ +import { ApolloClient } from "apollo-client"; +import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; +import { DeleteFolderResponse, DeleteFolderVariables } from "~/types"; +import { DELETE_FOLDER } from "~/graphql/folders.gql"; + +export class DeleteFolderGraphQLGateway implements IDeleteFolderGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(id: string) { + const { data: response } = await this.client.mutate< + DeleteFolderResponse, + DeleteFolderVariables + >({ + mutation: DELETE_FOLDER, + variables: { + id + } + }); + + if (!response) { + throw new Error("Network error while deleting folder"); + } + + const { data, error } = response.aco.deleteFolder; + + if (!data) { + throw new Error(error?.message || "Could not delete folder"); + } + + return; + } +} diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/IDeleteFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/DeleteFolder/IDeleteFolderGateway.ts new file mode 100644 index 00000000000..852a065ec5e --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/DeleteFolder/IDeleteFolderGateway.ts @@ -0,0 +1,3 @@ +export interface IDeleteFolderGateway { + execute: (id: string) => Promise; +} diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/index.ts b/packages/app-aco/src/Gateways/Folders/DeleteFolder/index.ts new file mode 100644 index 00000000000..d4ab6a408bd --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/DeleteFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./DeleteFolderGraphQLGateway"; +export * from "./IDeleteFolderGateway"; diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts new file mode 100644 index 00000000000..b7e9a86a712 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts @@ -0,0 +1,39 @@ +import { ApolloClient } from "apollo-client"; +import { IGetFolderGateway } from "./IGetFolderGateway"; +import { GetFolderFtaResponse, GetFolderQueryVariables } from "~/types"; +import { GET_FOLDER } from "~/graphql/folders.gql"; + +export class GetFolderGraphQLGateway implements IGetFolderGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(id: string) { + if (!id) { + throw new Error("Folder `id` is mandatory"); + } + + const { data: response } = await this.client.query< + GetFolderFtaResponse, + GetFolderQueryVariables + >({ + query: GET_FOLDER, + variables: { id }, + fetchPolicy: "network-only" + }); + + if (!response) { + throw new Error("Network error while fetch folder."); + } + + const { data, error } = response.aco.getFolder; + + if (!data) { + throw new Error(error?.message || `Could not fetch folder with id: ${id}`); + } + + return data; + } +} diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts new file mode 100644 index 00000000000..4affaca7fd2 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface IGetFolderGateway { + execute: (id: string) => Promise; +} diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/index.ts b/packages/app-aco/src/Gateways/Folders/GetFolder/index.ts new file mode 100644 index 00000000000..4f708bbc1cc --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/GetFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./GetFolderGraphQLGateway"; +export * from "./IGetFolderGateway"; diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts b/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts new file mode 100644 index 00000000000..e689f80a6ba --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface IListFoldersGateway { + execute: (type: string) => Promise; +} diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts new file mode 100644 index 00000000000..c60ca327706 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts @@ -0,0 +1,68 @@ +import { ApolloClient } from "apollo-client"; +import { IListFoldersGateway } from "./IListFoldersGateway"; +import { ListFoldersFtaResponse, ListFoldersQueryVariables } from "~/types"; +import { LIST_FOLDERS } from "~/graphql/folders.gql"; +import { ROOT_FOLDER } from "~/constants"; + +export class ListFoldersGraphQLGateway implements IListFoldersGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(type: string) { + const { data: response } = await this.client.query< + ListFoldersFtaResponse, + ListFoldersQueryVariables + >({ + query: LIST_FOLDERS, + variables: { + type, + limit: 10000 + }, + fetchPolicy: "network-only" + }); + + if (!response) { + throw new Error("Network error while listing folders."); + } + + const { data, error } = response.aco.listFolders; + + if (!data) { + throw new Error(error?.message || "Could not fetch folders"); + } + + return [this.getRootFolder(), ...(data || [])]; + } + + private getRootFolder() { + return { + id: ROOT_FOLDER, + title: "Home", + permissions: [], + parentId: "0", + slug: "", + createdOn: "", + createdBy: { + id: "", + displayName: "", + type: "" + }, + hasNonInheritedPermissions: false, + canManagePermissions: true, + canManageStructure: true, + canManageContent: true, + savedOn: "", + savedBy: { + id: "", + displayName: "", + type: "" + }, + modifiedOn: null, + modifiedBy: null, + type: "$ROOT" + }; + } +} diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/index.ts b/packages/app-aco/src/Gateways/Folders/ListFolders/index.ts new file mode 100644 index 00000000000..0c530bc59ec --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/ListFolders/index.ts @@ -0,0 +1,2 @@ +export * from "./IListFoldersGateway"; +export * from "./ListFoldersGraphQLGateway"; diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts new file mode 100644 index 00000000000..922921d4822 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts @@ -0,0 +1,5 @@ +import { FolderDTO } from "~/Domain/Models"; + +export interface IUpdateFolderGateway { + execute: (folder: FolderDTO) => Promise; +} diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts new file mode 100644 index 00000000000..16c81f96477 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts @@ -0,0 +1,45 @@ +import { ApolloClient } from "apollo-client"; +import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; +import { UpdateFolderFtaResponse, UpdateFolderFtaVariables } from "~/types"; +import { UPDATE_FOLDER } from "~/graphql/folders.gql"; +import { FolderDTO } from "~/Domain/Models"; + +export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(folder: FolderDTO) { + const { id, title, slug, permissions, parentId } = folder; + + const { data: response } = await this.client.mutate< + UpdateFolderFtaResponse, + UpdateFolderFtaVariables + >({ + mutation: UPDATE_FOLDER, + variables: { + id, + data: { + title, + slug, + permissions, + parentId + } + } + }); + + if (!response) { + throw new Error("Network error while updating folder."); + } + + const { data, error } = response.aco.updateFolder; + + if (!data) { + throw new Error(error?.message || "Could not update folder"); + } + + return data; + } +} diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts new file mode 100644 index 00000000000..bb669f4cf25 --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./IUpdateFolderGateway"; +export * from "./UpdateFolderGraphQLGateway"; diff --git a/packages/app-aco/src/Gateways/Folders/index.ts b/packages/app-aco/src/Gateways/Folders/index.ts new file mode 100644 index 00000000000..4e48864c20f --- /dev/null +++ b/packages/app-aco/src/Gateways/Folders/index.ts @@ -0,0 +1,5 @@ +export * from "./CreateFolder"; +export * from "./DeleteFolder"; +export * from "./GetFolder"; +export * from "./ListFolders"; +export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/Gateways/index.ts b/packages/app-aco/src/Gateways/index.ts new file mode 100644 index 00000000000..3d7438e1836 --- /dev/null +++ b/packages/app-aco/src/Gateways/index.ts @@ -0,0 +1 @@ +export * from "./Folders"; diff --git a/packages/app-aco/src/types.ts b/packages/app-aco/src/types.ts index 73ef6344160..9b64ff29f4c 100644 --- a/packages/app-aco/src/types.ts +++ b/packages/app-aco/src/types.ts @@ -4,6 +4,7 @@ import { CmsModelField, CmsModelFieldSettings } from "@webiny/app-headless-cms-common/types"; +import { FolderDTO } from "~/Domain/Models"; export { CmsIdentity } from "@webiny/app-headless-cms-common/types"; export * from "~/graphql/records/types"; @@ -67,6 +68,17 @@ export type LoadingActions = | "DELETE" | "MOVE"; +export enum LoadingActionsEnum { + init = "INIT", + list = "LIST", + listMore = "LIST_MORE", + get = "GET", + create = "CREATE", + update = "UPDATE", + delete = "DELETE", + move = "MOVE" +} + export interface AcoError { code: string; message: string; @@ -91,6 +103,16 @@ export interface ListFoldersResponse { }; } +// ListFoldersResponse - FTA +export interface ListFoldersFtaResponse { + aco: { + listFolders: { + data: FolderDTO[] | null; + error: AcoError | null; + }; + }; +} + export interface ListFoldersQueryVariables { type: string; limit: number; @@ -107,6 +129,16 @@ export interface GetFolderResponse { }; } +// GetFolderResponse - FTA +export interface GetFolderFtaResponse { + aco: { + getFolder: { + data: FolderDTO | null; + error: AcoError | null; + }; + }; +} + export interface GetFolderQueryVariables { id: string; } @@ -120,6 +152,16 @@ export interface UpdateFolderResponse { }; } +// UpdateFolderResponse - FTA +export interface UpdateFolderFtaResponse { + aco: { + updateFolder: { + data: FolderDTO; + error: AcoError | null; + }; + }; +} + export interface UpdateFolderVariables { id: string; data: Partial< @@ -130,6 +172,17 @@ export interface UpdateFolderVariables { >; } +// UpdateFolderVariables - FTA +export interface UpdateFolderFtaVariables { + id: string; + data: Partial< + Omit< + FolderDTO, + "id" | "createdOn" | "createdBy" | "savedOn" | "savedBy" | "modifiedOn" | "modifiedBy" + > + >; +} + export interface CreateFolderResponse { aco: { createFolder: { @@ -139,6 +192,16 @@ export interface CreateFolderResponse { }; } +// CreateFolderResponse - FTA +export interface CreateFolderFtaResponse { + aco: { + createFolder: { + data: FolderDTO; + error: AcoError | null; + }; + }; +} + export interface CreateFolderVariables { data: Omit< FolderItem, @@ -146,6 +209,14 @@ export interface CreateFolderVariables { >; } +// CreateFolderVariables - FTA +export interface CreateFolderFtaVariables { + data: Omit< + FolderDTO | FolderItem, + "id" | "createdOn" | "createdBy" | "savedOn" | "savedBy" | "modifiedOn" | "modifiedBy" + >; +} + export interface DeleteFolderVariables { id: string; } diff --git a/packages/app-aco/tsconfig.build.json b/packages/app-aco/tsconfig.build.json index e9fd945cba2..bda102d5c14 100644 --- a/packages/app-aco/tsconfig.build.json +++ b/packages/app-aco/tsconfig.build.json @@ -6,6 +6,7 @@ { "path": "../app-admin/tsconfig.build.json" }, { "path": "../app-headless-cms-common/tsconfig.build.json" }, { "path": "../app-security/tsconfig.build.json" }, + { "path": "../app-utils/tsconfig.build.json" }, { "path": "../app-wcp/tsconfig.build.json" }, { "path": "../form/tsconfig.build.json" }, { "path": "../plugins/tsconfig.build.json" }, diff --git a/packages/app-aco/tsconfig.json b/packages/app-aco/tsconfig.json index 83c93d96212..f7cb73a64e3 100644 --- a/packages/app-aco/tsconfig.json +++ b/packages/app-aco/tsconfig.json @@ -6,6 +6,7 @@ { "path": "../app-admin" }, { "path": "../app-headless-cms-common" }, { "path": "../app-security" }, + { "path": "../app-utils" }, { "path": "../app-wcp" }, { "path": "../form" }, { "path": "../plugins" }, @@ -30,6 +31,8 @@ "@webiny/app-headless-cms-common": ["../app-headless-cms-common/src"], "@webiny/app-security/*": ["../app-security/src/*"], "@webiny/app-security": ["../app-security/src"], + "@webiny/app-utils/*": ["../app-utils/src/*"], + "@webiny/app-utils": ["../app-utils/src"], "@webiny/app-wcp/*": ["../app-wcp/src/*"], "@webiny/app-wcp": ["../app-wcp/src"], "@webiny/form/*": ["../form/src/*"], diff --git a/yarn.lock b/yarn.lock index 727d4d14a63..f02024f7ded 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16069,6 +16069,7 @@ __metadata: "@webiny/app-admin": 0.0.0 "@webiny/app-headless-cms-common": 0.0.0 "@webiny/app-security": 0.0.0 + "@webiny/app-utils": 0.0.0 "@webiny/app-wcp": 0.0.0 "@webiny/cli": 0.0.0 "@webiny/form": 0.0.0 From f30304a0196781e109be89f540622ca45663acaf Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Tue, 25 Jun 2024 11:28:37 +0200 Subject: [PATCH 02/28] refactor(app-aco): use FTA in app-aco - folder entity --- .../app-aco/src/Domain/Caches/FoldersCache.ts | 2 +- .../src/Domain/Caches/FoldersCacheFactory.ts | 2 + packages/app-aco/src/Domain/Caches/ICache.ts | 2 +- .../src/Domain/Models/Folder/Folder.ts | 42 ++-- .../src/Domain/Models/Folder/FolderMapper.ts | 2 + .../src/Domain/Models/Folder/IFolderMapper.ts | 5 +- .../CreateFolder/CreateFolderRepository.ts | 5 +- .../CreateFolderRepositoryWithLoading.ts | 5 +- .../CreateFolder/ICreateFolderRepository.ts | 4 +- .../DeleteFolder/DeleteFolderRepository.ts | 4 +- .../DeleteFolderRepositoryWithLoading.ts | 5 +- .../DeleteFolder/IDeleteFolderRepository.ts | 4 +- .../GetDescendantFoldersRepository.ts | 45 ++++ .../IGetDescendantFoldersRepository.ts | 5 + .../Folders/GetDescendantFolders/index.ts | 2 + .../UpdateFolder/IUpdateFolderRepository.ts | 4 +- .../UpdateFolder/UpdateFolderRepository.ts | 5 +- .../UpdateFolderRepositoryWithLoading.ts | 4 +- .../src/Domain/Repositories/Folders/index.ts | 1 + .../CreateFolderGraphQLGateway.ts | 9 +- .../CreateFolder/ICreateFolderGateway.ts | 4 +- .../DeleteFolderGraphQLGateway.ts | 2 +- .../GetFolder/GetFolderGraphQLGateway.ts | 4 +- .../Folders/GetFolder/IGetFolderGateway.ts | 4 +- .../ListFolders/IListFoldersGateway.ts | 4 +- .../ListFolders/ListFoldersGraphQLGateway.ts | 6 +- .../UpdateFolder/IUpdateFolderGateway.ts | 4 +- .../UpdateFolderGraphQLGateway.ts | 9 +- packages/app-aco/src/contexts/acoList.tsx | 14 +- packages/app-aco/src/contexts/folders.tsx | 112 +--------- .../app-aco/src/dialogs/useDeleteDialog.tsx | 9 +- .../app-aco/src/dialogs/useEditDialog.tsx | 9 +- packages/app-aco/src/hooks/useFolders.ts | 205 ++++++++++++++++-- packages/app-aco/src/types.ts | 60 ----- 34 files changed, 327 insertions(+), 276 deletions(-) create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts create mode 100644 packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/index.ts diff --git a/packages/app-aco/src/Domain/Caches/FoldersCache.ts b/packages/app-aco/src/Domain/Caches/FoldersCache.ts index 7375b112669..64162a92b4d 100644 --- a/packages/app-aco/src/Domain/Caches/FoldersCache.ts +++ b/packages/app-aco/src/Domain/Caches/FoldersCache.ts @@ -10,7 +10,7 @@ export class FoldersCache implements ICache { makeAutoObservable(this); } - async get(): Promise { + getItems() { return this.folders; } diff --git a/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts b/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts index 9388c451ca9..153037a3269 100644 --- a/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts +++ b/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts @@ -17,3 +17,5 @@ export class FoldersCacheFactory { return namespace; } } + +export const folderCacheFactory = new FoldersCacheFactory(); diff --git a/packages/app-aco/src/Domain/Caches/ICache.ts b/packages/app-aco/src/Domain/Caches/ICache.ts index 32d538438fc..1f1be7afcca 100644 --- a/packages/app-aco/src/Domain/Caches/ICache.ts +++ b/packages/app-aco/src/Domain/Caches/ICache.ts @@ -1,5 +1,5 @@ export interface ICache { - get: () => Promise; + getItems: () => TItem[]; set: (item: TItem) => Promise; setMultiple: (items: TItem[]) => Promise; update: (id: string, item: TItem) => Promise; diff --git a/packages/app-aco/src/Domain/Models/Folder/Folder.ts b/packages/app-aco/src/Domain/Models/Folder/Folder.ts index 972bf27b6ba..da7fab2e2e8 100644 --- a/packages/app-aco/src/Domain/Models/Folder/Folder.ts +++ b/packages/app-aco/src/Domain/Models/Folder/Folder.ts @@ -1,23 +1,23 @@ -import { CmsIdentity, FolderPermission } from "~/types"; +import { CmsIdentity, FolderPermission, FolderItem } from "~/types"; -export interface FolderDTO { - id: string; - title: string; - slug: string; - type: string; - parentId: string; - createdBy: CmsIdentity; - createdOn: string; - savedBy: CmsIdentity; - savedOn: string; - modifiedBy: CmsIdentity | null; - modifiedOn: string | null; - permissions: FolderPermission[]; - hasNonInheritedPermissions: boolean; - canManagePermissions: boolean; - canManageStructure: boolean; - canManageContent: boolean; -} +// export interface FolderDTO { +// id: string; +// title: string; +// slug: string; +// type: string; +// parentId: string | null; +// createdBy: CmsIdentity; +// createdOn: string; +// savedBy: CmsIdentity; +// savedOn: string; +// modifiedBy: CmsIdentity | null; +// modifiedOn: string | null; +// permissions: FolderPermission[]; +// hasNonInheritedPermissions: boolean; +// canManagePermissions: boolean; +// canManageStructure: boolean; +// canManageContent: boolean; +// } export class Folder { public id: string; @@ -37,7 +37,7 @@ export class Folder { public canManageStructure: boolean; public canManageContent: boolean; - protected constructor(folder: FolderDTO) { + protected constructor(folder: FolderItem) { this.id = folder.id; this.title = folder.title; this.slug = folder.slug; @@ -56,7 +56,7 @@ export class Folder { this.canManageContent = folder.canManageContent; } - static create(folder: FolderDTO) { + static create(folder: FolderItem) { return new Folder(folder); } } diff --git a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts index f7c214024af..b041406be61 100644 --- a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts +++ b/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts @@ -3,6 +3,8 @@ import { IFolderMapper } from "./IFolderMapper"; export class FolderMapper implements IFolderMapper { toDTO(folder: Folder) { + console.log("FolderMapper", folder); + return { id: folder.id, title: folder.title, diff --git a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts index 93c15538b0e..8ffe13c8009 100644 --- a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts +++ b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts @@ -1,5 +1,6 @@ -import { Folder, FolderDTO } from "./Folder"; +import { Folder } from "./Folder"; +import { FolderItem } from "~/types"; export interface IFolderMapper { - toDTO: (folder: Folder | FolderDTO) => FolderDTO; + toDTO: (folder: Folder | FolderItem) => FolderItem; } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts index c741a0ecce9..d543177f78a 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts @@ -1,7 +1,8 @@ import { ICreateFolderRepository } from "./ICreateFolderRepository"; import { ICreateFolderGateway } from "~/Gateways"; -import { Folder, FolderDTO } from "~/Domain/Models"; +import { Folder } from "~/Domain/Models"; import { FoldersCache } from "~/Domain/Caches"; +import { FolderItem } from "~/types"; export class CreateFolderRepository implements ICreateFolderRepository { private cache: FoldersCache; @@ -12,7 +13,7 @@ export class CreateFolderRepository implements ICreateFolderRepository { this.gateway = gateway; } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { const response = await this.gateway.execute(folder); await this.cache.set(Folder.create(response)); } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts index d64928b843f..8122bd84539 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts @@ -1,8 +1,7 @@ import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; import { ICreateFolderRepository } from "~/Domain/Repositories"; -import { FolderDTO } from "~/Domain/Models"; -import { LoadingActionsEnum } from "~/types"; +import { FolderItem, LoadingActionsEnum } from "~/types"; export class CreateFolderRepositoryWithLoading implements ICreateFolderRepository { private loadingRepository: ILoadingRepository; @@ -17,7 +16,7 @@ export class CreateFolderRepositoryWithLoading implements ICreateFolderRepositor makeAutoObservable(this); } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { await this.loadingRepository.runCallBack( this.createFolderRepository.execute(folder), LoadingActionsEnum.create diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts index f839161f067..58ec48040d4 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface ICreateFolderRepository { - execute: (folder: FolderDTO) => Promise; + execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts index f051b34a528..1228074b8dd 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts @@ -1,7 +1,7 @@ import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; import { IDeleteFolderGateway } from "~/Gateways"; -import { FolderDTO } from "~/Domain/Models"; import { FoldersCache } from "~/Domain/Caches"; +import { FolderItem } from "~/types"; export class DeleteFolderRepository implements IDeleteFolderRepository { private cache: FoldersCache; @@ -12,7 +12,7 @@ export class DeleteFolderRepository implements IDeleteFolderRepository { this.gateway = gateway; } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { await this.gateway.execute(folder.id); await this.cache.remove(folder.id); } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts index ccaf380ef2b..e201f990a0f 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts @@ -1,8 +1,7 @@ import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; import { IDeleteFolderRepository } from "~/Domain/Repositories"; -import { FolderDTO } from "~/Domain/Models"; -import { LoadingActionsEnum } from "~/types"; +import { FolderItem, LoadingActionsEnum } from "~/types"; export class DeleteFolderRepositoryWithLoading implements IDeleteFolderRepository { private loadingRepository: ILoadingRepository; @@ -17,7 +16,7 @@ export class DeleteFolderRepositoryWithLoading implements IDeleteFolderRepositor makeAutoObservable(this); } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { await this.loadingRepository.runCallBack( this.deleteFolderRepository.execute(folder), LoadingActionsEnum.delete diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts index 28513cbe890..c7154e48e70 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface IDeleteFolderRepository { - execute: (folder: FolderDTO) => Promise; + execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts new file mode 100644 index 00000000000..8e88c8cfe03 --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts @@ -0,0 +1,45 @@ +import { Folder } from "~/Domain/Models"; +import { FoldersCache } from "~/Domain/Caches"; +import { IGetDescendantFoldersRepository } from "./IGetDescendantFoldersRepository"; +import { ROOT_FOLDER } from "~/constants"; +import { FolderItem } from "~/types"; + +export class GetDescendantFoldersRepository implements IGetDescendantFoldersRepository { + private readonly cache: FoldersCache; + + constructor(cache: FoldersCache) { + this.cache = cache; + } + + execute(id: string): Folder[] { + if (this.isInvalidId(id)) { + return []; + } + + if (!id || id === ROOT_FOLDER || !currentFolders?.length) { + return []; + } + + const folderMap = new Map(currentFolders.map(folder => [folder.id, folder])); + const result: FolderItem[] = []; + + const findChildren = (folderId: string) => { + const folder = folderMap.get(folderId); + if (!folder) { + return; + } + + result.push(folder); + + currentFolders.forEach(child => { + if (child.parentId === folder.id) { + findChildren(child.id); + } + }); + }; + + findChildren(id); + + return result; + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts new file mode 100644 index 00000000000..9a8e881b68b --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts @@ -0,0 +1,5 @@ +import { Folder } from "~/Domain/Models"; + +export interface IGetDescendantFoldersRepository { + execute: (id: string) => Folder[]; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/index.ts new file mode 100644 index 00000000000..c5a822742ba --- /dev/null +++ b/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/index.ts @@ -0,0 +1,2 @@ +export * from "./GetDescendantFoldersRepository"; +export * from "./IGetDescendantFoldersRepository"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts index d303f4c07b7..ff52c961f6e 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface IUpdateFolderRepository { - execute: (folder: FolderDTO) => Promise; + execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts index 99297f67102..16ea7ce1ea9 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts @@ -1,7 +1,8 @@ import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; import { IUpdateFolderGateway } from "~/Gateways"; -import { Folder, FolderDTO } from "~/Domain/Models"; +import { Folder } from "~/Domain/Models"; import { FoldersCache } from "~/Domain/Caches"; +import { FolderItem } from "~/types"; export class UpdateFolderRepository implements IUpdateFolderRepository { private cache: FoldersCache; @@ -12,7 +13,7 @@ export class UpdateFolderRepository implements IUpdateFolderRepository { this.gateway = gateway; } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { const item = await this.gateway.execute(folder); await this.cache.update(item.id, Folder.create(item)); } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts index ca176a4c396..a755c12137b 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts @@ -2,7 +2,7 @@ import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; import { IUpdateFolderRepository } from "~/Domain/Repositories"; import { LoadingActionsEnum } from "~/types"; -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export class UpdateFolderRepositoryWithLoading implements IUpdateFolderRepository { private loadingRepository: ILoadingRepository; @@ -17,7 +17,7 @@ export class UpdateFolderRepositoryWithLoading implements IUpdateFolderRepositor makeAutoObservable(this); } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { await this.loadingRepository.runCallBack( this.updateFolderRepository.execute(folder), LoadingActionsEnum.update diff --git a/packages/app-aco/src/Domain/Repositories/Folders/index.ts b/packages/app-aco/src/Domain/Repositories/Folders/index.ts index 4e48864c20f..cba36b04485 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/index.ts +++ b/packages/app-aco/src/Domain/Repositories/Folders/index.ts @@ -1,5 +1,6 @@ export * from "./CreateFolder"; export * from "./DeleteFolder"; +export * from "./GetDescendantFolders"; export * from "./GetFolder"; export * from "./ListFolders"; export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts index 71159b5ce8a..12b2288db44 100644 --- a/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts @@ -1,8 +1,7 @@ import { ApolloClient } from "apollo-client"; import { ICreateFolderGateway } from "./ICreateFolderGateway"; -import { CreateFolderFtaResponse, CreateFolderFtaVariables } from "~/types"; import { CREATE_FOLDER } from "~/graphql/folders.gql"; -import { FolderDTO } from "~/Domain/Models"; +import { CreateFolderResponse, CreateFolderVariables, FolderItem } from "~/types"; export class CreateFolderGraphQLGateway implements ICreateFolderGateway { private client: ApolloClient; @@ -11,10 +10,10 @@ export class CreateFolderGraphQLGateway implements ICreateFolderGateway { this.client = client; } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { const { data: response } = await this.client.mutate< - CreateFolderFtaResponse, - CreateFolderFtaVariables + CreateFolderResponse, + CreateFolderVariables >({ mutation: CREATE_FOLDER, variables: { diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts index 58ac43c9737..903829b0f0a 100644 --- a/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface ICreateFolderGateway { - execute: (folder: FolderDTO) => Promise; + execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts index 96f3e4567f7..b1a403931c4 100644 --- a/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts @@ -1,7 +1,7 @@ import { ApolloClient } from "apollo-client"; import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; -import { DeleteFolderResponse, DeleteFolderVariables } from "~/types"; import { DELETE_FOLDER } from "~/graphql/folders.gql"; +import { DeleteFolderResponse, DeleteFolderVariables } from "~/types"; export class DeleteFolderGraphQLGateway implements IDeleteFolderGateway { private client: ApolloClient; diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts index b7e9a86a712..cda71e7520a 100644 --- a/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts @@ -1,7 +1,7 @@ import { ApolloClient } from "apollo-client"; import { IGetFolderGateway } from "./IGetFolderGateway"; -import { GetFolderFtaResponse, GetFolderQueryVariables } from "~/types"; import { GET_FOLDER } from "~/graphql/folders.gql"; +import { GetFolderResponse, GetFolderQueryVariables } from "~/types"; export class GetFolderGraphQLGateway implements IGetFolderGateway { private client: ApolloClient; @@ -16,7 +16,7 @@ export class GetFolderGraphQLGateway implements IGetFolderGateway { } const { data: response } = await this.client.query< - GetFolderFtaResponse, + GetFolderResponse, GetFolderQueryVariables >({ query: GET_FOLDER, diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts index 4affaca7fd2..743f6bb90d4 100644 --- a/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface IGetFolderGateway { - execute: (id: string) => Promise; + execute: (id: string) => Promise; } diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts b/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts index e689f80a6ba..9b4a6ae1c79 100644 --- a/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface IListFoldersGateway { - execute: (type: string) => Promise; + execute: (type: string) => Promise; } diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts index c60ca327706..ace90c5f72d 100644 --- a/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts @@ -1,8 +1,8 @@ import { ApolloClient } from "apollo-client"; import { IListFoldersGateway } from "./IListFoldersGateway"; -import { ListFoldersFtaResponse, ListFoldersQueryVariables } from "~/types"; import { LIST_FOLDERS } from "~/graphql/folders.gql"; import { ROOT_FOLDER } from "~/constants"; +import { FolderItem, ListFoldersQueryVariables, ListFoldersResponse } from "~/types"; export class ListFoldersGraphQLGateway implements IListFoldersGateway { private client: ApolloClient; @@ -13,7 +13,7 @@ export class ListFoldersGraphQLGateway implements IListFoldersGateway { async execute(type: string) { const { data: response } = await this.client.query< - ListFoldersFtaResponse, + ListFoldersResponse, ListFoldersQueryVariables >({ query: LIST_FOLDERS, @@ -37,7 +37,7 @@ export class ListFoldersGraphQLGateway implements IListFoldersGateway { return [this.getRootFolder(), ...(data || [])]; } - private getRootFolder() { + private getRootFolder(): FolderItem { return { id: ROOT_FOLDER, title: "Home", diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts index 922921d4822..23df5ff7aee 100644 --- a/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts @@ -1,5 +1,5 @@ -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem } from "~/types"; export interface IUpdateFolderGateway { - execute: (folder: FolderDTO) => Promise; + execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts index 16c81f96477..36a609a4d81 100644 --- a/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts @@ -1,8 +1,7 @@ import { ApolloClient } from "apollo-client"; import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; -import { UpdateFolderFtaResponse, UpdateFolderFtaVariables } from "~/types"; import { UPDATE_FOLDER } from "~/graphql/folders.gql"; -import { FolderDTO } from "~/Domain/Models"; +import { FolderItem, UpdateFolderResponse, UpdateFolderVariables } from "~/types"; export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { private client: ApolloClient; @@ -11,12 +10,12 @@ export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { this.client = client; } - async execute(folder: FolderDTO) { + async execute(folder: FolderItem) { const { id, title, slug, permissions, parentId } = folder; const { data: response } = await this.client.mutate< - UpdateFolderFtaResponse, - UpdateFolderFtaVariables + UpdateFolderResponse, + UpdateFolderVariables >({ mutation: UPDATE_FOLDER, variables: { diff --git a/packages/app-aco/src/contexts/acoList.tsx b/packages/app-aco/src/contexts/acoList.tsx index 6b114ffa6a9..dc3d178cdd9 100644 --- a/packages/app-aco/src/contexts/acoList.tsx +++ b/packages/app-aco/src/contexts/acoList.tsx @@ -11,7 +11,7 @@ import { ListSearchRecordsSort, SearchRecordItem } from "~/types"; -import { useAcoApp, useNavigateFolder } from "~/hooks"; +import { useAcoApp, useFolders, useNavigateFolder } from "~/hooks"; import { FoldersContext } from "~/contexts/folders"; import { SearchRecordsContext } from "~/contexts/records"; import { sortTableItems, validateOrGetDefaultDbSort } from "~/sorting"; @@ -110,6 +110,12 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => const { identity } = useSecurity(); const { currentFolderId } = useNavigateFolder(); const { folderIdPath, folderIdInPath } = useAcoApp(); + const { + folders: originalFolders, + loading: foldersLoading, + listFolders, + getDescendantFolders + } = useFolders(); const folderContext = useContext(FoldersContext); const searchContext = useContext(SearchRecordsContext); @@ -122,12 +128,6 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => const [listTitle, setListTitle] = useStateIfMounted(undefined); const [state, setState] = useStateIfMounted>(initializeAcoListState()); - const { - folders: originalFolders, - loading: foldersLoading, - listFolders, - getDescendantFolders - } = folderContext; const { records: originalRecords, loading: recordsLoading, listRecords, meta } = searchContext; /** diff --git a/packages/app-aco/src/contexts/folders.tsx b/packages/app-aco/src/contexts/folders.tsx index a6b355d919c..79203e1d620 100644 --- a/packages/app-aco/src/contexts/folders.tsx +++ b/packages/app-aco/src/contexts/folders.tsx @@ -1,10 +1,8 @@ -import React, { ReactNode, useContext, useEffect, useMemo } from "react"; +import React, { ReactNode, useContext, useMemo } from "react"; import { useWcp } from "@webiny/app-wcp/hooks/useWcp"; import { useStateIfMounted } from "@webiny/app-admin"; -import { dataLoader, loadingHandler } from "~/handlers"; -import { FolderItem, Loading, LoadingActions } from "~/types"; +import { FolderItem } from "~/types"; import { AcoAppContext } from "~/contexts/app"; -import { useFoldersApi } from "~/hooks"; import { ROOT_FOLDER } from "~/constants"; export interface FoldersContextFolderLevelPermissions { @@ -16,22 +14,7 @@ export interface FoldersContextFolderLevelPermissions { } interface FoldersContext { - folders?: FolderItem[] | null; - loading: Loading; - listFolders: () => Promise; - getFolder: (id: string) => Promise; - createFolder: (folder: Omit) => Promise; - updateFolder: ( - folder: Omit, - options?: Partial<{ - refetchFoldersList: boolean; - }> - ) => Promise; - - deleteFolder(folder: Pick): Promise; - - getDescendantFolders(id?: string): FolderItem[]; - + type?: string | null; folderLevelPermissions: FoldersContextFolderLevelPermissions; } @@ -42,22 +25,9 @@ interface Props { children: ReactNode; } -const defaultLoading: Record = { - INIT: true, - LIST: false, - LIST_MORE: false, - GET: false, - MOVE: false, - CREATE: false, - UPDATE: false, - DELETE: false -}; - export const FoldersProvider = ({ children, ...props }: Props) => { const appContext = useContext(AcoAppContext); const [folders, setFolders] = useStateIfMounted(null); - const [loading, setLoading] = useStateIfMounted>(defaultLoading); - const foldersApi = useFoldersApi(); const { canUseFolderLevelPermissions } = useWcp(); const app = appContext ? appContext.app : undefined; @@ -67,12 +37,6 @@ export const FoldersProvider = ({ children, ...props }: Props) => { throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); } - useEffect(() => { - return foldersApi.onFoldersChanged(type, folders => { - setFolders(folders); - }); - }, []); - const folderLevelPermissions: FoldersContextFolderLevelPermissions = useMemo(() => { const createCanManage = (callback: (folder: FolderItem) => boolean) => (folderId: string) => { @@ -97,77 +61,9 @@ export const FoldersProvider = ({ children, ...props }: Props) => { const context = useMemo(() => { return { - folders, - loading, - async listFolders() { - const folders = await dataLoader(loadingHandler("LIST", setLoading), () => - foldersApi.listFolders(type) - ); - - setFolders(() => folders); - - setLoading(prev => ({ - ...prev, - INIT: false - })); - - return folders; - }, - - async getFolder(id) { - if (!id) { - throw new Error("Folder `id` is mandatory"); - } - - return await dataLoader(loadingHandler("GET", setLoading), () => - foldersApi.getFolder(type, id) - ); - }, - - async createFolder(folder) { - return await dataLoader(loadingHandler("CREATE", setLoading), () => - foldersApi.createFolder(type, folder) - ); - }, - - async updateFolder(folder, options) { - const { id, title, slug, permissions, parentId } = folder; - - // We must omit all inherited permissions. - const filteredPermissions = permissions.filter(p => !p.inheritedFrom); - - return await dataLoader(loadingHandler("UPDATE", setLoading), async () => { - const response = await foldersApi.updateFolder(type, { - id, - title, - slug, - permissions: filteredPermissions, - parentId - }); - - if (options?.refetchFoldersList) { - foldersApi.listFolders(type, { invalidateCache: true }).then(setFolders); - } - - return response; - }); - }, - - async deleteFolder(folder) { - const { id } = folder; - - return await dataLoader(loadingHandler("DELETE", setLoading), () => - foldersApi.deleteFolder(type, id) - ); - }, - - getDescendantFolders(id) { - return foldersApi.getDescendantFolders(type, id); - }, - folderLevelPermissions }; - }, [folders, loading, setLoading, setFolders]); + }, [folders, setFolders]); return {children}; }; diff --git a/packages/app-aco/src/dialogs/useDeleteDialog.tsx b/packages/app-aco/src/dialogs/useDeleteDialog.tsx index 0f30ea82867..a8dd8e65bf5 100644 --- a/packages/app-aco/src/dialogs/useDeleteDialog.tsx +++ b/packages/app-aco/src/dialogs/useDeleteDialog.tsx @@ -20,13 +20,8 @@ export const useDeleteDialog = (): UseDeleteDialogResponse => { const onAccept = useCallback(async (folder: FolderItem) => { try { - const result = await deleteFolder(folder); - - if (result) { - showSnackbar(`The folder "${folder.title}" was deleted successfully.`); - } else { - throw new Error(`Error while deleting folder "${folder.title}"!`); - } + await deleteFolder(folder); + showSnackbar(`The folder "${folder.title}" was deleted successfully.`); } catch (error) { showSnackbar(error.message); } diff --git a/packages/app-aco/src/dialogs/useEditDialog.tsx b/packages/app-aco/src/dialogs/useEditDialog.tsx index 39ee1e9367a..da03f9575ae 100644 --- a/packages/app-aco/src/dialogs/useEditDialog.tsx +++ b/packages/app-aco/src/dialogs/useEditDialog.tsx @@ -77,16 +77,11 @@ export const useEditDialog = (): UseEditDialogResponse => { const onAccept = useCallback(async (folder: FolderItem, data: GenericFormData) => { try { - const result = await updateFolder({ + await updateFolder({ ...folder, ...data }); - - if (result) { - showSnackbar(`The folder "${result.title}" was updated successfully!`); - } else { - throw new Error(`Error while updating folder "${folder.title}"!`); - } + showSnackbar(`The folder "${data.title}" was updated successfully!`); } catch (error) { showSnackbar(error.message); } diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index b8d6282a243..59a841a8a84 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,13 +1,163 @@ -import { useContext, useEffect, useMemo } from "react"; +import { useContext, useCallback, useEffect, useMemo, useState } from "react"; +import { autorun } from "mobx"; +import { useApolloClient } from "@apollo/react-hooks"; + import { FoldersContext } from "~/contexts/folders"; +import { AcoAppContext } from "~/contexts/app"; +import { FolderItem } from "~/types"; +import { folderCacheFactory } from "~/Domain/Caches"; +import { loadingRepositoryFactory } from "@webiny/app-utils"; +import { + CreateFolderGraphQLGateway, + DeleteFolderGraphQLGateway, + GetFolderGraphQLGateway, + ListFoldersGraphQLGateway, + UpdateFolderGraphQLGateway +} from "~/Gateways"; +import { + CreateFolderRepository, + CreateFolderRepositoryWithLoading, + DeleteFolderRepository, + DeleteFolderRepositoryWithLoading, + GetDescendantFoldersRepository, + GetFolderRepository, + GetFolderRepositoryWithLoading, + ListFoldersRepository, + ListFoldersRepositoryWithLoading, + UpdateFolderRepository, + UpdateFolderRepositoryWithLoading +} from "~/Domain/Repositories"; +import { FolderMapper } from "~/Domain/Models"; export const useFolders = () => { - const context = useContext(FoldersContext); - if (!context) { + const client = useApolloClient(); + const foldersContext = useContext(FoldersContext); + const appContext = useContext(AcoAppContext); + + const [vm, setVm] = useState<{ + folders: FolderItem[] | null; + loading: Record; + }>({ + folders: null, + loading: {} + }); + + if (!foldersContext) { throw new Error("useFolders must be used within a FoldersProvider"); } - const { folders, loading, listFolders, ...other } = context; + const app = appContext ? appContext.app : undefined; + + const type = foldersContext.type ?? app?.id; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } + + // Folders cache + const foldersCache = useMemo(() => { + return folderCacheFactory.getCache(type); + }, [type]); + + // Loading Cache + const loadingRepository = useMemo(() => { + return loadingRepositoryFactory.getRepository(); + }, []); + + // List + const listFolders = useCallback(() => { + const listFoldersGateway = new ListFoldersGraphQLGateway(client); + const listFoldersRepository = new ListFoldersRepository( + type, + foldersCache, + listFoldersGateway + ); + + const repository = new ListFoldersRepositoryWithLoading( + loadingRepository, + listFoldersRepository + ); + return repository.execute(); + }, [type, client, foldersCache, loadingRepository]); + + // Get + const getFolder = useCallback( + (id: string) => { + const getFolderGateway = new GetFolderGraphQLGateway(client); + const getFolderRepository = new GetFolderRepository(foldersCache, getFolderGateway); + + const repository = new GetFolderRepositoryWithLoading( + loadingRepository, + getFolderRepository + ); + return repository.execute(id); + }, + [client, foldersCache, loadingRepository] + ); + + const getDescendantFolders = useCallback( + (id: string) => { + const repository = new GetDescendantFoldersRepository(foldersCache); + return repository.execute(id); + }, + [foldersCache] + ); + + // Create + const createFolder = useCallback( + (folder: FolderItem) => { + const createFolderGateway = new CreateFolderGraphQLGateway(client); + const createFolderRepository = new CreateFolderRepository( + foldersCache, + createFolderGateway + ); + + const repository = new CreateFolderRepositoryWithLoading( + loadingRepository, + createFolderRepository + ); + return repository.execute(folder); + }, + [client, foldersCache, loadingRepository] + ); + + // Update + const updateFolder = useCallback( + (folder: FolderItem) => { + const updateFolderGateway = new UpdateFolderGraphQLGateway(client); + const updateFolderRepository = new UpdateFolderRepository( + foldersCache, + updateFolderGateway + ); + + const repository = new UpdateFolderRepositoryWithLoading( + loadingRepository, + updateFolderRepository + ); + return repository.execute(folder); + }, + [client, foldersCache, loadingRepository] + ); + + // Delete + const deleteFolder = useCallback( + (folder: FolderItem) => { + const deleteFolderGateway = new DeleteFolderGraphQLGateway(client); + const deleteFolderRepository = new DeleteFolderRepository( + foldersCache, + deleteFolderGateway + ); + + const repository = new DeleteFolderRepositoryWithLoading( + loadingRepository, + deleteFolderRepository + ); + return repository.execute(folder); + }, + [client, foldersCache, loadingRepository] + ); + + const { folderLevelPermissions } = foldersContext; useEffect(() => { /** @@ -18,23 +168,42 @@ export const useFolders = () => { * fetch the outdated list from Apollo Cache. Since the state is managed locally, we fetch the folders only * at the first mount. */ - if (folders) { + if (vm.folders) { return; } listFolders(); }, []); - return useMemo( - () => ({ - /** - * NOTE: do NOT expose listFolders from this hook, because you already have folders in the `folders` property. - * You'll never need to call `listFolders` from any component. As soon as you call `useFolders()`, you'll initiate - * fetching of `folders`, which is managed by the FoldersContext. - */ - loading, - folders, - ...other - }), - [folders, loading] - ); + useEffect(() => { + return autorun(() => { + const mapper = new FolderMapper(); + + setVm(vm => ({ + ...vm, + folders: foldersCache.getItems().map(folder => mapper.toDTO(folder)) + })); + }); + }, [foldersCache]); + + useEffect(() => { + return autorun(() => { + setVm(vm => ({ + ...vm, + loading: loadingRepository.get() + })); + }); + }, [loadingRepository]); + + return { + ...vm, + listFolders, + getFolder, + getDescendantFolders, + createFolder, + updateFolder, + deleteFolder, + + // OLD + folderLevelPermissions + }; }; diff --git a/packages/app-aco/src/types.ts b/packages/app-aco/src/types.ts index 9b64ff29f4c..15e5f876592 100644 --- a/packages/app-aco/src/types.ts +++ b/packages/app-aco/src/types.ts @@ -4,7 +4,6 @@ import { CmsModelField, CmsModelFieldSettings } from "@webiny/app-headless-cms-common/types"; -import { FolderDTO } from "~/Domain/Models"; export { CmsIdentity } from "@webiny/app-headless-cms-common/types"; export * from "~/graphql/records/types"; @@ -103,16 +102,6 @@ export interface ListFoldersResponse { }; } -// ListFoldersResponse - FTA -export interface ListFoldersFtaResponse { - aco: { - listFolders: { - data: FolderDTO[] | null; - error: AcoError | null; - }; - }; -} - export interface ListFoldersQueryVariables { type: string; limit: number; @@ -129,16 +118,6 @@ export interface GetFolderResponse { }; } -// GetFolderResponse - FTA -export interface GetFolderFtaResponse { - aco: { - getFolder: { - data: FolderDTO | null; - error: AcoError | null; - }; - }; -} - export interface GetFolderQueryVariables { id: string; } @@ -152,16 +131,6 @@ export interface UpdateFolderResponse { }; } -// UpdateFolderResponse - FTA -export interface UpdateFolderFtaResponse { - aco: { - updateFolder: { - data: FolderDTO; - error: AcoError | null; - }; - }; -} - export interface UpdateFolderVariables { id: string; data: Partial< @@ -172,17 +141,6 @@ export interface UpdateFolderVariables { >; } -// UpdateFolderVariables - FTA -export interface UpdateFolderFtaVariables { - id: string; - data: Partial< - Omit< - FolderDTO, - "id" | "createdOn" | "createdBy" | "savedOn" | "savedBy" | "modifiedOn" | "modifiedBy" - > - >; -} - export interface CreateFolderResponse { aco: { createFolder: { @@ -192,16 +150,6 @@ export interface CreateFolderResponse { }; } -// CreateFolderResponse - FTA -export interface CreateFolderFtaResponse { - aco: { - createFolder: { - data: FolderDTO; - error: AcoError | null; - }; - }; -} - export interface CreateFolderVariables { data: Omit< FolderItem, @@ -209,14 +157,6 @@ export interface CreateFolderVariables { >; } -// CreateFolderVariables - FTA -export interface CreateFolderFtaVariables { - data: Omit< - FolderDTO | FolderItem, - "id" | "createdOn" | "createdBy" | "savedOn" | "savedBy" | "modifiedOn" | "modifiedBy" - >; -} - export interface DeleteFolderVariables { id: string; } From ea0e4d5037278f7630e0d6c3132a331d4399944b Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Tue, 27 Aug 2024 05:29:51 +0200 Subject: [PATCH 03/28] refactor(app-aco): implement useCase and controller layers --- .../src/Domain/Models/Folder/Folder.ts | 62 ------------ .../src/Domain/Models/Folder/FolderMapper.ts | 27 +++--- .../src/Domain/Models/Folder/IFolderMapper.ts | 4 +- .../app-aco/src/Domain/Models/Folder/index.ts | 1 - .../ListFolders/IListFoldersRepository.ts | 3 - .../UpdateFolder/IUpdateFolderRepository.ts | 5 - .../app-aco/src/Domain/Repositories/index.ts | 1 - .../CreateFolder/ICreateFolderGateway.ts | 5 - .../Gateways/Folders/CreateFolder/index.ts | 2 - .../UpdateFolder/IUpdateFolderGateway.ts | 5 - .../Gateways/Folders/UpdateFolder/index.ts | 2 - packages/app-aco/src/Gateways/index.ts | 1 - .../src/components/FolderTree/List/index.tsx | 11 +-- .../src/dialogs/useSetPermissionsDialog.tsx | 2 +- .../Caches => folders/cache}/FoldersCache.ts | 2 +- .../cache}/FoldersCacheFactory.ts | 2 +- .../Caches => folders/cache}/ICache.ts | 0 .../{Domain/Caches => folders/cache}/index.ts | 2 +- .../CreateFolder/CreateFolderController.ts | 22 +++++ .../CreateFolder/ICreateFolderController.ts | 5 + .../folders/controllers/CreateFolder/index.ts | 2 + .../DeleteFolder/DeleteFolderController.ts | 15 +++ .../DeleteFolder/IDeleteFolderController.ts} | 2 +- .../folders/controllers/DeleteFolder/index.ts | 2 + .../GetFolder/GetFolderController.ts | 14 +++ .../GetFolder/IGetFolderController.ts | 3 + .../folders/controllers/GetFolder/index.ts | 2 + .../ListFolders/IListFoldersController.ts | 3 + .../ListFolders/ListFoldersController.ts | 14 +++ .../folders/controllers/ListFolders/index.ts | 2 + .../UpdateFolder/IUpdateFolderController.ts} | 2 +- .../UpdateFolder/UpdateFolderController.ts | 22 +++++ .../folders/controllers/UpdateFolder/index.ts | 2 + .../Folders => folders/controllers}/index.ts | 0 packages/app-aco/src/folders/domain/Folder.ts | 62 ++++++++++++ packages/app-aco/src/folders/domain/index.ts | 1 + .../CreateFolderGraphQLGateway.ts | 9 +- .../CreateFolder/CreateFolderGraphQLMapper.ts | 14 +++ .../CreateFolder/ICreateFolderGateway.ts | 6 ++ .../ICreateFolderGraphQLMapper.ts | 14 +++ .../folders/gateways/CreateFolder/index.ts | 4 + .../DeleteFolderGraphQLGateway.ts | 0 .../DeleteFolder/IDeleteFolderGateway.ts | 0 .../gateways}/DeleteFolder/index.ts | 0 .../GetFolder/GetFolderGraphQLGateway.ts | 0 .../gateways}/GetFolder/IGetFolderGateway.ts | 0 .../gateways}/GetFolder/index.ts | 0 .../ListFolders/IListFoldersGateway.ts | 0 .../ListFolders/ListFoldersGraphQLGateway.ts | 0 .../gateways}/ListFolders/index.ts | 0 .../UpdateFolder/IUpdateFolderGateway.ts | 6 ++ .../IUpdateFolderGraphQLMapper.ts | 14 +++ .../UpdateFolderGraphQLGateway.ts | 10 +- .../UpdateFolder/UpdateFolderGraphQLMapper.ts | 14 +++ .../folders/gateways/UpdateFolder/index.ts | 4 + .../app-aco/src/folders/gateways/index.ts | 5 + packages/app-aco/src/folders/index.ts | 5 + .../CreateFolder/CreateFolderRepository.ts | 12 +-- .../CreateFolderRepositoryWithLoading.ts | 9 +- .../CreateFolder/ICreateFolderRepository.ts | 5 + .../repositories}/CreateFolder/index.ts | 0 .../DeleteFolder/DeleteFolderRepository.ts | 11 +-- .../DeleteFolderRepositoryWithLoading.ts | 10 +- .../DeleteFolder/IDeleteFolderRepository.ts | 3 + .../repositories}/DeleteFolder/index.ts | 0 .../GetDescendantFoldersRepository.ts | 13 +-- .../IGetDescendantFoldersRepository.ts | 2 +- .../GetDescendantFolders/index.ts | 0 .../GetFolder/GetFolderRepository.ts | 6 +- .../GetFolderRepositoryWithLoading.ts | 4 +- .../GetFolder/IGetFolderRepository.ts | 0 .../repositories}/GetFolder/index.ts | 0 .../ListFolders/IListFoldersRepository.ts | 3 + .../ListFolders/ListFoldersRepository.ts | 14 ++- .../ListFoldersRepositoryWithLoading.ts | 8 +- .../repositories}/ListFolders/index.ts | 0 .../UpdateFolder/IUpdateFolderRepository.ts | 5 + .../UpdateFolder/UpdateFolderRepository.ts | 12 +-- .../UpdateFolderRepositoryWithLoading.ts | 8 +- .../repositories}/UpdateFolder/index.ts | 0 .../Folders => folders/repositories}/index.ts | 0 .../CreateFolder/CreateFolderUseCase.ts | 23 +++++ .../CreateFolder/ICreateFolderUseCase.ts | 13 +++ .../folders/useCases/CreateFolder/index.ts | 2 + .../DeleteFolder/DeleteFolderUseCase.ts | 14 +++ .../DeleteFolder/IDeleteFolderUseCase.ts | 7 ++ .../folders/useCases/DeleteFolder/index.ts | 2 + .../useCases/GetFolder/GetFolderUseCase.ts | 14 +++ .../useCases/GetFolder/IGetFolderUseCase.ts | 7 ++ .../src/folders/useCases/GetFolder/index.ts | 2 + .../ListFolders/IListFoldersUseCase.ts | 7 ++ .../ListFolders/ListFoldersUseCase.ts | 14 +++ .../src/folders/useCases/ListFolders/index.ts | 2 + .../UpdateFolder/IUpdateFolderUseCase.ts | 14 +++ .../UpdateFolder/UpdateFolderUseCase.ts | 24 +++++ .../folders/useCases/UpdateFolder/index.ts | 2 + .../app-aco/src/folders/useCases/index.ts | 5 + packages/app-aco/src/hooks/useFolders.ts | 95 +++++++++++-------- packages/app-aco/src/types.ts | 12 ++- 99 files changed, 574 insertions(+), 227 deletions(-) delete mode 100644 packages/app-aco/src/Domain/Models/Folder/Folder.ts delete mode 100644 packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts delete mode 100644 packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts delete mode 100644 packages/app-aco/src/Domain/Repositories/index.ts delete mode 100644 packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts delete mode 100644 packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts delete mode 100644 packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts delete mode 100644 packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts delete mode 100644 packages/app-aco/src/Gateways/index.ts rename packages/app-aco/src/{Domain/Caches => folders/cache}/FoldersCache.ts (95%) rename packages/app-aco/src/{Domain/Caches => folders/cache}/FoldersCacheFactory.ts (89%) rename packages/app-aco/src/{Domain/Caches => folders/cache}/ICache.ts (100%) rename packages/app-aco/src/{Domain/Caches => folders/cache}/index.ts (100%) create mode 100644 packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts create mode 100644 packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts create mode 100644 packages/app-aco/src/folders/controllers/CreateFolder/index.ts create mode 100644 packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts rename packages/app-aco/src/{Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts => folders/controllers/DeleteFolder/IDeleteFolderController.ts} (68%) create mode 100644 packages/app-aco/src/folders/controllers/DeleteFolder/index.ts create mode 100644 packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts create mode 100644 packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts create mode 100644 packages/app-aco/src/folders/controllers/GetFolder/index.ts create mode 100644 packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts create mode 100644 packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts create mode 100644 packages/app-aco/src/folders/controllers/ListFolders/index.ts rename packages/app-aco/src/{Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts => folders/controllers/UpdateFolder/IUpdateFolderController.ts} (68%) create mode 100644 packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts create mode 100644 packages/app-aco/src/folders/controllers/UpdateFolder/index.ts rename packages/app-aco/src/{Gateways/Folders => folders/controllers}/index.ts (100%) create mode 100644 packages/app-aco/src/folders/domain/Folder.ts create mode 100644 packages/app-aco/src/folders/domain/index.ts rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/CreateFolder/CreateFolderGraphQLGateway.ts (77%) create mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts create mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts create mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts create mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/index.ts rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/DeleteFolder/DeleteFolderGraphQLGateway.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/DeleteFolder/IDeleteFolderGateway.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/DeleteFolder/index.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/GetFolder/GetFolderGraphQLGateway.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/GetFolder/IGetFolderGateway.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/GetFolder/index.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/ListFolders/IListFoldersGateway.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/ListFolders/ListFoldersGraphQLGateway.ts (100%) rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/ListFolders/index.ts (100%) create mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts create mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts rename packages/app-aco/src/{Gateways/Folders => folders/gateways}/UpdateFolder/UpdateFolderGraphQLGateway.ts (73%) create mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts create mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/index.ts create mode 100644 packages/app-aco/src/folders/gateways/index.ts create mode 100644 packages/app-aco/src/folders/index.ts rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/CreateFolder/CreateFolderRepository.ts (54%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/CreateFolder/CreateFolderRepositoryWithLoading.ts (73%) create mode 100644 packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/CreateFolder/index.ts (100%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/DeleteFolder/DeleteFolderRepository.ts (57%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/DeleteFolder/DeleteFolderRepositoryWithLoading.ts (67%) create mode 100644 packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/DeleteFolder/index.ts (100%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetDescendantFolders/GetDescendantFoldersRepository.ts (75%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetDescendantFolders/IGetDescendantFoldersRepository.ts (68%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetDescendantFolders/index.ts (100%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetFolder/GetFolderRepository.ts (76%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetFolder/GetFolderRepositoryWithLoading.ts (83%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetFolder/IGetFolderRepository.ts (100%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/GetFolder/index.ts (100%) create mode 100644 packages/app-aco/src/folders/repositories/ListFolders/IListFoldersRepository.ts rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/ListFolders/ListFoldersRepository.ts (50%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/ListFolders/ListFoldersRepositoryWithLoading.ts (75%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/ListFolders/index.ts (100%) create mode 100644 packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/UpdateFolder/UpdateFolderRepository.ts (55%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/UpdateFolder/UpdateFolderRepositoryWithLoading.ts (76%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/UpdateFolder/index.ts (100%) rename packages/app-aco/src/{Domain/Repositories/Folders => folders/repositories}/index.ts (100%) create mode 100644 packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/CreateFolder/ICreateFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/CreateFolder/index.ts create mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/index.ts create mode 100644 packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/GetFolder/IGetFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/GetFolder/index.ts create mode 100644 packages/app-aco/src/folders/useCases/ListFolders/IListFoldersUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/ListFolders/index.ts create mode 100644 packages/app-aco/src/folders/useCases/UpdateFolder/IUpdateFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts create mode 100644 packages/app-aco/src/folders/useCases/UpdateFolder/index.ts create mode 100644 packages/app-aco/src/folders/useCases/index.ts diff --git a/packages/app-aco/src/Domain/Models/Folder/Folder.ts b/packages/app-aco/src/Domain/Models/Folder/Folder.ts deleted file mode 100644 index da7fab2e2e8..00000000000 --- a/packages/app-aco/src/Domain/Models/Folder/Folder.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { CmsIdentity, FolderPermission, FolderItem } from "~/types"; - -// export interface FolderDTO { -// id: string; -// title: string; -// slug: string; -// type: string; -// parentId: string | null; -// createdBy: CmsIdentity; -// createdOn: string; -// savedBy: CmsIdentity; -// savedOn: string; -// modifiedBy: CmsIdentity | null; -// modifiedOn: string | null; -// permissions: FolderPermission[]; -// hasNonInheritedPermissions: boolean; -// canManagePermissions: boolean; -// canManageStructure: boolean; -// canManageContent: boolean; -// } - -export class Folder { - public id: string; - public title: string; - public slug: string; - public type: string; - public parentId: string | null; - public createdBy: CmsIdentity; - public createdOn: string; - public savedBy: CmsIdentity; - public savedOn: string; - public modifiedBy: CmsIdentity | null; - public modifiedOn: string | null; - public permissions: FolderPermission[]; - public hasNonInheritedPermissions: boolean; - public canManagePermissions: boolean; - public canManageStructure: boolean; - public canManageContent: boolean; - - protected constructor(folder: FolderItem) { - this.id = folder.id; - this.title = folder.title; - this.slug = folder.slug; - this.type = folder.type; - this.parentId = folder.parentId; - this.createdBy = folder.createdBy; - this.createdOn = folder.createdOn; - this.savedBy = folder.savedBy; - this.savedOn = folder.savedOn; - this.modifiedBy = folder.modifiedBy; - this.modifiedOn = folder.modifiedOn; - this.permissions = folder.permissions; - this.hasNonInheritedPermissions = folder.hasNonInheritedPermissions; - this.canManagePermissions = folder.canManagePermissions; - this.canManageStructure = folder.canManageStructure; - this.canManageContent = folder.canManageContent; - } - - static create(folder: FolderItem) { - return new Folder(folder); - } -} diff --git a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts index b041406be61..fbc0359f45b 100644 --- a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts +++ b/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts @@ -1,27 +1,26 @@ -import { Folder } from "./Folder"; import { IFolderMapper } from "./IFolderMapper"; +import { ROOT_FOLDER } from "~/constants"; +import { Folder } from "~/folders/domain"; export class FolderMapper implements IFolderMapper { toDTO(folder: Folder) { - console.log("FolderMapper", folder); - return { id: folder.id, title: folder.title, slug: folder.slug, type: folder.type, - parentId: folder.parentId || "root", - createdBy: folder.createdBy, - createdOn: folder.createdOn, - savedBy: folder.savedBy, - savedOn: folder.savedOn, - modifiedBy: folder.modifiedBy, - modifiedOn: folder.modifiedOn, + parentId: folder.parentId ?? ROOT_FOLDER, permissions: folder.permissions, - hasNonInheritedPermissions: folder.hasNonInheritedPermissions, - canManagePermissions: folder.canManagePermissions, - canManageStructure: folder.canManageStructure, - canManageContent: folder.canManageContent + hasNonInheritedPermissions: folder.hasNonInheritedPermissions ?? false, + canManagePermissions: folder.canManagePermissions ?? false, + canManageStructure: folder.canManageStructure ?? false, + canManageContent: folder.canManageContent ?? false, + createdBy: folder.createdBy ?? { id: "", type: "", displayName: "" }, + createdOn: folder.createdOn ?? "", + savedBy: folder.savedBy ?? { id: "", type: "", displayName: "" }, + savedOn: folder.savedOn ?? "", + modifiedBy: folder.modifiedBy ?? null, + modifiedOn: folder.modifiedOn ?? null }; } } diff --git a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts index 8ffe13c8009..492257cf13d 100644 --- a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts +++ b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts @@ -1,6 +1,6 @@ -import { Folder } from "./Folder"; +import { Folder } from "~/folders/domain"; import { FolderItem } from "~/types"; export interface IFolderMapper { - toDTO: (folder: Folder | FolderItem) => FolderItem; + toDTO: (folder: Folder) => FolderItem; } diff --git a/packages/app-aco/src/Domain/Models/Folder/index.ts b/packages/app-aco/src/Domain/Models/Folder/index.ts index efb55b7bcdb..09f3ac0eae3 100644 --- a/packages/app-aco/src/Domain/Models/Folder/index.ts +++ b/packages/app-aco/src/Domain/Models/Folder/index.ts @@ -1,3 +1,2 @@ -export * from "./Folder"; export * from "./FolderMapper"; export * from "./IFolderMapper"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts deleted file mode 100644 index f9aedf93d50..00000000000 --- a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/IListFoldersRepository.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IListFoldersRepository { - execute: () => Promise; -} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts b/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts deleted file mode 100644 index ff52c961f6e..00000000000 --- a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/IUpdateFolderRepository.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface IUpdateFolderRepository { - execute: (folder: FolderItem) => Promise; -} diff --git a/packages/app-aco/src/Domain/Repositories/index.ts b/packages/app-aco/src/Domain/Repositories/index.ts deleted file mode 100644 index 3d7438e1836..00000000000 --- a/packages/app-aco/src/Domain/Repositories/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Folders"; diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts deleted file mode 100644 index 903829b0f0a..00000000000 --- a/packages/app-aco/src/Gateways/Folders/CreateFolder/ICreateFolderGateway.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface ICreateFolderGateway { - execute: (folder: FolderItem) => Promise; -} diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts b/packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts deleted file mode 100644 index f2607ede986..00000000000 --- a/packages/app-aco/src/Gateways/Folders/CreateFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./CreateFolderGraphQLGateway"; -export * from "./ICreateFolderGateway"; diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts deleted file mode 100644 index 23df5ff7aee..00000000000 --- a/packages/app-aco/src/Gateways/Folders/UpdateFolder/IUpdateFolderGateway.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface IUpdateFolderGateway { - execute: (folder: FolderItem) => Promise; -} diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts b/packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts deleted file mode 100644 index bb669f4cf25..00000000000 --- a/packages/app-aco/src/Gateways/Folders/UpdateFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./IUpdateFolderGateway"; -export * from "./UpdateFolderGraphQLGateway"; diff --git a/packages/app-aco/src/Gateways/index.ts b/packages/app-aco/src/Gateways/index.ts deleted file mode 100644 index 3d7438e1836..00000000000 --- a/packages/app-aco/src/Gateways/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Folders"; diff --git a/packages/app-aco/src/components/FolderTree/List/index.tsx b/packages/app-aco/src/components/FolderTree/List/index.tsx index 627035ca5ad..c0f244c242a 100644 --- a/packages/app-aco/src/components/FolderTree/List/index.tsx +++ b/packages/app-aco/src/components/FolderTree/List/index.tsx @@ -65,13 +65,10 @@ export const List = ({ setTreeData(newTree); - await updateFolder( - { - ...item, - parentId: dropTargetId !== ROOT_FOLDER ? (dropTargetId as string) : null - }, - { refetchFoldersList: true } - ); + await updateFolder({ + ...item, + parentId: dropTargetId !== ROOT_FOLDER ? (dropTargetId as string) : null + }); } catch (error) { return showSnackbar(error.message); } diff --git a/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx b/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx index 352414caa24..8758d00bc74 100644 --- a/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx +++ b/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx @@ -122,7 +122,7 @@ export const useSetPermissionsDialog = (): UseSetPermissionsDialogResponse => { const updateData = { ...folder, ...data }; try { - await updateFolder(updateData, { refetchFoldersList: true }); + await updateFolder(updateData); showSnackbar("Folder permissions updated successfully!"); } catch (error) { showSnackbar(error.message); diff --git a/packages/app-aco/src/Domain/Caches/FoldersCache.ts b/packages/app-aco/src/folders/cache/FoldersCache.ts similarity index 95% rename from packages/app-aco/src/Domain/Caches/FoldersCache.ts rename to packages/app-aco/src/folders/cache/FoldersCache.ts index 64162a92b4d..6e1f6f8f5af 100644 --- a/packages/app-aco/src/Domain/Caches/FoldersCache.ts +++ b/packages/app-aco/src/folders/cache/FoldersCache.ts @@ -1,6 +1,6 @@ import { makeAutoObservable } from "mobx"; +import { Folder } from "~/folders/domain"; import { ICache } from "./ICache"; -import { Folder } from "~/Domain/Models"; export class FoldersCache implements ICache { private folders: Folder[]; diff --git a/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts b/packages/app-aco/src/folders/cache/FoldersCacheFactory.ts similarity index 89% rename from packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts rename to packages/app-aco/src/folders/cache/FoldersCacheFactory.ts index 153037a3269..dfda95e49df 100644 --- a/packages/app-aco/src/Domain/Caches/FoldersCacheFactory.ts +++ b/packages/app-aco/src/folders/cache/FoldersCacheFactory.ts @@ -1,4 +1,4 @@ -import { FoldersCache } from "~/Domain/Caches/FoldersCache"; +import { FoldersCache } from "./FoldersCache"; export class FoldersCacheFactory { private cache: Map = new Map(); diff --git a/packages/app-aco/src/Domain/Caches/ICache.ts b/packages/app-aco/src/folders/cache/ICache.ts similarity index 100% rename from packages/app-aco/src/Domain/Caches/ICache.ts rename to packages/app-aco/src/folders/cache/ICache.ts diff --git a/packages/app-aco/src/Domain/Caches/index.ts b/packages/app-aco/src/folders/cache/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Caches/index.ts rename to packages/app-aco/src/folders/cache/index.ts index 84d81e89572..bc66ba6e954 100644 --- a/packages/app-aco/src/Domain/Caches/index.ts +++ b/packages/app-aco/src/folders/cache/index.ts @@ -1,3 +1,3 @@ -export * from "./ICache"; export * from "./FoldersCache"; export * from "./FoldersCacheFactory"; +export * from "./ICache"; diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts b/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts new file mode 100644 index 00000000000..6bd350873e2 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts @@ -0,0 +1,22 @@ +import { ICreateFolderController } from "./ICreateFolderController"; +import { ICreateFolderUseCase } from "~/folders/useCases"; +import { FolderItem } from "~/types"; + +export class CreateFolderController implements ICreateFolderController { + private useCase: ICreateFolderUseCase; + + constructor(useCase: ICreateFolderUseCase) { + this.useCase = useCase; + } + + async execute(folder: FolderItem, type: string) { + console.log("type", type); + await this.useCase.execute({ + type: type, + title: folder.title, + slug: folder.slug, + parentId: folder.parentId, + permissions: folder.permissions + }); + } +} diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts b/packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts new file mode 100644 index 00000000000..9ca9dba8d7d --- /dev/null +++ b/packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts @@ -0,0 +1,5 @@ +import { FolderItem } from "~/types"; + +export interface ICreateFolderController { + execute: (folder: FolderItem, type: string) => Promise; +} diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/index.ts b/packages/app-aco/src/folders/controllers/CreateFolder/index.ts new file mode 100644 index 00000000000..3126f8fa4eb --- /dev/null +++ b/packages/app-aco/src/folders/controllers/CreateFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./CreateFolderController"; +export * from "./ICreateFolderController"; diff --git a/packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts b/packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts new file mode 100644 index 00000000000..9f17a5247f0 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts @@ -0,0 +1,15 @@ +import { IDeleteFolderController } from "./IDeleteFolderController"; +import { IDeleteFolderUseCase } from "~/folders/useCases"; +import { FolderItem } from "~/types"; + +export class DeleteFolderController implements IDeleteFolderController { + private useCase: IDeleteFolderUseCase; + + constructor(useCase: IDeleteFolderUseCase) { + this.useCase = useCase; + } + + async execute(folder: FolderItem) { + await this.useCase.execute({ id: folder.id }); + } +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts b/packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts similarity index 68% rename from packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts rename to packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts index 58ec48040d4..b7801538100 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/ICreateFolderRepository.ts +++ b/packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts @@ -1,5 +1,5 @@ import { FolderItem } from "~/types"; -export interface ICreateFolderRepository { +export interface IDeleteFolderController { execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/folders/controllers/DeleteFolder/index.ts b/packages/app-aco/src/folders/controllers/DeleteFolder/index.ts new file mode 100644 index 00000000000..99b8b6a43a1 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/DeleteFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./DeleteFolderController"; +export * from "./IDeleteFolderController"; diff --git a/packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts b/packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts new file mode 100644 index 00000000000..cdd4770fc6e --- /dev/null +++ b/packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts @@ -0,0 +1,14 @@ +import { IGetFolderController } from "./IGetFolderController"; +import { IGetFolderUseCase } from "~/folders/useCases"; + +export class GetFolderController implements IGetFolderController { + private useCase: IGetFolderUseCase; + + constructor(useCase: IGetFolderUseCase) { + this.useCase = useCase; + } + + async execute(id: string) { + await this.useCase.execute({ id }); + } +} diff --git a/packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts b/packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts new file mode 100644 index 00000000000..13dd7db6a80 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts @@ -0,0 +1,3 @@ +export interface IGetFolderController { + execute: (id: string) => Promise; +} diff --git a/packages/app-aco/src/folders/controllers/GetFolder/index.ts b/packages/app-aco/src/folders/controllers/GetFolder/index.ts new file mode 100644 index 00000000000..dbe12140495 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/GetFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./GetFolderController"; +export * from "./IGetFolderController"; diff --git a/packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts b/packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts new file mode 100644 index 00000000000..5bc07d1d8ae --- /dev/null +++ b/packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts @@ -0,0 +1,3 @@ +export interface IListFoldersController { + execute: (type: string) => Promise; +} diff --git a/packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts b/packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts new file mode 100644 index 00000000000..1d0b778f679 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts @@ -0,0 +1,14 @@ +import { IListFoldersController } from "./IListFoldersController"; +import { IListFoldersUseCase } from "~/folders/useCases"; + +export class ListFoldersController implements IListFoldersController { + private useCase: IListFoldersUseCase; + + constructor(useCase: IListFoldersUseCase) { + this.useCase = useCase; + } + + async execute(type: string): Promise { + await this.useCase.execute({ type }); + } +} diff --git a/packages/app-aco/src/folders/controllers/ListFolders/index.ts b/packages/app-aco/src/folders/controllers/ListFolders/index.ts new file mode 100644 index 00000000000..a9fb92708d0 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/ListFolders/index.ts @@ -0,0 +1,2 @@ +export * from "./IListFoldersController"; +export * from "./ListFoldersController"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts b/packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts similarity index 68% rename from packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts rename to packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts index c7154e48e70..fdb3c429b00 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/IDeleteFolderRepository.ts +++ b/packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts @@ -1,5 +1,5 @@ import { FolderItem } from "~/types"; -export interface IDeleteFolderRepository { +export interface IUpdateFolderController { execute: (folder: FolderItem) => Promise; } diff --git a/packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts b/packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts new file mode 100644 index 00000000000..b162ba63b1a --- /dev/null +++ b/packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts @@ -0,0 +1,22 @@ +import { IUpdateFolderController } from "./IUpdateFolderController"; +import { IUpdateFolderUseCase } from "~/folders/useCases"; +import { FolderItem } from "~/types"; + +export class UpdateFolderController implements IUpdateFolderController { + private useCase: IUpdateFolderUseCase; + + constructor(useCase: IUpdateFolderUseCase) { + this.useCase = useCase; + } + + async execute(folder: FolderItem) { + await this.useCase.execute({ + id: folder.id, + title: folder.title, + slug: folder.slug, + type: folder.type, + parentId: folder.parentId, + permissions: folder.permissions + }); + } +} diff --git a/packages/app-aco/src/folders/controllers/UpdateFolder/index.ts b/packages/app-aco/src/folders/controllers/UpdateFolder/index.ts new file mode 100644 index 00000000000..72ff9f02928 --- /dev/null +++ b/packages/app-aco/src/folders/controllers/UpdateFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./IUpdateFolderController"; +export * from "./UpdateFolderController"; diff --git a/packages/app-aco/src/Gateways/Folders/index.ts b/packages/app-aco/src/folders/controllers/index.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/index.ts rename to packages/app-aco/src/folders/controllers/index.ts diff --git a/packages/app-aco/src/folders/domain/Folder.ts b/packages/app-aco/src/folders/domain/Folder.ts new file mode 100644 index 00000000000..23abccd015d --- /dev/null +++ b/packages/app-aco/src/folders/domain/Folder.ts @@ -0,0 +1,62 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderData { + id?: string; + title: string; + slug: string; + type: string; + parentId: string | null; + permissions: FolderPermission[]; + hasNonInheritedPermissions?: boolean; + canManagePermissions?: boolean; + canManageStructure?: boolean; + canManageContent?: boolean; + createdBy?: CmsIdentity; + createdOn?: string; + savedBy?: CmsIdentity; + savedOn?: string; + modifiedBy?: CmsIdentity | null; + modifiedOn?: string | null; +} + +export class Folder { + public id: string; + public title: string; + public slug: string; + public type: string; + public parentId: string | null; + public permissions: FolderPermission[]; + public hasNonInheritedPermissions?: boolean; + public canManagePermissions?: boolean; + public canManageStructure?: boolean; + public canManageContent?: boolean; + public createdBy?: CmsIdentity; + public createdOn?: string; + public savedBy?: CmsIdentity; + public savedOn?: string; + public modifiedBy?: CmsIdentity | null; + public modifiedOn?: string | null; + + protected constructor(folder: FolderData) { + this.id = folder.id ?? ""; + this.title = folder.title; + this.slug = folder.slug; + this.type = folder.type; + this.parentId = folder.parentId; + this.permissions = folder.permissions; + this.hasNonInheritedPermissions = folder.hasNonInheritedPermissions; + this.canManagePermissions = folder.canManagePermissions; + this.canManageStructure = folder.canManageStructure; + this.canManageContent = folder.canManageContent; + this.createdBy = folder.createdBy; + this.createdOn = folder.createdOn; + this.savedBy = folder.savedBy; + this.savedOn = folder.savedOn; + this.modifiedBy = folder.modifiedBy; + this.modifiedOn = folder.modifiedOn; + } + + static create(folder: FolderData) { + return new Folder(folder); + } +} diff --git a/packages/app-aco/src/folders/domain/index.ts b/packages/app-aco/src/folders/domain/index.ts new file mode 100644 index 00000000000..b6ab82d77ce --- /dev/null +++ b/packages/app-aco/src/folders/domain/index.ts @@ -0,0 +1 @@ +export * from "./Folder"; diff --git a/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts similarity index 77% rename from packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts rename to packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts index 12b2288db44..cfe50984d6d 100644 --- a/packages/app-aco/src/Gateways/Folders/CreateFolder/CreateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts @@ -1,7 +1,8 @@ import { ApolloClient } from "apollo-client"; import { ICreateFolderGateway } from "./ICreateFolderGateway"; import { CREATE_FOLDER } from "~/graphql/folders.gql"; -import { CreateFolderResponse, CreateFolderVariables, FolderItem } from "~/types"; +import { CreateFolderResponse, CreateFolderVariables } from "~/types"; +import { CreateFolderGraphQLDTO } from "./ICreateFolderGraphQLMapper"; export class CreateFolderGraphQLGateway implements ICreateFolderGateway { private client: ApolloClient; @@ -10,14 +11,16 @@ export class CreateFolderGraphQLGateway implements ICreateFolderGateway { this.client = client; } - async execute(folder: FolderItem) { + async execute(folder: CreateFolderGraphQLDTO) { const { data: response } = await this.client.mutate< CreateFolderResponse, CreateFolderVariables >({ mutation: CREATE_FOLDER, variables: { - data: folder + data: { + ...folder + } } }); diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts new file mode 100644 index 00000000000..1d9f56cd406 --- /dev/null +++ b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts @@ -0,0 +1,14 @@ +import { Folder } from "~/folders/domain"; +import { ICreateFolderGraphQLMapper } from "./ICreateFolderGraphQLMapper"; + +export class CreateFolderGraphQLMapper implements ICreateFolderGraphQLMapper { + toGraphQLDTO(folder: Folder) { + return { + title: folder.title, + slug: folder.slug, + permissions: folder.permissions, + parentId: folder.parentId, + type: folder.type + }; + } +} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts b/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts new file mode 100644 index 00000000000..0b17a191e7a --- /dev/null +++ b/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts @@ -0,0 +1,6 @@ +import { CreateFolderGraphQLDTO } from "./ICreateFolderGraphQLMapper"; +import { FolderItem } from "~/types"; + +export interface ICreateFolderGateway { + execute: (folderDTO: CreateFolderGraphQLDTO) => Promise; +} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts new file mode 100644 index 00000000000..f098016171a --- /dev/null +++ b/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts @@ -0,0 +1,14 @@ +import { Folder } from "~/folders/domain"; +import { FolderPermission } from "~/types"; + +export interface CreateFolderGraphQLDTO { + title: string; + slug: string; + permissions: FolderPermission[]; + type: string; + parentId: string | null; +} + +export interface ICreateFolderGraphQLMapper { + toGraphQLDTO: (folder: Folder) => CreateFolderGraphQLDTO; +} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/index.ts b/packages/app-aco/src/folders/gateways/CreateFolder/index.ts new file mode 100644 index 00000000000..e04cc59a9b7 --- /dev/null +++ b/packages/app-aco/src/folders/gateways/CreateFolder/index.ts @@ -0,0 +1,4 @@ +export * from "./CreateFolderGraphQLGateway"; +export * from "./CreateFolderGraphQLMapper"; +export * from "./ICreateFolderGateway"; +export * from "./ICreateFolderGraphQLMapper"; diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/DeleteFolder/DeleteFolderGraphQLGateway.ts rename to packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/IDeleteFolderGateway.ts b/packages/app-aco/src/folders/gateways/DeleteFolder/IDeleteFolderGateway.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/DeleteFolder/IDeleteFolderGateway.ts rename to packages/app-aco/src/folders/gateways/DeleteFolder/IDeleteFolderGateway.ts diff --git a/packages/app-aco/src/Gateways/Folders/DeleteFolder/index.ts b/packages/app-aco/src/folders/gateways/DeleteFolder/index.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/DeleteFolder/index.ts rename to packages/app-aco/src/folders/gateways/DeleteFolder/index.ts diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/GetFolder/GetFolderGraphQLGateway.ts rename to packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts b/packages/app-aco/src/folders/gateways/GetFolder/IGetFolderGateway.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/GetFolder/IGetFolderGateway.ts rename to packages/app-aco/src/folders/gateways/GetFolder/IGetFolderGateway.ts diff --git a/packages/app-aco/src/Gateways/Folders/GetFolder/index.ts b/packages/app-aco/src/folders/gateways/GetFolder/index.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/GetFolder/index.ts rename to packages/app-aco/src/folders/gateways/GetFolder/index.ts diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts b/packages/app-aco/src/folders/gateways/ListFolders/IListFoldersGateway.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/ListFolders/IListFoldersGateway.ts rename to packages/app-aco/src/folders/gateways/ListFolders/IListFoldersGateway.ts diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/ListFolders/ListFoldersGraphQLGateway.ts rename to packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts diff --git a/packages/app-aco/src/Gateways/Folders/ListFolders/index.ts b/packages/app-aco/src/folders/gateways/ListFolders/index.ts similarity index 100% rename from packages/app-aco/src/Gateways/Folders/ListFolders/index.ts rename to packages/app-aco/src/folders/gateways/ListFolders/index.ts diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts new file mode 100644 index 00000000000..a813d4c95f3 --- /dev/null +++ b/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts @@ -0,0 +1,6 @@ +import { UpdateFolderGraphQLDTO } from "./IUpdateFolderGraphQLMapper"; +import { FolderItem } from "~/types"; + +export interface IUpdateFolderGateway { + execute: (folder: UpdateFolderGraphQLDTO) => Promise; +} diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts new file mode 100644 index 00000000000..1b9a1b9a57f --- /dev/null +++ b/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts @@ -0,0 +1,14 @@ +import { Folder } from "~/folders/domain"; +import { FolderPermission } from "~/types"; + +export interface UpdateFolderGraphQLDTO { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + parentId: string | null; +} + +export interface IUpdateFolderGraphQLMapper { + toGraphQLDTO: (folder: Folder) => UpdateFolderGraphQLDTO; +} diff --git a/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts similarity index 73% rename from packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts rename to packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts index 36a609a4d81..5e021290c4c 100644 --- a/packages/app-aco/src/Gateways/Folders/UpdateFolder/UpdateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts @@ -1,7 +1,9 @@ import { ApolloClient } from "apollo-client"; import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; import { UPDATE_FOLDER } from "~/graphql/folders.gql"; -import { FolderItem, UpdateFolderResponse, UpdateFolderVariables } from "~/types"; +import { UpdateFolderResponse, UpdateFolderVariables } from "~/types"; +import { ROOT_FOLDER } from "~/constants"; +import { UpdateFolderGraphQLDTO } from "./IUpdateFolderGraphQLMapper"; export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { private client: ApolloClient; @@ -10,7 +12,7 @@ export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { this.client = client; } - async execute(folder: FolderItem) { + async execute(folder: UpdateFolderGraphQLDTO) { const { id, title, slug, permissions, parentId } = folder; const { data: response } = await this.client.mutate< @@ -23,8 +25,8 @@ export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { data: { title, slug, - permissions, - parentId + parentId: parentId === ROOT_FOLDER ? null : parentId, + permissions: permissions.filter(p => !p.inheritedFrom) } } }); diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts new file mode 100644 index 00000000000..77132533922 --- /dev/null +++ b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts @@ -0,0 +1,14 @@ +import { Folder } from "~/folders/domain"; +import { IUpdateFolderGraphQLMapper } from "./IUpdateFolderGraphQLMapper"; + +export class UpdateFolderGraphQLMapper implements IUpdateFolderGraphQLMapper { + toGraphQLDTO(folder: Folder) { + return { + id: folder.id, + title: folder.title, + slug: folder.slug, + permissions: folder.permissions, + parentId: folder.parentId + }; + } +} diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/index.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/index.ts new file mode 100644 index 00000000000..e5f7f5f2aac --- /dev/null +++ b/packages/app-aco/src/folders/gateways/UpdateFolder/index.ts @@ -0,0 +1,4 @@ +export * from "./IUpdateFolderGateway"; +export * from "./IUpdateFolderGraphQLMapper"; +export * from "./UpdateFolderGraphQLGateway"; +export * from "./UpdateFolderGraphQLMapper"; diff --git a/packages/app-aco/src/folders/gateways/index.ts b/packages/app-aco/src/folders/gateways/index.ts new file mode 100644 index 00000000000..4e48864c20f --- /dev/null +++ b/packages/app-aco/src/folders/gateways/index.ts @@ -0,0 +1,5 @@ +export * from "./CreateFolder"; +export * from "./DeleteFolder"; +export * from "./GetFolder"; +export * from "./ListFolders"; +export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/folders/index.ts b/packages/app-aco/src/folders/index.ts new file mode 100644 index 00000000000..1c1f86daee7 --- /dev/null +++ b/packages/app-aco/src/folders/index.ts @@ -0,0 +1,5 @@ +export * from "./cache"; +export * from "./domain"; +export * from "./gateways"; +export * from "./repositories"; +export * from "./useCases"; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts b/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts similarity index 54% rename from packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts rename to packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts index d543177f78a..7a06963813b 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepository.ts +++ b/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts @@ -1,8 +1,7 @@ import { ICreateFolderRepository } from "./ICreateFolderRepository"; -import { ICreateFolderGateway } from "~/Gateways"; -import { Folder } from "~/Domain/Models"; -import { FoldersCache } from "~/Domain/Caches"; -import { FolderItem } from "~/types"; +import { Folder } from "~/folders/domain"; +import { CreateFolderGraphQLMapper, ICreateFolderGateway } from "~/folders/gateways"; +import { FoldersCache } from "~/folders/cache"; export class CreateFolderRepository implements ICreateFolderRepository { private cache: FoldersCache; @@ -13,8 +12,9 @@ export class CreateFolderRepository implements ICreateFolderRepository { this.gateway = gateway; } - async execute(folder: FolderItem) { - const response = await this.gateway.execute(folder); + async execute(folder: Folder) { + const mapper = new CreateFolderGraphQLMapper(); + const response = await this.gateway.execute(mapper.toGraphQLDTO(folder)); await this.cache.set(Folder.create(response)); } } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts similarity index 73% rename from packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts rename to packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts index 8122bd84539..2ed48c30af2 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/CreateFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts @@ -1,7 +1,7 @@ -import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; -import { ICreateFolderRepository } from "~/Domain/Repositories"; -import { FolderItem, LoadingActionsEnum } from "~/types"; +import { Folder } from "~/folders/domain"; +import { ICreateFolderRepository } from "~/folders/repositories"; +import { LoadingActionsEnum } from "~/types"; export class CreateFolderRepositoryWithLoading implements ICreateFolderRepository { private loadingRepository: ILoadingRepository; @@ -13,10 +13,9 @@ export class CreateFolderRepositoryWithLoading implements ICreateFolderRepositor ) { this.loadingRepository = loadingRepository; this.createFolderRepository = createFolderRepository; - makeAutoObservable(this); } - async execute(folder: FolderItem) { + async execute(folder: Folder) { await this.loadingRepository.runCallBack( this.createFolderRepository.execute(folder), LoadingActionsEnum.create diff --git a/packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts b/packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts new file mode 100644 index 00000000000..e00e31413ae --- /dev/null +++ b/packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts @@ -0,0 +1,5 @@ +import { Folder } from "~/folders/domain"; + +export interface ICreateFolderRepository { + execute: (folder: Folder) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/index.ts b/packages/app-aco/src/folders/repositories/CreateFolder/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/CreateFolder/index.ts rename to packages/app-aco/src/folders/repositories/CreateFolder/index.ts diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepository.ts similarity index 57% rename from packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts rename to packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepository.ts index 1228074b8dd..8ba1942e06d 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepository.ts +++ b/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepository.ts @@ -1,7 +1,6 @@ import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; -import { IDeleteFolderGateway } from "~/Gateways"; -import { FoldersCache } from "~/Domain/Caches"; -import { FolderItem } from "~/types"; +import { FoldersCache } from "~/folders/cache"; +import { IDeleteFolderGateway } from "~/folders/gateways"; export class DeleteFolderRepository implements IDeleteFolderRepository { private cache: FoldersCache; @@ -12,8 +11,8 @@ export class DeleteFolderRepository implements IDeleteFolderRepository { this.gateway = gateway; } - async execute(folder: FolderItem) { - await this.gateway.execute(folder.id); - await this.cache.remove(folder.id); + async execute(id: string) { + await this.gateway.execute(id); + await this.cache.remove(id); } } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts similarity index 67% rename from packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts rename to packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts index e201f990a0f..cb1dea65a3b 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/DeleteFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts @@ -1,7 +1,6 @@ -import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; -import { IDeleteFolderRepository } from "~/Domain/Repositories"; -import { FolderItem, LoadingActionsEnum } from "~/types"; +import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; +import { LoadingActionsEnum } from "~/types"; export class DeleteFolderRepositoryWithLoading implements IDeleteFolderRepository { private loadingRepository: ILoadingRepository; @@ -13,12 +12,11 @@ export class DeleteFolderRepositoryWithLoading implements IDeleteFolderRepositor ) { this.loadingRepository = loadingRepository; this.deleteFolderRepository = deleteFolderRepository; - makeAutoObservable(this); } - async execute(folder: FolderItem) { + async execute(id: string) { await this.loadingRepository.runCallBack( - this.deleteFolderRepository.execute(folder), + this.deleteFolderRepository.execute(id), LoadingActionsEnum.delete ); } diff --git a/packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts new file mode 100644 index 00000000000..d1792ca80e9 --- /dev/null +++ b/packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts @@ -0,0 +1,3 @@ +export interface IDeleteFolderRepository { + execute: (id: string) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/index.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/DeleteFolder/index.ts rename to packages/app-aco/src/folders/repositories/DeleteFolder/index.ts diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts b/packages/app-aco/src/folders/repositories/GetDescendantFolders/GetDescendantFoldersRepository.ts similarity index 75% rename from packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts rename to packages/app-aco/src/folders/repositories/GetDescendantFolders/GetDescendantFoldersRepository.ts index 8e88c8cfe03..352242d849d 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/GetDescendantFoldersRepository.ts +++ b/packages/app-aco/src/folders/repositories/GetDescendantFolders/GetDescendantFoldersRepository.ts @@ -1,8 +1,7 @@ -import { Folder } from "~/Domain/Models"; -import { FoldersCache } from "~/Domain/Caches"; import { IGetDescendantFoldersRepository } from "./IGetDescendantFoldersRepository"; import { ROOT_FOLDER } from "~/constants"; -import { FolderItem } from "~/types"; +import { FoldersCache } from "~/folders/cache"; +import { Folder } from "~/folders/domain"; export class GetDescendantFoldersRepository implements IGetDescendantFoldersRepository { private readonly cache: FoldersCache; @@ -12,16 +11,14 @@ export class GetDescendantFoldersRepository implements IGetDescendantFoldersRepo } execute(id: string): Folder[] { - if (this.isInvalidId(id)) { - return []; - } + const currentFolders = this.cache.getItems(); - if (!id || id === ROOT_FOLDER || !currentFolders?.length) { + if (!id || id === ROOT_FOLDER || !currentFolders.length) { return []; } const folderMap = new Map(currentFolders.map(folder => [folder.id, folder])); - const result: FolderItem[] = []; + const result: Folder[] = []; const findChildren = (folderId: string) => { const folder = folderMap.get(folderId); diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts b/packages/app-aco/src/folders/repositories/GetDescendantFolders/IGetDescendantFoldersRepository.ts similarity index 68% rename from packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts rename to packages/app-aco/src/folders/repositories/GetDescendantFolders/IGetDescendantFoldersRepository.ts index 9a8e881b68b..8629f0c15e4 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/IGetDescendantFoldersRepository.ts +++ b/packages/app-aco/src/folders/repositories/GetDescendantFolders/IGetDescendantFoldersRepository.ts @@ -1,4 +1,4 @@ -import { Folder } from "~/Domain/Models"; +import { Folder } from "~/folders/domain"; export interface IGetDescendantFoldersRepository { execute: (id: string) => Folder[]; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/index.ts b/packages/app-aco/src/folders/repositories/GetDescendantFolders/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/GetDescendantFolders/index.ts rename to packages/app-aco/src/folders/repositories/GetDescendantFolders/index.ts diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts b/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepository.ts similarity index 76% rename from packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts rename to packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepository.ts index dd723c6f5be..3114e67d57b 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepository.ts +++ b/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepository.ts @@ -1,7 +1,7 @@ import { IGetFolderRepository } from "./IGetFolderRepository"; -import { IGetFolderGateway } from "~/Gateways"; -import { FoldersCache } from "~/Domain/Caches"; -import { Folder } from "~/Domain/Models"; +import { FoldersCache } from "~/folders/cache"; +import { Folder } from "~/folders/domain"; +import { IGetFolderGateway } from "~/folders/gateways"; export class GetFolderRepository implements IGetFolderRepository { private cache: FoldersCache; diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts similarity index 83% rename from packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts rename to packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts index 2c7bbabdb3f..22feebebf03 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/GetFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts @@ -1,6 +1,5 @@ -import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; -import { IGetFolderRepository } from "~/Domain/Repositories"; +import { IGetFolderRepository } from "./IGetFolderRepository"; import { LoadingActionsEnum } from "~/types"; export class GetFolderRepositoryWithLoading implements IGetFolderRepository { @@ -10,7 +9,6 @@ export class GetFolderRepositoryWithLoading implements IGetFolderRepository { constructor(loadingRepository: ILoadingRepository, getFolderRepository: IGetFolderRepository) { this.loadingRepository = loadingRepository; this.getFolderRepository = getFolderRepository; - makeAutoObservable(this); } async execute(id: string) { diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/IGetFolderRepository.ts b/packages/app-aco/src/folders/repositories/GetFolder/IGetFolderRepository.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/GetFolder/IGetFolderRepository.ts rename to packages/app-aco/src/folders/repositories/GetFolder/IGetFolderRepository.ts diff --git a/packages/app-aco/src/Domain/Repositories/Folders/GetFolder/index.ts b/packages/app-aco/src/folders/repositories/GetFolder/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/GetFolder/index.ts rename to packages/app-aco/src/folders/repositories/GetFolder/index.ts diff --git a/packages/app-aco/src/folders/repositories/ListFolders/IListFoldersRepository.ts b/packages/app-aco/src/folders/repositories/ListFolders/IListFoldersRepository.ts new file mode 100644 index 00000000000..69f0efc910e --- /dev/null +++ b/packages/app-aco/src/folders/repositories/ListFolders/IListFoldersRepository.ts @@ -0,0 +1,3 @@ +export interface IListFoldersRepository { + execute: (type: string) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts b/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepository.ts similarity index 50% rename from packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts rename to packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepository.ts index 1e2421b559a..5b9579ad336 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepository.ts +++ b/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepository.ts @@ -1,21 +1,19 @@ import { IListFoldersRepository } from "./IListFoldersRepository"; -import { IListFoldersGateway } from "~/Gateways"; -import { FoldersCache } from "~/Domain/Caches"; -import { Folder } from "~/Domain/Models"; +import { IListFoldersGateway } from "~/folders/gateways"; +import { FoldersCache } from "~/folders/cache"; +import { Folder } from "~/folders/domain"; export class ListFoldersRepository implements IListFoldersRepository { - private readonly type: string; private cache: FoldersCache; private gateway: IListFoldersGateway; - constructor(type: string, cache: FoldersCache, gateway: IListFoldersGateway) { - this.type = type; + constructor(cache: FoldersCache, gateway: IListFoldersGateway) { this.cache = cache; this.gateway = gateway; } - async execute() { - const items = await this.gateway.execute(this.type); + async execute(type: string) { + const items = await this.gateway.execute(type); await this.cache.setMultiple(items.map(item => Folder.create(item))); } } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts similarity index 75% rename from packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts rename to packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts index 0bdb6c94e9c..9e1a26e856b 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/ListFoldersRepositoryWithLoading.ts +++ b/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts @@ -1,6 +1,5 @@ -import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; -import { IListFoldersRepository } from "~/Domain/Repositories"; +import { IListFoldersRepository } from "~/folders/repositories"; import { LoadingActionsEnum } from "~/types"; export class ListFoldersRepositoryWithLoading implements IListFoldersRepository { @@ -13,12 +12,11 @@ export class ListFoldersRepositoryWithLoading implements IListFoldersRepository ) { this.loadingRepository = loadingRepository; this.listFoldersRepository = listFoldersRepository; - makeAutoObservable(this); } - async execute() { + async execute(type: string) { await this.loadingRepository.runCallBack( - this.listFoldersRepository.execute(), + this.listFoldersRepository.execute(type), LoadingActionsEnum.list ); } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/ListFolders/index.ts b/packages/app-aco/src/folders/repositories/ListFolders/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/ListFolders/index.ts rename to packages/app-aco/src/folders/repositories/ListFolders/index.ts diff --git a/packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts new file mode 100644 index 00000000000..f28ad2d75bb --- /dev/null +++ b/packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts @@ -0,0 +1,5 @@ +import { Folder } from "~/folders/domain"; + +export interface IUpdateFolderRepository { + execute: (folder: Folder) => Promise; +} diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts similarity index 55% rename from packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts rename to packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts index 16ea7ce1ea9..6d3922a096f 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepository.ts +++ b/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts @@ -1,8 +1,7 @@ import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; -import { IUpdateFolderGateway } from "~/Gateways"; -import { Folder } from "~/Domain/Models"; -import { FoldersCache } from "~/Domain/Caches"; -import { FolderItem } from "~/types"; +import { Folder } from "~/folders/domain"; +import { FoldersCache } from "~/folders/cache"; +import { IUpdateFolderGateway, UpdateFolderGraphQLMapper } from "~/folders/gateways"; export class UpdateFolderRepository implements IUpdateFolderRepository { private cache: FoldersCache; @@ -13,8 +12,9 @@ export class UpdateFolderRepository implements IUpdateFolderRepository { this.gateway = gateway; } - async execute(folder: FolderItem) { - const item = await this.gateway.execute(folder); + async execute(folder: Folder) { + const mapper = new UpdateFolderGraphQLMapper(); + const item = await this.gateway.execute(mapper.toGraphQLDTO(folder)); await this.cache.update(item.id, Folder.create(item)); } } diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts similarity index 76% rename from packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts rename to packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts index a755c12137b..d4f5156aeee 100644 --- a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/UpdateFolderRepositoryWithLoading.ts +++ b/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts @@ -1,8 +1,7 @@ -import { makeAutoObservable } from "mobx"; import { ILoadingRepository } from "@webiny/app-utils"; -import { IUpdateFolderRepository } from "~/Domain/Repositories"; +import { Folder } from "~/folders/domain"; +import { IUpdateFolderRepository } from "~/folders/repositories"; import { LoadingActionsEnum } from "~/types"; -import { FolderItem } from "~/types"; export class UpdateFolderRepositoryWithLoading implements IUpdateFolderRepository { private loadingRepository: ILoadingRepository; @@ -14,10 +13,9 @@ export class UpdateFolderRepositoryWithLoading implements IUpdateFolderRepositor ) { this.loadingRepository = loadingRepository; this.updateFolderRepository = updateFolderRepository; - makeAutoObservable(this); } - async execute(folder: FolderItem) { + async execute(folder: Folder) { await this.loadingRepository.runCallBack( this.updateFolderRepository.execute(folder), LoadingActionsEnum.update diff --git a/packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/index.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/UpdateFolder/index.ts rename to packages/app-aco/src/folders/repositories/UpdateFolder/index.ts diff --git a/packages/app-aco/src/Domain/Repositories/Folders/index.ts b/packages/app-aco/src/folders/repositories/index.ts similarity index 100% rename from packages/app-aco/src/Domain/Repositories/Folders/index.ts rename to packages/app-aco/src/folders/repositories/index.ts diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts b/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts new file mode 100644 index 00000000000..e878817d0ee --- /dev/null +++ b/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts @@ -0,0 +1,23 @@ +import { CreateFolderParams, ICreateFolderUseCase } from "./ICreateFolderUseCase"; +import { Folder } from "~/folders/domain"; +import { ICreateFolderRepository } from "~/folders/repositories"; + +export class CreateFolderUseCase implements ICreateFolderUseCase { + private repository: ICreateFolderRepository; + + constructor(repository: ICreateFolderRepository) { + this.repository = repository; + } + + async execute(params: CreateFolderParams) { + await this.repository.execute( + Folder.create({ + title: params.title, + slug: params.slug, + type: params.type, + parentId: params.parentId, + permissions: params.permissions + }) + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/ICreateFolderUseCase.ts b/packages/app-aco/src/folders/useCases/CreateFolder/ICreateFolderUseCase.ts new file mode 100644 index 00000000000..45517a3200e --- /dev/null +++ b/packages/app-aco/src/folders/useCases/CreateFolder/ICreateFolderUseCase.ts @@ -0,0 +1,13 @@ +import { FolderPermission } from "~/types"; + +export interface CreateFolderParams { + title: string; + slug: string; + type: string; + parentId: string | null; + permissions: FolderPermission[]; +} + +export interface ICreateFolderUseCase { + execute: (params: CreateFolderParams) => Promise; +} diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/index.ts b/packages/app-aco/src/folders/useCases/CreateFolder/index.ts new file mode 100644 index 00000000000..d28fd0dd08c --- /dev/null +++ b/packages/app-aco/src/folders/useCases/CreateFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./CreateFolderUseCase"; +export * from "./ICreateFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts new file mode 100644 index 00000000000..2eb4d953bcd --- /dev/null +++ b/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts @@ -0,0 +1,14 @@ +import { DeleteFolderParams, IDeleteFolderUseCase } from "./IDeleteFolderUseCase"; +import { IDeleteFolderRepository } from "../../repositories/DeleteFolder"; + +export class DeleteFolderUseCase implements IDeleteFolderUseCase { + private repository: IDeleteFolderRepository; + + constructor(repository: IDeleteFolderRepository) { + this.repository = repository; + } + + async execute(params: DeleteFolderParams) { + await this.repository.execute(params.id); + } +} diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts new file mode 100644 index 00000000000..c4963f82922 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts @@ -0,0 +1,7 @@ +export interface DeleteFolderParams { + id: string; +} + +export interface IDeleteFolderUseCase { + execute: (params: DeleteFolderParams) => Promise; +} diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts new file mode 100644 index 00000000000..b90144a2cd6 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./DeleteFolderUseCase"; +export * from "./IDeleteFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts b/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts new file mode 100644 index 00000000000..2d1640a8b5b --- /dev/null +++ b/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts @@ -0,0 +1,14 @@ +import { IGetFolderRepository } from "~/folders/repositories"; +import { GetFolderParams, IGetFolderUseCase } from "./IGetFolderUseCase"; + +export class GetFolderUseCase implements IGetFolderUseCase { + private repository: IGetFolderRepository; + + constructor(repository: IGetFolderRepository) { + this.repository = repository; + } + + async execute(params: GetFolderParams) { + await this.repository.execute(params.id); + } +} diff --git a/packages/app-aco/src/folders/useCases/GetFolder/IGetFolderUseCase.ts b/packages/app-aco/src/folders/useCases/GetFolder/IGetFolderUseCase.ts new file mode 100644 index 00000000000..22cf8bcc44a --- /dev/null +++ b/packages/app-aco/src/folders/useCases/GetFolder/IGetFolderUseCase.ts @@ -0,0 +1,7 @@ +export interface GetFolderParams { + id: string; +} + +export interface IGetFolderUseCase { + execute: (params: GetFolderParams) => Promise; +} diff --git a/packages/app-aco/src/folders/useCases/GetFolder/index.ts b/packages/app-aco/src/folders/useCases/GetFolder/index.ts new file mode 100644 index 00000000000..c36cac287d7 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/GetFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./GetFolderUseCase"; +export * from "./IGetFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/ListFolders/IListFoldersUseCase.ts b/packages/app-aco/src/folders/useCases/ListFolders/IListFoldersUseCase.ts new file mode 100644 index 00000000000..1aa7a9609a7 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/ListFolders/IListFoldersUseCase.ts @@ -0,0 +1,7 @@ +export interface ListFoldersParams { + type: string; +} + +export interface IListFoldersUseCase { + execute: (params: ListFoldersParams) => Promise; +} diff --git a/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts b/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts new file mode 100644 index 00000000000..96a972ba507 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts @@ -0,0 +1,14 @@ +import { IListFoldersRepository } from "~/folders/repositories"; +import { IListFoldersUseCase, ListFoldersParams } from "./IListFoldersUseCase"; + +export class ListFoldersUseCase implements IListFoldersUseCase { + private repository: IListFoldersRepository; + + constructor(repository: IListFoldersRepository) { + this.repository = repository; + } + + async execute(params: ListFoldersParams) { + await this.repository.execute(params.type); + } +} diff --git a/packages/app-aco/src/folders/useCases/ListFolders/index.ts b/packages/app-aco/src/folders/useCases/ListFolders/index.ts new file mode 100644 index 00000000000..593590d3265 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/ListFolders/index.ts @@ -0,0 +1,2 @@ +export * from "./IListFoldersUseCase"; +export * from "./ListFoldersUseCase"; diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/IUpdateFolderUseCase.ts b/packages/app-aco/src/folders/useCases/UpdateFolder/IUpdateFolderUseCase.ts new file mode 100644 index 00000000000..173404f49ae --- /dev/null +++ b/packages/app-aco/src/folders/useCases/UpdateFolder/IUpdateFolderUseCase.ts @@ -0,0 +1,14 @@ +import { FolderPermission } from "~/types"; + +export interface UpdateFolderParams { + id: string; + title: string; + slug: string; + type: string; + parentId: string | null; + permissions: FolderPermission[]; +} + +export interface IUpdateFolderUseCase { + execute: (params: UpdateFolderParams) => Promise; +} diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts b/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts new file mode 100644 index 00000000000..cd18d9b8b7d --- /dev/null +++ b/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts @@ -0,0 +1,24 @@ +import { UpdateFolderParams, IUpdateFolderUseCase } from "./IUpdateFolderUseCase"; +import { Folder } from "~/folders/domain"; +import { IUpdateFolderRepository } from "~/folders/repositories"; + +export class UpdateFolderUseCase implements IUpdateFolderUseCase { + private repository: IUpdateFolderRepository; + + constructor(repository: IUpdateFolderRepository) { + this.repository = repository; + } + + async execute(params: UpdateFolderParams) { + await this.repository.execute( + Folder.create({ + id: params.id, + title: params.title, + slug: params.slug, + type: params.type, + parentId: params.parentId, + permissions: params.permissions + }) + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts b/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts new file mode 100644 index 00000000000..082a71e7862 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts @@ -0,0 +1,2 @@ +export * from "./IUpdateFolderUseCase"; +export * from "./UpdateFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/index.ts b/packages/app-aco/src/folders/useCases/index.ts new file mode 100644 index 00000000000..4e48864c20f --- /dev/null +++ b/packages/app-aco/src/folders/useCases/index.ts @@ -0,0 +1,5 @@ +export * from "./CreateFolder"; +export * from "./DeleteFolder"; +export * from "./GetFolder"; +export * from "./ListFolders"; +export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 59a841a8a84..7f0dc481485 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -5,42 +5,54 @@ import { useApolloClient } from "@apollo/react-hooks"; import { FoldersContext } from "~/contexts/folders"; import { AcoAppContext } from "~/contexts/app"; import { FolderItem } from "~/types"; -import { folderCacheFactory } from "~/Domain/Caches"; + import { loadingRepositoryFactory } from "@webiny/app-utils"; + +import { FolderMapper } from "~/Domain/Models"; + +import { folderCacheFactory } from "~/folders/cache"; import { CreateFolderGraphQLGateway, DeleteFolderGraphQLGateway, GetFolderGraphQLGateway, ListFoldersGraphQLGateway, UpdateFolderGraphQLGateway -} from "~/Gateways"; +} from "~/folders/gateways"; +import { + CreateFolderUseCase, + DeleteFolderUseCase, + GetFolderUseCase, + ListFoldersUseCase, + UpdateFolderUseCase +} from "~/folders/useCases"; +import { + CreateFolderController, + DeleteFolderController, + GetFolderController, + ListFoldersController, + UpdateFolderController +} from "~/folders/controllers"; import { CreateFolderRepository, CreateFolderRepositoryWithLoading, DeleteFolderRepository, DeleteFolderRepositoryWithLoading, - GetDescendantFoldersRepository, GetFolderRepository, GetFolderRepositoryWithLoading, + GetDescendantFoldersRepository, ListFoldersRepository, ListFoldersRepositoryWithLoading, UpdateFolderRepository, UpdateFolderRepositoryWithLoading -} from "~/Domain/Repositories"; -import { FolderMapper } from "~/Domain/Models"; +} from "~/folders/repositories"; export const useFolders = () => { const client = useApolloClient(); const foldersContext = useContext(FoldersContext); const appContext = useContext(AcoAppContext); - const [vm, setVm] = useState<{ - folders: FolderItem[] | null; - loading: Record; - }>({ - folders: null, - loading: {} - }); + const [folders, setFolders] = useState(null); + const [loading, setLoading] = useState>({}); if (!foldersContext) { throw new Error("useFolders must be used within a FoldersProvider"); @@ -67,17 +79,14 @@ export const useFolders = () => { // List const listFolders = useCallback(() => { const listFoldersGateway = new ListFoldersGraphQLGateway(client); - const listFoldersRepository = new ListFoldersRepository( - type, - foldersCache, - listFoldersGateway - ); - + const listFoldersRepository = new ListFoldersRepository(foldersCache, listFoldersGateway); const repository = new ListFoldersRepositoryWithLoading( loadingRepository, listFoldersRepository ); - return repository.execute(); + const listFoldersUseCase = new ListFoldersUseCase(repository); + const listFoldersController = new ListFoldersController(listFoldersUseCase); + return listFoldersController.execute(type); }, [type, client, foldersCache, loadingRepository]); // Get @@ -85,12 +94,13 @@ export const useFolders = () => { (id: string) => { const getFolderGateway = new GetFolderGraphQLGateway(client); const getFolderRepository = new GetFolderRepository(foldersCache, getFolderGateway); - const repository = new GetFolderRepositoryWithLoading( loadingRepository, getFolderRepository ); - return repository.execute(id); + const getFolderUseCase = new GetFolderUseCase(repository); + const getFolderController = new GetFolderController(getFolderUseCase); + return getFolderController.execute(id); }, [client, foldersCache, loadingRepository] ); @@ -111,14 +121,15 @@ export const useFolders = () => { foldersCache, createFolderGateway ); - const repository = new CreateFolderRepositoryWithLoading( loadingRepository, createFolderRepository ); - return repository.execute(folder); + const createFolderUseCase = new CreateFolderUseCase(repository); + const createFolderController = new CreateFolderController(createFolderUseCase); + return createFolderController.execute(folder, type); }, - [client, foldersCache, loadingRepository] + [client, foldersCache, loadingRepository, type] ); // Update @@ -129,12 +140,13 @@ export const useFolders = () => { foldersCache, updateFolderGateway ); - const repository = new UpdateFolderRepositoryWithLoading( loadingRepository, updateFolderRepository ); - return repository.execute(folder); + const updateFolderUseCase = new UpdateFolderUseCase(repository); + const updateFolderController = new UpdateFolderController(updateFolderUseCase); + return updateFolderController.execute(folder); }, [client, foldersCache, loadingRepository] ); @@ -152,7 +164,9 @@ export const useFolders = () => { loadingRepository, deleteFolderRepository ); - return repository.execute(folder); + const deleteFolderUseCase = new DeleteFolderUseCase(repository); + const deleteFolderController = new DeleteFolderController(deleteFolderUseCase); + return deleteFolderController.execute(folder); }, [client, foldersCache, loadingRepository] ); @@ -168,34 +182,33 @@ export const useFolders = () => { * fetch the outdated list from Apollo Cache. Since the state is managed locally, we fetch the folders only * at the first mount. */ - if (vm.folders) { - return; + const cachedItems = foldersCache.getItems(); + + if (cachedItems) { + return; // Skip if we already have folders in the cache. } + listFolders(); - }, []); + }, [foldersCache]); useEffect(() => { + const mapper = new FolderMapper(); return autorun(() => { - const mapper = new FolderMapper(); - - setVm(vm => ({ - ...vm, - folders: foldersCache.getItems().map(folder => mapper.toDTO(folder)) - })); + const newFolderState = foldersCache.getItems().map(folder => mapper.toDTO(folder)); + setFolders(newFolderState); }); }, [foldersCache]); useEffect(() => { return autorun(() => { - setVm(vm => ({ - ...vm, - loading: loadingRepository.get() - })); + const newLoadingState = loadingRepository.get(); + setLoading(newLoadingState); }); }, [loadingRepository]); return { - ...vm, + folders, + loading, listFolders, getFolder, getDescendantFolders, diff --git a/packages/app-aco/src/types.ts b/packages/app-aco/src/types.ts index 15e5f876592..1f3c61190fc 100644 --- a/packages/app-aco/src/types.ts +++ b/packages/app-aco/src/types.ts @@ -153,7 +153,17 @@ export interface CreateFolderResponse { export interface CreateFolderVariables { data: Omit< FolderItem, - "id" | "createdOn" | "createdBy" | "savedOn" | "savedBy" | "modifiedOn" | "modifiedBy" + | "id" + | "createdOn" + | "createdBy" + | "savedOn" + | "savedBy" + | "modifiedOn" + | "modifiedBy" + | "hasNonInheritedPermissions" + | "canManageContent" + | "canManagePermissions" + | "canManageStructure" >; } From ce1bfe2228f97b931d09da84302f46284ea44a66 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Tue, 27 Aug 2024 06:06:56 +0200 Subject: [PATCH 04/28] refactor(app-aco): implement presenter --- .../src/Domain/Models/Folder/IFolderMapper.ts | 6 --- .../app-aco/src/Domain/Models/Folder/index.ts | 2 - packages/app-aco/src/Domain/Models/index.ts | 1 - packages/app-aco/src/folders/index.ts | 2 + .../presenters/FoldersPresenter.ts} | 24 ++++++++++-- .../app-aco/src/folders/presenters/index.ts | 1 + packages/app-aco/src/hooks/useFolders.ts | 39 +++++++------------ 7 files changed, 38 insertions(+), 37 deletions(-) delete mode 100644 packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts delete mode 100644 packages/app-aco/src/Domain/Models/Folder/index.ts delete mode 100644 packages/app-aco/src/Domain/Models/index.ts rename packages/app-aco/src/{Domain/Models/Folder/FolderMapper.ts => folders/presenters/FoldersPresenter.ts} (60%) create mode 100644 packages/app-aco/src/folders/presenters/index.ts diff --git a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts b/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts deleted file mode 100644 index 492257cf13d..00000000000 --- a/packages/app-aco/src/Domain/Models/Folder/IFolderMapper.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Folder } from "~/folders/domain"; -import { FolderItem } from "~/types"; - -export interface IFolderMapper { - toDTO: (folder: Folder) => FolderItem; -} diff --git a/packages/app-aco/src/Domain/Models/Folder/index.ts b/packages/app-aco/src/Domain/Models/Folder/index.ts deleted file mode 100644 index 09f3ac0eae3..00000000000 --- a/packages/app-aco/src/Domain/Models/Folder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./FolderMapper"; -export * from "./IFolderMapper"; diff --git a/packages/app-aco/src/Domain/Models/index.ts b/packages/app-aco/src/Domain/Models/index.ts deleted file mode 100644 index b6ab82d77ce..00000000000 --- a/packages/app-aco/src/Domain/Models/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Folder"; diff --git a/packages/app-aco/src/folders/index.ts b/packages/app-aco/src/folders/index.ts index 1c1f86daee7..3d87529adf7 100644 --- a/packages/app-aco/src/folders/index.ts +++ b/packages/app-aco/src/folders/index.ts @@ -1,5 +1,7 @@ export * from "./cache"; +export * from "./controllers"; export * from "./domain"; export * from "./gateways"; +export * from "./presenters"; export * from "./repositories"; export * from "./useCases"; diff --git a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts b/packages/app-aco/src/folders/presenters/FoldersPresenter.ts similarity index 60% rename from packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts rename to packages/app-aco/src/folders/presenters/FoldersPresenter.ts index fbc0359f45b..9fac2153bae 100644 --- a/packages/app-aco/src/Domain/Models/Folder/FolderMapper.ts +++ b/packages/app-aco/src/folders/presenters/FoldersPresenter.ts @@ -1,9 +1,25 @@ -import { IFolderMapper } from "./IFolderMapper"; -import { ROOT_FOLDER } from "~/constants"; +import { LoadingRepository } from "@webiny/app-utils"; +import { FoldersCache } from "~/folders/cache"; import { Folder } from "~/folders/domain"; +import { ROOT_FOLDER } from "~/constants"; + +export class FoldersPresenter { + private foldersCache: FoldersCache; + private loadingRepository: LoadingRepository; + + constructor(foldersCache: FoldersCache, loadingRepository: LoadingRepository) { + this.foldersCache = foldersCache; + this.loadingRepository = loadingRepository; + } + + get vm() { + return { + folders: this.foldersCache.getItems().map(folder => this.folderMapper(folder)), + loading: this.loadingRepository.get() + }; + } -export class FolderMapper implements IFolderMapper { - toDTO(folder: Folder) { + private folderMapper(folder: Folder) { return { id: folder.id, title: folder.title, diff --git a/packages/app-aco/src/folders/presenters/index.ts b/packages/app-aco/src/folders/presenters/index.ts new file mode 100644 index 00000000000..a8e3bc39220 --- /dev/null +++ b/packages/app-aco/src/folders/presenters/index.ts @@ -0,0 +1 @@ +export * from "./FoldersPresenter"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 7f0dc481485..9c809d0ab1e 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,14 +1,10 @@ import { useContext, useCallback, useEffect, useMemo, useState } from "react"; import { autorun } from "mobx"; import { useApolloClient } from "@apollo/react-hooks"; +import { loadingRepositoryFactory } from "@webiny/app-utils"; import { FoldersContext } from "~/contexts/folders"; import { AcoAppContext } from "~/contexts/app"; -import { FolderItem } from "~/types"; - -import { loadingRepositoryFactory } from "@webiny/app-utils"; - -import { FolderMapper } from "~/Domain/Models"; import { folderCacheFactory } from "~/folders/cache"; import { @@ -45,14 +41,16 @@ import { UpdateFolderRepository, UpdateFolderRepositoryWithLoading } from "~/folders/repositories"; +import { FoldersPresenter } from "~/folders/presenters"; + +import { FolderItem } from "~/types"; export const useFolders = () => { const client = useApolloClient(); const foldersContext = useContext(FoldersContext); const appContext = useContext(AcoAppContext); - const [folders, setFolders] = useState(null); - const [loading, setLoading] = useState>({}); + const [vm, setVm] = useState({}); if (!foldersContext) { throw new Error("useFolders must be used within a FoldersProvider"); @@ -76,6 +74,15 @@ export const useFolders = () => { return loadingRepositoryFactory.getRepository(); }, []); + // Presenter vm + useEffect(() => { + const presenter = new FoldersPresenter(foldersCache, loadingRepository); + return autorun(() => { + const newState = presenter.vm; + setVm(newState); + }); + }, [foldersCache, loadingRepository]); + // List const listFolders = useCallback(() => { const listFoldersGateway = new ListFoldersGraphQLGateway(client); @@ -191,24 +198,8 @@ export const useFolders = () => { listFolders(); }, [foldersCache]); - useEffect(() => { - const mapper = new FolderMapper(); - return autorun(() => { - const newFolderState = foldersCache.getItems().map(folder => mapper.toDTO(folder)); - setFolders(newFolderState); - }); - }, [foldersCache]); - - useEffect(() => { - return autorun(() => { - const newLoadingState = loadingRepository.get(); - setLoading(newLoadingState); - }); - }, [loadingRepository]); - return { - folders, - loading, + ...vm, listFolders, getFolder, getDescendantFolders, From a5be5e18976d370c6b790a46b6de4d92d405dc8a Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Tue, 27 Aug 2024 06:34:32 +0200 Subject: [PATCH 05/28] refactor(app-aco): add loading use case decoration --- .../CreateFolder/CreateFolderController.ts | 1 - .../CreateFolderRepositoryWithLoading.ts | 24 ------- .../repositories/CreateFolder/index.ts | 1 - .../DeleteFolderRepositoryWithLoading.ts | 23 ------- .../repositories/DeleteFolder/index.ts | 1 - .../GetFolderRepositoryWithLoading.ts | 20 ------ .../folders/repositories/GetFolder/index.ts | 1 - .../ListFoldersRepositoryWithLoading.ts | 23 ------- .../folders/repositories/ListFolders/index.ts | 1 - .../UpdateFolderRepositoryWithLoading.ts | 24 ------- .../repositories/UpdateFolder/index.ts | 1 - .../CreateFolderUseCaseWithLoading.ts | 20 ++++++ .../folders/useCases/CreateFolder/index.ts | 1 + .../DeleteFolderUseCaseWithLoading.ts | 20 ++++++ .../folders/useCases/DeleteFolder/index.ts | 1 + .../GetFolder/GetFolderUseCaseWithLoading.ts | 20 ++++++ .../src/folders/useCases/GetFolder/index.ts | 1 + .../ListFoldersUseCaseWithLoading.ts | 20 ++++++ .../src/folders/useCases/ListFolders/index.ts | 1 + .../UpdateFolderUseCaseWithLoading.ts | 20 ++++++ .../folders/useCases/UpdateFolder/index.ts | 1 + packages/app-aco/src/hooks/useFolders.ts | 62 ++++++++++--------- 22 files changed, 139 insertions(+), 148 deletions(-) delete mode 100644 packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts delete mode 100644 packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts delete mode 100644 packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts delete mode 100644 packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts delete mode 100644 packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts create mode 100644 packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts create mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts create mode 100644 packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCaseWithLoading.ts create mode 100644 packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts create mode 100644 packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts b/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts index 6bd350873e2..7cf8a111e77 100644 --- a/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts +++ b/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts @@ -10,7 +10,6 @@ export class CreateFolderController implements ICreateFolderController { } async execute(folder: FolderItem, type: string) { - console.log("type", type); await this.useCase.execute({ type: type, title: folder.title, diff --git a/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts deleted file mode 100644 index 2ed48c30af2..00000000000 --- a/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepositoryWithLoading.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ILoadingRepository } from "@webiny/app-utils"; -import { Folder } from "~/folders/domain"; -import { ICreateFolderRepository } from "~/folders/repositories"; -import { LoadingActionsEnum } from "~/types"; - -export class CreateFolderRepositoryWithLoading implements ICreateFolderRepository { - private loadingRepository: ILoadingRepository; - private createFolderRepository: ICreateFolderRepository; - - constructor( - loadingRepository: ILoadingRepository, - createFolderRepository: ICreateFolderRepository - ) { - this.loadingRepository = loadingRepository; - this.createFolderRepository = createFolderRepository; - } - - async execute(folder: Folder) { - await this.loadingRepository.runCallBack( - this.createFolderRepository.execute(folder), - LoadingActionsEnum.create - ); - } -} diff --git a/packages/app-aco/src/folders/repositories/CreateFolder/index.ts b/packages/app-aco/src/folders/repositories/CreateFolder/index.ts index f68097987bb..4e37aab1c91 100644 --- a/packages/app-aco/src/folders/repositories/CreateFolder/index.ts +++ b/packages/app-aco/src/folders/repositories/CreateFolder/index.ts @@ -1,3 +1,2 @@ export * from "./CreateFolderRepository"; -export * from "./CreateFolderRepositoryWithLoading"; export * from "./ICreateFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts deleted file mode 100644 index cb1dea65a3b..00000000000 --- a/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepositoryWithLoading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ILoadingRepository } from "@webiny/app-utils"; -import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; -import { LoadingActionsEnum } from "~/types"; - -export class DeleteFolderRepositoryWithLoading implements IDeleteFolderRepository { - private loadingRepository: ILoadingRepository; - private deleteFolderRepository: IDeleteFolderRepository; - - constructor( - loadingRepository: ILoadingRepository, - deleteFolderRepository: IDeleteFolderRepository - ) { - this.loadingRepository = loadingRepository; - this.deleteFolderRepository = deleteFolderRepository; - } - - async execute(id: string) { - await this.loadingRepository.runCallBack( - this.deleteFolderRepository.execute(id), - LoadingActionsEnum.delete - ); - } -} diff --git a/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts index 85d104dcfcb..6b58ffbd6b0 100644 --- a/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts +++ b/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts @@ -1,3 +1,2 @@ export * from "./DeleteFolderRepository"; -export * from "./DeleteFolderRepositoryWithLoading"; export * from "./IDeleteFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts deleted file mode 100644 index 22feebebf03..00000000000 --- a/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepositoryWithLoading.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ILoadingRepository } from "@webiny/app-utils"; -import { IGetFolderRepository } from "./IGetFolderRepository"; -import { LoadingActionsEnum } from "~/types"; - -export class GetFolderRepositoryWithLoading implements IGetFolderRepository { - private loadingRepository: ILoadingRepository; - private getFolderRepository: IGetFolderRepository; - - constructor(loadingRepository: ILoadingRepository, getFolderRepository: IGetFolderRepository) { - this.loadingRepository = loadingRepository; - this.getFolderRepository = getFolderRepository; - } - - async execute(id: string) { - await this.loadingRepository.runCallBack( - this.getFolderRepository.execute(id), - LoadingActionsEnum.get - ); - } -} diff --git a/packages/app-aco/src/folders/repositories/GetFolder/index.ts b/packages/app-aco/src/folders/repositories/GetFolder/index.ts index 87f4a5be0b7..6577f1c3868 100644 --- a/packages/app-aco/src/folders/repositories/GetFolder/index.ts +++ b/packages/app-aco/src/folders/repositories/GetFolder/index.ts @@ -1,3 +1,2 @@ export * from "./GetFolderRepository"; -export * from "./GetFolderRepositoryWithLoading"; export * from "./IGetFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts deleted file mode 100644 index 9e1a26e856b..00000000000 --- a/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepositoryWithLoading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ILoadingRepository } from "@webiny/app-utils"; -import { IListFoldersRepository } from "~/folders/repositories"; -import { LoadingActionsEnum } from "~/types"; - -export class ListFoldersRepositoryWithLoading implements IListFoldersRepository { - private loadingRepository: ILoadingRepository; - private listFoldersRepository: IListFoldersRepository; - - constructor( - loadingRepository: ILoadingRepository, - listFoldersRepository: IListFoldersRepository - ) { - this.loadingRepository = loadingRepository; - this.listFoldersRepository = listFoldersRepository; - } - - async execute(type: string) { - await this.loadingRepository.runCallBack( - this.listFoldersRepository.execute(type), - LoadingActionsEnum.list - ); - } -} diff --git a/packages/app-aco/src/folders/repositories/ListFolders/index.ts b/packages/app-aco/src/folders/repositories/ListFolders/index.ts index 888cf6c98f5..5c25989ea67 100644 --- a/packages/app-aco/src/folders/repositories/ListFolders/index.ts +++ b/packages/app-aco/src/folders/repositories/ListFolders/index.ts @@ -1,3 +1,2 @@ export * from "./ListFoldersRepository"; -export * from "./ListFoldersRepositoryWithLoading"; export * from "./IListFoldersRepository"; diff --git a/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts deleted file mode 100644 index d4f5156aeee..00000000000 --- a/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepositoryWithLoading.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ILoadingRepository } from "@webiny/app-utils"; -import { Folder } from "~/folders/domain"; -import { IUpdateFolderRepository } from "~/folders/repositories"; -import { LoadingActionsEnum } from "~/types"; - -export class UpdateFolderRepositoryWithLoading implements IUpdateFolderRepository { - private loadingRepository: ILoadingRepository; - private updateFolderRepository: IUpdateFolderRepository; - - constructor( - loadingRepository: ILoadingRepository, - updateFolderRepository: IUpdateFolderRepository - ) { - this.loadingRepository = loadingRepository; - this.updateFolderRepository = updateFolderRepository; - } - - async execute(folder: Folder) { - await this.loadingRepository.runCallBack( - this.updateFolderRepository.execute(folder), - LoadingActionsEnum.update - ); - } -} diff --git a/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts index e2ff5740d81..dc518afec08 100644 --- a/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts +++ b/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts @@ -1,3 +1,2 @@ export * from "./UpdateFolderRepository"; -export * from "./UpdateFolderRepositoryWithLoading"; export * from "./IUpdateFolderRepository"; diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts b/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts new file mode 100644 index 00000000000..e61367cfd92 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts @@ -0,0 +1,20 @@ +import { CreateFolderParams, ICreateFolderUseCase } from "./ICreateFolderUseCase"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { LoadingActionsEnum } from "~/types"; + +export class CreateFolderUseCaseWithLoading implements ICreateFolderUseCase { + private loadingRepository: ILoadingRepository; + private useCase: ICreateFolderUseCase; + + constructor(loadingRepository: ILoadingRepository, useCase: ICreateFolderUseCase) { + this.loadingRepository = loadingRepository; + this.useCase = useCase; + } + + async execute(params: CreateFolderParams) { + await this.loadingRepository.runCallBack( + this.useCase.execute(params), + LoadingActionsEnum.create + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/index.ts b/packages/app-aco/src/folders/useCases/CreateFolder/index.ts index d28fd0dd08c..7151cb9b941 100644 --- a/packages/app-aco/src/folders/useCases/CreateFolder/index.ts +++ b/packages/app-aco/src/folders/useCases/CreateFolder/index.ts @@ -1,2 +1,3 @@ export * from "./CreateFolderUseCase"; +export * from "./CreateFolderUseCaseWithLoading"; export * from "./ICreateFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts new file mode 100644 index 00000000000..895d8aacd22 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts @@ -0,0 +1,20 @@ +import { DeleteFolderParams, IDeleteFolderUseCase } from "~/folders/useCases"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { LoadingActionsEnum } from "~/types"; + +export class DeleteFolderUseCaseWithLoading implements IDeleteFolderUseCase { + private loadingRepository: ILoadingRepository; + private useCase: IDeleteFolderUseCase; + + constructor(loadingRepository: ILoadingRepository, useCase: IDeleteFolderUseCase) { + this.loadingRepository = loadingRepository; + this.useCase = useCase; + } + + async execute(params: DeleteFolderParams) { + await this.loadingRepository.runCallBack( + this.useCase.execute(params), + LoadingActionsEnum.delete + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts index b90144a2cd6..d7596acbfca 100644 --- a/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts +++ b/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts @@ -1,2 +1,3 @@ export * from "./DeleteFolderUseCase"; +export * from "./DeleteFolderUseCaseWithLoading"; export * from "./IDeleteFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCaseWithLoading.ts b/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCaseWithLoading.ts new file mode 100644 index 00000000000..a1ee2e0816d --- /dev/null +++ b/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCaseWithLoading.ts @@ -0,0 +1,20 @@ +import { GetFolderParams, IGetFolderUseCase } from "./IGetFolderUseCase"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { LoadingActionsEnum } from "~/types"; + +export class GetFolderUseCaseWithLoading implements IGetFolderUseCase { + private loadingRepository: ILoadingRepository; + private useCase: IGetFolderUseCase; + + constructor(loadingRepository: ILoadingRepository, useCase: IGetFolderUseCase) { + this.loadingRepository = loadingRepository; + this.useCase = useCase; + } + + async execute(params: GetFolderParams) { + await this.loadingRepository.runCallBack( + this.useCase.execute(params), + LoadingActionsEnum.get + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/GetFolder/index.ts b/packages/app-aco/src/folders/useCases/GetFolder/index.ts index c36cac287d7..6056dd18809 100644 --- a/packages/app-aco/src/folders/useCases/GetFolder/index.ts +++ b/packages/app-aco/src/folders/useCases/GetFolder/index.ts @@ -1,2 +1,3 @@ export * from "./GetFolderUseCase"; +export * from "./GetFolderUseCaseWithLoading"; export * from "./IGetFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts b/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts new file mode 100644 index 00000000000..b77c777ad94 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts @@ -0,0 +1,20 @@ +import { IListFoldersUseCase, ListFoldersParams } from "~/folders/useCases"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { LoadingActionsEnum } from "~/types"; + +export class ListFoldersUseCaseWithLoading implements IListFoldersUseCase { + private loadingRepository: ILoadingRepository; + private useCase: IListFoldersUseCase; + + constructor(loadingRepository: ILoadingRepository, useCase: IListFoldersUseCase) { + this.loadingRepository = loadingRepository; + this.useCase = useCase; + } + + async execute(params: ListFoldersParams) { + await this.loadingRepository.runCallBack( + this.useCase.execute(params), + LoadingActionsEnum.list + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/ListFolders/index.ts b/packages/app-aco/src/folders/useCases/ListFolders/index.ts index 593590d3265..d053f14253d 100644 --- a/packages/app-aco/src/folders/useCases/ListFolders/index.ts +++ b/packages/app-aco/src/folders/useCases/ListFolders/index.ts @@ -1,2 +1,3 @@ export * from "./IListFoldersUseCase"; export * from "./ListFoldersUseCase"; +export * from "./ListFoldersUseCaseWithLoading"; diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts b/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts new file mode 100644 index 00000000000..01fb6ed6931 --- /dev/null +++ b/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts @@ -0,0 +1,20 @@ +import { IUpdateFolderUseCase, UpdateFolderParams } from "~/folders/useCases"; +import { ILoadingRepository } from "@webiny/app-utils"; +import { LoadingActionsEnum } from "~/types"; + +export class UpdateFolderUseCaseWithLoading implements IUpdateFolderUseCase { + private loadingRepository: ILoadingRepository; + private useCase: IUpdateFolderUseCase; + + constructor(loadingRepository: ILoadingRepository, useCase: IUpdateFolderUseCase) { + this.loadingRepository = loadingRepository; + this.useCase = useCase; + } + + async execute(params: UpdateFolderParams) { + await this.loadingRepository.runCallBack( + this.useCase.execute(params), + LoadingActionsEnum.update + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts b/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts index 082a71e7862..b56516d7fc3 100644 --- a/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts +++ b/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts @@ -1,2 +1,3 @@ export * from "./IUpdateFolderUseCase"; export * from "./UpdateFolderUseCase"; +export * from "./UpdateFolderUseCaseWithLoading"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 9c809d0ab1e..fc10342b60f 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -16,10 +16,15 @@ import { } from "~/folders/gateways"; import { CreateFolderUseCase, + CreateFolderUseCaseWithLoading, DeleteFolderUseCase, + DeleteFolderUseCaseWithLoading, GetFolderUseCase, + GetFolderUseCaseWithLoading, ListFoldersUseCase, - UpdateFolderUseCase + ListFoldersUseCaseWithLoading, + UpdateFolderUseCase, + UpdateFolderUseCaseWithLoading } from "~/folders/useCases"; import { CreateFolderController, @@ -30,16 +35,11 @@ import { } from "~/folders/controllers"; import { CreateFolderRepository, - CreateFolderRepositoryWithLoading, DeleteFolderRepository, - DeleteFolderRepositoryWithLoading, GetFolderRepository, - GetFolderRepositoryWithLoading, GetDescendantFoldersRepository, ListFoldersRepository, - ListFoldersRepositoryWithLoading, - UpdateFolderRepository, - UpdateFolderRepositoryWithLoading + UpdateFolderRepository } from "~/folders/repositories"; import { FoldersPresenter } from "~/folders/presenters"; @@ -87,12 +87,12 @@ export const useFolders = () => { const listFolders = useCallback(() => { const listFoldersGateway = new ListFoldersGraphQLGateway(client); const listFoldersRepository = new ListFoldersRepository(foldersCache, listFoldersGateway); - const repository = new ListFoldersRepositoryWithLoading( + const listFoldersUseCase = new ListFoldersUseCase(listFoldersRepository); + const listFoldersUseCaseWithLoading = new ListFoldersUseCaseWithLoading( loadingRepository, - listFoldersRepository + listFoldersUseCase ); - const listFoldersUseCase = new ListFoldersUseCase(repository); - const listFoldersController = new ListFoldersController(listFoldersUseCase); + const listFoldersController = new ListFoldersController(listFoldersUseCaseWithLoading); return listFoldersController.execute(type); }, [type, client, foldersCache, loadingRepository]); @@ -101,17 +101,18 @@ export const useFolders = () => { (id: string) => { const getFolderGateway = new GetFolderGraphQLGateway(client); const getFolderRepository = new GetFolderRepository(foldersCache, getFolderGateway); - const repository = new GetFolderRepositoryWithLoading( + const getFolderUseCase = new GetFolderUseCase(getFolderRepository); + const getFolderUseCaseWithLoading = new GetFolderUseCaseWithLoading( loadingRepository, - getFolderRepository + getFolderUseCase ); - const getFolderUseCase = new GetFolderUseCase(repository); - const getFolderController = new GetFolderController(getFolderUseCase); + const getFolderController = new GetFolderController(getFolderUseCaseWithLoading); return getFolderController.execute(id); }, [client, foldersCache, loadingRepository] ); + // Get Descendant Folders const getDescendantFolders = useCallback( (id: string) => { const repository = new GetDescendantFoldersRepository(foldersCache); @@ -128,12 +129,14 @@ export const useFolders = () => { foldersCache, createFolderGateway ); - const repository = new CreateFolderRepositoryWithLoading( + const createFolderUseCase = new CreateFolderUseCase(createFolderRepository); + const createFolderUseCaseWithLoading = new CreateFolderUseCaseWithLoading( loadingRepository, - createFolderRepository + createFolderUseCase + ); + const createFolderController = new CreateFolderController( + createFolderUseCaseWithLoading ); - const createFolderUseCase = new CreateFolderUseCase(repository); - const createFolderController = new CreateFolderController(createFolderUseCase); return createFolderController.execute(folder, type); }, [client, foldersCache, loadingRepository, type] @@ -147,12 +150,14 @@ export const useFolders = () => { foldersCache, updateFolderGateway ); - const repository = new UpdateFolderRepositoryWithLoading( + const updateFolderUseCase = new UpdateFolderUseCase(updateFolderRepository); + const updateFolderUseCaseWithLoading = new UpdateFolderUseCaseWithLoading( loadingRepository, - updateFolderRepository + updateFolderUseCase + ); + const updateFolderController = new UpdateFolderController( + updateFolderUseCaseWithLoading ); - const updateFolderUseCase = new UpdateFolderUseCase(repository); - const updateFolderController = new UpdateFolderController(updateFolderUseCase); return updateFolderController.execute(folder); }, [client, foldersCache, loadingRepository] @@ -166,13 +171,14 @@ export const useFolders = () => { foldersCache, deleteFolderGateway ); - - const repository = new DeleteFolderRepositoryWithLoading( + const deleteFolderUseCase = new DeleteFolderUseCase(deleteFolderRepository); + const deleteFolderUseCaseWithLoading = new DeleteFolderUseCaseWithLoading( loadingRepository, - deleteFolderRepository + deleteFolderUseCase + ); + const deleteFolderController = new DeleteFolderController( + deleteFolderUseCaseWithLoading ); - const deleteFolderUseCase = new DeleteFolderUseCase(repository); - const deleteFolderController = new DeleteFolderController(deleteFolderUseCase); return deleteFolderController.execute(folder); }, [client, foldersCache, loadingRepository] From 2370f07892190c9b7c4e0886320bfb41e4e4e635 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Tue, 27 Aug 2024 09:49:51 +0200 Subject: [PATCH 06/28] refactor(app-aco): move Graphql interface to gateway --- .../CreateFolderGraphQLGateway.ts | 30 +++++++++++++++++-- .../DeleteFolderGraphQLGateway.ts | 15 +++++++++- .../GetFolder/GetFolderGraphQLGateway.ts | 15 +++++++++- .../ListFolders/ListFoldersGraphQLGateway.ts | 18 ++++++++++- .../UpdateFolderGraphQLGateway.ts | 21 ++++++++++++- 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts index cfe50984d6d..6a90d536926 100644 --- a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts @@ -1,8 +1,34 @@ import { ApolloClient } from "apollo-client"; import { ICreateFolderGateway } from "./ICreateFolderGateway"; -import { CREATE_FOLDER } from "~/graphql/folders.gql"; -import { CreateFolderResponse, CreateFolderVariables } from "~/types"; import { CreateFolderGraphQLDTO } from "./ICreateFolderGraphQLMapper"; +import { CREATE_FOLDER } from "~/graphql/folders.gql"; +import { AcoError, FolderItem } from "~/types"; + +export interface CreateFolderResponse { + aco: { + createFolder: { + data: FolderItem; + error: AcoError | null; + }; + }; +} + +export interface CreateFolderVariables { + data: Omit< + FolderItem, + | "id" + | "createdOn" + | "createdBy" + | "savedOn" + | "savedBy" + | "modifiedOn" + | "modifiedBy" + | "hasNonInheritedPermissions" + | "canManageContent" + | "canManagePermissions" + | "canManageStructure" + >; +} export class CreateFolderGraphQLGateway implements ICreateFolderGateway { private client: ApolloClient; diff --git a/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts index b1a403931c4..db0d3eb00d8 100644 --- a/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts @@ -1,7 +1,20 @@ import { ApolloClient } from "apollo-client"; import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; import { DELETE_FOLDER } from "~/graphql/folders.gql"; -import { DeleteFolderResponse, DeleteFolderVariables } from "~/types"; +import { AcoError } from "~/types"; + +export interface DeleteFolderVariables { + id: string; +} + +export interface DeleteFolderResponse { + aco: { + deleteFolder: { + data: boolean; + error: AcoError | null; + }; + }; +} export class DeleteFolderGraphQLGateway implements IDeleteFolderGateway { private client: ApolloClient; diff --git a/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts index cda71e7520a..acbd731dfc3 100644 --- a/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts @@ -1,7 +1,20 @@ import { ApolloClient } from "apollo-client"; import { IGetFolderGateway } from "./IGetFolderGateway"; import { GET_FOLDER } from "~/graphql/folders.gql"; -import { GetFolderResponse, GetFolderQueryVariables } from "~/types"; +import { FolderItem, AcoError } from "~/types"; + +export interface GetFolderResponse { + aco: { + getFolder: { + data: FolderItem | null; + error: AcoError | null; + }; + }; +} + +export interface GetFolderQueryVariables { + id: string; +} export class GetFolderGraphQLGateway implements IGetFolderGateway { private client: ApolloClient; diff --git a/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts index ace90c5f72d..ef74a1604d4 100644 --- a/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts @@ -2,7 +2,23 @@ import { ApolloClient } from "apollo-client"; import { IListFoldersGateway } from "./IListFoldersGateway"; import { LIST_FOLDERS } from "~/graphql/folders.gql"; import { ROOT_FOLDER } from "~/constants"; -import { FolderItem, ListFoldersQueryVariables, ListFoldersResponse } from "~/types"; +import { AcoError, FolderItem } from "~/types"; + +export interface ListFoldersResponse { + aco: { + listFolders: { + data: FolderItem[] | null; + error: AcoError | null; + }; + }; +} + +export interface ListFoldersQueryVariables { + type: string; + limit: number; + sort?: Record; + after?: string | null; +} export class ListFoldersGraphQLGateway implements IListFoldersGateway { private client: ApolloClient; diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts index 5e021290c4c..54136a0b31c 100644 --- a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts @@ -1,10 +1,29 @@ import { ApolloClient } from "apollo-client"; import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; import { UPDATE_FOLDER } from "~/graphql/folders.gql"; -import { UpdateFolderResponse, UpdateFolderVariables } from "~/types"; +import { AcoError, FolderItem } from "~/types"; import { ROOT_FOLDER } from "~/constants"; import { UpdateFolderGraphQLDTO } from "./IUpdateFolderGraphQLMapper"; +export interface UpdateFolderResponse { + aco: { + updateFolder: { + data: FolderItem; + error: AcoError | null; + }; + }; +} + +export interface UpdateFolderVariables { + id: string; + data: Partial< + Omit< + FolderItem, + "id" | "createdOn" | "createdBy" | "savedOn" | "savedBy" | "modifiedOn" | "modifiedBy" + > + >; +} + export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { private client: ApolloClient; From bf1e730aca15272f6194868f1aa6f4aef0bc8131 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Wed, 18 Sep 2024 14:26:01 +0200 Subject: [PATCH 07/28] chore: wip --- .../app-aco/src/folders/presenters/FoldersPresenter.ts | 3 ++- packages/app-aco/src/hooks/useFolders.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/app-aco/src/folders/presenters/FoldersPresenter.ts b/packages/app-aco/src/folders/presenters/FoldersPresenter.ts index 9fac2153bae..ef8cf046225 100644 --- a/packages/app-aco/src/folders/presenters/FoldersPresenter.ts +++ b/packages/app-aco/src/folders/presenters/FoldersPresenter.ts @@ -2,6 +2,7 @@ import { LoadingRepository } from "@webiny/app-utils"; import { FoldersCache } from "~/folders/cache"; import { Folder } from "~/folders/domain"; import { ROOT_FOLDER } from "~/constants"; +import { FolderItem } from "~/types"; export class FoldersPresenter { private foldersCache: FoldersCache; @@ -19,7 +20,7 @@ export class FoldersPresenter { }; } - private folderMapper(folder: Folder) { + private folderMapper(folder: Folder): FolderItem { return { id: folder.id, title: folder.title, diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index fc10342b60f..792d63181e7 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -50,7 +50,13 @@ export const useFolders = () => { const foldersContext = useContext(FoldersContext); const appContext = useContext(AcoAppContext); - const [vm, setVm] = useState({}); + const [vm, setVm] = useState<{ + folders: FolderItem[] | undefined; + loading: Record | undefined; + }>({ + folders: undefined, + loading: undefined + }); if (!foldersContext) { throw new Error("useFolders must be used within a FoldersProvider"); @@ -202,7 +208,7 @@ export const useFolders = () => { } listFolders(); - }, [foldersCache]); + }, []); return { ...vm, From 171d1ade9de67c8368923213cc20f86e7b44ce99 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 17 Oct 2024 12:04:34 +0200 Subject: [PATCH 08/28] wip: folders FTA --- .../src/components/FolderTree/Node/index.tsx | 2 + packages/app-aco/src/contexts/acoList.tsx | 11 +- .../domain => features/folder}/Folder.ts | 4 +- .../folder}/cache/FoldersCache.ts | 6 +- .../folder}/cache/FoldersCacheFactory.ts | 0 .../folder}/cache/ICache.ts | 1 + .../folder}/cache/index.ts | 0 .../createFolder/CreateFolderGqlGateway.ts | 110 +++++++++ .../createFolder/CreateFolderRepository.ts | 30 +++ .../createFolder}/CreateFolderUseCase.ts | 4 +- .../CreateFolderUseCaseWithLoading.ts | 2 +- .../features/folder/createFolder/FolderDto.ts | 9 + .../folder/createFolder/FolderGqlDto.ts | 20 ++ .../createFolder/ICreateFolderGateway.ts | 6 + .../createFolder}/ICreateFolderRepository.ts | 2 +- .../createFolder}/ICreateFolderUseCase.ts | 0 .../folder/createFolder/useCreateFolder.ts | 37 +++ .../deleteFolder/DeleteFolderGqlGateway.ts} | 21 +- .../deleteFolder}/DeleteFolderRepository.ts | 13 +- .../deleteFolder/DeleteFolderUseCase.ts | 24 ++ .../DeleteFolderUseCaseWithLoading.ts | 2 +- .../deleteFolder}/IDeleteFolderGateway.ts | 0 .../deleteFolder/IDeleteFolderRepository.ts | 5 + .../deleteFolder/IDeleteFolderUseCase.ts | 14 ++ .../folder/deleteFolder/useDeleteFolder.ts | 37 +++ .../folder/getDescendantFolders/FolderDto.ts | 10 + .../GetDescendantFoldersRepository.ts | 6 +- .../GetDescendantFoldersUseCase.ts | 26 ++ .../IGetDescendantFoldersRepository.ts | 2 +- .../IGetDescendantFoldersUseCase.ts | 9 + .../useGetDescendantFolders.ts | 25 ++ .../folder/getFolder/GetFolderGqlGateway.ts | 97 ++++++++ .../folder/getFolder}/GetFolderRepository.ts | 8 +- .../folder/getFolder}/GetFolderUseCase.ts | 2 +- .../getFolder}/GetFolderUseCaseWithLoading.ts | 0 .../folder/getFolder/IGetFolderGateway.ts | 24 ++ .../folder/getFolder}/IGetFolderRepository.ts | 0 .../folder/getFolder}/IGetFolderUseCase.ts | 0 .../features/folder/getFolder/useGetFolder.ts | 37 +++ .../features/folder/listFolders/FolderDto.ts | 53 +++++ .../folder/listFolders/IListFoldersGateway.ts | 24 ++ .../listFolders}/IListFoldersRepository.ts | 0 .../listFolders}/IListFoldersUseCase.ts | 0 .../listFolders/ListFoldersGqlGateway.ts} | 53 ++++- .../listFolders}/ListFoldersRepository.ts | 8 +- .../folder/listFolders}/ListFoldersUseCase.ts | 2 +- .../ListFoldersUseCaseWithLoading.ts | 2 +- .../folder/listFolders/useListFolders.ts | 33 +++ .../features/folder/updateFolder/FolderDto.ts | 9 + .../updateFolder/IUpdateFolderGateway.ts | 5 + .../updateFolder}/IUpdateFolderRepository.ts | 2 +- .../updateFolder}/IUpdateFolderUseCase.ts | 0 .../updateFolder/UpdateFolderGqlGateway.ts} | 57 ++++- .../updateFolder/UpdateFolderRepository.ts | 30 +++ .../updateFolder}/UpdateFolderUseCase.ts | 4 +- .../UpdateFolderUseCaseWithLoading.ts | 2 +- .../folder/updateFolder/useUpdateFolder.ts | 37 +++ .../CreateFolder/CreateFolderController.ts | 21 -- .../CreateFolder/ICreateFolderController.ts | 5 - .../folders/controllers/CreateFolder/index.ts | 2 - .../DeleteFolder/DeleteFolderController.ts | 15 -- .../DeleteFolder/IDeleteFolderController.ts | 5 - .../folders/controllers/DeleteFolder/index.ts | 2 - .../GetFolder/GetFolderController.ts | 14 -- .../GetFolder/IGetFolderController.ts | 3 - .../folders/controllers/GetFolder/index.ts | 2 - .../ListFolders/IListFoldersController.ts | 3 - .../ListFolders/ListFoldersController.ts | 14 -- .../folders/controllers/ListFolders/index.ts | 2 - .../UpdateFolder/IUpdateFolderController.ts | 5 - .../UpdateFolder/UpdateFolderController.ts | 22 -- .../folders/controllers/UpdateFolder/index.ts | 2 - .../app-aco/src/folders/controllers/index.ts | 5 - packages/app-aco/src/folders/domain/index.ts | 1 - .../CreateFolderGraphQLGateway.ts | 65 ----- .../CreateFolder/CreateFolderGraphQLMapper.ts | 14 -- .../CreateFolder/ICreateFolderGateway.ts | 6 - .../ICreateFolderGraphQLMapper.ts | 14 -- .../folders/gateways/CreateFolder/index.ts | 4 - .../folders/gateways/DeleteFolder/index.ts | 2 - .../GetFolder/GetFolderGraphQLGateway.ts | 52 ---- .../gateways/GetFolder/IGetFolderGateway.ts | 5 - .../src/folders/gateways/GetFolder/index.ts | 2 - .../ListFolders/IListFoldersGateway.ts | 5 - .../src/folders/gateways/ListFolders/index.ts | 2 - .../UpdateFolder/IUpdateFolderGateway.ts | 6 - .../IUpdateFolderGraphQLMapper.ts | 14 -- .../UpdateFolder/UpdateFolderGraphQLMapper.ts | 14 -- .../folders/gateways/UpdateFolder/index.ts | 4 - .../app-aco/src/folders/gateways/index.ts | 5 - packages/app-aco/src/folders/index.ts | 7 - .../folders/presenters/FoldersPresenter.ts | 43 ---- .../app-aco/src/folders/presenters/index.ts | 1 - .../CreateFolder/CreateFolderRepository.ts | 20 -- .../repositories/CreateFolder/index.ts | 2 - .../DeleteFolder/IDeleteFolderRepository.ts | 3 - .../repositories/DeleteFolder/index.ts | 2 - .../GetDescendantFolders/index.ts | 2 - .../folders/repositories/GetFolder/index.ts | 2 - .../folders/repositories/ListFolders/index.ts | 2 - .../UpdateFolder/UpdateFolderRepository.ts | 20 -- .../repositories/UpdateFolder/index.ts | 2 - .../app-aco/src/folders/repositories/index.ts | 6 - .../folders/useCases/CreateFolder/index.ts | 3 - .../DeleteFolder/DeleteFolderUseCase.ts | 14 -- .../DeleteFolder/IDeleteFolderUseCase.ts | 7 - .../folders/useCases/DeleteFolder/index.ts | 3 - .../src/folders/useCases/GetFolder/index.ts | 3 - .../src/folders/useCases/ListFolders/index.ts | 3 - .../folders/useCases/UpdateFolder/index.ts | 3 - .../app-aco/src/folders/useCases/index.ts | 5 - packages/app-aco/src/hooks/useFolders.ts | 224 ++++-------------- 112 files changed, 930 insertions(+), 711 deletions(-) rename packages/app-aco/src/{folders/domain => features/folder}/Folder.ts (97%) rename packages/app-aco/src/{folders => features/folder}/cache/FoldersCache.ts (90%) rename packages/app-aco/src/{folders => features/folder}/cache/FoldersCacheFactory.ts (100%) rename packages/app-aco/src/{folders => features/folder}/cache/ICache.ts (89%) rename packages/app-aco/src/{folders => features/folder}/cache/index.ts (100%) create mode 100644 packages/app-aco/src/features/folder/createFolder/CreateFolderGqlGateway.ts create mode 100644 packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts rename packages/app-aco/src/{folders/useCases/CreateFolder => features/folder/createFolder}/CreateFolderUseCase.ts (85%) rename packages/app-aco/src/{folders/useCases/CreateFolder => features/folder/createFolder}/CreateFolderUseCaseWithLoading.ts (100%) create mode 100644 packages/app-aco/src/features/folder/createFolder/FolderDto.ts create mode 100644 packages/app-aco/src/features/folder/createFolder/FolderGqlDto.ts create mode 100644 packages/app-aco/src/features/folder/createFolder/ICreateFolderGateway.ts rename packages/app-aco/src/{folders/repositories/CreateFolder => features/folder/createFolder}/ICreateFolderRepository.ts (68%) rename packages/app-aco/src/{folders/useCases/CreateFolder => features/folder/createFolder}/ICreateFolderUseCase.ts (100%) create mode 100644 packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts rename packages/app-aco/src/{folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts => features/folder/deleteFolder/DeleteFolderGqlGateway.ts} (69%) rename packages/app-aco/src/{folders/repositories/DeleteFolder => features/folder/deleteFolder}/DeleteFolderRepository.ts (51%) create mode 100644 packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCase.ts rename packages/app-aco/src/{folders/useCases/DeleteFolder => features/folder/deleteFolder}/DeleteFolderUseCaseWithLoading.ts (88%) rename packages/app-aco/src/{folders/gateways/DeleteFolder => features/folder/deleteFolder}/IDeleteFolderGateway.ts (100%) create mode 100644 packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderRepository.ts create mode 100644 packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts create mode 100644 packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/FolderDto.ts rename packages/app-aco/src/{folders/repositories/GetDescendantFolders => features/folder/getDescendantFolders}/GetDescendantFoldersRepository.ts (87%) create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersUseCase.ts rename packages/app-aco/src/{folders/repositories/GetDescendantFolders => features/folder/getDescendantFolders}/IGetDescendantFoldersRepository.ts (68%) create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts create mode 100644 packages/app-aco/src/features/folder/getFolder/GetFolderGqlGateway.ts rename packages/app-aco/src/{folders/repositories/GetFolder => features/folder/getFolder}/GetFolderRepository.ts (69%) rename packages/app-aco/src/{folders/useCases/GetFolder => features/folder/getFolder}/GetFolderUseCase.ts (85%) rename packages/app-aco/src/{folders/useCases/GetFolder => features/folder/getFolder}/GetFolderUseCaseWithLoading.ts (100%) create mode 100644 packages/app-aco/src/features/folder/getFolder/IGetFolderGateway.ts rename packages/app-aco/src/{folders/repositories/GetFolder => features/folder/getFolder}/IGetFolderRepository.ts (100%) rename packages/app-aco/src/{folders/useCases/GetFolder => features/folder/getFolder}/IGetFolderUseCase.ts (100%) create mode 100644 packages/app-aco/src/features/folder/getFolder/useGetFolder.ts create mode 100644 packages/app-aco/src/features/folder/listFolders/FolderDto.ts create mode 100644 packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts rename packages/app-aco/src/{folders/repositories/ListFolders => features/folder/listFolders}/IListFoldersRepository.ts (100%) rename packages/app-aco/src/{folders/useCases/ListFolders => features/folder/listFolders}/IListFoldersUseCase.ts (100%) rename packages/app-aco/src/{folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts => features/folder/listFolders/ListFoldersGqlGateway.ts} (59%) rename packages/app-aco/src/{folders/repositories/ListFolders => features/folder/listFolders}/ListFoldersRepository.ts (71%) rename packages/app-aco/src/{folders/useCases/ListFolders => features/folder/listFolders}/ListFoldersUseCase.ts (85%) rename packages/app-aco/src/{folders/useCases/ListFolders => features/folder/listFolders}/ListFoldersUseCaseWithLoading.ts (88%) create mode 100644 packages/app-aco/src/features/folder/listFolders/useListFolders.ts create mode 100644 packages/app-aco/src/features/folder/updateFolder/FolderDto.ts create mode 100644 packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts rename packages/app-aco/src/{folders/repositories/UpdateFolder => features/folder/updateFolder}/IUpdateFolderRepository.ts (68%) rename packages/app-aco/src/{folders/useCases/UpdateFolder => features/folder/updateFolder}/IUpdateFolderUseCase.ts (100%) rename packages/app-aco/src/{folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts => features/folder/updateFolder/UpdateFolderGqlGateway.ts} (50%) create mode 100644 packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts rename packages/app-aco/src/{folders/useCases/UpdateFolder => features/folder/updateFolder}/UpdateFolderUseCase.ts (86%) rename packages/app-aco/src/{folders/useCases/UpdateFolder => features/folder/updateFolder}/UpdateFolderUseCaseWithLoading.ts (88%) create mode 100644 packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts delete mode 100644 packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/CreateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/DeleteFolder/index.ts delete mode 100644 packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/GetFolder/index.ts delete mode 100644 packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts delete mode 100644 packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts delete mode 100644 packages/app-aco/src/folders/controllers/ListFolders/index.ts delete mode 100644 packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts delete mode 100644 packages/app-aco/src/folders/controllers/UpdateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/controllers/index.ts delete mode 100644 packages/app-aco/src/folders/domain/index.ts delete mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts delete mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts delete mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts delete mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts delete mode 100644 packages/app-aco/src/folders/gateways/CreateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/gateways/DeleteFolder/index.ts delete mode 100644 packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts delete mode 100644 packages/app-aco/src/folders/gateways/GetFolder/IGetFolderGateway.ts delete mode 100644 packages/app-aco/src/folders/gateways/GetFolder/index.ts delete mode 100644 packages/app-aco/src/folders/gateways/ListFolders/IListFoldersGateway.ts delete mode 100644 packages/app-aco/src/folders/gateways/ListFolders/index.ts delete mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts delete mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts delete mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts delete mode 100644 packages/app-aco/src/folders/gateways/UpdateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/gateways/index.ts delete mode 100644 packages/app-aco/src/folders/index.ts delete mode 100644 packages/app-aco/src/folders/presenters/FoldersPresenter.ts delete mode 100644 packages/app-aco/src/folders/presenters/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts delete mode 100644 packages/app-aco/src/folders/repositories/CreateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts delete mode 100644 packages/app-aco/src/folders/repositories/DeleteFolder/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/GetDescendantFolders/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/GetFolder/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/ListFolders/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts delete mode 100644 packages/app-aco/src/folders/repositories/UpdateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/repositories/index.ts delete mode 100644 packages/app-aco/src/folders/useCases/CreateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts delete mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts delete mode 100644 packages/app-aco/src/folders/useCases/DeleteFolder/index.ts delete mode 100644 packages/app-aco/src/folders/useCases/GetFolder/index.ts delete mode 100644 packages/app-aco/src/folders/useCases/ListFolders/index.ts delete mode 100644 packages/app-aco/src/folders/useCases/UpdateFolder/index.ts delete mode 100644 packages/app-aco/src/folders/useCases/index.ts diff --git a/packages/app-aco/src/components/FolderTree/Node/index.tsx b/packages/app-aco/src/components/FolderTree/Node/index.tsx index cf3fe1d3ef4..39bc2b10c60 100644 --- a/packages/app-aco/src/components/FolderTree/Node/index.tsx +++ b/packages/app-aco/src/components/FolderTree/Node/index.tsx @@ -79,6 +79,8 @@ export const Node = ({ node, depth, isOpen, enableActions, onToggle, onClick }: }; const id = useMemo(() => { + console.log("folder.id", folder.id); + const { id } = parseIdentifier(String(folder.id)); return id; }, [folder.id]); diff --git a/packages/app-aco/src/contexts/acoList.tsx b/packages/app-aco/src/contexts/acoList.tsx index 7add4b27b30..2695295319a 100644 --- a/packages/app-aco/src/contexts/acoList.tsx +++ b/packages/app-aco/src/contexts/acoList.tsx @@ -123,7 +123,6 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => const { folders: originalFolders, loading: foldersLoading, - listFolders, getDescendantFolders } = useFolders(); const folderContext = useContext(FoldersContext); @@ -155,10 +154,6 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => return; } - if (!originalFolders) { - listFolders(); - } - setState(state => { return { ...state, @@ -253,6 +248,10 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => // Initialize an empty object let where = {}; + if (!state.folderId) { + return where; + } + // Check if the current folder ID is not the ROOT_FOLDER folder if (state.folderId !== ROOT_FOLDER) { // Get descendant folder IDs of the current folder @@ -331,7 +330,7 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => const { hasMoreItems } = meta; // Retrieve all descendant folders of the current folderId - const folderWithChildren = getDescendantFolders(folderId); + const folderWithChildren = folderId ? getDescendantFolders(folderId) : []; // Compute the lengths of various arrays for later comparisons const foldersLength = folders.length; diff --git a/packages/app-aco/src/folders/domain/Folder.ts b/packages/app-aco/src/features/folder/Folder.ts similarity index 97% rename from packages/app-aco/src/folders/domain/Folder.ts rename to packages/app-aco/src/features/folder/Folder.ts index 23abccd015d..9d1564f286e 100644 --- a/packages/app-aco/src/folders/domain/Folder.ts +++ b/packages/app-aco/src/features/folder/Folder.ts @@ -1,7 +1,7 @@ import { CmsIdentity, FolderPermission } from "~/types"; export interface FolderData { - id?: string; + id: string; title: string; slug: string; type: string; @@ -38,7 +38,7 @@ export class Folder { public modifiedOn?: string | null; protected constructor(folder: FolderData) { - this.id = folder.id ?? ""; + this.id = folder.id; this.title = folder.title; this.slug = folder.slug; this.type = folder.type; diff --git a/packages/app-aco/src/folders/cache/FoldersCache.ts b/packages/app-aco/src/features/folder/cache/FoldersCache.ts similarity index 90% rename from packages/app-aco/src/folders/cache/FoldersCache.ts rename to packages/app-aco/src/features/folder/cache/FoldersCache.ts index 6e1f6f8f5af..4d69d04cbbf 100644 --- a/packages/app-aco/src/folders/cache/FoldersCache.ts +++ b/packages/app-aco/src/features/folder/cache/FoldersCache.ts @@ -1,6 +1,6 @@ import { makeAutoObservable } from "mobx"; -import { Folder } from "~/folders/domain"; import { ICache } from "./ICache"; +import { Folder } from "../Folder"; export class FoldersCache implements ICache { private folders: Folder[]; @@ -10,6 +10,10 @@ export class FoldersCache implements ICache { makeAutoObservable(this); } + hasItems() { + return this.folders.length > 0; + } + getItems() { return this.folders; } diff --git a/packages/app-aco/src/folders/cache/FoldersCacheFactory.ts b/packages/app-aco/src/features/folder/cache/FoldersCacheFactory.ts similarity index 100% rename from packages/app-aco/src/folders/cache/FoldersCacheFactory.ts rename to packages/app-aco/src/features/folder/cache/FoldersCacheFactory.ts diff --git a/packages/app-aco/src/folders/cache/ICache.ts b/packages/app-aco/src/features/folder/cache/ICache.ts similarity index 89% rename from packages/app-aco/src/folders/cache/ICache.ts rename to packages/app-aco/src/features/folder/cache/ICache.ts index 1f1be7afcca..994ca7a29fe 100644 --- a/packages/app-aco/src/folders/cache/ICache.ts +++ b/packages/app-aco/src/features/folder/cache/ICache.ts @@ -1,4 +1,5 @@ export interface ICache { + hasItems: () => boolean; getItems: () => TItem[]; set: (item: TItem) => Promise; setMultiple: (items: TItem[]) => Promise; diff --git a/packages/app-aco/src/folders/cache/index.ts b/packages/app-aco/src/features/folder/cache/index.ts similarity index 100% rename from packages/app-aco/src/folders/cache/index.ts rename to packages/app-aco/src/features/folder/cache/index.ts diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolderGqlGateway.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderGqlGateway.ts new file mode 100644 index 00000000000..4db71c88118 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderGqlGateway.ts @@ -0,0 +1,110 @@ +import ApolloClient from "apollo-client"; +import gql from "graphql-tag"; +import { ICreateFolderGateway } from "./ICreateFolderGateway"; +import { FolderDto } from "./FolderDto"; +import { AcoError, FolderItem } from "~/types"; + +export interface CreateFolderResponse { + aco: { + createFolder: { + data: FolderItem; + error: AcoError | null; + }; + }; +} + +export interface CreateFolderVariables { + data: Omit< + FolderItem, + | "id" + | "createdOn" + | "createdBy" + | "savedOn" + | "savedBy" + | "modifiedOn" + | "modifiedBy" + | "hasNonInheritedPermissions" + | "canManageContent" + | "canManagePermissions" + | "canManageStructure" + >; +} + +export const CREATE_FOLDER = gql` + mutation CreateFolder($data: FolderCreateInput!) { + aco { + createFolder(data: $data) { + data { + id + title + slug + permissions { + target + level + inheritedFrom + } + hasNonInheritedPermissions + canManagePermissions + canManageStructure + canManageContent + parentId + type + savedOn + savedBy { + id + displayName + } + createdOn + createdBy { + id + displayName + } + modifiedOn + modifiedBy { + id + displayName + } + } + error { + code + data + message + } + } + } + } +`; + +export class CreateFolderGqlGateway implements ICreateFolderGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(folder: FolderDto) { + const { data: response } = await this.client.mutate< + CreateFolderResponse, + CreateFolderVariables + >({ + mutation: CREATE_FOLDER, + variables: { + data: { + ...folder + } + } + }); + + if (!response) { + throw new Error("Network error while creating folder."); + } + + const { data, error } = response.aco.createFolder; + + if (!data) { + throw new Error(error?.message || "Could not create folder"); + } + + return data; + } +} diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts new file mode 100644 index 00000000000..c9c7e065265 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts @@ -0,0 +1,30 @@ +import { makeAutoObservable } from "mobx"; +import { ICreateFolderRepository } from "./ICreateFolderRepository"; +import { Folder } from "../Folder"; +import { FoldersCache } from "../cache"; +import { ICreateFolderGateway } from "./ICreateFolderGateway"; +import { FolderDto } from "./FolderDto"; + +export class CreateFolderRepository implements ICreateFolderRepository { + private cache: FoldersCache; + private gateway: ICreateFolderGateway; + + constructor(cache: FoldersCache, gateway: ICreateFolderGateway) { + this.cache = cache; + this.gateway = gateway; + makeAutoObservable(this); + } + + async execute(folder: Folder) { + const dto: FolderDto = { + title: folder.title, + slug: folder.slug, + permissions: folder.permissions, + type: folder.type, + parentId: folder.parentId + }; + + const result = await this.gateway.execute(dto); + await this.cache.set(Folder.create(result)); + } +} diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderUseCase.ts similarity index 85% rename from packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts rename to packages/app-aco/src/features/folder/createFolder/CreateFolderUseCase.ts index e878817d0ee..fb42c3be0e5 100644 --- a/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCase.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderUseCase.ts @@ -1,6 +1,6 @@ import { CreateFolderParams, ICreateFolderUseCase } from "./ICreateFolderUseCase"; -import { Folder } from "~/folders/domain"; -import { ICreateFolderRepository } from "~/folders/repositories"; +import { ICreateFolderRepository } from "./ICreateFolderRepository"; +import { Folder } from "../Folder"; export class CreateFolderUseCase implements ICreateFolderUseCase { private repository: ICreateFolderRepository; diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderUseCaseWithLoading.ts similarity index 100% rename from packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts rename to packages/app-aco/src/features/folder/createFolder/CreateFolderUseCaseWithLoading.ts index e61367cfd92..75578757903 100644 --- a/packages/app-aco/src/folders/useCases/CreateFolder/CreateFolderUseCaseWithLoading.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderUseCaseWithLoading.ts @@ -1,5 +1,5 @@ -import { CreateFolderParams, ICreateFolderUseCase } from "./ICreateFolderUseCase"; import { ILoadingRepository } from "@webiny/app-utils"; +import { CreateFolderParams, ICreateFolderUseCase } from "./ICreateFolderUseCase"; import { LoadingActionsEnum } from "~/types"; export class CreateFolderUseCaseWithLoading implements ICreateFolderUseCase { diff --git a/packages/app-aco/src/features/folder/createFolder/FolderDto.ts b/packages/app-aco/src/features/folder/createFolder/FolderDto.ts new file mode 100644 index 00000000000..09733f3ede8 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/FolderDto.ts @@ -0,0 +1,9 @@ +import { FolderPermission } from "~/types"; + +export interface FolderDto { + title: string; + slug: string; + permissions: FolderPermission[]; + type: string; + parentId: string | null; +} diff --git a/packages/app-aco/src/features/folder/createFolder/FolderGqlDto.ts b/packages/app-aco/src/features/folder/createFolder/FolderGqlDto.ts new file mode 100644 index 00000000000..0d2ff62504c --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/FolderGqlDto.ts @@ -0,0 +1,20 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderGqlDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; + type: string; + parentId: string | null; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity | null; + modifiedOn: string | null; +} diff --git a/packages/app-aco/src/features/folder/createFolder/ICreateFolderGateway.ts b/packages/app-aco/src/features/folder/createFolder/ICreateFolderGateway.ts new file mode 100644 index 00000000000..ba10ce21f07 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/ICreateFolderGateway.ts @@ -0,0 +1,6 @@ +import { FolderDto } from "./FolderDto"; +import { FolderGqlDto } from "./FolderGqlDto"; + +export interface ICreateFolderGateway { + execute: (folderDto: FolderDto) => Promise; +} diff --git a/packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts b/packages/app-aco/src/features/folder/createFolder/ICreateFolderRepository.ts similarity index 68% rename from packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts rename to packages/app-aco/src/features/folder/createFolder/ICreateFolderRepository.ts index e00e31413ae..d4cf5b909b9 100644 --- a/packages/app-aco/src/folders/repositories/CreateFolder/ICreateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/createFolder/ICreateFolderRepository.ts @@ -1,4 +1,4 @@ -import { Folder } from "~/folders/domain"; +import { Folder } from "../Folder"; export interface ICreateFolderRepository { execute: (folder: Folder) => Promise; diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/ICreateFolderUseCase.ts b/packages/app-aco/src/features/folder/createFolder/ICreateFolderUseCase.ts similarity index 100% rename from packages/app-aco/src/folders/useCases/CreateFolder/ICreateFolderUseCase.ts rename to packages/app-aco/src/features/folder/createFolder/ICreateFolderUseCase.ts diff --git a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts new file mode 100644 index 00000000000..1a7fd042ebb --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts @@ -0,0 +1,37 @@ +import { useCallback, useMemo } from "react"; +import { useApolloClient } from "@apollo/react-hooks"; +import { LoadingRepository } from "@webiny/app-utils"; +import { FoldersCache } from "../cache"; +import { CreateFolderGqlGateway } from "./CreateFolderGqlGateway"; +import { CreateFolderRepository } from "./CreateFolderRepository"; +import { CreateFolderUseCase } from "./CreateFolderUseCase"; +import { CreateFolderUseCaseWithLoading } from "./CreateFolderUseCaseWithLoading"; +import { CreateFolderParams } from "./ICreateFolderUseCase"; + +export const useCreateFolder = (cache: FoldersCache, loading: LoadingRepository, type: string) => { + const client = useApolloClient(); + + const gateway = useMemo(() => { + return new CreateFolderGqlGateway(client); + }, [client]); + + const repository = useMemo(() => { + return new CreateFolderRepository(cache, gateway); + }, [cache, gateway]); + + const useCase = useMemo(() => { + const createFolderUseCase = new CreateFolderUseCase(repository); + return new CreateFolderUseCaseWithLoading(loading, createFolderUseCase); + }, [repository, loading]); + + const createFolder = useCallback( + (params: CreateFolderParams) => { + return useCase.execute({ ...params, type }); + }, + [useCase] + ); + + return { + createFolder + }; +}; diff --git a/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderGqlGateway.ts similarity index 69% rename from packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts rename to packages/app-aco/src/features/folder/deleteFolder/DeleteFolderGqlGateway.ts index db0d3eb00d8..1de619638e6 100644 --- a/packages/app-aco/src/folders/gateways/DeleteFolder/DeleteFolderGraphQLGateway.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderGqlGateway.ts @@ -1,6 +1,6 @@ -import { ApolloClient } from "apollo-client"; +import ApolloClient from "apollo-client"; +import gql from "graphql-tag"; import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; -import { DELETE_FOLDER } from "~/graphql/folders.gql"; import { AcoError } from "~/types"; export interface DeleteFolderVariables { @@ -16,7 +16,22 @@ export interface DeleteFolderResponse { }; } -export class DeleteFolderGraphQLGateway implements IDeleteFolderGateway { +export const DELETE_FOLDER = gql` + mutation DeleteFolder($id: ID!) { + aco { + deleteFolder(id: $id) { + data + error { + code + data + message + } + } + } + } +`; + +export class DeleteFolderGqlGateway implements IDeleteFolderGateway { private client: ApolloClient; constructor(client: ApolloClient) { diff --git a/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepository.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts similarity index 51% rename from packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepository.ts rename to packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts index 8ba1942e06d..6b6c898b5db 100644 --- a/packages/app-aco/src/folders/repositories/DeleteFolder/DeleteFolderRepository.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts @@ -1,6 +1,8 @@ +import { makeAutoObservable } from "mobx"; import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; -import { FoldersCache } from "~/folders/cache"; -import { IDeleteFolderGateway } from "~/folders/gateways"; +import { FoldersCache } from "../cache"; +import { Folder } from "../Folder"; +import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; export class DeleteFolderRepository implements IDeleteFolderRepository { private cache: FoldersCache; @@ -9,10 +11,11 @@ export class DeleteFolderRepository implements IDeleteFolderRepository { constructor(cache: FoldersCache, gateway: IDeleteFolderGateway) { this.cache = cache; this.gateway = gateway; + makeAutoObservable(this); } - async execute(id: string) { - await this.gateway.execute(id); - await this.cache.remove(id); + async execute(folder: Folder) { + await this.gateway.execute(folder.id); + await this.cache.remove(folder.id); } } diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCase.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCase.ts new file mode 100644 index 00000000000..9dcbfb942ef --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCase.ts @@ -0,0 +1,24 @@ +import { DeleteFolderParams, IDeleteFolderUseCase } from "./IDeleteFolderUseCase"; +import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; +import { Folder } from "../Folder"; + +export class DeleteFolderUseCase implements IDeleteFolderUseCase { + private repository: IDeleteFolderRepository; + + constructor(repository: IDeleteFolderRepository) { + this.repository = repository; + } + + async execute(params: DeleteFolderParams) { + await this.repository.execute( + Folder.create({ + id: params.id, + title: params.title, + slug: params.slug, + type: params.type, + parentId: params.parentId, + permissions: params.permissions + }) + ); + } +} diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCaseWithLoading.ts similarity index 88% rename from packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts rename to packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCaseWithLoading.ts index 895d8aacd22..12717658c02 100644 --- a/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCaseWithLoading.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderUseCaseWithLoading.ts @@ -1,6 +1,6 @@ -import { DeleteFolderParams, IDeleteFolderUseCase } from "~/folders/useCases"; import { ILoadingRepository } from "@webiny/app-utils"; import { LoadingActionsEnum } from "~/types"; +import { DeleteFolderParams, IDeleteFolderUseCase } from "./IDeleteFolderUseCase"; export class DeleteFolderUseCaseWithLoading implements IDeleteFolderUseCase { private loadingRepository: ILoadingRepository; diff --git a/packages/app-aco/src/folders/gateways/DeleteFolder/IDeleteFolderGateway.ts b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderGateway.ts similarity index 100% rename from packages/app-aco/src/folders/gateways/DeleteFolder/IDeleteFolderGateway.ts rename to packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderGateway.ts diff --git a/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderRepository.ts b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderRepository.ts new file mode 100644 index 00000000000..d771713a47c --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderRepository.ts @@ -0,0 +1,5 @@ +import { Folder } from "../Folder"; + +export interface IDeleteFolderRepository { + execute: (folder: Folder) => Promise; +} diff --git a/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts new file mode 100644 index 00000000000..a257dd5b0e0 --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts @@ -0,0 +1,14 @@ +import { FolderPermission } from "~/types"; + +export interface DeleteFolderParams { + id: string; + title: string; + slug: string; + type: string; + parentId: string | null; + permissions: FolderPermission[]; +} + +export interface IDeleteFolderUseCase { + execute: (params: DeleteFolderParams) => Promise; +} diff --git a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts new file mode 100644 index 00000000000..425fbc4aa30 --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts @@ -0,0 +1,37 @@ +import { useCallback, useMemo } from "react"; +import { useApolloClient } from "@apollo/react-hooks"; +import { FoldersCache } from "../cache"; +import { LoadingRepository } from "@webiny/app-utils"; +import { DeleteFolderGqlGateway } from "./DeleteFolderGqlGateway"; +import { DeleteFolderRepository } from "./DeleteFolderRepository"; +import { DeleteFolderUseCase } from "./DeleteFolderUseCase"; +import { DeleteFolderUseCaseWithLoading } from "./DeleteFolderUseCaseWithLoading"; +import { DeleteFolderParams } from "./IDeleteFolderUseCase"; + +export const useDeleteFolder = (cache: FoldersCache, loading: LoadingRepository, type: string) => { + const client = useApolloClient(); + + const gateway = useMemo(() => { + return new DeleteFolderGqlGateway(client); + }, [client]); + + const repository = useMemo(() => { + return new DeleteFolderRepository(cache, gateway); + }, [cache, gateway]); + + const useCase = useMemo(() => { + const deleteFolderUseCase = new DeleteFolderUseCase(repository); + return new DeleteFolderUseCaseWithLoading(loading, deleteFolderUseCase); + }, [repository, loading]); + + const deleteFolder = useCallback( + (params: DeleteFolderParams) => { + return useCase.execute({ ...params, type }); + }, + [useCase] + ); + + return { + deleteFolder + }; +}; diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/FolderDto.ts b/packages/app-aco/src/features/folder/getDescendantFolders/FolderDto.ts new file mode 100644 index 00000000000..766a6f65f29 --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/FolderDto.ts @@ -0,0 +1,10 @@ +import { FolderPermission } from "~/types"; + +export interface FolderDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + type: string; + parentId: string | null; +} diff --git a/packages/app-aco/src/folders/repositories/GetDescendantFolders/GetDescendantFoldersRepository.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts similarity index 87% rename from packages/app-aco/src/folders/repositories/GetDescendantFolders/GetDescendantFoldersRepository.ts rename to packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts index 352242d849d..5c4fb977a81 100644 --- a/packages/app-aco/src/folders/repositories/GetDescendantFolders/GetDescendantFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts @@ -1,13 +1,15 @@ +import { makeAutoObservable } from "mobx"; import { IGetDescendantFoldersRepository } from "./IGetDescendantFoldersRepository"; +import { FoldersCache } from "../cache"; +import { Folder } from "../Folder"; import { ROOT_FOLDER } from "~/constants"; -import { FoldersCache } from "~/folders/cache"; -import { Folder } from "~/folders/domain"; export class GetDescendantFoldersRepository implements IGetDescendantFoldersRepository { private readonly cache: FoldersCache; constructor(cache: FoldersCache) { this.cache = cache; + makeAutoObservable(this); } execute(id: string): Folder[] { diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersUseCase.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersUseCase.ts new file mode 100644 index 00000000000..af95700892d --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersUseCase.ts @@ -0,0 +1,26 @@ +import { IGetDescendantFoldersRepository } from "./IGetDescendantFoldersRepository"; +import { + GetDescendantFoldersParams, + IGetDescendantFoldersUseCase +} from "./IGetDescendantFoldersUseCase"; + +export class GetDescendantFoldersUseCase implements IGetDescendantFoldersUseCase { + private repository: IGetDescendantFoldersRepository; + + constructor(repository: IGetDescendantFoldersRepository) { + this.repository = repository; + } + + execute(params: GetDescendantFoldersParams) { + const folders = this.repository.execute(params.id); + + return folders.map(folder => ({ + id: folder.id, + title: folder.title, + slug: folder.slug, + permissions: folder.permissions, + type: folder.type, + parentId: folder.parentId + })); + } +} diff --git a/packages/app-aco/src/folders/repositories/GetDescendantFolders/IGetDescendantFoldersRepository.ts b/packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersRepository.ts similarity index 68% rename from packages/app-aco/src/folders/repositories/GetDescendantFolders/IGetDescendantFoldersRepository.ts rename to packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersRepository.ts index 8629f0c15e4..97cbe4c59ff 100644 --- a/packages/app-aco/src/folders/repositories/GetDescendantFolders/IGetDescendantFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersRepository.ts @@ -1,4 +1,4 @@ -import { Folder } from "~/folders/domain"; +import { Folder } from "../Folder"; export interface IGetDescendantFoldersRepository { execute: (id: string) => Folder[]; diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersUseCase.ts b/packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersUseCase.ts new file mode 100644 index 00000000000..142753f7c72 --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/IGetDescendantFoldersUseCase.ts @@ -0,0 +1,9 @@ +import { FolderDto } from "./FolderDto"; + +export interface GetDescendantFoldersParams { + id: string; +} + +export interface IGetDescendantFoldersUseCase { + execute: (params: GetDescendantFoldersParams) => FolderDto[]; +} diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts b/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts new file mode 100644 index 00000000000..38c90cf318d --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts @@ -0,0 +1,25 @@ +import { useCallback, useMemo } from "react"; +import { FoldersCache } from "../cache"; +import { GetDescendantFoldersRepository } from "./GetDescendantFoldersRepository"; +import { GetDescendantFoldersUseCase } from "./GetDescendantFoldersUseCase"; + +export const useGetDescendantFolders = (cache: FoldersCache) => { + const repository = useMemo(() => { + return new GetDescendantFoldersRepository(cache); + }, [cache]); + + const useCase = useMemo(() => { + return new GetDescendantFoldersUseCase(repository); + }, [repository]); + + const getDescendantFolders = useCallback( + (id: string) => { + return useCase.execute({ id }); + }, + [useCase] + ); + + return { + getDescendantFolders + }; +}; diff --git a/packages/app-aco/src/features/folder/getFolder/GetFolderGqlGateway.ts b/packages/app-aco/src/features/folder/getFolder/GetFolderGqlGateway.ts new file mode 100644 index 00000000000..3439569c7de --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolder/GetFolderGqlGateway.ts @@ -0,0 +1,97 @@ +import ApolloClient from "apollo-client"; +import gql from "graphql-tag"; +import { IGetFolderGateway } from "./IGetFolderGateway"; +import { FolderItem, AcoError } from "~/types"; + +export interface GetFolderResponse { + aco: { + getFolder: { + data: FolderItem | null; + error: AcoError | null; + }; + }; +} + +export interface GetFolderQueryVariables { + id: string; +} + +export const GET_FOLDER = gql` + query GetFolder($id: ID!) { + aco { + getFolder(id: $id) { + data { + id + title + slug + permissions { + target + level + inheritedFrom + } + hasNonInheritedPermissions + canManagePermissions + canManageStructure + canManageContent + parentId + type + savedOn + savedBy { + id + displayName + } + createdOn + createdBy { + id + displayName + } + modifiedOn + modifiedBy { + id + displayName + } + } + error { + code + data + message + } + } + } + } +`; + +export class GetFolderGqlGateway implements IGetFolderGateway { + private client: ApolloClient; + + constructor(client: ApolloClient) { + this.client = client; + } + + async execute(id: string) { + if (!id) { + throw new Error("Folder `id` is mandatory"); + } + + const { data: response } = await this.client.query< + GetFolderResponse, + GetFolderQueryVariables + >({ + query: GET_FOLDER, + variables: { id }, + fetchPolicy: "network-only" + }); + + if (!response) { + throw new Error("Network error while fetch folder."); + } + + const { data, error } = response.aco.getFolder; + + if (!data) { + throw new Error(error?.message || `Could not fetch folder with id: ${id}`); + } + + return data; + } +} diff --git a/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepository.ts b/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts similarity index 69% rename from packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepository.ts rename to packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts index 3114e67d57b..5e863b8eef5 100644 --- a/packages/app-aco/src/folders/repositories/GetFolder/GetFolderRepository.ts +++ b/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts @@ -1,7 +1,8 @@ +import { makeAutoObservable } from "mobx"; +import { Folder } from "../Folder"; +import { FoldersCache } from "../cache"; import { IGetFolderRepository } from "./IGetFolderRepository"; -import { FoldersCache } from "~/folders/cache"; -import { Folder } from "~/folders/domain"; -import { IGetFolderGateway } from "~/folders/gateways"; +import { IGetFolderGateway } from "./IGetFolderGateway"; export class GetFolderRepository implements IGetFolderRepository { private cache: FoldersCache; @@ -10,6 +11,7 @@ export class GetFolderRepository implements IGetFolderRepository { constructor(cache: FoldersCache, gateway: IGetFolderGateway) { this.cache = cache; this.gateway = gateway; + makeAutoObservable(this); } async execute(id: string) { diff --git a/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts b/packages/app-aco/src/features/folder/getFolder/GetFolderUseCase.ts similarity index 85% rename from packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts rename to packages/app-aco/src/features/folder/getFolder/GetFolderUseCase.ts index 2d1640a8b5b..68cd0e14f4d 100644 --- a/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCase.ts +++ b/packages/app-aco/src/features/folder/getFolder/GetFolderUseCase.ts @@ -1,5 +1,5 @@ -import { IGetFolderRepository } from "~/folders/repositories"; import { GetFolderParams, IGetFolderUseCase } from "./IGetFolderUseCase"; +import { IGetFolderRepository } from "./IGetFolderRepository"; export class GetFolderUseCase implements IGetFolderUseCase { private repository: IGetFolderRepository; diff --git a/packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCaseWithLoading.ts b/packages/app-aco/src/features/folder/getFolder/GetFolderUseCaseWithLoading.ts similarity index 100% rename from packages/app-aco/src/folders/useCases/GetFolder/GetFolderUseCaseWithLoading.ts rename to packages/app-aco/src/features/folder/getFolder/GetFolderUseCaseWithLoading.ts diff --git a/packages/app-aco/src/features/folder/getFolder/IGetFolderGateway.ts b/packages/app-aco/src/features/folder/getFolder/IGetFolderGateway.ts new file mode 100644 index 00000000000..401dcb4f004 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolder/IGetFolderGateway.ts @@ -0,0 +1,24 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; + type: string; + parentId: string | null; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity | null; + modifiedOn: string | null; +} + +export interface IGetFolderGateway { + execute: (id: string) => Promise; +} diff --git a/packages/app-aco/src/folders/repositories/GetFolder/IGetFolderRepository.ts b/packages/app-aco/src/features/folder/getFolder/IGetFolderRepository.ts similarity index 100% rename from packages/app-aco/src/folders/repositories/GetFolder/IGetFolderRepository.ts rename to packages/app-aco/src/features/folder/getFolder/IGetFolderRepository.ts diff --git a/packages/app-aco/src/folders/useCases/GetFolder/IGetFolderUseCase.ts b/packages/app-aco/src/features/folder/getFolder/IGetFolderUseCase.ts similarity index 100% rename from packages/app-aco/src/folders/useCases/GetFolder/IGetFolderUseCase.ts rename to packages/app-aco/src/features/folder/getFolder/IGetFolderUseCase.ts diff --git a/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts b/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts new file mode 100644 index 00000000000..d2abb1954b6 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts @@ -0,0 +1,37 @@ +import { useCallback, useMemo } from "react"; +import { useApolloClient } from "@apollo/react-hooks"; +import { LoadingRepository } from "@webiny/app-utils"; +import { FoldersCache } from "../cache"; +import { GetFolderGqlGateway } from "./GetFolderGqlGateway"; +import { GetFolderRepository } from "./GetFolderRepository"; +import { GetFolderUseCaseWithLoading } from "./GetFolderUseCaseWithLoading"; +import { GetFolderUseCase } from "./GetFolderUseCase"; +import { GetFolderParams } from "./IGetFolderUseCase"; + +export const useGetFolder = (cache: FoldersCache, loading: LoadingRepository) => { + const client = useApolloClient(); + + const gateway = useMemo(() => { + return new GetFolderGqlGateway(client); + }, [client]); + + const repository = useMemo(() => { + return new GetFolderRepository(cache, gateway); + }, [cache, gateway]); + + const useCase = useMemo(() => { + const getFolderUseCase = new GetFolderUseCase(repository); + return new GetFolderUseCaseWithLoading(loading, getFolderUseCase); + }, [repository, loading]); + + const getFolder = useCallback( + (params: GetFolderParams) => { + return useCase.execute(params); + }, + [useCase] + ); + + return { + getFolder + }; +}; diff --git a/packages/app-aco/src/features/folder/listFolders/FolderDto.ts b/packages/app-aco/src/features/folder/listFolders/FolderDto.ts new file mode 100644 index 00000000000..053a523ebc9 --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/FolderDto.ts @@ -0,0 +1,53 @@ +import { CmsIdentity, FolderPermission } from "~/types"; +import { Folder } from "../Folder"; +import { ROOT_FOLDER } from "~/constants"; + +export interface FolderDto { + id: string; + title: string; + slug: string; + type: string; + parentId: string; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity; + modifiedOn: string; +} + +export class FolderDtoMapper { + static toDTO(folder: Folder): FolderDto { + return { + id: folder.id, + title: folder.title, + canManageContent: folder.canManageContent ?? false, + canManagePermissions: folder.canManagePermissions ?? false, + canManageStructure: folder.canManageStructure ?? false, + createdBy: this.createIdentity(folder.createdBy), + createdOn: folder.createdOn ?? "", + hasNonInheritedPermissions: folder.hasNonInheritedPermissions ?? false, + modifiedBy: this.createIdentity(folder.modifiedBy), + modifiedOn: folder.modifiedOn ?? "", + parentId: folder.parentId ?? ROOT_FOLDER, + permissions: folder.permissions ?? [], + savedBy: this.createIdentity(folder.savedBy), + savedOn: folder.savedOn ?? "", + slug: folder.slug, + type: folder.type + }; + } + + private static createIdentity(identity?: CmsIdentity | null): CmsIdentity { + return { + id: identity?.id || "", + displayName: identity?.displayName || "", + type: identity?.type || "" + }; + } +} diff --git a/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts b/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts new file mode 100644 index 00000000000..7e010d72607 --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts @@ -0,0 +1,24 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; + type: string; + parentId: string | null; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity | null; + modifiedOn: string | null; +} + +export interface IListFoldersGateway { + execute: (type: string) => Promise; +} diff --git a/packages/app-aco/src/folders/repositories/ListFolders/IListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/IListFoldersRepository.ts similarity index 100% rename from packages/app-aco/src/folders/repositories/ListFolders/IListFoldersRepository.ts rename to packages/app-aco/src/features/folder/listFolders/IListFoldersRepository.ts diff --git a/packages/app-aco/src/folders/useCases/ListFolders/IListFoldersUseCase.ts b/packages/app-aco/src/features/folder/listFolders/IListFoldersUseCase.ts similarity index 100% rename from packages/app-aco/src/folders/useCases/ListFolders/IListFoldersUseCase.ts rename to packages/app-aco/src/features/folder/listFolders/IListFoldersUseCase.ts diff --git a/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts similarity index 59% rename from packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts rename to packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts index ef74a1604d4..5a301622a9e 100644 --- a/packages/app-aco/src/folders/gateways/ListFolders/ListFoldersGraphQLGateway.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts @@ -1,8 +1,8 @@ -import { ApolloClient } from "apollo-client"; +import ApolloClient from "apollo-client"; +import gql from "graphql-tag"; import { IListFoldersGateway } from "./IListFoldersGateway"; -import { LIST_FOLDERS } from "~/graphql/folders.gql"; -import { ROOT_FOLDER } from "~/constants"; import { AcoError, FolderItem } from "~/types"; +import { ROOT_FOLDER } from "~/constants"; export interface ListFoldersResponse { aco: { @@ -20,7 +20,52 @@ export interface ListFoldersQueryVariables { after?: string | null; } -export class ListFoldersGraphQLGateway implements IListFoldersGateway { +export const LIST_FOLDERS = gql` + query ListFolders($type: String!, $limit: Int!) { + aco { + listFolders(where: { type: $type }, limit: $limit) { + data { + id + title + slug + permissions { + target + level + inheritedFrom + } + hasNonInheritedPermissions + canManagePermissions + canManageStructure + canManageContent + parentId + type + savedOn + savedBy { + id + displayName + } + createdOn + createdBy { + id + displayName + } + modifiedOn + modifiedBy { + id + displayName + } + } + error { + code + data + message + } + } + } + } +`; + +export class ListFoldersGqlGateway implements IListFoldersGateway { private client: ApolloClient; constructor(client: ApolloClient) { diff --git a/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts similarity index 71% rename from packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepository.ts rename to packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts index 5b9579ad336..3097768bc48 100644 --- a/packages/app-aco/src/folders/repositories/ListFolders/ListFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts @@ -1,7 +1,8 @@ +import { makeAutoObservable } from "mobx"; +import { FoldersCache } from "../cache"; +import { Folder } from "../Folder"; +import { IListFoldersGateway } from "./IListFoldersGateway"; import { IListFoldersRepository } from "./IListFoldersRepository"; -import { IListFoldersGateway } from "~/folders/gateways"; -import { FoldersCache } from "~/folders/cache"; -import { Folder } from "~/folders/domain"; export class ListFoldersRepository implements IListFoldersRepository { private cache: FoldersCache; @@ -10,6 +11,7 @@ export class ListFoldersRepository implements IListFoldersRepository { constructor(cache: FoldersCache, gateway: IListFoldersGateway) { this.cache = cache; this.gateway = gateway; + makeAutoObservable(this); } async execute(type: string) { diff --git a/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts similarity index 85% rename from packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts rename to packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts index 96a972ba507..dd9be8990a4 100644 --- a/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCase.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts @@ -1,5 +1,5 @@ -import { IListFoldersRepository } from "~/folders/repositories"; import { IListFoldersUseCase, ListFoldersParams } from "./IListFoldersUseCase"; +import { IListFoldersRepository } from "./IListFoldersRepository"; export class ListFoldersUseCase implements IListFoldersUseCase { private repository: IListFoldersRepository; diff --git a/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts similarity index 88% rename from packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts rename to packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts index b77c777ad94..d2c014d8919 100644 --- a/packages/app-aco/src/folders/useCases/ListFolders/ListFoldersUseCaseWithLoading.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts @@ -1,6 +1,6 @@ -import { IListFoldersUseCase, ListFoldersParams } from "~/folders/useCases"; import { ILoadingRepository } from "@webiny/app-utils"; import { LoadingActionsEnum } from "~/types"; +import { IListFoldersUseCase, ListFoldersParams } from "./IListFoldersUseCase"; export class ListFoldersUseCaseWithLoading implements IListFoldersUseCase { private loadingRepository: ILoadingRepository; diff --git a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts new file mode 100644 index 00000000000..47b5ca357f9 --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts @@ -0,0 +1,33 @@ +import { useCallback, useMemo } from "react"; +import { useApolloClient } from "@apollo/react-hooks"; +import { LoadingRepository } from "@webiny/app-utils"; +import { FoldersCache } from "../cache"; +import { ListFoldersRepository } from "./ListFoldersRepository"; +import { ListFoldersGqlGateway } from "./ListFoldersGqlGateway"; +import { ListFoldersUseCaseWithLoading } from "./ListFoldersUseCaseWithLoading"; +import { ListFoldersUseCase } from "./ListFoldersUseCase"; + +export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, type: string) => { + const client = useApolloClient(); + + const gateway = useMemo(() => { + return new ListFoldersGqlGateway(client); + }, [client]); + + const repository = useMemo(() => { + return new ListFoldersRepository(cache, gateway); + }, [cache, gateway]); + + const useCase = useMemo(() => { + const listFolderUseCase = new ListFoldersUseCase(repository); + return new ListFoldersUseCaseWithLoading(loading, listFolderUseCase); + }, [repository, loading]); + + const listFolders = useCallback(() => { + return useCase.execute({ type }); + }, [useCase]); + + return { + listFolders + }; +}; diff --git a/packages/app-aco/src/features/folder/updateFolder/FolderDto.ts b/packages/app-aco/src/features/folder/updateFolder/FolderDto.ts new file mode 100644 index 00000000000..b162e2cc1e3 --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/FolderDto.ts @@ -0,0 +1,9 @@ +import { FolderPermission } from "~/types"; + +export interface FolderDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + parentId: string | null; +} diff --git a/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts new file mode 100644 index 00000000000..7cdb1fba69e --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts @@ -0,0 +1,5 @@ +import { FolderDto } from "./FolderDto"; + +export interface IUpdateFolderGateway { + execute: (folder: FolderDto) => Promise; +} diff --git a/packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderRepository.ts similarity index 68% rename from packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts rename to packages/app-aco/src/features/folder/updateFolder/IUpdateFolderRepository.ts index f28ad2d75bb..76c55d36275 100644 --- a/packages/app-aco/src/folders/repositories/UpdateFolder/IUpdateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderRepository.ts @@ -1,4 +1,4 @@ -import { Folder } from "~/folders/domain"; +import { Folder } from "../Folder"; export interface IUpdateFolderRepository { execute: (folder: Folder) => Promise; diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/IUpdateFolderUseCase.ts b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderUseCase.ts similarity index 100% rename from packages/app-aco/src/folders/useCases/UpdateFolder/IUpdateFolderUseCase.ts rename to packages/app-aco/src/features/folder/updateFolder/IUpdateFolderUseCase.ts diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts similarity index 50% rename from packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts rename to packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts index 54136a0b31c..4f363a27fff 100644 --- a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLGateway.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts @@ -1,9 +1,9 @@ -import { ApolloClient } from "apollo-client"; +import ApolloClient from "apollo-client"; +import gql from "graphql-tag"; import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; -import { UPDATE_FOLDER } from "~/graphql/folders.gql"; +import { FolderDto } from "./FolderDto"; import { AcoError, FolderItem } from "~/types"; import { ROOT_FOLDER } from "~/constants"; -import { UpdateFolderGraphQLDTO } from "./IUpdateFolderGraphQLMapper"; export interface UpdateFolderResponse { aco: { @@ -24,14 +24,59 @@ export interface UpdateFolderVariables { >; } -export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { +export const UPDATE_FOLDER = gql` + mutation UpdateFolder($id: ID!, $data: FolderUpdateInput!) { + aco { + updateFolder(id: $id, data: $data) { + data { + id + title + slug + permissions { + target + level + inheritedFrom + } + hasNonInheritedPermissions + canManagePermissions + canManageStructure + canManageContent + parentId + type + savedOn + savedBy { + id + displayName + } + createdOn + createdBy { + id + displayName + } + modifiedOn + modifiedBy { + id + displayName + } + } + error { + code + data + message + } + } + } + } +`; + +export class UpdateFolderGqlGateway implements IUpdateFolderGateway { private client: ApolloClient; constructor(client: ApolloClient) { this.client = client; } - async execute(folder: UpdateFolderGraphQLDTO) { + async execute(folder: FolderDto) { const { id, title, slug, permissions, parentId } = folder; const { data: response } = await this.client.mutate< @@ -60,6 +105,6 @@ export class UpdateFolderGraphQLGateway implements IUpdateFolderGateway { throw new Error(error?.message || "Could not update folder"); } - return data; + return; } } diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts new file mode 100644 index 00000000000..3c77c3c0fc1 --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts @@ -0,0 +1,30 @@ +import { makeAutoObservable } from "mobx"; +import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; +import { FoldersCache } from "../cache"; +import { Folder } from "../Folder"; +import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; +import { FolderDto } from "./FolderDto"; + +export class UpdateFolderRepository implements IUpdateFolderRepository { + private cache: FoldersCache; + private gateway: IUpdateFolderGateway; + + constructor(cache: FoldersCache, gateway: IUpdateFolderGateway) { + this.cache = cache; + this.gateway = gateway; + makeAutoObservable(this); + } + + async execute(folder: Folder) { + const dto: FolderDto = { + id: folder.id, + title: folder.title, + slug: folder.slug, + permissions: folder.permissions, + parentId: folder.parentId + }; + + await this.gateway.execute(dto); + await this.cache.update(folder.id, Folder.create(folder)); + } +} diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCase.ts similarity index 86% rename from packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts rename to packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCase.ts index cd18d9b8b7d..f86690f6025 100644 --- a/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCase.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCase.ts @@ -1,6 +1,6 @@ import { UpdateFolderParams, IUpdateFolderUseCase } from "./IUpdateFolderUseCase"; -import { Folder } from "~/folders/domain"; -import { IUpdateFolderRepository } from "~/folders/repositories"; +import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; +import { Folder } from "../Folder"; export class UpdateFolderUseCase implements IUpdateFolderUseCase { private repository: IUpdateFolderRepository; diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithLoading.ts similarity index 88% rename from packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts rename to packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithLoading.ts index 01fb6ed6931..6c75936edbc 100644 --- a/packages/app-aco/src/folders/useCases/UpdateFolder/UpdateFolderUseCaseWithLoading.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithLoading.ts @@ -1,6 +1,6 @@ -import { IUpdateFolderUseCase, UpdateFolderParams } from "~/folders/useCases"; import { ILoadingRepository } from "@webiny/app-utils"; import { LoadingActionsEnum } from "~/types"; +import { IUpdateFolderUseCase, UpdateFolderParams } from "./IUpdateFolderUseCase"; export class UpdateFolderUseCaseWithLoading implements IUpdateFolderUseCase { private loadingRepository: ILoadingRepository; diff --git a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts new file mode 100644 index 00000000000..592b9ebe3b1 --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts @@ -0,0 +1,37 @@ +import { useCallback, useMemo } from "react"; +import { useApolloClient } from "@apollo/react-hooks"; +import { FoldersCache } from "../cache"; +import { UpdateFolderGqlGateway } from "./UpdateFolderGqlGateway"; +import { UpdateFolderRepository } from "./UpdateFolderRepository"; +import { LoadingRepository } from "@webiny/app-utils"; +import { UpdateFolderUseCase } from "./UpdateFolderUseCase"; +import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading"; +import { UpdateFolderParams } from "./IUpdateFolderUseCase"; + +export const useUpdateFolder = (cache: FoldersCache, loading: LoadingRepository, type: string) => { + const client = useApolloClient(); + + const gateway = useMemo(() => { + return new UpdateFolderGqlGateway(client); + }, [client]); + + const repository = useMemo(() => { + return new UpdateFolderRepository(cache, gateway); + }, [cache, gateway]); + + const useCase = useMemo(() => { + const updateFolderUseCase = new UpdateFolderUseCase(repository); + return new UpdateFolderUseCaseWithLoading(loading, updateFolderUseCase); + }, [repository, loading]); + + const updateFolder = useCallback( + (params: UpdateFolderParams) => { + return useCase.execute({ ...params, type }); + }, + [useCase] + ); + + return { + updateFolder + }; +}; diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts b/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts deleted file mode 100644 index 7cf8a111e77..00000000000 --- a/packages/app-aco/src/folders/controllers/CreateFolder/CreateFolderController.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ICreateFolderController } from "./ICreateFolderController"; -import { ICreateFolderUseCase } from "~/folders/useCases"; -import { FolderItem } from "~/types"; - -export class CreateFolderController implements ICreateFolderController { - private useCase: ICreateFolderUseCase; - - constructor(useCase: ICreateFolderUseCase) { - this.useCase = useCase; - } - - async execute(folder: FolderItem, type: string) { - await this.useCase.execute({ - type: type, - title: folder.title, - slug: folder.slug, - parentId: folder.parentId, - permissions: folder.permissions - }); - } -} diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts b/packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts deleted file mode 100644 index 9ca9dba8d7d..00000000000 --- a/packages/app-aco/src/folders/controllers/CreateFolder/ICreateFolderController.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface ICreateFolderController { - execute: (folder: FolderItem, type: string) => Promise; -} diff --git a/packages/app-aco/src/folders/controllers/CreateFolder/index.ts b/packages/app-aco/src/folders/controllers/CreateFolder/index.ts deleted file mode 100644 index 3126f8fa4eb..00000000000 --- a/packages/app-aco/src/folders/controllers/CreateFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./CreateFolderController"; -export * from "./ICreateFolderController"; diff --git a/packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts b/packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts deleted file mode 100644 index 9f17a5247f0..00000000000 --- a/packages/app-aco/src/folders/controllers/DeleteFolder/DeleteFolderController.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { IDeleteFolderController } from "./IDeleteFolderController"; -import { IDeleteFolderUseCase } from "~/folders/useCases"; -import { FolderItem } from "~/types"; - -export class DeleteFolderController implements IDeleteFolderController { - private useCase: IDeleteFolderUseCase; - - constructor(useCase: IDeleteFolderUseCase) { - this.useCase = useCase; - } - - async execute(folder: FolderItem) { - await this.useCase.execute({ id: folder.id }); - } -} diff --git a/packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts b/packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts deleted file mode 100644 index b7801538100..00000000000 --- a/packages/app-aco/src/folders/controllers/DeleteFolder/IDeleteFolderController.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface IDeleteFolderController { - execute: (folder: FolderItem) => Promise; -} diff --git a/packages/app-aco/src/folders/controllers/DeleteFolder/index.ts b/packages/app-aco/src/folders/controllers/DeleteFolder/index.ts deleted file mode 100644 index 99b8b6a43a1..00000000000 --- a/packages/app-aco/src/folders/controllers/DeleteFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./DeleteFolderController"; -export * from "./IDeleteFolderController"; diff --git a/packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts b/packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts deleted file mode 100644 index cdd4770fc6e..00000000000 --- a/packages/app-aco/src/folders/controllers/GetFolder/GetFolderController.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IGetFolderController } from "./IGetFolderController"; -import { IGetFolderUseCase } from "~/folders/useCases"; - -export class GetFolderController implements IGetFolderController { - private useCase: IGetFolderUseCase; - - constructor(useCase: IGetFolderUseCase) { - this.useCase = useCase; - } - - async execute(id: string) { - await this.useCase.execute({ id }); - } -} diff --git a/packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts b/packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts deleted file mode 100644 index 13dd7db6a80..00000000000 --- a/packages/app-aco/src/folders/controllers/GetFolder/IGetFolderController.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetFolderController { - execute: (id: string) => Promise; -} diff --git a/packages/app-aco/src/folders/controllers/GetFolder/index.ts b/packages/app-aco/src/folders/controllers/GetFolder/index.ts deleted file mode 100644 index dbe12140495..00000000000 --- a/packages/app-aco/src/folders/controllers/GetFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./GetFolderController"; -export * from "./IGetFolderController"; diff --git a/packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts b/packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts deleted file mode 100644 index 5bc07d1d8ae..00000000000 --- a/packages/app-aco/src/folders/controllers/ListFolders/IListFoldersController.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IListFoldersController { - execute: (type: string) => Promise; -} diff --git a/packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts b/packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts deleted file mode 100644 index 1d0b778f679..00000000000 --- a/packages/app-aco/src/folders/controllers/ListFolders/ListFoldersController.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IListFoldersController } from "./IListFoldersController"; -import { IListFoldersUseCase } from "~/folders/useCases"; - -export class ListFoldersController implements IListFoldersController { - private useCase: IListFoldersUseCase; - - constructor(useCase: IListFoldersUseCase) { - this.useCase = useCase; - } - - async execute(type: string): Promise { - await this.useCase.execute({ type }); - } -} diff --git a/packages/app-aco/src/folders/controllers/ListFolders/index.ts b/packages/app-aco/src/folders/controllers/ListFolders/index.ts deleted file mode 100644 index a9fb92708d0..00000000000 --- a/packages/app-aco/src/folders/controllers/ListFolders/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./IListFoldersController"; -export * from "./ListFoldersController"; diff --git a/packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts b/packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts deleted file mode 100644 index fdb3c429b00..00000000000 --- a/packages/app-aco/src/folders/controllers/UpdateFolder/IUpdateFolderController.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface IUpdateFolderController { - execute: (folder: FolderItem) => Promise; -} diff --git a/packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts b/packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts deleted file mode 100644 index b162ba63b1a..00000000000 --- a/packages/app-aco/src/folders/controllers/UpdateFolder/UpdateFolderController.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { IUpdateFolderController } from "./IUpdateFolderController"; -import { IUpdateFolderUseCase } from "~/folders/useCases"; -import { FolderItem } from "~/types"; - -export class UpdateFolderController implements IUpdateFolderController { - private useCase: IUpdateFolderUseCase; - - constructor(useCase: IUpdateFolderUseCase) { - this.useCase = useCase; - } - - async execute(folder: FolderItem) { - await this.useCase.execute({ - id: folder.id, - title: folder.title, - slug: folder.slug, - type: folder.type, - parentId: folder.parentId, - permissions: folder.permissions - }); - } -} diff --git a/packages/app-aco/src/folders/controllers/UpdateFolder/index.ts b/packages/app-aco/src/folders/controllers/UpdateFolder/index.ts deleted file mode 100644 index 72ff9f02928..00000000000 --- a/packages/app-aco/src/folders/controllers/UpdateFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./IUpdateFolderController"; -export * from "./UpdateFolderController"; diff --git a/packages/app-aco/src/folders/controllers/index.ts b/packages/app-aco/src/folders/controllers/index.ts deleted file mode 100644 index 4e48864c20f..00000000000 --- a/packages/app-aco/src/folders/controllers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./CreateFolder"; -export * from "./DeleteFolder"; -export * from "./GetFolder"; -export * from "./ListFolders"; -export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/folders/domain/index.ts b/packages/app-aco/src/folders/domain/index.ts deleted file mode 100644 index b6ab82d77ce..00000000000 --- a/packages/app-aco/src/folders/domain/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Folder"; diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts deleted file mode 100644 index 6a90d536926..00000000000 --- a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLGateway.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ApolloClient } from "apollo-client"; -import { ICreateFolderGateway } from "./ICreateFolderGateway"; -import { CreateFolderGraphQLDTO } from "./ICreateFolderGraphQLMapper"; -import { CREATE_FOLDER } from "~/graphql/folders.gql"; -import { AcoError, FolderItem } from "~/types"; - -export interface CreateFolderResponse { - aco: { - createFolder: { - data: FolderItem; - error: AcoError | null; - }; - }; -} - -export interface CreateFolderVariables { - data: Omit< - FolderItem, - | "id" - | "createdOn" - | "createdBy" - | "savedOn" - | "savedBy" - | "modifiedOn" - | "modifiedBy" - | "hasNonInheritedPermissions" - | "canManageContent" - | "canManagePermissions" - | "canManageStructure" - >; -} - -export class CreateFolderGraphQLGateway implements ICreateFolderGateway { - private client: ApolloClient; - - constructor(client: ApolloClient) { - this.client = client; - } - - async execute(folder: CreateFolderGraphQLDTO) { - const { data: response } = await this.client.mutate< - CreateFolderResponse, - CreateFolderVariables - >({ - mutation: CREATE_FOLDER, - variables: { - data: { - ...folder - } - } - }); - - if (!response) { - throw new Error("Network error while creating folder."); - } - - const { data, error } = response.aco.createFolder; - - if (!data) { - throw new Error(error?.message || "Could not create folder"); - } - - return data; - } -} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts deleted file mode 100644 index 1d9f56cd406..00000000000 --- a/packages/app-aco/src/folders/gateways/CreateFolder/CreateFolderGraphQLMapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Folder } from "~/folders/domain"; -import { ICreateFolderGraphQLMapper } from "./ICreateFolderGraphQLMapper"; - -export class CreateFolderGraphQLMapper implements ICreateFolderGraphQLMapper { - toGraphQLDTO(folder: Folder) { - return { - title: folder.title, - slug: folder.slug, - permissions: folder.permissions, - parentId: folder.parentId, - type: folder.type - }; - } -} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts b/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts deleted file mode 100644 index 0b17a191e7a..00000000000 --- a/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGateway.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CreateFolderGraphQLDTO } from "./ICreateFolderGraphQLMapper"; -import { FolderItem } from "~/types"; - -export interface ICreateFolderGateway { - execute: (folderDTO: CreateFolderGraphQLDTO) => Promise; -} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts deleted file mode 100644 index f098016171a..00000000000 --- a/packages/app-aco/src/folders/gateways/CreateFolder/ICreateFolderGraphQLMapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Folder } from "~/folders/domain"; -import { FolderPermission } from "~/types"; - -export interface CreateFolderGraphQLDTO { - title: string; - slug: string; - permissions: FolderPermission[]; - type: string; - parentId: string | null; -} - -export interface ICreateFolderGraphQLMapper { - toGraphQLDTO: (folder: Folder) => CreateFolderGraphQLDTO; -} diff --git a/packages/app-aco/src/folders/gateways/CreateFolder/index.ts b/packages/app-aco/src/folders/gateways/CreateFolder/index.ts deleted file mode 100644 index e04cc59a9b7..00000000000 --- a/packages/app-aco/src/folders/gateways/CreateFolder/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./CreateFolderGraphQLGateway"; -export * from "./CreateFolderGraphQLMapper"; -export * from "./ICreateFolderGateway"; -export * from "./ICreateFolderGraphQLMapper"; diff --git a/packages/app-aco/src/folders/gateways/DeleteFolder/index.ts b/packages/app-aco/src/folders/gateways/DeleteFolder/index.ts deleted file mode 100644 index d4ab6a408bd..00000000000 --- a/packages/app-aco/src/folders/gateways/DeleteFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./DeleteFolderGraphQLGateway"; -export * from "./IDeleteFolderGateway"; diff --git a/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts b/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts deleted file mode 100644 index acbd731dfc3..00000000000 --- a/packages/app-aco/src/folders/gateways/GetFolder/GetFolderGraphQLGateway.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ApolloClient } from "apollo-client"; -import { IGetFolderGateway } from "./IGetFolderGateway"; -import { GET_FOLDER } from "~/graphql/folders.gql"; -import { FolderItem, AcoError } from "~/types"; - -export interface GetFolderResponse { - aco: { - getFolder: { - data: FolderItem | null; - error: AcoError | null; - }; - }; -} - -export interface GetFolderQueryVariables { - id: string; -} - -export class GetFolderGraphQLGateway implements IGetFolderGateway { - private client: ApolloClient; - - constructor(client: ApolloClient) { - this.client = client; - } - - async execute(id: string) { - if (!id) { - throw new Error("Folder `id` is mandatory"); - } - - const { data: response } = await this.client.query< - GetFolderResponse, - GetFolderQueryVariables - >({ - query: GET_FOLDER, - variables: { id }, - fetchPolicy: "network-only" - }); - - if (!response) { - throw new Error("Network error while fetch folder."); - } - - const { data, error } = response.aco.getFolder; - - if (!data) { - throw new Error(error?.message || `Could not fetch folder with id: ${id}`); - } - - return data; - } -} diff --git a/packages/app-aco/src/folders/gateways/GetFolder/IGetFolderGateway.ts b/packages/app-aco/src/folders/gateways/GetFolder/IGetFolderGateway.ts deleted file mode 100644 index 743f6bb90d4..00000000000 --- a/packages/app-aco/src/folders/gateways/GetFolder/IGetFolderGateway.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface IGetFolderGateway { - execute: (id: string) => Promise; -} diff --git a/packages/app-aco/src/folders/gateways/GetFolder/index.ts b/packages/app-aco/src/folders/gateways/GetFolder/index.ts deleted file mode 100644 index 4f708bbc1cc..00000000000 --- a/packages/app-aco/src/folders/gateways/GetFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./GetFolderGraphQLGateway"; -export * from "./IGetFolderGateway"; diff --git a/packages/app-aco/src/folders/gateways/ListFolders/IListFoldersGateway.ts b/packages/app-aco/src/folders/gateways/ListFolders/IListFoldersGateway.ts deleted file mode 100644 index 9b4a6ae1c79..00000000000 --- a/packages/app-aco/src/folders/gateways/ListFolders/IListFoldersGateway.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FolderItem } from "~/types"; - -export interface IListFoldersGateway { - execute: (type: string) => Promise; -} diff --git a/packages/app-aco/src/folders/gateways/ListFolders/index.ts b/packages/app-aco/src/folders/gateways/ListFolders/index.ts deleted file mode 100644 index 0c530bc59ec..00000000000 --- a/packages/app-aco/src/folders/gateways/ListFolders/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./IListFoldersGateway"; -export * from "./ListFoldersGraphQLGateway"; diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts deleted file mode 100644 index a813d4c95f3..00000000000 --- a/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGateway.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { UpdateFolderGraphQLDTO } from "./IUpdateFolderGraphQLMapper"; -import { FolderItem } from "~/types"; - -export interface IUpdateFolderGateway { - execute: (folder: UpdateFolderGraphQLDTO) => Promise; -} diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts deleted file mode 100644 index 1b9a1b9a57f..00000000000 --- a/packages/app-aco/src/folders/gateways/UpdateFolder/IUpdateFolderGraphQLMapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Folder } from "~/folders/domain"; -import { FolderPermission } from "~/types"; - -export interface UpdateFolderGraphQLDTO { - id: string; - title: string; - slug: string; - permissions: FolderPermission[]; - parentId: string | null; -} - -export interface IUpdateFolderGraphQLMapper { - toGraphQLDTO: (folder: Folder) => UpdateFolderGraphQLDTO; -} diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts deleted file mode 100644 index 77132533922..00000000000 --- a/packages/app-aco/src/folders/gateways/UpdateFolder/UpdateFolderGraphQLMapper.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Folder } from "~/folders/domain"; -import { IUpdateFolderGraphQLMapper } from "./IUpdateFolderGraphQLMapper"; - -export class UpdateFolderGraphQLMapper implements IUpdateFolderGraphQLMapper { - toGraphQLDTO(folder: Folder) { - return { - id: folder.id, - title: folder.title, - slug: folder.slug, - permissions: folder.permissions, - parentId: folder.parentId - }; - } -} diff --git a/packages/app-aco/src/folders/gateways/UpdateFolder/index.ts b/packages/app-aco/src/folders/gateways/UpdateFolder/index.ts deleted file mode 100644 index e5f7f5f2aac..00000000000 --- a/packages/app-aco/src/folders/gateways/UpdateFolder/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./IUpdateFolderGateway"; -export * from "./IUpdateFolderGraphQLMapper"; -export * from "./UpdateFolderGraphQLGateway"; -export * from "./UpdateFolderGraphQLMapper"; diff --git a/packages/app-aco/src/folders/gateways/index.ts b/packages/app-aco/src/folders/gateways/index.ts deleted file mode 100644 index 4e48864c20f..00000000000 --- a/packages/app-aco/src/folders/gateways/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./CreateFolder"; -export * from "./DeleteFolder"; -export * from "./GetFolder"; -export * from "./ListFolders"; -export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/folders/index.ts b/packages/app-aco/src/folders/index.ts deleted file mode 100644 index 3d87529adf7..00000000000 --- a/packages/app-aco/src/folders/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from "./cache"; -export * from "./controllers"; -export * from "./domain"; -export * from "./gateways"; -export * from "./presenters"; -export * from "./repositories"; -export * from "./useCases"; diff --git a/packages/app-aco/src/folders/presenters/FoldersPresenter.ts b/packages/app-aco/src/folders/presenters/FoldersPresenter.ts deleted file mode 100644 index ef8cf046225..00000000000 --- a/packages/app-aco/src/folders/presenters/FoldersPresenter.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { LoadingRepository } from "@webiny/app-utils"; -import { FoldersCache } from "~/folders/cache"; -import { Folder } from "~/folders/domain"; -import { ROOT_FOLDER } from "~/constants"; -import { FolderItem } from "~/types"; - -export class FoldersPresenter { - private foldersCache: FoldersCache; - private loadingRepository: LoadingRepository; - - constructor(foldersCache: FoldersCache, loadingRepository: LoadingRepository) { - this.foldersCache = foldersCache; - this.loadingRepository = loadingRepository; - } - - get vm() { - return { - folders: this.foldersCache.getItems().map(folder => this.folderMapper(folder)), - loading: this.loadingRepository.get() - }; - } - - private folderMapper(folder: Folder): FolderItem { - return { - id: folder.id, - title: folder.title, - slug: folder.slug, - type: folder.type, - parentId: folder.parentId ?? ROOT_FOLDER, - permissions: folder.permissions, - hasNonInheritedPermissions: folder.hasNonInheritedPermissions ?? false, - canManagePermissions: folder.canManagePermissions ?? false, - canManageStructure: folder.canManageStructure ?? false, - canManageContent: folder.canManageContent ?? false, - createdBy: folder.createdBy ?? { id: "", type: "", displayName: "" }, - createdOn: folder.createdOn ?? "", - savedBy: folder.savedBy ?? { id: "", type: "", displayName: "" }, - savedOn: folder.savedOn ?? "", - modifiedBy: folder.modifiedBy ?? null, - modifiedOn: folder.modifiedOn ?? null - }; - } -} diff --git a/packages/app-aco/src/folders/presenters/index.ts b/packages/app-aco/src/folders/presenters/index.ts deleted file mode 100644 index a8e3bc39220..00000000000 --- a/packages/app-aco/src/folders/presenters/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./FoldersPresenter"; diff --git a/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts b/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts deleted file mode 100644 index 7a06963813b..00000000000 --- a/packages/app-aco/src/folders/repositories/CreateFolder/CreateFolderRepository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ICreateFolderRepository } from "./ICreateFolderRepository"; -import { Folder } from "~/folders/domain"; -import { CreateFolderGraphQLMapper, ICreateFolderGateway } from "~/folders/gateways"; -import { FoldersCache } from "~/folders/cache"; - -export class CreateFolderRepository implements ICreateFolderRepository { - private cache: FoldersCache; - private gateway: ICreateFolderGateway; - - constructor(cache: FoldersCache, gateway: ICreateFolderGateway) { - this.cache = cache; - this.gateway = gateway; - } - - async execute(folder: Folder) { - const mapper = new CreateFolderGraphQLMapper(); - const response = await this.gateway.execute(mapper.toGraphQLDTO(folder)); - await this.cache.set(Folder.create(response)); - } -} diff --git a/packages/app-aco/src/folders/repositories/CreateFolder/index.ts b/packages/app-aco/src/folders/repositories/CreateFolder/index.ts deleted file mode 100644 index 4e37aab1c91..00000000000 --- a/packages/app-aco/src/folders/repositories/CreateFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./CreateFolderRepository"; -export * from "./ICreateFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts deleted file mode 100644 index d1792ca80e9..00000000000 --- a/packages/app-aco/src/folders/repositories/DeleteFolder/IDeleteFolderRepository.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IDeleteFolderRepository { - execute: (id: string) => Promise; -} diff --git a/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts b/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts deleted file mode 100644 index 6b58ffbd6b0..00000000000 --- a/packages/app-aco/src/folders/repositories/DeleteFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./DeleteFolderRepository"; -export * from "./IDeleteFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/GetDescendantFolders/index.ts b/packages/app-aco/src/folders/repositories/GetDescendantFolders/index.ts deleted file mode 100644 index c5a822742ba..00000000000 --- a/packages/app-aco/src/folders/repositories/GetDescendantFolders/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./GetDescendantFoldersRepository"; -export * from "./IGetDescendantFoldersRepository"; diff --git a/packages/app-aco/src/folders/repositories/GetFolder/index.ts b/packages/app-aco/src/folders/repositories/GetFolder/index.ts deleted file mode 100644 index 6577f1c3868..00000000000 --- a/packages/app-aco/src/folders/repositories/GetFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./GetFolderRepository"; -export * from "./IGetFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/ListFolders/index.ts b/packages/app-aco/src/folders/repositories/ListFolders/index.ts deleted file mode 100644 index 5c25989ea67..00000000000 --- a/packages/app-aco/src/folders/repositories/ListFolders/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./ListFoldersRepository"; -export * from "./IListFoldersRepository"; diff --git a/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts deleted file mode 100644 index 6d3922a096f..00000000000 --- a/packages/app-aco/src/folders/repositories/UpdateFolder/UpdateFolderRepository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; -import { Folder } from "~/folders/domain"; -import { FoldersCache } from "~/folders/cache"; -import { IUpdateFolderGateway, UpdateFolderGraphQLMapper } from "~/folders/gateways"; - -export class UpdateFolderRepository implements IUpdateFolderRepository { - private cache: FoldersCache; - private gateway: IUpdateFolderGateway; - - constructor(cache: FoldersCache, gateway: IUpdateFolderGateway) { - this.cache = cache; - this.gateway = gateway; - } - - async execute(folder: Folder) { - const mapper = new UpdateFolderGraphQLMapper(); - const item = await this.gateway.execute(mapper.toGraphQLDTO(folder)); - await this.cache.update(item.id, Folder.create(item)); - } -} diff --git a/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts b/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts deleted file mode 100644 index dc518afec08..00000000000 --- a/packages/app-aco/src/folders/repositories/UpdateFolder/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./UpdateFolderRepository"; -export * from "./IUpdateFolderRepository"; diff --git a/packages/app-aco/src/folders/repositories/index.ts b/packages/app-aco/src/folders/repositories/index.ts deleted file mode 100644 index cba36b04485..00000000000 --- a/packages/app-aco/src/folders/repositories/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from "./CreateFolder"; -export * from "./DeleteFolder"; -export * from "./GetDescendantFolders"; -export * from "./GetFolder"; -export * from "./ListFolders"; -export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/folders/useCases/CreateFolder/index.ts b/packages/app-aco/src/folders/useCases/CreateFolder/index.ts deleted file mode 100644 index 7151cb9b941..00000000000 --- a/packages/app-aco/src/folders/useCases/CreateFolder/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./CreateFolderUseCase"; -export * from "./CreateFolderUseCaseWithLoading"; -export * from "./ICreateFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts deleted file mode 100644 index 2eb4d953bcd..00000000000 --- a/packages/app-aco/src/folders/useCases/DeleteFolder/DeleteFolderUseCase.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DeleteFolderParams, IDeleteFolderUseCase } from "./IDeleteFolderUseCase"; -import { IDeleteFolderRepository } from "../../repositories/DeleteFolder"; - -export class DeleteFolderUseCase implements IDeleteFolderUseCase { - private repository: IDeleteFolderRepository; - - constructor(repository: IDeleteFolderRepository) { - this.repository = repository; - } - - async execute(params: DeleteFolderParams) { - await this.repository.execute(params.id); - } -} diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts deleted file mode 100644 index c4963f82922..00000000000 --- a/packages/app-aco/src/folders/useCases/DeleteFolder/IDeleteFolderUseCase.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface DeleteFolderParams { - id: string; -} - -export interface IDeleteFolderUseCase { - execute: (params: DeleteFolderParams) => Promise; -} diff --git a/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts b/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts deleted file mode 100644 index d7596acbfca..00000000000 --- a/packages/app-aco/src/folders/useCases/DeleteFolder/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./DeleteFolderUseCase"; -export * from "./DeleteFolderUseCaseWithLoading"; -export * from "./IDeleteFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/GetFolder/index.ts b/packages/app-aco/src/folders/useCases/GetFolder/index.ts deleted file mode 100644 index 6056dd18809..00000000000 --- a/packages/app-aco/src/folders/useCases/GetFolder/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./GetFolderUseCase"; -export * from "./GetFolderUseCaseWithLoading"; -export * from "./IGetFolderUseCase"; diff --git a/packages/app-aco/src/folders/useCases/ListFolders/index.ts b/packages/app-aco/src/folders/useCases/ListFolders/index.ts deleted file mode 100644 index d053f14253d..00000000000 --- a/packages/app-aco/src/folders/useCases/ListFolders/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./IListFoldersUseCase"; -export * from "./ListFoldersUseCase"; -export * from "./ListFoldersUseCaseWithLoading"; diff --git a/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts b/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts deleted file mode 100644 index b56516d7fc3..00000000000 --- a/packages/app-aco/src/folders/useCases/UpdateFolder/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./IUpdateFolderUseCase"; -export * from "./UpdateFolderUseCase"; -export * from "./UpdateFolderUseCaseWithLoading"; diff --git a/packages/app-aco/src/folders/useCases/index.ts b/packages/app-aco/src/folders/useCases/index.ts deleted file mode 100644 index 4e48864c20f..00000000000 --- a/packages/app-aco/src/folders/useCases/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./CreateFolder"; -export * from "./DeleteFolder"; -export * from "./GetFolder"; -export * from "./ListFolders"; -export * from "./UpdateFolder"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 792d63181e7..f79dd6b203c 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,63 +1,32 @@ -import { useContext, useCallback, useEffect, useMemo, useState } from "react"; +import { useContext, useEffect, useMemo, useState } from "react"; import { autorun } from "mobx"; -import { useApolloClient } from "@apollo/react-hooks"; import { loadingRepositoryFactory } from "@webiny/app-utils"; - import { FoldersContext } from "~/contexts/folders"; import { AcoAppContext } from "~/contexts/app"; - -import { folderCacheFactory } from "~/folders/cache"; -import { - CreateFolderGraphQLGateway, - DeleteFolderGraphQLGateway, - GetFolderGraphQLGateway, - ListFoldersGraphQLGateway, - UpdateFolderGraphQLGateway -} from "~/folders/gateways"; -import { - CreateFolderUseCase, - CreateFolderUseCaseWithLoading, - DeleteFolderUseCase, - DeleteFolderUseCaseWithLoading, - GetFolderUseCase, - GetFolderUseCaseWithLoading, - ListFoldersUseCase, - ListFoldersUseCaseWithLoading, - UpdateFolderUseCase, - UpdateFolderUseCaseWithLoading -} from "~/folders/useCases"; -import { - CreateFolderController, - DeleteFolderController, - GetFolderController, - ListFoldersController, - UpdateFolderController -} from "~/folders/controllers"; -import { - CreateFolderRepository, - DeleteFolderRepository, - GetFolderRepository, - GetDescendantFoldersRepository, - ListFoldersRepository, - UpdateFolderRepository -} from "~/folders/repositories"; -import { FoldersPresenter } from "~/folders/presenters"; - +import { folderCacheFactory } from "~/features/folder/cache"; +import { useCreateFolder } from "~/features/folder/createFolder/useCreateFolder"; +import { useDeleteFolder } from "~/features/folder/deleteFolder/useDeleteFolder"; +import { useGetDescendantFolders } from "~/features/folder/getDescendantFolders/useGetDescendantFolders"; +import { useGetFolder } from "~/features/folder/getFolder/useGetFolder"; +import { useListFolders } from "~/features/folder/listFolders/useListFolders"; +import { useUpdateFolder } from "~/features/folder/updateFolder/useUpdateFolder"; import { FolderItem } from "~/types"; +import { FolderDtoMapper } from "~/features/folder/listFolders/FolderDto"; export const useFolders = () => { - const client = useApolloClient(); - const foldersContext = useContext(FoldersContext); - const appContext = useContext(AcoAppContext); - const [vm, setVm] = useState<{ - folders: FolderItem[] | undefined; - loading: Record | undefined; + folders: FolderItem[]; + loading: Record; }>({ - folders: undefined, - loading: undefined + folders: [], + loading: { + INIT: true + } }); + const foldersContext = useContext(FoldersContext); + const appContext = useContext(AcoAppContext); + if (!foldersContext) { throw new Error("useFolders must be used within a FoldersProvider"); } @@ -70,146 +39,55 @@ export const useFolders = () => { throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); } + const { folderLevelPermissions } = foldersContext; + // Folders cache const foldersCache = useMemo(() => { return folderCacheFactory.getCache(type); }, [type]); - // Loading Cache + // Loading repository const loadingRepository = useMemo(() => { return loadingRepositoryFactory.getRepository(); - }, []); - - // Presenter vm - useEffect(() => { - const presenter = new FoldersPresenter(foldersCache, loadingRepository); - return autorun(() => { - const newState = presenter.vm; - setVm(newState); - }); - }, [foldersCache, loadingRepository]); - - // List - const listFolders = useCallback(() => { - const listFoldersGateway = new ListFoldersGraphQLGateway(client); - const listFoldersRepository = new ListFoldersRepository(foldersCache, listFoldersGateway); - const listFoldersUseCase = new ListFoldersUseCase(listFoldersRepository); - const listFoldersUseCaseWithLoading = new ListFoldersUseCaseWithLoading( - loadingRepository, - listFoldersUseCase - ); - const listFoldersController = new ListFoldersController(listFoldersUseCaseWithLoading); - return listFoldersController.execute(type); - }, [type, client, foldersCache, loadingRepository]); - - // Get - const getFolder = useCallback( - (id: string) => { - const getFolderGateway = new GetFolderGraphQLGateway(client); - const getFolderRepository = new GetFolderRepository(foldersCache, getFolderGateway); - const getFolderUseCase = new GetFolderUseCase(getFolderRepository); - const getFolderUseCaseWithLoading = new GetFolderUseCaseWithLoading( - loadingRepository, - getFolderUseCase - ); - const getFolderController = new GetFolderController(getFolderUseCaseWithLoading); - return getFolderController.execute(id); - }, - [client, foldersCache, loadingRepository] - ); - - // Get Descendant Folders - const getDescendantFolders = useCallback( - (id: string) => { - const repository = new GetDescendantFoldersRepository(foldersCache); - return repository.execute(id); - }, - [foldersCache] - ); - - // Create - const createFolder = useCallback( - (folder: FolderItem) => { - const createFolderGateway = new CreateFolderGraphQLGateway(client); - const createFolderRepository = new CreateFolderRepository( - foldersCache, - createFolderGateway - ); - const createFolderUseCase = new CreateFolderUseCase(createFolderRepository); - const createFolderUseCaseWithLoading = new CreateFolderUseCaseWithLoading( - loadingRepository, - createFolderUseCase - ); - const createFolderController = new CreateFolderController( - createFolderUseCaseWithLoading - ); - return createFolderController.execute(folder, type); - }, - [client, foldersCache, loadingRepository, type] - ); - - // Update - const updateFolder = useCallback( - (folder: FolderItem) => { - const updateFolderGateway = new UpdateFolderGraphQLGateway(client); - const updateFolderRepository = new UpdateFolderRepository( - foldersCache, - updateFolderGateway - ); - const updateFolderUseCase = new UpdateFolderUseCase(updateFolderRepository); - const updateFolderUseCaseWithLoading = new UpdateFolderUseCaseWithLoading( - loadingRepository, - updateFolderUseCase - ); - const updateFolderController = new UpdateFolderController( - updateFolderUseCaseWithLoading - ); - return updateFolderController.execute(folder); - }, - [client, foldersCache, loadingRepository] - ); - - // Delete - const deleteFolder = useCallback( - (folder: FolderItem) => { - const deleteFolderGateway = new DeleteFolderGraphQLGateway(client); - const deleteFolderRepository = new DeleteFolderRepository( - foldersCache, - deleteFolderGateway - ); - const deleteFolderUseCase = new DeleteFolderUseCase(deleteFolderRepository); - const deleteFolderUseCaseWithLoading = new DeleteFolderUseCaseWithLoading( - loadingRepository, - deleteFolderUseCase - ); - const deleteFolderController = new DeleteFolderController( - deleteFolderUseCaseWithLoading - ); - return deleteFolderController.execute(folder); - }, - [client, foldersCache, loadingRepository] - ); + }, [type]); - const { folderLevelPermissions } = foldersContext; + const { createFolder } = useCreateFolder(foldersCache, loadingRepository, type); + const { deleteFolder } = useDeleteFolder(foldersCache, loadingRepository, type); + const { listFolders } = useListFolders(foldersCache, loadingRepository, type); + const { updateFolder } = useUpdateFolder(foldersCache, loadingRepository, type); + const { getDescendantFolders } = useGetDescendantFolders(foldersCache); + const { getFolder } = useGetFolder(foldersCache, loadingRepository); useEffect(() => { - /** - * On first mount, call `listFolders`, which will either issue a network request, or load folders from cache. - * We don't need to store the result of it to any local state; that is managed by the context provider. - * - * IMPORTANT: we check if the folders array exists: the hook can be used from multiple components and - * fetch the outdated list from Apollo Cache. Since the state is managed locally, we fetch the folders only - * at the first mount. - */ - const cachedItems = foldersCache.getItems(); - - if (cachedItems) { + if (foldersCache.hasItems()) { return; // Skip if we already have folders in the cache. } listFolders(); }, []); + useEffect(() => { + return autorun(() => { + const folders = foldersCache.getItems().map(folder => FolderDtoMapper.toDTO(folder)); + + setVm(vm => ({ + ...vm, + folders + })); + }); + }, [foldersCache]); + + useEffect(() => { + return autorun(() => { + const loading = loadingRepository.get(); + + setVm(vm => ({ + ...vm, + loading + })); + }); + }, [loadingRepository]); + return { ...vm, listFolders, From 292441e5d89a0fd6e118e65575b20380d5e287dd Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 17 Oct 2024 12:18:36 +0200 Subject: [PATCH 09/28] wip: retrieve data from gateway --- .../src/components/FolderTree/Node/index.tsx | 2 -- .../folder/updateFolder/FolderGqlDto.ts | 20 +++++++++++++++++++ .../updateFolder/IUpdateFolderGateway.ts | 3 ++- .../updateFolder/UpdateFolderGqlGateway.ts | 2 +- .../updateFolder/UpdateFolderRepository.ts | 4 ++-- 5 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 packages/app-aco/src/features/folder/updateFolder/FolderGqlDto.ts diff --git a/packages/app-aco/src/components/FolderTree/Node/index.tsx b/packages/app-aco/src/components/FolderTree/Node/index.tsx index 39bc2b10c60..cf3fe1d3ef4 100644 --- a/packages/app-aco/src/components/FolderTree/Node/index.tsx +++ b/packages/app-aco/src/components/FolderTree/Node/index.tsx @@ -79,8 +79,6 @@ export const Node = ({ node, depth, isOpen, enableActions, onToggle, onClick }: }; const id = useMemo(() => { - console.log("folder.id", folder.id); - const { id } = parseIdentifier(String(folder.id)); return id; }, [folder.id]); diff --git a/packages/app-aco/src/features/folder/updateFolder/FolderGqlDto.ts b/packages/app-aco/src/features/folder/updateFolder/FolderGqlDto.ts new file mode 100644 index 00000000000..0d2ff62504c --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/FolderGqlDto.ts @@ -0,0 +1,20 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderGqlDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; + type: string; + parentId: string | null; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity | null; + modifiedOn: string | null; +} diff --git a/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts index 7cdb1fba69e..f6003e70efc 100644 --- a/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts +++ b/packages/app-aco/src/features/folder/updateFolder/IUpdateFolderGateway.ts @@ -1,5 +1,6 @@ import { FolderDto } from "./FolderDto"; +import { FolderGqlDto } from "./FolderGqlDto"; export interface IUpdateFolderGateway { - execute: (folder: FolderDto) => Promise; + execute: (folder: FolderDto) => Promise; } diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts index 4f363a27fff..21855ab4b44 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderGqlGateway.ts @@ -105,6 +105,6 @@ export class UpdateFolderGqlGateway implements IUpdateFolderGateway { throw new Error(error?.message || "Could not update folder"); } - return; + return data; } } diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts index 3c77c3c0fc1..7c620a5a005 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts @@ -24,7 +24,7 @@ export class UpdateFolderRepository implements IUpdateFolderRepository { parentId: folder.parentId }; - await this.gateway.execute(dto); - await this.cache.update(folder.id, Folder.create(folder)); + const result = await this.gateway.execute(dto); + await this.cache.update(folder.id, Folder.create(result)); } } From d87bf4f210642e0157dcdabb07ff35bf2a6ce008 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 17 Oct 2024 13:26:33 +0200 Subject: [PATCH 10/28] fix: loading folders --- packages/app-aco/src/components/FolderTree/index.tsx | 4 ++-- packages/app-aco/src/features/folder/Folder.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/app-aco/src/components/FolderTree/index.tsx b/packages/app-aco/src/components/FolderTree/index.tsx index b5e6edb5f8e..2bbbbc73a36 100644 --- a/packages/app-aco/src/components/FolderTree/index.tsx +++ b/packages/app-aco/src/components/FolderTree/index.tsx @@ -29,7 +29,7 @@ export const FolderTree = ({ onFolderClick, rootFolderLabel }: FolderTreeProps) => { - const { folders, folderLevelPermissions: flp } = useFolders(); + const { folders, folderLevelPermissions: flp, loading } = useFolders(); const localFolders = useMemo(() => { if (!folders) { return []; @@ -44,7 +44,7 @@ export const FolderTree = ({ }, [folders]); const renderList = () => { - if (!folders) { + if (loading.INIT || loading.LIST) { return ; } diff --git a/packages/app-aco/src/features/folder/Folder.ts b/packages/app-aco/src/features/folder/Folder.ts index 9d1564f286e..23abccd015d 100644 --- a/packages/app-aco/src/features/folder/Folder.ts +++ b/packages/app-aco/src/features/folder/Folder.ts @@ -1,7 +1,7 @@ import { CmsIdentity, FolderPermission } from "~/types"; export interface FolderData { - id: string; + id?: string; title: string; slug: string; type: string; @@ -38,7 +38,7 @@ export class Folder { public modifiedOn?: string | null; protected constructor(folder: FolderData) { - this.id = folder.id; + this.id = folder.id ?? ""; this.title = folder.title; this.slug = folder.slug; this.type = folder.type; From f155108c4e3294c558c2563e0327ec12c3990ff0 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 17 Oct 2024 13:48:40 +0200 Subject: [PATCH 11/28] fix: move folderLevelPermissions into new hook --- packages/app-aco/src/contexts/folders.tsx | 34 ++---------- .../src/features/folder/createFolder/index.ts | 1 + .../src/features/folder/deleteFolder/index.ts | 1 + .../folder/getDescendantFolders/index.ts | 1 + .../src/features/folder/getFolder/index.ts | 1 + packages/app-aco/src/features/folder/index.ts | 8 +++ .../src/features/folder/listFolders/index.ts | 2 + .../src/features/folder/updateFolder/index.ts | 1 + packages/app-aco/src/hooks/useFolders.ts | 54 +++++++++++++------ 9 files changed, 56 insertions(+), 47 deletions(-) create mode 100644 packages/app-aco/src/features/folder/createFolder/index.ts create mode 100644 packages/app-aco/src/features/folder/deleteFolder/index.ts create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/index.ts create mode 100644 packages/app-aco/src/features/folder/getFolder/index.ts create mode 100644 packages/app-aco/src/features/folder/index.ts create mode 100644 packages/app-aco/src/features/folder/listFolders/index.ts create mode 100644 packages/app-aco/src/features/folder/updateFolder/index.ts diff --git a/packages/app-aco/src/contexts/folders.tsx b/packages/app-aco/src/contexts/folders.tsx index 79203e1d620..b769b898a08 100644 --- a/packages/app-aco/src/contexts/folders.tsx +++ b/packages/app-aco/src/contexts/folders.tsx @@ -1,9 +1,5 @@ import React, { ReactNode, useContext, useMemo } from "react"; -import { useWcp } from "@webiny/app-wcp/hooks/useWcp"; -import { useStateIfMounted } from "@webiny/app-admin"; -import { FolderItem } from "~/types"; import { AcoAppContext } from "~/contexts/app"; -import { ROOT_FOLDER } from "~/constants"; export interface FoldersContextFolderLevelPermissions { canManageStructure(folderId: string): boolean; @@ -15,7 +11,6 @@ export interface FoldersContextFolderLevelPermissions { interface FoldersContext { type?: string | null; - folderLevelPermissions: FoldersContextFolderLevelPermissions; } export const FoldersContext = React.createContext(undefined); @@ -27,43 +22,20 @@ interface Props { export const FoldersProvider = ({ children, ...props }: Props) => { const appContext = useContext(AcoAppContext); - const [folders, setFolders] = useStateIfMounted(null); - const { canUseFolderLevelPermissions } = useWcp(); const app = appContext ? appContext.app : undefined; const type = props.type ?? app?.id; + if (!type) { throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); } - const folderLevelPermissions: FoldersContextFolderLevelPermissions = useMemo(() => { - const createCanManage = - (callback: (folder: FolderItem) => boolean) => (folderId: string) => { - if (!canUseFolderLevelPermissions() || folderId === ROOT_FOLDER) { - return true; - } - - const folder = folders?.find(folder => folder.id === folderId); - if (!folder) { - return false; - } - - return callback(folder); - }; - - return { - canManageStructure: createCanManage(folder => folder.canManageStructure), - canManagePermissions: createCanManage(folder => folder.canManagePermissions), - canManageContent: createCanManage(folder => folder.canManageContent) - }; - }, [folders]); - const context = useMemo(() => { return { - folderLevelPermissions + type }; - }, [folders, setFolders]); + }, [type]); return {children}; }; diff --git a/packages/app-aco/src/features/folder/createFolder/index.ts b/packages/app-aco/src/features/folder/createFolder/index.ts new file mode 100644 index 00000000000..26134b3d69d --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/index.ts @@ -0,0 +1 @@ +export * from "./useCreateFolder"; diff --git a/packages/app-aco/src/features/folder/deleteFolder/index.ts b/packages/app-aco/src/features/folder/deleteFolder/index.ts new file mode 100644 index 00000000000..87fcddfbf54 --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/index.ts @@ -0,0 +1 @@ +export * from "./useDeleteFolder"; diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/index.ts b/packages/app-aco/src/features/folder/getDescendantFolders/index.ts new file mode 100644 index 00000000000..b08ebc4e8ec --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/index.ts @@ -0,0 +1 @@ +export * from "./useGetDescendantFolders"; diff --git a/packages/app-aco/src/features/folder/getFolder/index.ts b/packages/app-aco/src/features/folder/getFolder/index.ts new file mode 100644 index 00000000000..ed6c1f0e032 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolder/index.ts @@ -0,0 +1 @@ +export * from "./useGetFolder"; diff --git a/packages/app-aco/src/features/folder/index.ts b/packages/app-aco/src/features/folder/index.ts new file mode 100644 index 00000000000..79bccfd91e3 --- /dev/null +++ b/packages/app-aco/src/features/folder/index.ts @@ -0,0 +1,8 @@ +export * from "./cache"; +export * from "./createFolder"; +export * from "./deleteFolder"; +export * from "./getDescendantFolders"; +export * from "./getFolder"; +export * from "./listFolders"; +export * from "./updateFolder"; +export * from "./Folder"; diff --git a/packages/app-aco/src/features/folder/listFolders/index.ts b/packages/app-aco/src/features/folder/listFolders/index.ts new file mode 100644 index 00000000000..92780101758 --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/index.ts @@ -0,0 +1,2 @@ +export * from "./useListFolders"; +export * from "./FolderDto"; diff --git a/packages/app-aco/src/features/folder/updateFolder/index.ts b/packages/app-aco/src/features/folder/updateFolder/index.ts new file mode 100644 index 00000000000..776c694e3e8 --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/index.ts @@ -0,0 +1 @@ +export * from "./useUpdateFolder"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index f79dd6b203c..3e186fda736 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,19 +1,24 @@ import { useContext, useEffect, useMemo, useState } from "react"; import { autorun } from "mobx"; import { loadingRepositoryFactory } from "@webiny/app-utils"; -import { FoldersContext } from "~/contexts/folders"; -import { AcoAppContext } from "~/contexts/app"; -import { folderCacheFactory } from "~/features/folder/cache"; -import { useCreateFolder } from "~/features/folder/createFolder/useCreateFolder"; -import { useDeleteFolder } from "~/features/folder/deleteFolder/useDeleteFolder"; -import { useGetDescendantFolders } from "~/features/folder/getDescendantFolders/useGetDescendantFolders"; -import { useGetFolder } from "~/features/folder/getFolder/useGetFolder"; -import { useListFolders } from "~/features/folder/listFolders/useListFolders"; -import { useUpdateFolder } from "~/features/folder/updateFolder/useUpdateFolder"; +import { useWcp } from "@webiny/app-wcp"; +import { FoldersContext, FoldersContextFolderLevelPermissions } from "~/contexts/folders"; +import { + folderCacheFactory, + FolderDtoMapper, + useCreateFolder, + useDeleteFolder, + useGetDescendantFolders, + useGetFolder, + useListFolders, + useUpdateFolder +} from "~/features/folder"; import { FolderItem } from "~/types"; -import { FolderDtoMapper } from "~/features/folder/listFolders/FolderDto"; +import { ROOT_FOLDER } from "~/constants"; export const useFolders = () => { + const { canUseFolderLevelPermissions } = useWcp(); + const [vm, setVm] = useState<{ folders: FolderItem[]; loading: Record; @@ -25,22 +30,17 @@ export const useFolders = () => { }); const foldersContext = useContext(FoldersContext); - const appContext = useContext(AcoAppContext); if (!foldersContext) { throw new Error("useFolders must be used within a FoldersProvider"); } - const app = appContext ? appContext.app : undefined; - - const type = foldersContext.type ?? app?.id; + const { type } = foldersContext; if (!type) { throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); } - const { folderLevelPermissions } = foldersContext; - // Folders cache const foldersCache = useMemo(() => { return folderCacheFactory.getCache(type); @@ -88,6 +88,28 @@ export const useFolders = () => { }); }, [loadingRepository]); + const folderLevelPermissions: FoldersContextFolderLevelPermissions = useMemo(() => { + const createCanManage = + (callback: (folder: FolderItem) => boolean) => (folderId: string) => { + if (!canUseFolderLevelPermissions() || folderId === ROOT_FOLDER) { + return true; + } + + const folder = vm.folders?.find(folder => folder.id === folderId); + if (!folder) { + return false; + } + + return callback(folder); + }; + + return { + canManageStructure: createCanManage(folder => folder.canManageStructure), + canManagePermissions: createCanManage(folder => folder.canManagePermissions), + canManageContent: createCanManage(folder => folder.canManageContent) + }; + }, [vm.folders]); + return { ...vm, listFolders, From 11f093ed580394d8f7347cfd7b045c93f83b35c6 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 17 Oct 2024 16:36:32 +0200 Subject: [PATCH 12/28] refactor: pass type as repo dependency --- .../folder/createFolder/CreateFolderRepository.ts | 6 ++++-- .../src/features/folder/createFolder/useCreateFolder.ts | 6 +++--- .../src/features/folder/deleteFolder/useDeleteFolder.ts | 4 ++-- .../folder/listFolders/IListFoldersRepository.ts | 2 +- .../features/folder/listFolders/IListFoldersUseCase.ts | 6 +----- .../features/folder/listFolders/ListFoldersRepository.ts | 8 +++++--- .../features/folder/listFolders/ListFoldersUseCase.ts | 6 +++--- .../folder/listFolders/ListFoldersUseCaseWithLoading.ts | 9 +++------ .../src/features/folder/listFolders/useListFolders.ts | 6 +++--- .../src/features/folder/updateFolder/useUpdateFolder.ts | 4 ++-- packages/app-aco/src/hooks/useFolders.ts | 4 ++-- 11 files changed, 29 insertions(+), 32 deletions(-) diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts index c9c7e065265..b3398b03b58 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts @@ -8,10 +8,12 @@ import { FolderDto } from "./FolderDto"; export class CreateFolderRepository implements ICreateFolderRepository { private cache: FoldersCache; private gateway: ICreateFolderGateway; + private type: string; - constructor(cache: FoldersCache, gateway: ICreateFolderGateway) { + constructor(cache: FoldersCache, gateway: ICreateFolderGateway, type: string) { this.cache = cache; this.gateway = gateway; + this.type = type; makeAutoObservable(this); } @@ -20,7 +22,7 @@ export class CreateFolderRepository implements ICreateFolderRepository { title: folder.title, slug: folder.slug, permissions: folder.permissions, - type: folder.type, + type: this.type, parentId: folder.parentId }; diff --git a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts index 1a7fd042ebb..5359bb51310 100644 --- a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts +++ b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts @@ -16,8 +16,8 @@ export const useCreateFolder = (cache: FoldersCache, loading: LoadingRepository, }, [client]); const repository = useMemo(() => { - return new CreateFolderRepository(cache, gateway); - }, [cache, gateway]); + return new CreateFolderRepository(cache, gateway, type); + }, [cache, gateway, type]); const useCase = useMemo(() => { const createFolderUseCase = new CreateFolderUseCase(repository); @@ -26,7 +26,7 @@ export const useCreateFolder = (cache: FoldersCache, loading: LoadingRepository, const createFolder = useCallback( (params: CreateFolderParams) => { - return useCase.execute({ ...params, type }); + return useCase.execute(params); }, [useCase] ); diff --git a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts index 425fbc4aa30..9498ecc4b1c 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts @@ -8,7 +8,7 @@ import { DeleteFolderUseCase } from "./DeleteFolderUseCase"; import { DeleteFolderUseCaseWithLoading } from "./DeleteFolderUseCaseWithLoading"; import { DeleteFolderParams } from "./IDeleteFolderUseCase"; -export const useDeleteFolder = (cache: FoldersCache, loading: LoadingRepository, type: string) => { +export const useDeleteFolder = (cache: FoldersCache, loading: LoadingRepository) => { const client = useApolloClient(); const gateway = useMemo(() => { @@ -26,7 +26,7 @@ export const useDeleteFolder = (cache: FoldersCache, loading: LoadingRepository, const deleteFolder = useCallback( (params: DeleteFolderParams) => { - return useCase.execute({ ...params, type }); + return useCase.execute(params); }, [useCase] ); diff --git a/packages/app-aco/src/features/folder/listFolders/IListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/IListFoldersRepository.ts index 69f0efc910e..f9aedf93d50 100644 --- a/packages/app-aco/src/features/folder/listFolders/IListFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/listFolders/IListFoldersRepository.ts @@ -1,3 +1,3 @@ export interface IListFoldersRepository { - execute: (type: string) => Promise; + execute: () => Promise; } diff --git a/packages/app-aco/src/features/folder/listFolders/IListFoldersUseCase.ts b/packages/app-aco/src/features/folder/listFolders/IListFoldersUseCase.ts index 1aa7a9609a7..7024ce59ede 100644 --- a/packages/app-aco/src/features/folder/listFolders/IListFoldersUseCase.ts +++ b/packages/app-aco/src/features/folder/listFolders/IListFoldersUseCase.ts @@ -1,7 +1,3 @@ -export interface ListFoldersParams { - type: string; -} - export interface IListFoldersUseCase { - execute: (params: ListFoldersParams) => Promise; + execute: () => Promise; } diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts index 3097768bc48..1afe0c9536e 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts @@ -7,15 +7,17 @@ import { IListFoldersRepository } from "./IListFoldersRepository"; export class ListFoldersRepository implements IListFoldersRepository { private cache: FoldersCache; private gateway: IListFoldersGateway; + private type: string; - constructor(cache: FoldersCache, gateway: IListFoldersGateway) { + constructor(cache: FoldersCache, gateway: IListFoldersGateway, type: string) { this.cache = cache; this.gateway = gateway; + this.type = type; makeAutoObservable(this); } - async execute(type: string) { - const items = await this.gateway.execute(type); + async execute() { + const items = await this.gateway.execute(this.type); await this.cache.setMultiple(items.map(item => Folder.create(item))); } } diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts index dd9be8990a4..ac913080897 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCase.ts @@ -1,4 +1,4 @@ -import { IListFoldersUseCase, ListFoldersParams } from "./IListFoldersUseCase"; +import { IListFoldersUseCase } from "./IListFoldersUseCase"; import { IListFoldersRepository } from "./IListFoldersRepository"; export class ListFoldersUseCase implements IListFoldersUseCase { @@ -8,7 +8,7 @@ export class ListFoldersUseCase implements IListFoldersUseCase { this.repository = repository; } - async execute(params: ListFoldersParams) { - await this.repository.execute(params.type); + async execute() { + await this.repository.execute(); } } diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts index d2c014d8919..ff772fbb964 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersUseCaseWithLoading.ts @@ -1,6 +1,6 @@ import { ILoadingRepository } from "@webiny/app-utils"; import { LoadingActionsEnum } from "~/types"; -import { IListFoldersUseCase, ListFoldersParams } from "./IListFoldersUseCase"; +import { IListFoldersUseCase } from "./IListFoldersUseCase"; export class ListFoldersUseCaseWithLoading implements IListFoldersUseCase { private loadingRepository: ILoadingRepository; @@ -11,10 +11,7 @@ export class ListFoldersUseCaseWithLoading implements IListFoldersUseCase { this.useCase = useCase; } - async execute(params: ListFoldersParams) { - await this.loadingRepository.runCallBack( - this.useCase.execute(params), - LoadingActionsEnum.list - ); + async execute() { + await this.loadingRepository.runCallBack(this.useCase.execute(), LoadingActionsEnum.list); } } diff --git a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts index 47b5ca357f9..5352cf172ad 100644 --- a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts @@ -15,8 +15,8 @@ export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, }, [client]); const repository = useMemo(() => { - return new ListFoldersRepository(cache, gateway); - }, [cache, gateway]); + return new ListFoldersRepository(cache, gateway, type); + }, [cache, gateway, type]); const useCase = useMemo(() => { const listFolderUseCase = new ListFoldersUseCase(repository); @@ -24,7 +24,7 @@ export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, }, [repository, loading]); const listFolders = useCallback(() => { - return useCase.execute({ type }); + return useCase.execute(); }, [useCase]); return { diff --git a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts index 592b9ebe3b1..59756b5b90b 100644 --- a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts @@ -8,7 +8,7 @@ import { UpdateFolderUseCase } from "./UpdateFolderUseCase"; import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading"; import { UpdateFolderParams } from "./IUpdateFolderUseCase"; -export const useUpdateFolder = (cache: FoldersCache, loading: LoadingRepository, type: string) => { +export const useUpdateFolder = (cache: FoldersCache, loading: LoadingRepository) => { const client = useApolloClient(); const gateway = useMemo(() => { @@ -26,7 +26,7 @@ export const useUpdateFolder = (cache: FoldersCache, loading: LoadingRepository, const updateFolder = useCallback( (params: UpdateFolderParams) => { - return useCase.execute({ ...params, type }); + return useCase.execute(params); }, [useCase] ); diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 3e186fda736..7cdfaf4ba1e 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -52,9 +52,9 @@ export const useFolders = () => { }, [type]); const { createFolder } = useCreateFolder(foldersCache, loadingRepository, type); - const { deleteFolder } = useDeleteFolder(foldersCache, loadingRepository, type); + const { deleteFolder } = useDeleteFolder(foldersCache, loadingRepository); const { listFolders } = useListFolders(foldersCache, loadingRepository, type); - const { updateFolder } = useUpdateFolder(foldersCache, loadingRepository, type); + const { updateFolder } = useUpdateFolder(foldersCache, loadingRepository); const { getDescendantFolders } = useGetDescendantFolders(foldersCache); const { getFolder } = useGetFolder(foldersCache, loadingRepository); From 730942839154736fdca8de44a0dfb9d4072c28ab Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 17 Oct 2024 18:19:03 +0200 Subject: [PATCH 13/28] refactor: flp FTA --- packages/app-aco/src/contexts/folders.tsx | 8 ---- .../src/features/folder/cache/FoldersCache.ts | 4 ++ .../src/features/folder/cache/ICache.ts | 1 + .../GetCanManageContentRepository.ts | 20 +++++++++ .../GetCanManageContentUseCase.ts | 14 +++++++ .../GetCanManageContentWithFlpUseCase.ts | 23 ++++++++++ .../IGetCanManageContentRepository.ts | 3 ++ .../IGetCanManageContentUseCase.ts | 3 ++ .../folder/getCanManageContent/index.ts | 1 + .../useGetCanManageContent.ts | 33 +++++++++++++++ .../GetCanManagePermissionsRepository.ts | 20 +++++++++ .../GetCanManagePermissionsUseCase.ts | 14 +++++++ .../GetCanManagePermissionsWithFlpUseCase.ts | 23 ++++++++++ .../IGetCanManagePermissionsRepository.ts | 3 ++ .../IGetCanManagePermissionsUseCase.ts | 3 ++ .../folder/getCanManagePermissions/index.ts | 1 + .../useGetCanManagePermissions.ts | 36 ++++++++++++++++ .../GetCanManageStructureRepository.ts | 20 +++++++++ .../GetCanManageStructureUseCase.ts | 14 +++++++ .../GetCanManageStructureWithFlpUseCase.ts | 23 ++++++++++ .../IGetCanManageStructureRepository.ts | 3 ++ .../IGetCanManageStructureUseCase.ts | 3 ++ .../folder/getCanManageStructure/index.ts | 1 + .../useGetCanManageStructure.ts | 36 ++++++++++++++++ packages/app-aco/src/features/folder/index.ts | 3 ++ packages/app-aco/src/hooks/useFolders.ts | 42 ++++++------------- 26 files changed, 317 insertions(+), 38 deletions(-) create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/index.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/index.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/index.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts diff --git a/packages/app-aco/src/contexts/folders.tsx b/packages/app-aco/src/contexts/folders.tsx index b769b898a08..6f243c9949c 100644 --- a/packages/app-aco/src/contexts/folders.tsx +++ b/packages/app-aco/src/contexts/folders.tsx @@ -1,14 +1,6 @@ import React, { ReactNode, useContext, useMemo } from "react"; import { AcoAppContext } from "~/contexts/app"; -export interface FoldersContextFolderLevelPermissions { - canManageStructure(folderId: string): boolean; - - canManagePermissions(folderId: string): boolean; - - canManageContent(folderId: string): boolean; -} - interface FoldersContext { type?: string | null; } diff --git a/packages/app-aco/src/features/folder/cache/FoldersCache.ts b/packages/app-aco/src/features/folder/cache/FoldersCache.ts index 4d69d04cbbf..b0cc7da79f9 100644 --- a/packages/app-aco/src/features/folder/cache/FoldersCache.ts +++ b/packages/app-aco/src/features/folder/cache/FoldersCache.ts @@ -18,6 +18,10 @@ export class FoldersCache implements ICache { return this.folders; } + getItem(id: string) { + return this.folders.find(f => f.id === id); + } + async set(item: Folder): Promise { this.folders.push(item); } diff --git a/packages/app-aco/src/features/folder/cache/ICache.ts b/packages/app-aco/src/features/folder/cache/ICache.ts index 994ca7a29fe..3672a3a57f9 100644 --- a/packages/app-aco/src/features/folder/cache/ICache.ts +++ b/packages/app-aco/src/features/folder/cache/ICache.ts @@ -1,6 +1,7 @@ export interface ICache { hasItems: () => boolean; getItems: () => TItem[]; + getItem: (id: string) => TItem; set: (item: TItem) => Promise; setMultiple: (items: TItem[]) => Promise; update: (id: string, item: TItem) => Promise; diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts new file mode 100644 index 00000000000..94ca30ce47b --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts @@ -0,0 +1,20 @@ +import { FoldersCache } from "../cache"; +import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository"; + +export class GetCanManageContentRepository implements IGetCanManageContentRepository { + private cache: FoldersCache; + + constructor(cache: FoldersCache) { + this.cache = cache; + } + + execute(id: string) { + const folder = this.cache.getItem(id); + + if (!folder) { + return false; + } + + return folder.canManageContent ?? false; + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts new file mode 100644 index 00000000000..42e15e22484 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts @@ -0,0 +1,14 @@ +import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; +import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository"; + +export class GetCanManageContentUseCase implements IGetCanManageContentUseCase { + private repository: IGetCanManageContentRepository; + + constructor(repository: IGetCanManageContentRepository) { + this.repository = repository; + } + + execute(id: string) { + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts new file mode 100644 index 00000000000..802f4163011 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts @@ -0,0 +1,23 @@ +import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; +import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository"; + +export class GetCanManageContentWithFlpUseCase implements IGetCanManageContentUseCase { + private repository: IGetCanManageContentRepository; + private canUseFolderLevelPermissions: () => boolean; + + constructor( + repository: IGetCanManageContentRepository, + canUseFolderLevelPermissions: () => boolean + ) { + this.repository = repository; + this.canUseFolderLevelPermissions = canUseFolderLevelPermissions; + } + + execute(id: string) { + if (!this.canUseFolderLevelPermissions) { + return true; + } + + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts b/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts new file mode 100644 index 00000000000..54752ef9362 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts @@ -0,0 +1,3 @@ +export interface IGetCanManageContentRepository { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts new file mode 100644 index 00000000000..79228e7b053 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts @@ -0,0 +1,3 @@ +export interface IGetCanManageContentUseCase { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/index.ts b/packages/app-aco/src/features/folder/getCanManageContent/index.ts new file mode 100644 index 00000000000..17ccf4b067a --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/index.ts @@ -0,0 +1 @@ +export * from "./useGetCanManageContent"; diff --git a/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts b/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts new file mode 100644 index 00000000000..599cccaaf79 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts @@ -0,0 +1,33 @@ +import { useCallback, useMemo } from "react"; +import { useWcp } from "@webiny/app-wcp"; +import { FoldersCache } from "../cache"; +import { GetCanManageContentRepository } from "./GetCanManageContentRepository"; +import { GetCanManageContentWithFlpUseCase } from "./GetCanManageContentWithFlpUseCase"; +import { GetCanManageContentUseCase } from "./GetCanManageContentUseCase"; + +export const useGetCanManageContent = (cache: FoldersCache) => { + const { canUseFolderLevelPermissions } = useWcp(); + + const repository = useMemo(() => { + return new GetCanManageContentRepository(cache); + }, [cache]); + + const useCase = useMemo(() => { + if (canUseFolderLevelPermissions) { + return new GetCanManageContentWithFlpUseCase(repository, canUseFolderLevelPermissions); + } + + return new GetCanManageContentUseCase(repository); + }, [repository, canUseFolderLevelPermissions]); + + const canManageContent = useCallback( + (id: string) => { + return useCase.execute(id); + }, + [useCase] + ); + + return { + canManageContent + }; +}; diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts new file mode 100644 index 00000000000..6fb7a160aeb --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts @@ -0,0 +1,20 @@ +import { FoldersCache } from "../cache"; +import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRepository"; + +export class GetCanManagePermissionsRepository implements IGetCanManagePermissionsRepository { + private cache: FoldersCache; + + constructor(cache: FoldersCache) { + this.cache = cache; + } + + execute(id: string) { + const folder = this.cache.getItem(id); + + if (!folder) { + return false; + } + + return folder.canManagePermissions ?? false; + } +} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts new file mode 100644 index 00000000000..98676583dca --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts @@ -0,0 +1,14 @@ +import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; +import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRepository"; + +export class GetCanManagePermissionsUseCase implements IGetCanManagePermissionsUseCase { + private repository: IGetCanManagePermissionsRepository; + + constructor(repository: IGetCanManagePermissionsRepository) { + this.repository = repository; + } + + execute(id: string) { + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts new file mode 100644 index 00000000000..78ee2c316b9 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts @@ -0,0 +1,23 @@ +import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; +import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRepository"; + +export class GetCanManagePermissionsWithFlpUseCase implements IGetCanManagePermissionsUseCase { + private repository: IGetCanManagePermissionsRepository; + private canUseFolderLevelPermissions: () => boolean; + + constructor( + repository: IGetCanManagePermissionsRepository, + canUseFolderLevelPermissions: () => boolean + ) { + this.repository = repository; + this.canUseFolderLevelPermissions = canUseFolderLevelPermissions; + } + + execute(id: string) { + if (!this.canUseFolderLevelPermissions) { + return true; + } + + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts new file mode 100644 index 00000000000..a158522c9a1 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts @@ -0,0 +1,3 @@ +export interface IGetCanManagePermissionsRepository { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts new file mode 100644 index 00000000000..735a3424afc --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts @@ -0,0 +1,3 @@ +export interface IGetCanManagePermissionsUseCase { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/index.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/index.ts new file mode 100644 index 00000000000..1886a775b37 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/index.ts @@ -0,0 +1 @@ +export * from "./useGetCanManagePermissions"; diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts new file mode 100644 index 00000000000..22d9da1c345 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts @@ -0,0 +1,36 @@ +import { useCallback, useMemo } from "react"; +import { useWcp } from "@webiny/app-wcp"; +import { FoldersCache } from "../cache"; +import { GetCanManagePermissionsRepository } from "./GetCanManagePermissionsRepository"; +import { GetCanManagePermissionsWithFlpUseCase } from "./GetCanManagePermissionsWithFlpUseCase"; +import { GetCanManagePermissionsUseCase } from "./GetCanManagePermissionsUseCase"; + +export const useGetCanManagePermissions = (cache: FoldersCache) => { + const { canUseFolderLevelPermissions } = useWcp(); + + const repository = useMemo(() => { + return new GetCanManagePermissionsRepository(cache); + }, [cache]); + + const useCase = useMemo(() => { + if (canUseFolderLevelPermissions) { + return new GetCanManagePermissionsWithFlpUseCase( + repository, + canUseFolderLevelPermissions + ); + } + + return new GetCanManagePermissionsUseCase(repository); + }, [repository, canUseFolderLevelPermissions]); + + const canManagePermissions = useCallback( + (id: string) => { + return useCase.execute(id); + }, + [useCase] + ); + + return { + canManagePermissions + }; +}; diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts new file mode 100644 index 00000000000..bc92f12c0cd --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts @@ -0,0 +1,20 @@ +import { FoldersCache } from "../cache"; +import { IGetCanManageStructureRepository } from "./IGetCanManageStructureRepository"; + +export class GetCanManageStructureRepository implements IGetCanManageStructureRepository { + private cache: FoldersCache; + + constructor(cache: FoldersCache) { + this.cache = cache; + } + + execute(id: string) { + const folder = this.cache.getItem(id); + + if (!folder) { + return false; + } + + return folder.canManageStructure ?? false; + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts new file mode 100644 index 00000000000..4cd824a88cb --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts @@ -0,0 +1,14 @@ +import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; +import { IGetCanManageStructureRepository } from "./IGetCanManageStructureRepository"; + +export class GetCanManageStructureUseCase implements IGetCanManageStructureUseCase { + private repository: IGetCanManageStructureRepository; + + constructor(repository: IGetCanManageStructureRepository) { + this.repository = repository; + } + + execute(id: string) { + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts new file mode 100644 index 00000000000..3a5d1fad6ff --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts @@ -0,0 +1,23 @@ +import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; +import { IGetCanManageStructureRepository } from "./IGetCanManageStructureRepository"; + +export class GetCanManageStructureWithFlpUseCase implements IGetCanManageStructureUseCase { + private repository: IGetCanManageStructureRepository; + private canUseFolderLevelPermissions: () => boolean; + + constructor( + repository: IGetCanManageStructureRepository, + canUseFolderLevelPermissions: () => boolean + ) { + this.repository = repository; + this.canUseFolderLevelPermissions = canUseFolderLevelPermissions; + } + + execute(id: string) { + if (!this.canUseFolderLevelPermissions) { + return true; + } + + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts b/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts new file mode 100644 index 00000000000..dd792ff2d85 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts @@ -0,0 +1,3 @@ +export interface IGetCanManageStructureRepository { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts new file mode 100644 index 00000000000..6d49f9c4048 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts @@ -0,0 +1,3 @@ +export interface IGetCanManageStructureUseCase { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/index.ts b/packages/app-aco/src/features/folder/getCanManageStructure/index.ts new file mode 100644 index 00000000000..7223c9c3e60 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/index.ts @@ -0,0 +1 @@ +export * from "./useGetCanManageStructure"; diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts b/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts new file mode 100644 index 00000000000..b9c703a106d --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts @@ -0,0 +1,36 @@ +import { useCallback, useMemo } from "react"; +import { useWcp } from "@webiny/app-wcp"; +import { FoldersCache } from "../cache"; +import { GetCanManageStructureRepository } from "./GetCanManageStructureRepository"; +import { GetCanManageStructureWithFlpUseCase } from "./GetCanManageStructureWithFlpUseCase"; +import { GetCanManageStructureUseCase } from "./GetCanManageStructureUseCase"; + +export const useGetCanManageStructure = (cache: FoldersCache) => { + const { canUseFolderLevelPermissions } = useWcp(); + + const repository = useMemo(() => { + return new GetCanManageStructureRepository(cache); + }, [cache]); + + const useCase = useMemo(() => { + if (canUseFolderLevelPermissions) { + return new GetCanManageStructureWithFlpUseCase( + repository, + canUseFolderLevelPermissions + ); + } + + return new GetCanManageStructureUseCase(repository); + }, [repository, canUseFolderLevelPermissions]); + + const canManageStructure = useCallback( + (id: string) => { + return useCase.execute(id); + }, + [useCase] + ); + + return { + canManageStructure + }; +}; diff --git a/packages/app-aco/src/features/folder/index.ts b/packages/app-aco/src/features/folder/index.ts index 79bccfd91e3..9605ca1e3e5 100644 --- a/packages/app-aco/src/features/folder/index.ts +++ b/packages/app-aco/src/features/folder/index.ts @@ -1,6 +1,9 @@ export * from "./cache"; export * from "./createFolder"; export * from "./deleteFolder"; +export * from "./getCanManageStructure"; +export * from "./getCanManagePermissions"; +export * from "./getCanManageContent"; export * from "./getDescendantFolders"; export * from "./getFolder"; export * from "./listFolders"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 7cdfaf4ba1e..9e2cf9f1791 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,24 +1,23 @@ import { useContext, useEffect, useMemo, useState } from "react"; import { autorun } from "mobx"; import { loadingRepositoryFactory } from "@webiny/app-utils"; -import { useWcp } from "@webiny/app-wcp"; -import { FoldersContext, FoldersContextFolderLevelPermissions } from "~/contexts/folders"; +import { FoldersContext } from "~/contexts/folders"; import { folderCacheFactory, FolderDtoMapper, useCreateFolder, useDeleteFolder, + useGetCanManageContent, + useGetCanManagePermissions, + useGetCanManageStructure, useGetDescendantFolders, useGetFolder, useListFolders, useUpdateFolder } from "~/features/folder"; import { FolderItem } from "~/types"; -import { ROOT_FOLDER } from "~/constants"; export const useFolders = () => { - const { canUseFolderLevelPermissions } = useWcp(); - const [vm, setVm] = useState<{ folders: FolderItem[]; loading: Record; @@ -57,6 +56,9 @@ export const useFolders = () => { const { updateFolder } = useUpdateFolder(foldersCache, loadingRepository); const { getDescendantFolders } = useGetDescendantFolders(foldersCache); const { getFolder } = useGetFolder(foldersCache, loadingRepository); + const { canManageStructure } = useGetCanManageStructure(foldersCache); + const { canManagePermissions } = useGetCanManagePermissions(foldersCache); + const { canManageContent } = useGetCanManageContent(foldersCache); useEffect(() => { if (foldersCache.hasItems()) { @@ -88,28 +90,6 @@ export const useFolders = () => { }); }, [loadingRepository]); - const folderLevelPermissions: FoldersContextFolderLevelPermissions = useMemo(() => { - const createCanManage = - (callback: (folder: FolderItem) => boolean) => (folderId: string) => { - if (!canUseFolderLevelPermissions() || folderId === ROOT_FOLDER) { - return true; - } - - const folder = vm.folders?.find(folder => folder.id === folderId); - if (!folder) { - return false; - } - - return callback(folder); - }; - - return { - canManageStructure: createCanManage(folder => folder.canManageStructure), - canManagePermissions: createCanManage(folder => folder.canManagePermissions), - canManageContent: createCanManage(folder => folder.canManageContent) - }; - }, [vm.folders]); - return { ...vm, listFolders, @@ -118,8 +98,10 @@ export const useFolders = () => { createFolder, updateFolder, deleteFolder, - - // OLD - folderLevelPermissions + folderLevelPermissions: { + canManageStructure, + canManagePermissions, + canManageContent + } }; }; From 4ee8d254699bb74addfb1258fb3afdb215bca363 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 18 Oct 2024 11:24:21 +0200 Subject: [PATCH 14/28] fix: revert the folder tree state in case of error on drop --- packages/app-aco/src/components/FolderTree/List/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/app-aco/src/components/FolderTree/List/index.tsx b/packages/app-aco/src/components/FolderTree/List/index.tsx index c0f244c242a..11fa30881cb 100644 --- a/packages/app-aco/src/components/FolderTree/List/index.tsx +++ b/packages/app-aco/src/components/FolderTree/List/index.tsx @@ -56,6 +56,8 @@ export const List = ({ newTree: NodeModel[], { dragSourceId, dropTargetId }: DropOptions ) => { + // Store the current state of the tree before the drop action + const oldTree = [...treeData]; try { const item = folders.find(folder => folder.id === dragSourceId); @@ -70,6 +72,8 @@ export const List = ({ parentId: dropTargetId !== ROOT_FOLDER ? (dropTargetId as string) : null }); } catch (error) { + // If an error occurs, revert the tree back to its original state + setTreeData(oldTree); return showSnackbar(error.message); } }; From 295039ae23d14eba3db49efc17b5b9aed178ceff Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 18 Oct 2024 12:11:19 +0200 Subject: [PATCH 15/28] fix: remove previous implementation files --- packages/app-aco/src/Folders.tsx | 21 -- .../FoldersApi/FoldersApiProvider.tsx | 350 ------------------ .../app-aco/src/contexts/FoldersApi/index.ts | 2 - .../src/contexts/FoldersApi/useFoldersApi.ts | 11 - .../src/features/folder/cache/ICache.ts | 2 +- packages/app-aco/src/graphql/folders.gql.ts | 98 ----- packages/app-aco/src/hooks/index.ts | 1 - packages/app-aco/src/index.ts | 1 - packages/app-serverless-cms/src/Admin.tsx | 2 - 9 files changed, 1 insertion(+), 487 deletions(-) delete mode 100644 packages/app-aco/src/Folders.tsx delete mode 100644 packages/app-aco/src/contexts/FoldersApi/FoldersApiProvider.tsx delete mode 100644 packages/app-aco/src/contexts/FoldersApi/index.ts delete mode 100644 packages/app-aco/src/contexts/FoldersApi/useFoldersApi.ts delete mode 100644 packages/app-aco/src/graphql/folders.gql.ts diff --git a/packages/app-aco/src/Folders.tsx b/packages/app-aco/src/Folders.tsx deleted file mode 100644 index 170e5c72ae2..00000000000 --- a/packages/app-aco/src/Folders.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from "react"; -import { Plugin } from "@webiny/app-admin"; -import { FoldersApiProvider } from "~/contexts/FoldersApi"; - -interface FoldersApiProviderHOCProps { - children: React.ReactNode; -} - -const FoldersApiProviderHOC = (Component: React.ComponentType) => { - return function FoldersApiProviderHOC({ children }: FoldersApiProviderHOCProps) { - return ( - - {children} - - ); - }; -}; - -export const Folders = () => { - return ; -}; diff --git a/packages/app-aco/src/contexts/FoldersApi/FoldersApiProvider.tsx b/packages/app-aco/src/contexts/FoldersApi/FoldersApiProvider.tsx deleted file mode 100644 index 379afcbde0a..00000000000 --- a/packages/app-aco/src/contexts/FoldersApi/FoldersApiProvider.tsx +++ /dev/null @@ -1,350 +0,0 @@ -import React, { ReactNode, useEffect, useRef, useState } from "react"; -import { useApolloClient } from "@apollo/react-hooks"; -import { - CREATE_FOLDER, - DELETE_FOLDER, - GET_FOLDER, - LIST_FOLDERS, - UPDATE_FOLDER -} from "~/graphql/folders.gql"; - -import { - CreateFolderResponse, - CreateFolderVariables, - DeleteFolderResponse, - DeleteFolderVariables, - FolderItem, - GetFolderQueryVariables, - GetFolderResponse, - ListFoldersQueryVariables, - ListFoldersResponse, - UpdateFolderResponse, - UpdateFolderVariables -} from "~/types"; -import { ROOT_FOLDER } from "~/constants"; - -interface OffCacheUpdate { - (): void; -} - -export interface OnCacheUpdate { - (folders: FolderItem[]): void; -} - -export interface FoldersApiContext { - listFolders: ( - type: string, - options?: Partial<{ invalidateCache: boolean }> - ) => Promise; - getFolder: (type: string, id: string) => Promise; - createFolder: (type: string, folder: Omit) => Promise; - updateFolder: ( - type: string, - folder: Omit< - FolderItem, - | "type" - | "canManagePermissions" - | "canManageStructure" - | "canManageContent" - | "hasNonInheritedPermissions" - | "createdOn" - | "createdBy" - | "savedOn" - | "savedBy" - | "modifiedOn" - | "modifiedBy" - > - ) => Promise; - - deleteFolder(type: string, id: string): Promise; - - invalidateCache(folderType: string): FoldersApiContext; - - getDescendantFolders(type: string, id?: string): FolderItem[]; - - onFoldersChanged(type: string, cb: OnCacheUpdate): OffCacheUpdate; -} - -export const FoldersApiContext = React.createContext(undefined); - -interface Props { - children: ReactNode; -} - -const rootFolder: FolderItem = { - id: ROOT_FOLDER, - title: "Home", - permissions: [], - parentId: "0", - slug: "", - createdOn: "", - createdBy: { - id: "", - displayName: "", - type: "" - }, - hasNonInheritedPermissions: false, - canManagePermissions: true, - canManageStructure: true, - canManageContent: true, - savedOn: "", - savedBy: { - id: "", - displayName: "", - type: "" - }, - modifiedOn: null, - modifiedBy: null, - type: "$ROOT" -}; - -interface FoldersByType { - [type: string]: FolderItem[]; -} - -export const FoldersApiProvider = ({ children }: Props) => { - const client = useApolloClient(); - const folderObservers = useRef(new Map>()); - const [cache, setCache] = useState({}); - - useEffect(() => { - folderObservers.current.forEach((observers, type) => { - observers.forEach(observer => observer(cache[type])); - }); - }, [cache]); - - useEffect(() => { - return () => { - folderObservers.current.clear(); - }; - }, []); - - const context: FoldersApiContext = { - onFoldersChanged: (type, cb) => { - if (!folderObservers.current.has(type)) { - folderObservers.current.set(type, new Set()); - } - - folderObservers.current.get(type)!.add(cb); - return () => { - folderObservers.current.get(type)?.delete(cb); - }; - }, - invalidateCache: folderType => { - setCache(cache => { - const cacheClone = structuredClone(cache); - delete cacheClone[folderType]; - return cacheClone; - }); - return context; - }, - async listFolders(type, options) { - const invalidateCache = options?.invalidateCache === true; - if (cache[type] && !invalidateCache) { - return cache[type]; - } - - const { data: response } = await client.query< - ListFoldersResponse, - ListFoldersQueryVariables - >({ - query: LIST_FOLDERS, - variables: { - type, - limit: 10000 - }, - fetchPolicy: "network-only" - }); - - if (!response) { - throw new Error("Network error while listing folders."); - } - - const { data, error } = response.aco.listFolders; - - if (!data) { - throw new Error(error?.message || "Could not fetch folders"); - } - - const foldersWithRoot = [rootFolder, ...(data || [])]; - - setCache(cache => ({ - ...cache, - [type]: foldersWithRoot - })); - - return foldersWithRoot; - }, - - async getFolder(type, id) { - if (!id) { - throw new Error("Folder `id` is mandatory"); - } - - const folder = cache[type]?.find(folder => folder.id === id); - if (folder) { - return folder; - } - - const { data: response } = await client.query< - GetFolderResponse, - GetFolderQueryVariables - >({ - query: GET_FOLDER, - variables: { id } - }); - - if (!response) { - throw new Error("Network error while fetch folder."); - } - - const { data, error } = response.aco.getFolder; - - if (!data) { - throw new Error(error?.message || `Could not fetch folder with id: ${id}`); - } - - return data; - }, - - async createFolder(type, folder) { - const { data: response } = await client.mutate< - CreateFolderResponse, - CreateFolderVariables - >({ - mutation: CREATE_FOLDER, - variables: { - data: { - ...folder, - type - } - } - }); - - if (!response) { - throw new Error("Network error while creating folder."); - } - - const { data, error } = response.aco.createFolder; - - if (!data) { - throw new Error(error?.message || "Could not create folder"); - } - - setCache(cache => ({ - ...cache, - [type]: [...cache[type], data] - })); - - return data; - }, - - async updateFolder(type, folder) { - const { id, title, slug, permissions, parentId } = folder; - - const { data: response } = await client.mutate< - UpdateFolderResponse, - UpdateFolderVariables - >({ - mutation: UPDATE_FOLDER, - variables: { - id, - data: { - title, - slug, - permissions, - parentId - } - } - }); - - if (!response) { - throw new Error("Network error while updating folder."); - } - - const { data, error } = response.aco.updateFolder; - - if (!data) { - throw new Error(error?.message || "Could not update folder"); - } - - const folderIndex = cache[type]?.findIndex(f => f.id === id); - if (folderIndex > -1) { - setCache(cache => ({ - ...cache, - [type]: [ - ...cache[type].slice(0, folderIndex), - { - ...cache[type][folderIndex], - ...data - }, - ...cache[type].slice(folderIndex + 1) - ] - })); - } - - return data; - }, - - async deleteFolder(type, id) { - const { data: response } = await client.mutate< - DeleteFolderResponse, - DeleteFolderVariables - >({ - mutation: DELETE_FOLDER, - variables: { - id - } - }); - - if (!response) { - throw new Error("Network error while deleting folder"); - } - - const { data, error } = response.aco.deleteFolder; - - if (!data) { - throw new Error(error?.message || "Could not delete folder"); - } - - setCache(cache => ({ - ...cache, - [type]: cache[type].filter(f => f.id !== id) - })); - - return true; - }, - - getDescendantFolders(type, id) { - const currentFolders = cache[type]; - - if (!id || id === ROOT_FOLDER || !currentFolders?.length) { - return []; - } - - const folderMap = new Map(currentFolders.map(folder => [folder.id, folder])); - const result: FolderItem[] = []; - - const findChildren = (folderId: string) => { - const folder = folderMap.get(folderId); - if (!folder) { - return; - } - - result.push(folder); - - currentFolders.forEach(child => { - if (child.parentId === folder.id) { - findChildren(child.id); - } - }); - }; - - findChildren(id); - - return result; - } - }; - - return {children}; -}; diff --git a/packages/app-aco/src/contexts/FoldersApi/index.ts b/packages/app-aco/src/contexts/FoldersApi/index.ts deleted file mode 100644 index 69c1b07b6b8..00000000000 --- a/packages/app-aco/src/contexts/FoldersApi/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./FoldersApiProvider"; -export * from "./useFoldersApi"; diff --git a/packages/app-aco/src/contexts/FoldersApi/useFoldersApi.ts b/packages/app-aco/src/contexts/FoldersApi/useFoldersApi.ts deleted file mode 100644 index d0ccc58a998..00000000000 --- a/packages/app-aco/src/contexts/FoldersApi/useFoldersApi.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useContext } from "react"; -import { FoldersApiContext } from "./FoldersApiProvider"; - -export function useFoldersApi() { - const context = useContext(FoldersApiContext); - if (!context) { - throw new Error(`Missing "FoldersApiProvider" in the component hierarchy!`); - } - - return context; -} diff --git a/packages/app-aco/src/features/folder/cache/ICache.ts b/packages/app-aco/src/features/folder/cache/ICache.ts index 3672a3a57f9..5818456bfe5 100644 --- a/packages/app-aco/src/features/folder/cache/ICache.ts +++ b/packages/app-aco/src/features/folder/cache/ICache.ts @@ -1,7 +1,7 @@ export interface ICache { hasItems: () => boolean; getItems: () => TItem[]; - getItem: (id: string) => TItem; + getItem: (id: string) => TItem | undefined; set: (item: TItem) => Promise; setMultiple: (items: TItem[]) => Promise; update: (id: string, item: TItem) => Promise; diff --git a/packages/app-aco/src/graphql/folders.gql.ts b/packages/app-aco/src/graphql/folders.gql.ts deleted file mode 100644 index add1cece388..00000000000 --- a/packages/app-aco/src/graphql/folders.gql.ts +++ /dev/null @@ -1,98 +0,0 @@ -import gql from "graphql-tag"; - -const ERROR_FIELD = /* GraphQL */ ` - { - code - data - message - } -`; - -const DATA_FIELD = /* GraphQL */ ` - { - id - title - slug - permissions { - target - level - inheritedFrom - } - hasNonInheritedPermissions - canManagePermissions - canManageStructure - canManageContent - parentId - type - savedOn - savedBy { - id - displayName - } - createdOn - createdBy { - id - displayName - } - modifiedOn - modifiedBy { - id - displayName - } - } -`; - -export const CREATE_FOLDER = gql` - mutation CreateFolder($data: FolderCreateInput!) { - aco { - createFolder(data: $data) { - data ${DATA_FIELD} - error ${ERROR_FIELD} - } - } - } -`; - -export const LIST_FOLDERS = gql` - query ListFolders ($type: String!, $limit: Int!) { - aco { - listFolders(where: { type: $type }, limit: $limit) { - data ${DATA_FIELD} - error ${ERROR_FIELD} - } - } - } -`; - -export const GET_FOLDER = gql` - query GetFolder ($id: ID!) { - aco { - getFolder(id: $id) { - data ${DATA_FIELD} - error ${ERROR_FIELD} - } - } - } -`; - -export const UPDATE_FOLDER = gql` - mutation UpdateFolder($id: ID!, $data: FolderUpdateInput!) { - aco { - updateFolder(id: $id, data: $data) { - data ${DATA_FIELD} - error ${ERROR_FIELD} - } - } - } -`; - -export const DELETE_FOLDER = gql` - mutation DeleteFolder($id: ID!) { - aco { - deleteFolder(id: $id) { - data - error ${ERROR_FIELD} - } - } - } -`; diff --git a/packages/app-aco/src/hooks/index.ts b/packages/app-aco/src/hooks/index.ts index a25f3b8d2b4..60907b72441 100644 --- a/packages/app-aco/src/hooks/index.ts +++ b/packages/app-aco/src/hooks/index.ts @@ -5,4 +5,3 @@ export * from "./useFolders"; export * from "./useRecords"; export * from "./useTags"; export * from "./useNavigateFolder"; -export { useFoldersApi } from "../contexts/FoldersApi"; diff --git a/packages/app-aco/src/index.ts b/packages/app-aco/src/index.ts index c7c297a3415..1c69c067f52 100644 --- a/packages/app-aco/src/index.ts +++ b/packages/app-aco/src/index.ts @@ -3,5 +3,4 @@ export * from "./config"; export * from "./contexts"; export * from "./hooks"; export * from "./dialogs"; -export * from "./Folders"; export * from "./sorting"; diff --git a/packages/app-serverless-cms/src/Admin.tsx b/packages/app-serverless-cms/src/Admin.tsx index 103c0b66434..d46d168fb34 100644 --- a/packages/app-serverless-cms/src/Admin.tsx +++ b/packages/app-serverless-cms/src/Admin.tsx @@ -28,7 +28,6 @@ import { AuditLogs } from "@webiny/app-audit-logs"; import { LexicalEditorPlugin } from "@webiny/lexical-editor-pb-element"; import { LexicalEditorActions } from "@webiny/lexical-editor-actions"; import { Module as MailerSettings } from "@webiny/app-mailer"; -import { Folders } from "@webiny/app-aco"; import { Websockets } from "@webiny/app-websockets"; import { RecordLocking } from "@webiny/app-record-locking"; import { TrashBinConfigs } from "@webiny/app-trash-bin"; @@ -51,7 +50,6 @@ const App = (props: AdminProps) => { - From c6c467c66661661c758b43bf7de17a96adcfbd46 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 18 Oct 2024 12:55:39 +0200 Subject: [PATCH 16/28] feat: move vm into listFolders --- .../folder/listFolders/useListFolders.ts | 46 ++++++++++++++++- packages/app-aco/src/hooks/useFolders.ts | 50 ++----------------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts index 5352cf172ad..631b33420c6 100644 --- a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts @@ -1,4 +1,5 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { autorun } from "mobx"; import { useApolloClient } from "@apollo/react-hooks"; import { LoadingRepository } from "@webiny/app-utils"; import { FoldersCache } from "../cache"; @@ -6,8 +7,20 @@ import { ListFoldersRepository } from "./ListFoldersRepository"; import { ListFoldersGqlGateway } from "./ListFoldersGqlGateway"; import { ListFoldersUseCaseWithLoading } from "./ListFoldersUseCaseWithLoading"; import { ListFoldersUseCase } from "./ListFoldersUseCase"; +import { FolderDtoMapper } from "./FolderDto"; +import { FolderItem } from "~/types"; export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, type: string) => { + const [vm, setVm] = useState<{ + folders: FolderItem[]; + loading: Record; + }>({ + folders: [], + loading: { + INIT: true + } + }); + const client = useApolloClient(); const gateway = useMemo(() => { @@ -27,7 +40,38 @@ export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, return useCase.execute(); }, [useCase]); + useEffect(() => { + if (cache.hasItems()) { + return; // Skip if we already have folders in the cache. + } + + listFolders(); + }, []); + + useEffect(() => { + return autorun(() => { + const folders = cache.getItems().map(folder => FolderDtoMapper.toDTO(folder)); + + setVm(vm => ({ + ...vm, + folders + })); + }); + }, [cache]); + + useEffect(() => { + return autorun(() => { + const loadingState = loading.get(); + + setVm(vm => ({ + ...vm, + loading: loadingState + })); + }); + }, [loading]); + return { + ...vm, listFolders }; }; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 9e2cf9f1791..920479f8c03 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,10 +1,8 @@ -import { useContext, useEffect, useMemo, useState } from "react"; -import { autorun } from "mobx"; +import { useContext, useMemo } from "react"; import { loadingRepositoryFactory } from "@webiny/app-utils"; import { FoldersContext } from "~/contexts/folders"; import { folderCacheFactory, - FolderDtoMapper, useCreateFolder, useDeleteFolder, useGetCanManageContent, @@ -15,19 +13,8 @@ import { useListFolders, useUpdateFolder } from "~/features/folder"; -import { FolderItem } from "~/types"; export const useFolders = () => { - const [vm, setVm] = useState<{ - folders: FolderItem[]; - loading: Record; - }>({ - folders: [], - loading: { - INIT: true - } - }); - const foldersContext = useContext(FoldersContext); if (!foldersContext) { @@ -52,7 +39,7 @@ export const useFolders = () => { const { createFolder } = useCreateFolder(foldersCache, loadingRepository, type); const { deleteFolder } = useDeleteFolder(foldersCache, loadingRepository); - const { listFolders } = useListFolders(foldersCache, loadingRepository, type); + const { listFolders, folders, loading } = useListFolders(foldersCache, loadingRepository, type); const { updateFolder } = useUpdateFolder(foldersCache, loadingRepository); const { getDescendantFolders } = useGetDescendantFolders(foldersCache); const { getFolder } = useGetFolder(foldersCache, loadingRepository); @@ -60,38 +47,9 @@ export const useFolders = () => { const { canManagePermissions } = useGetCanManagePermissions(foldersCache); const { canManageContent } = useGetCanManageContent(foldersCache); - useEffect(() => { - if (foldersCache.hasItems()) { - return; // Skip if we already have folders in the cache. - } - - listFolders(); - }, []); - - useEffect(() => { - return autorun(() => { - const folders = foldersCache.getItems().map(folder => FolderDtoMapper.toDTO(folder)); - - setVm(vm => ({ - ...vm, - folders - })); - }); - }, [foldersCache]); - - useEffect(() => { - return autorun(() => { - const loading = loadingRepository.get(); - - setVm(vm => ({ - ...vm, - loading - })); - }); - }, [loadingRepository]); - return { - ...vm, + folders, + loading, listFolders, getFolder, getDescendantFolders, From ba5011d2a485d92e380d4a3321003376d5ab19a7 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Sat, 19 Oct 2024 19:30:36 +0200 Subject: [PATCH 17/28] refactor: create separate folders useCases --- .../folder/createFolder/CreateFolder.test.ts | 55 +++++++++++++++++++ .../folder/createFolder/CreateFolder.ts | 31 +++++++++++ .../folder/createFolder/useCreateFolder.ts | 36 ++++++------ .../folder/deleteFolder/DeleteFolder.ts | 31 +++++++++++ .../folder/deleteFolder/useDeleteFolder.ts | 36 ++++++------ .../GetCanManageContent.ts | 26 +++++++++ .../GetCanManageContentUseCase.ts | 11 +--- .../GetCanManageContentWithFlpUseCase.ts | 11 +--- .../useGetCanManageContent.ts | 33 ++++++----- .../GetCanManagePermissions.ts | 26 +++++++++ .../GetCanManagePermissionsUseCase.ts | 11 +--- .../GetCanManagePermissionsWithFlpUseCase.ts | 11 +--- .../useGetCanManagePermissions.ts | 36 ++++++------ .../GetCanManageStructure.ts | 26 +++++++++ .../GetCanManageStructureUseCase.ts | 11 +--- .../GetCanManageStructureWithFlpUseCase.ts | 11 +--- .../useGetCanManageStructure.ts | 36 ++++++------ .../GetDescendantFolders.ts | 20 +++++++ .../useGetDescendantFolders.ts | 30 +++++----- .../features/folder/getFolder/GetFolder.ts | 28 ++++++++++ .../features/folder/getFolder/useGetFolder.ts | 36 ++++++------ .../folder/listFolders/ListFolders.ts | 51 +++++++++++++++++ .../folder/listFolders/useListFolders.ts | 47 +++++++++------- .../folder/updateFolder/UpdateFolder.ts | 31 +++++++++++ .../folder/updateFolder/useUpdateFolder.ts | 36 ++++++------ packages/app-aco/src/hooks/useFolders.ts | 44 +++------------ 26 files changed, 502 insertions(+), 259 deletions(-) create mode 100644 packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts create mode 100644 packages/app-aco/src/features/folder/createFolder/CreateFolder.ts create mode 100644 packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts create mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts create mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts create mode 100644 packages/app-aco/src/features/folder/getFolder/GetFolder.ts create mode 100644 packages/app-aco/src/features/folder/listFolders/ListFolders.ts create mode 100644 packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts new file mode 100644 index 00000000000..dbdaafe6ef4 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts @@ -0,0 +1,55 @@ +import { ICreateFolderGateway } from "~/features/folder/createFolder/ICreateFolderGateway"; +import { FolderGqlDto } from "~/features/folder/createFolder/FolderGqlDto"; +import { CmsIdentity } from "~/types"; +import pick from "lodash/pick"; +import { CreateFolder } from "./CreateFolder"; + +const createFolderGateway = ({ execute }: ICreateFolderGateway): ICreateFolderGateway => ({ + execute +}); + +const user1: CmsIdentity = { + id: "user-1", + type: "admin", + displayName: "User 1" +}; + +const type = "demo-type"; + +const folder1: FolderGqlDto = { + id: "folder-1", + title: "Folder 1", + slug: "folder-1", + permissions: [], + hasNonInheritedPermissions: true, + canManageContent: true, + canManagePermissions: true, + canManageStructure: true, + type, + parentId: null, + createdBy: user1, + createdOn: new Date().toString(), + savedBy: user1, + savedOn: new Date().toString(), + modifiedBy: null, + modifiedOn: null +}; + +describe("CreateFolder", () => { + it("should be able to create a folder", async () => { + const gateway = createFolderGateway({ + execute: jest.fn().mockImplementation(() => { + return Promise.resolve(folder1); + }) + }); + + const createFolder = CreateFolder.getInstance(gateway, type); + + const createPromise = createFolder.execute( + pick(folder1, ["title", "slug", "type", "parentId", "permissions"]) + ); + + await createPromise; + expect(gateway.execute).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts new file mode 100644 index 00000000000..cf0186f3139 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts @@ -0,0 +1,31 @@ +import { loadingRepositoryFactory } from "@webiny/app-utils"; +import { ICreateFolderUseCase } from "./ICreateFolderUseCase"; +import { ICreateFolderGateway } from "./ICreateFolderGateway"; +import { CreateFolderRepository } from "./CreateFolderRepository"; +import { CreateFolderUseCase } from "./CreateFolderUseCase"; +import { CreateFolderUseCaseWithLoading } from "./CreateFolderUseCaseWithLoading"; +import { folderCacheFactory } from "../cache"; + +export class CreateFolder { + static cache: Map = new Map(); + + public static instance(gateway: ICreateFolderGateway, type: string): ICreateFolderUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new CreateFolderRepository(foldersCache, gateway, type); + const useCase = new CreateFolderUseCase(repository); + const useCaseWithLoading = new CreateFolderUseCaseWithLoading( + loadingRepository, + useCase + ); + + // Store in cache + this.cache.set(type, useCaseWithLoading); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts index 5359bb51310..22a1d77b5c9 100644 --- a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts +++ b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts @@ -1,34 +1,32 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useApolloClient } from "@apollo/react-hooks"; -import { LoadingRepository } from "@webiny/app-utils"; -import { FoldersCache } from "../cache"; import { CreateFolderGqlGateway } from "./CreateFolderGqlGateway"; -import { CreateFolderRepository } from "./CreateFolderRepository"; -import { CreateFolderUseCase } from "./CreateFolderUseCase"; -import { CreateFolderUseCaseWithLoading } from "./CreateFolderUseCaseWithLoading"; import { CreateFolderParams } from "./ICreateFolderUseCase"; +import { CreateFolder } from "./CreateFolder"; +import { FoldersContext } from "~/contexts/folders"; -export const useCreateFolder = (cache: FoldersCache, loading: LoadingRepository, type: string) => { +export const useCreateFolder = () => { const client = useApolloClient(); + const gateway = new CreateFolderGqlGateway(client); - const gateway = useMemo(() => { - return new CreateFolderGqlGateway(client); - }, [client]); + const foldersContext = useContext(FoldersContext); - const repository = useMemo(() => { - return new CreateFolderRepository(cache, gateway, type); - }, [cache, gateway, type]); + if (!foldersContext) { + throw new Error("useCreateFolder must be used within a FoldersProvider"); + } - const useCase = useMemo(() => { - const createFolderUseCase = new CreateFolderUseCase(repository); - return new CreateFolderUseCaseWithLoading(loading, createFolderUseCase); - }, [repository, loading]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const createFolder = useCallback( (params: CreateFolderParams) => { - return useCase.execute(params); + const instance = CreateFolder.instance(gateway, type); + return instance.execute(params); }, - [useCase] + [type, gateway] ); return { diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts new file mode 100644 index 00000000000..15d27f83e79 --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts @@ -0,0 +1,31 @@ +import { loadingRepositoryFactory } from "@webiny/app-utils"; +import { IDeleteFolderUseCase } from "./IDeleteFolderUseCase"; +import { DeleteFolderRepository } from "./DeleteFolderRepository"; +import { DeleteFolderUseCase } from "./DeleteFolderUseCase"; +import { DeleteFolderUseCaseWithLoading } from "./DeleteFolderUseCaseWithLoading"; +import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; +import { folderCacheFactory } from "../cache"; + +export class DeleteFolder { + static cache: Map = new Map(); + + public static getInstance(gateway: IDeleteFolderGateway, type: string): IDeleteFolderUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new DeleteFolderRepository(foldersCache, gateway); + const useCase = new DeleteFolderUseCase(repository); + const useCaseWithLoading = new DeleteFolderUseCaseWithLoading( + loadingRepository, + useCase + ); + + // Store in cache + this.cache.set(type, useCaseWithLoading); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts index 9498ecc4b1c..2a4fd637ec8 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts @@ -1,34 +1,32 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useApolloClient } from "@apollo/react-hooks"; -import { FoldersCache } from "../cache"; -import { LoadingRepository } from "@webiny/app-utils"; import { DeleteFolderGqlGateway } from "./DeleteFolderGqlGateway"; -import { DeleteFolderRepository } from "./DeleteFolderRepository"; -import { DeleteFolderUseCase } from "./DeleteFolderUseCase"; -import { DeleteFolderUseCaseWithLoading } from "./DeleteFolderUseCaseWithLoading"; import { DeleteFolderParams } from "./IDeleteFolderUseCase"; +import { DeleteFolder } from "./DeleteFolder"; +import { FoldersContext } from "~/contexts/folders"; -export const useDeleteFolder = (cache: FoldersCache, loading: LoadingRepository) => { +export const useDeleteFolder = () => { const client = useApolloClient(); + const gateway = new DeleteFolderGqlGateway(client); - const gateway = useMemo(() => { - return new DeleteFolderGqlGateway(client); - }, [client]); + const foldersContext = useContext(FoldersContext); - const repository = useMemo(() => { - return new DeleteFolderRepository(cache, gateway); - }, [cache, gateway]); + if (!foldersContext) { + throw new Error("useFolders must be used within a FoldersProvider"); + } - const useCase = useMemo(() => { - const deleteFolderUseCase = new DeleteFolderUseCase(repository); - return new DeleteFolderUseCaseWithLoading(loading, deleteFolderUseCase); - }, [repository, loading]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const deleteFolder = useCallback( (params: DeleteFolderParams) => { - return useCase.execute(params); + const instance = DeleteFolder.getInstance(gateway, type); + return instance.execute(params); }, - [useCase] + [type, gateway] ); return { diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts new file mode 100644 index 00000000000..3104bb899da --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts @@ -0,0 +1,26 @@ +import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; +import { GetCanManageContentRepository } from "./GetCanManageContentRepository"; +import { GetCanManageContentWithFlpUseCase } from "./GetCanManageContentWithFlpUseCase"; +import { GetCanManageContentUseCase } from "./GetCanManageContentUseCase"; +import { folderCacheFactory } from "../cache"; + +export class GetCanManageContent { + static cache: Map = new Map(); + + public static instance(type: string, canUseFlp: boolean): IGetCanManageContentUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetCanManageContentRepository(foldersCache); + + if (canUseFlp) { + return new GetCanManageContentWithFlpUseCase(repository); + } + + return new GetCanManageContentUseCase(); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts index 42e15e22484..877e72e8510 100644 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts @@ -1,14 +1,7 @@ import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; -import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository"; export class GetCanManageContentUseCase implements IGetCanManageContentUseCase { - private repository: IGetCanManageContentRepository; - - constructor(repository: IGetCanManageContentRepository) { - this.repository = repository; - } - - execute(id: string) { - return this.repository.execute(id); + execute() { + return true; } } diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts index 802f4163011..ad9a0ed4176 100644 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts @@ -3,21 +3,12 @@ import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository export class GetCanManageContentWithFlpUseCase implements IGetCanManageContentUseCase { private repository: IGetCanManageContentRepository; - private canUseFolderLevelPermissions: () => boolean; - constructor( - repository: IGetCanManageContentRepository, - canUseFolderLevelPermissions: () => boolean - ) { + constructor(repository: IGetCanManageContentRepository) { this.repository = repository; - this.canUseFolderLevelPermissions = canUseFolderLevelPermissions; } execute(id: string) { - if (!this.canUseFolderLevelPermissions) { - return true; - } - return this.repository.execute(id); } } diff --git a/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts b/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts index 599cccaaf79..84e269cf29a 100644 --- a/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts +++ b/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts @@ -1,30 +1,29 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useWcp } from "@webiny/app-wcp"; -import { FoldersCache } from "../cache"; -import { GetCanManageContentRepository } from "./GetCanManageContentRepository"; -import { GetCanManageContentWithFlpUseCase } from "./GetCanManageContentWithFlpUseCase"; -import { GetCanManageContentUseCase } from "./GetCanManageContentUseCase"; +import { FoldersContext } from "~/contexts/folders"; +import { GetCanManageContent } from "./GetCanManageContent"; -export const useGetCanManageContent = (cache: FoldersCache) => { +export const useGetCanManageContent = () => { const { canUseFolderLevelPermissions } = useWcp(); - const repository = useMemo(() => { - return new GetCanManageContentRepository(cache); - }, [cache]); + const foldersContext = useContext(FoldersContext); - const useCase = useMemo(() => { - if (canUseFolderLevelPermissions) { - return new GetCanManageContentWithFlpUseCase(repository, canUseFolderLevelPermissions); - } + if (!foldersContext) { + throw new Error("useGetCanManageContent must be used within a FoldersProvider"); + } - return new GetCanManageContentUseCase(repository); - }, [repository, canUseFolderLevelPermissions]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const canManageContent = useCallback( (id: string) => { - return useCase.execute(id); + const instance = GetCanManageContent.instance(type, canUseFolderLevelPermissions()); + return instance.execute(id); }, - [useCase] + [type, canUseFolderLevelPermissions] ); return { diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts new file mode 100644 index 00000000000..dc60e49aa1a --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts @@ -0,0 +1,26 @@ +import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; +import { GetCanManagePermissionsRepository } from "./GetCanManagePermissionsRepository"; +import { GetCanManagePermissionsWithFlpUseCase } from "./GetCanManagePermissionsWithFlpUseCase"; +import { GetCanManagePermissionsUseCase } from "./GetCanManagePermissionsUseCase"; +import { folderCacheFactory } from "~/features/folder"; + +export class GetCanManagePermissions { + static cache: Map = new Map(); + + public static instance(type: string, canUseFlp: boolean): IGetCanManagePermissionsUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetCanManagePermissionsRepository(foldersCache); + + if (canUseFlp) { + return new GetCanManagePermissionsWithFlpUseCase(repository); + } + + return new GetCanManagePermissionsUseCase(); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts index 98676583dca..38cd627d143 100644 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts @@ -1,14 +1,7 @@ import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; -import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRepository"; export class GetCanManagePermissionsUseCase implements IGetCanManagePermissionsUseCase { - private repository: IGetCanManagePermissionsRepository; - - constructor(repository: IGetCanManagePermissionsRepository) { - this.repository = repository; - } - - execute(id: string) { - return this.repository.execute(id); + execute() { + return true; } } diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts index 78ee2c316b9..ba34911471e 100644 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts @@ -3,21 +3,12 @@ import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRe export class GetCanManagePermissionsWithFlpUseCase implements IGetCanManagePermissionsUseCase { private repository: IGetCanManagePermissionsRepository; - private canUseFolderLevelPermissions: () => boolean; - constructor( - repository: IGetCanManagePermissionsRepository, - canUseFolderLevelPermissions: () => boolean - ) { + constructor(repository: IGetCanManagePermissionsRepository) { this.repository = repository; - this.canUseFolderLevelPermissions = canUseFolderLevelPermissions; } execute(id: string) { - if (!this.canUseFolderLevelPermissions) { - return true; - } - return this.repository.execute(id); } } diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts index 22d9da1c345..a984d616c22 100644 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts @@ -1,33 +1,29 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useWcp } from "@webiny/app-wcp"; -import { FoldersCache } from "../cache"; -import { GetCanManagePermissionsRepository } from "./GetCanManagePermissionsRepository"; -import { GetCanManagePermissionsWithFlpUseCase } from "./GetCanManagePermissionsWithFlpUseCase"; -import { GetCanManagePermissionsUseCase } from "./GetCanManagePermissionsUseCase"; +import { FoldersContext } from "~/contexts/folders"; +import { GetCanManagePermissions } from "./GetCanManagePermissions"; -export const useGetCanManagePermissions = (cache: FoldersCache) => { +export const useGetCanManagePermissions = () => { const { canUseFolderLevelPermissions } = useWcp(); - const repository = useMemo(() => { - return new GetCanManagePermissionsRepository(cache); - }, [cache]); + const foldersContext = useContext(FoldersContext); - const useCase = useMemo(() => { - if (canUseFolderLevelPermissions) { - return new GetCanManagePermissionsWithFlpUseCase( - repository, - canUseFolderLevelPermissions - ); - } + if (!foldersContext) { + throw new Error("useGetCanManagePermissions must be used within a FoldersProvider"); + } - return new GetCanManagePermissionsUseCase(repository); - }, [repository, canUseFolderLevelPermissions]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const canManagePermissions = useCallback( (id: string) => { - return useCase.execute(id); + const instance = GetCanManagePermissions.instance(type, canUseFolderLevelPermissions()); + return instance.execute(id); }, - [useCase] + [type, canUseFolderLevelPermissions] ); return { diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts new file mode 100644 index 00000000000..acde666dd51 --- /dev/null +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts @@ -0,0 +1,26 @@ +import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; +import { GetCanManageStructureRepository } from "./GetCanManageStructureRepository"; +import { GetCanManageStructureWithFlpUseCase } from "./GetCanManageStructureWithFlpUseCase"; +import { GetCanManageStructureUseCase } from "./GetCanManageStructureUseCase"; +import { folderCacheFactory } from "../cache"; + +export class GetCanManageStructure { + static cache: Map = new Map(); + + public static instance(type: string, canUseFlp: boolean): IGetCanManageStructureUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetCanManageStructureRepository(foldersCache); + + if (canUseFlp) { + return new GetCanManageStructureWithFlpUseCase(repository); + } + + return new GetCanManageStructureUseCase(); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts index 4cd824a88cb..70cc57cdf64 100644 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts @@ -1,14 +1,7 @@ import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; -import { IGetCanManageStructureRepository } from "./IGetCanManageStructureRepository"; export class GetCanManageStructureUseCase implements IGetCanManageStructureUseCase { - private repository: IGetCanManageStructureRepository; - - constructor(repository: IGetCanManageStructureRepository) { - this.repository = repository; - } - - execute(id: string) { - return this.repository.execute(id); + execute() { + return true; } } diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts index 3a5d1fad6ff..1e4dc63aa00 100644 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts @@ -3,21 +3,12 @@ import { IGetCanManageStructureRepository } from "./IGetCanManageStructureReposi export class GetCanManageStructureWithFlpUseCase implements IGetCanManageStructureUseCase { private repository: IGetCanManageStructureRepository; - private canUseFolderLevelPermissions: () => boolean; - constructor( - repository: IGetCanManageStructureRepository, - canUseFolderLevelPermissions: () => boolean - ) { + constructor(repository: IGetCanManageStructureRepository) { this.repository = repository; - this.canUseFolderLevelPermissions = canUseFolderLevelPermissions; } execute(id: string) { - if (!this.canUseFolderLevelPermissions) { - return true; - } - return this.repository.execute(id); } } diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts b/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts index b9c703a106d..eba471678a0 100644 --- a/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts +++ b/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts @@ -1,33 +1,29 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useWcp } from "@webiny/app-wcp"; -import { FoldersCache } from "../cache"; -import { GetCanManageStructureRepository } from "./GetCanManageStructureRepository"; -import { GetCanManageStructureWithFlpUseCase } from "./GetCanManageStructureWithFlpUseCase"; -import { GetCanManageStructureUseCase } from "./GetCanManageStructureUseCase"; +import { FoldersContext } from "~/contexts/folders"; +import { GetCanManageStructure } from "./GetCanManageStructure"; -export const useGetCanManageStructure = (cache: FoldersCache) => { +export const useGetCanManageStructure = () => { const { canUseFolderLevelPermissions } = useWcp(); - const repository = useMemo(() => { - return new GetCanManageStructureRepository(cache); - }, [cache]); + const foldersContext = useContext(FoldersContext); - const useCase = useMemo(() => { - if (canUseFolderLevelPermissions) { - return new GetCanManageStructureWithFlpUseCase( - repository, - canUseFolderLevelPermissions - ); - } + if (!foldersContext) { + throw new Error("useGetCanManageContent must be used within a FoldersProvider"); + } - return new GetCanManageStructureUseCase(repository); - }, [repository, canUseFolderLevelPermissions]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const canManageStructure = useCallback( (id: string) => { - return useCase.execute(id); + const instance = GetCanManageStructure.instance(type, canUseFolderLevelPermissions()); + return instance.execute(id); }, - [useCase] + [type, canUseFolderLevelPermissions] ); return { diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts new file mode 100644 index 00000000000..3763cd1d349 --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts @@ -0,0 +1,20 @@ +import { IGetDescendantFoldersUseCase } from "./IGetDescendantFoldersUseCase"; +import { GetDescendantFoldersRepository } from "./GetDescendantFoldersRepository"; +import { GetDescendantFoldersUseCase } from "./GetDescendantFoldersUseCase"; +import { folderCacheFactory } from "../cache"; + +export class GetDescendantFolders { + static cache: Map = new Map(); + + public static instance(type: string): IGetDescendantFoldersUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetDescendantFoldersRepository(foldersCache); + return new GetDescendantFoldersUseCase(repository); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts b/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts index 38c90cf318d..10509563968 100644 --- a/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts +++ b/packages/app-aco/src/features/folder/getDescendantFolders/useGetDescendantFolders.ts @@ -1,22 +1,26 @@ -import { useCallback, useMemo } from "react"; -import { FoldersCache } from "../cache"; -import { GetDescendantFoldersRepository } from "./GetDescendantFoldersRepository"; -import { GetDescendantFoldersUseCase } from "./GetDescendantFoldersUseCase"; +import { useCallback, useContext } from "react"; +import { GetDescendantFolders } from "./GetDescendantFolders"; +import { FoldersContext } from "~/contexts/folders"; -export const useGetDescendantFolders = (cache: FoldersCache) => { - const repository = useMemo(() => { - return new GetDescendantFoldersRepository(cache); - }, [cache]); +export const useGetDescendantFolders = () => { + const foldersContext = useContext(FoldersContext); - const useCase = useMemo(() => { - return new GetDescendantFoldersUseCase(repository); - }, [repository]); + if (!foldersContext) { + throw new Error("useCreateFolder must be used within a FoldersProvider"); + } + + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const getDescendantFolders = useCallback( (id: string) => { - return useCase.execute({ id }); + const instance = GetDescendantFolders.instance(type); + return instance.execute({ id }); }, - [useCase] + [type] ); return { diff --git a/packages/app-aco/src/features/folder/getFolder/GetFolder.ts b/packages/app-aco/src/features/folder/getFolder/GetFolder.ts new file mode 100644 index 00000000000..8a13f8fbf5a --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolder/GetFolder.ts @@ -0,0 +1,28 @@ +import { loadingRepositoryFactory } from "@webiny/app-utils"; +import { IGetFolderUseCase } from "./IGetFolderUseCase"; +import { IGetFolderGateway } from "./IGetFolderGateway"; +import { GetFolderRepository } from "./GetFolderRepository"; +import { GetFolderUseCase } from "./GetFolderUseCase"; +import { GetFolderUseCaseWithLoading } from "./GetFolderUseCaseWithLoading"; +import { folderCacheFactory } from "../cache"; + +export class GetFolder { + static cache: Map = new Map(); + + public static instance(gateway: IGetFolderGateway, type: string): IGetFolderUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new GetFolderRepository(foldersCache, gateway); + const useCase = new GetFolderUseCase(repository); + const useCaseWithLoading = new GetFolderUseCaseWithLoading(loadingRepository, useCase); + + // Store in cache + this.cache.set(type, useCaseWithLoading); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts b/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts index d2abb1954b6..2d655537320 100644 --- a/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts +++ b/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts @@ -1,34 +1,32 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useApolloClient } from "@apollo/react-hooks"; -import { LoadingRepository } from "@webiny/app-utils"; -import { FoldersCache } from "../cache"; import { GetFolderGqlGateway } from "./GetFolderGqlGateway"; -import { GetFolderRepository } from "./GetFolderRepository"; -import { GetFolderUseCaseWithLoading } from "./GetFolderUseCaseWithLoading"; -import { GetFolderUseCase } from "./GetFolderUseCase"; import { GetFolderParams } from "./IGetFolderUseCase"; +import { GetFolder } from "./GetFolder"; +import { FoldersContext } from "~/contexts/folders"; -export const useGetFolder = (cache: FoldersCache, loading: LoadingRepository) => { +export const useGetFolder = () => { const client = useApolloClient(); + const gateway = new GetFolderGqlGateway(client); - const gateway = useMemo(() => { - return new GetFolderGqlGateway(client); - }, [client]); + const foldersContext = useContext(FoldersContext); - const repository = useMemo(() => { - return new GetFolderRepository(cache, gateway); - }, [cache, gateway]); + if (!foldersContext) { + throw new Error("useGetFolder must be used within a FoldersProvider"); + } - const useCase = useMemo(() => { - const getFolderUseCase = new GetFolderUseCase(repository); - return new GetFolderUseCaseWithLoading(loading, getFolderUseCase); - }, [repository, loading]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const getFolder = useCallback( (params: GetFolderParams) => { - return useCase.execute(params); + const instance = GetFolder.instance(gateway, type); + return instance.execute(params); }, - [useCase] + [type, gateway] ); return { diff --git a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts new file mode 100644 index 00000000000..a0ebf04d1b0 --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts @@ -0,0 +1,51 @@ +import { LoadingRepository, loadingRepositoryFactory } from "@webiny/app-utils"; +import { IListFoldersUseCase } from "./IListFoldersUseCase"; +import { IListFoldersGateway } from "./IListFoldersGateway"; +import { ListFoldersRepository } from "./ListFoldersRepository"; +import { ListFoldersUseCaseWithLoading } from "./ListFoldersUseCaseWithLoading"; +import { ListFoldersUseCase } from "./ListFoldersUseCase"; +import { folderCacheFactory, FoldersCache } from "../cache"; + +interface IListFoldersInstance { + useCase: IListFoldersUseCase; + folders: FoldersCache; + loading: LoadingRepository; +} + +export class ListFolders { + static useCaseCache: Map = new Map(); + static foldersCache: Map = new Map(); + static loadingCache: Map = new Map(); + + public static instance(gateway: IListFoldersGateway, type: string): IListFoldersInstance { + if (!this.foldersCache.has(type)) { + this.foldersCache.set(type, folderCacheFactory.getCache(type)); + } + + if (!this.loadingCache.has(type)) { + this.loadingCache.set(type, loadingRepositoryFactory.getRepository()); + } + + if (!this.useCaseCache.has(type)) { + // Create a new instance if not cached + const foldersCache = this.foldersCache.get(type)!; + const loadingRepository = this.loadingCache.get(type)!; + const repository = new ListFoldersRepository(foldersCache, gateway, type); + const useCase = new ListFoldersUseCase(repository); + const useCaseWithLoading = new ListFoldersUseCaseWithLoading( + loadingRepository, + useCase + ); + + // Store in cache + this.useCaseCache.set(type, useCaseWithLoading); + } + + // Return the cached instance + return { + useCase: this.useCaseCache.get(type)!, + folders: this.foldersCache.get(type)!, + loading: this.loadingCache.get(type)! + }; + } +} diff --git a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts index 631b33420c6..33736c33d82 100644 --- a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts @@ -1,16 +1,16 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useContext, useEffect, useMemo, useState } from "react"; import { autorun } from "mobx"; import { useApolloClient } from "@apollo/react-hooks"; -import { LoadingRepository } from "@webiny/app-utils"; -import { FoldersCache } from "../cache"; -import { ListFoldersRepository } from "./ListFoldersRepository"; import { ListFoldersGqlGateway } from "./ListFoldersGqlGateway"; -import { ListFoldersUseCaseWithLoading } from "./ListFoldersUseCaseWithLoading"; -import { ListFoldersUseCase } from "./ListFoldersUseCase"; +import { ListFolders } from "./ListFolders"; import { FolderDtoMapper } from "./FolderDto"; +import { FoldersContext } from "~/contexts/folders"; import { FolderItem } from "~/types"; -export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, type: string) => { +export const useListFolders = () => { + const client = useApolloClient(); + const gateway = new ListFoldersGqlGateway(client); + const [vm, setVm] = useState<{ folders: FolderItem[]; loading: Record; @@ -21,27 +21,32 @@ export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, } }); - const client = useApolloClient(); + const foldersContext = useContext(FoldersContext); + + if (!foldersContext) { + throw new Error("useCreateFolder must be used within a FoldersProvider"); + } - const gateway = useMemo(() => { - return new ListFoldersGqlGateway(client); - }, [client]); + const { type } = foldersContext; - const repository = useMemo(() => { - return new ListFoldersRepository(cache, gateway, type); - }, [cache, gateway, type]); + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } - const useCase = useMemo(() => { - const listFolderUseCase = new ListFoldersUseCase(repository); - return new ListFoldersUseCaseWithLoading(loading, listFolderUseCase); - }, [repository, loading]); + const { + useCase, + folders: foldersCache, + loading + } = useMemo(() => { + return ListFolders.instance(gateway, type); + }, [type, gateway]); const listFolders = useCallback(() => { return useCase.execute(); }, [useCase]); useEffect(() => { - if (cache.hasItems()) { + if (foldersCache.hasItems()) { return; // Skip if we already have folders in the cache. } @@ -50,14 +55,14 @@ export const useListFolders = (cache: FoldersCache, loading: LoadingRepository, useEffect(() => { return autorun(() => { - const folders = cache.getItems().map(folder => FolderDtoMapper.toDTO(folder)); + const folders = foldersCache.getItems().map(folder => FolderDtoMapper.toDTO(folder)); setVm(vm => ({ ...vm, folders })); }); - }, [cache]); + }, [foldersCache]); useEffect(() => { return autorun(() => { diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts new file mode 100644 index 00000000000..3efd392250f --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts @@ -0,0 +1,31 @@ +import { loadingRepositoryFactory } from "@webiny/app-utils"; +import { IUpdateFolderUseCase } from "./IUpdateFolderUseCase"; +import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; +import { UpdateFolderRepository } from "./UpdateFolderRepository"; +import { UpdateFolderUseCase } from "./UpdateFolderUseCase"; +import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading"; +import { folderCacheFactory } from "~/features/folder"; + +export class UpdateFolder { + static cache: Map = new Map(); + + public static instance(gateway: IUpdateFolderGateway, type: string): IUpdateFolderUseCase { + if (!this.cache.has(type)) { + // Create a new instance if not cached + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new UpdateFolderRepository(foldersCache, gateway); + const useCase = new UpdateFolderUseCase(repository); + const useCaseWithLoading = new UpdateFolderUseCaseWithLoading( + loadingRepository, + useCase + ); + + // Store in cache + this.cache.set(type, useCaseWithLoading); + } + + // Return the cached instance + return this.cache.get(type)!; + } +} diff --git a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts index 59756b5b90b..cbfb8cd081d 100644 --- a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts @@ -1,34 +1,32 @@ -import { useCallback, useMemo } from "react"; +import { useCallback, useContext } from "react"; import { useApolloClient } from "@apollo/react-hooks"; -import { FoldersCache } from "../cache"; import { UpdateFolderGqlGateway } from "./UpdateFolderGqlGateway"; -import { UpdateFolderRepository } from "./UpdateFolderRepository"; -import { LoadingRepository } from "@webiny/app-utils"; -import { UpdateFolderUseCase } from "./UpdateFolderUseCase"; -import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading"; +import { UpdateFolder } from "./UpdateFolder"; import { UpdateFolderParams } from "./IUpdateFolderUseCase"; +import { FoldersContext } from "~/contexts/folders"; -export const useUpdateFolder = (cache: FoldersCache, loading: LoadingRepository) => { +export const useUpdateFolder = () => { const client = useApolloClient(); + const gateway = new UpdateFolderGqlGateway(client); - const gateway = useMemo(() => { - return new UpdateFolderGqlGateway(client); - }, [client]); + const foldersContext = useContext(FoldersContext); - const repository = useMemo(() => { - return new UpdateFolderRepository(cache, gateway); - }, [cache, gateway]); + if (!foldersContext) { + throw new Error("useUpdateFolder must be used within a FoldersProvider"); + } - const useCase = useMemo(() => { - const updateFolderUseCase = new UpdateFolderUseCase(repository); - return new UpdateFolderUseCaseWithLoading(loading, updateFolderUseCase); - }, [repository, loading]); + const { type } = foldersContext; + + if (!type) { + throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); + } const updateFolder = useCallback( (params: UpdateFolderParams) => { - return useCase.execute(params); + const instance = UpdateFolder.instance(gateway, type); + return instance.execute(params); }, - [useCase] + [type, gateway] ); return { diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 920479f8c03..092c34f0a1d 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,8 +1,4 @@ -import { useContext, useMemo } from "react"; -import { loadingRepositoryFactory } from "@webiny/app-utils"; -import { FoldersContext } from "~/contexts/folders"; import { - folderCacheFactory, useCreateFolder, useDeleteFolder, useGetCanManageContent, @@ -15,37 +11,15 @@ import { } from "~/features/folder"; export const useFolders = () => { - const foldersContext = useContext(FoldersContext); - - if (!foldersContext) { - throw new Error("useFolders must be used within a FoldersProvider"); - } - - const { type } = foldersContext; - - if (!type) { - throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); - } - - // Folders cache - const foldersCache = useMemo(() => { - return folderCacheFactory.getCache(type); - }, [type]); - - // Loading repository - const loadingRepository = useMemo(() => { - return loadingRepositoryFactory.getRepository(); - }, [type]); - - const { createFolder } = useCreateFolder(foldersCache, loadingRepository, type); - const { deleteFolder } = useDeleteFolder(foldersCache, loadingRepository); - const { listFolders, folders, loading } = useListFolders(foldersCache, loadingRepository, type); - const { updateFolder } = useUpdateFolder(foldersCache, loadingRepository); - const { getDescendantFolders } = useGetDescendantFolders(foldersCache); - const { getFolder } = useGetFolder(foldersCache, loadingRepository); - const { canManageStructure } = useGetCanManageStructure(foldersCache); - const { canManagePermissions } = useGetCanManagePermissions(foldersCache); - const { canManageContent } = useGetCanManageContent(foldersCache); + const { createFolder } = useCreateFolder(); + const { deleteFolder } = useDeleteFolder(); + const { listFolders, folders, loading } = useListFolders(); + const { updateFolder } = useUpdateFolder(); + const { getDescendantFolders } = useGetDescendantFolders(); + const { getFolder } = useGetFolder(); + const { canManageStructure } = useGetCanManageStructure(); + const { canManagePermissions } = useGetCanManagePermissions(); + const { canManageContent } = useGetCanManageContent(); return { folders, From 22bd6894481cbff911fbabf00b05337e6458cfa9 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Mon, 21 Oct 2024 11:51:57 +0200 Subject: [PATCH 18/28] wip: create instance class --- .../folder/createFolder/CreateFolder.test.ts | 2 +- .../folder/createFolder/CreateFolder.ts | 26 +++++-------------- .../folder/createFolder/useCreateFolder.ts | 2 +- .../folder/deleteFolder/DeleteFolder.ts | 26 +++++-------------- .../folder/deleteFolder/useDeleteFolder.ts | 2 +- .../GetCanManageContent.ts | 18 ++++--------- .../GetCanManagePermissions.ts | 18 ++++--------- .../GetCanManageStructure.ts | 16 ++++-------- .../GetDescendantFolders.ts | 14 +++------- .../features/folder/getFolder/GetFolder.ts | 23 +++++----------- .../features/folder/getFolder/useGetFolder.ts | 2 +- .../folder/listFolders/ListFolders.ts | 2 +- .../folder/listFolders/useListFolders.ts | 2 +- .../folder/updateFolder/UpdateFolder.ts | 26 +++++-------------- .../folder/updateFolder/useUpdateFolder.ts | 2 +- 15 files changed, 49 insertions(+), 132 deletions(-) diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts index dbdaafe6ef4..c18f145450f 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts @@ -43,7 +43,7 @@ describe("CreateFolder", () => { }) }); - const createFolder = CreateFolder.getInstance(gateway, type); + const createFolder = CreateFolder.instance(type, gateway); const createPromise = createFolder.execute( pick(folder1, ["title", "slug", "type", "parentId", "permissions"]) diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts index cf0186f3139..5ca40f5aebf 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts @@ -7,25 +7,11 @@ import { CreateFolderUseCaseWithLoading } from "./CreateFolderUseCaseWithLoading import { folderCacheFactory } from "../cache"; export class CreateFolder { - static cache: Map = new Map(); - - public static instance(gateway: ICreateFolderGateway, type: string): ICreateFolderUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); - const repository = new CreateFolderRepository(foldersCache, gateway, type); - const useCase = new CreateFolderUseCase(repository); - const useCaseWithLoading = new CreateFolderUseCaseWithLoading( - loadingRepository, - useCase - ); - - // Store in cache - this.cache.set(type, useCaseWithLoading); - } - - // Return the cached instance - return this.cache.get(type)!; + public static instance(type: string, gateway: ICreateFolderGateway): ICreateFolderUseCase { + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new CreateFolderRepository(foldersCache, gateway, type); + const useCase = new CreateFolderUseCase(repository); + return new CreateFolderUseCaseWithLoading(loadingRepository, useCase); } } diff --git a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts index 22a1d77b5c9..99193b73097 100644 --- a/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts +++ b/packages/app-aco/src/features/folder/createFolder/useCreateFolder.ts @@ -23,7 +23,7 @@ export const useCreateFolder = () => { const createFolder = useCallback( (params: CreateFolderParams) => { - const instance = CreateFolder.instance(gateway, type); + const instance = CreateFolder.instance(type, gateway); return instance.execute(params); }, [type, gateway] diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts index 15d27f83e79..920d5bcfa87 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts @@ -7,25 +7,11 @@ import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; import { folderCacheFactory } from "../cache"; export class DeleteFolder { - static cache: Map = new Map(); - - public static getInstance(gateway: IDeleteFolderGateway, type: string): IDeleteFolderUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); - const repository = new DeleteFolderRepository(foldersCache, gateway); - const useCase = new DeleteFolderUseCase(repository); - const useCaseWithLoading = new DeleteFolderUseCaseWithLoading( - loadingRepository, - useCase - ); - - // Store in cache - this.cache.set(type, useCaseWithLoading); - } - - // Return the cached instance - return this.cache.get(type)!; + public static instance(type: string, gateway: IDeleteFolderGateway): IDeleteFolderUseCase { + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new DeleteFolderRepository(foldersCache, gateway); + const useCase = new DeleteFolderUseCase(repository); + return new DeleteFolderUseCaseWithLoading(loadingRepository, useCase); } } diff --git a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts index 2a4fd637ec8..5f36f3fb893 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts @@ -23,7 +23,7 @@ export const useDeleteFolder = () => { const deleteFolder = useCallback( (params: DeleteFolderParams) => { - const instance = DeleteFolder.getInstance(gateway, type); + const instance = DeleteFolder.instance(type, gateway); return instance.execute(params); }, [type, gateway] diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts index 3104bb899da..d4e34b8b2eb 100644 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts +++ b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts @@ -5,22 +5,14 @@ import { GetCanManageContentUseCase } from "./GetCanManageContentUseCase"; import { folderCacheFactory } from "../cache"; export class GetCanManageContent { - static cache: Map = new Map(); - public static instance(type: string, canUseFlp: boolean): IGetCanManageContentUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetCanManageContentRepository(foldersCache); - - if (canUseFlp) { - return new GetCanManageContentWithFlpUseCase(repository); - } + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetCanManageContentRepository(foldersCache); - return new GetCanManageContentUseCase(); + if (canUseFlp) { + return new GetCanManageContentWithFlpUseCase(repository); } - // Return the cached instance - return this.cache.get(type)!; + return new GetCanManageContentUseCase(); } } diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts index dc60e49aa1a..83f01f6cc62 100644 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts +++ b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts @@ -5,22 +5,14 @@ import { GetCanManagePermissionsUseCase } from "./GetCanManagePermissionsUseCase import { folderCacheFactory } from "~/features/folder"; export class GetCanManagePermissions { - static cache: Map = new Map(); - public static instance(type: string, canUseFlp: boolean): IGetCanManagePermissionsUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetCanManagePermissionsRepository(foldersCache); - - if (canUseFlp) { - return new GetCanManagePermissionsWithFlpUseCase(repository); - } + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetCanManagePermissionsRepository(foldersCache); - return new GetCanManagePermissionsUseCase(); + if (canUseFlp) { + return new GetCanManagePermissionsWithFlpUseCase(repository); } - // Return the cached instance - return this.cache.get(type)!; + return new GetCanManagePermissionsUseCase(); } } diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts index acde666dd51..2c960032748 100644 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts +++ b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts @@ -8,19 +8,13 @@ export class GetCanManageStructure { static cache: Map = new Map(); public static instance(type: string, canUseFlp: boolean): IGetCanManageStructureUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetCanManageStructureRepository(foldersCache); + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetCanManageStructureRepository(foldersCache); - if (canUseFlp) { - return new GetCanManageStructureWithFlpUseCase(repository); - } - - return new GetCanManageStructureUseCase(); + if (canUseFlp) { + return new GetCanManageStructureWithFlpUseCase(repository); } - // Return the cached instance - return this.cache.get(type)!; + return new GetCanManageStructureUseCase(); } } diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts index 3763cd1d349..ac33309677f 100644 --- a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.ts @@ -4,17 +4,9 @@ import { GetDescendantFoldersUseCase } from "./GetDescendantFoldersUseCase"; import { folderCacheFactory } from "../cache"; export class GetDescendantFolders { - static cache: Map = new Map(); - public static instance(type: string): IGetDescendantFoldersUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetDescendantFoldersRepository(foldersCache); - return new GetDescendantFoldersUseCase(repository); - } - - // Return the cached instance - return this.cache.get(type)!; + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetDescendantFoldersRepository(foldersCache); + return new GetDescendantFoldersUseCase(repository); } } diff --git a/packages/app-aco/src/features/folder/getFolder/GetFolder.ts b/packages/app-aco/src/features/folder/getFolder/GetFolder.ts index 8a13f8fbf5a..e74b7662ab3 100644 --- a/packages/app-aco/src/features/folder/getFolder/GetFolder.ts +++ b/packages/app-aco/src/features/folder/getFolder/GetFolder.ts @@ -7,22 +7,11 @@ import { GetFolderUseCaseWithLoading } from "./GetFolderUseCaseWithLoading"; import { folderCacheFactory } from "../cache"; export class GetFolder { - static cache: Map = new Map(); - - public static instance(gateway: IGetFolderGateway, type: string): IGetFolderUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); - const repository = new GetFolderRepository(foldersCache, gateway); - const useCase = new GetFolderUseCase(repository); - const useCaseWithLoading = new GetFolderUseCaseWithLoading(loadingRepository, useCase); - - // Store in cache - this.cache.set(type, useCaseWithLoading); - } - - // Return the cached instance - return this.cache.get(type)!; + public static instance(type: string, gateway: IGetFolderGateway): IGetFolderUseCase { + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new GetFolderRepository(foldersCache, gateway); + const useCase = new GetFolderUseCase(repository); + return new GetFolderUseCaseWithLoading(loadingRepository, useCase); } } diff --git a/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts b/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts index 2d655537320..c0d606a38e3 100644 --- a/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts +++ b/packages/app-aco/src/features/folder/getFolder/useGetFolder.ts @@ -23,7 +23,7 @@ export const useGetFolder = () => { const getFolder = useCallback( (params: GetFolderParams) => { - const instance = GetFolder.instance(gateway, type); + const instance = GetFolder.instance(type, gateway); return instance.execute(params); }, [type, gateway] diff --git a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts index a0ebf04d1b0..da9003366be 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts @@ -17,7 +17,7 @@ export class ListFolders { static foldersCache: Map = new Map(); static loadingCache: Map = new Map(); - public static instance(gateway: IListFoldersGateway, type: string): IListFoldersInstance { + public static instance(type: string, gateway: IListFoldersGateway): IListFoldersInstance { if (!this.foldersCache.has(type)) { this.foldersCache.set(type, folderCacheFactory.getCache(type)); } diff --git a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts index 33736c33d82..96db86776cf 100644 --- a/packages/app-aco/src/features/folder/listFolders/useListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/useListFolders.ts @@ -38,7 +38,7 @@ export const useListFolders = () => { folders: foldersCache, loading } = useMemo(() => { - return ListFolders.instance(gateway, type); + return ListFolders.instance(type, gateway); }, [type, gateway]); const listFolders = useCallback(() => { diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts index 3efd392250f..731a5563805 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts @@ -7,25 +7,11 @@ import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading import { folderCacheFactory } from "~/features/folder"; export class UpdateFolder { - static cache: Map = new Map(); - - public static instance(gateway: IUpdateFolderGateway, type: string): IUpdateFolderUseCase { - if (!this.cache.has(type)) { - // Create a new instance if not cached - const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); - const repository = new UpdateFolderRepository(foldersCache, gateway); - const useCase = new UpdateFolderUseCase(repository); - const useCaseWithLoading = new UpdateFolderUseCaseWithLoading( - loadingRepository, - useCase - ); - - // Store in cache - this.cache.set(type, useCaseWithLoading); - } - - // Return the cached instance - return this.cache.get(type)!; + public static instance(type: string, gateway: IUpdateFolderGateway): IUpdateFolderUseCase { + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(); + const repository = new UpdateFolderRepository(foldersCache, gateway); + const useCase = new UpdateFolderUseCase(repository); + return new UpdateFolderUseCaseWithLoading(loadingRepository, useCase); } } diff --git a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts index cbfb8cd081d..962d04a0d69 100644 --- a/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/useUpdateFolder.ts @@ -23,7 +23,7 @@ export const useUpdateFolder = () => { const updateFolder = useCallback( (params: UpdateFolderParams) => { - const instance = UpdateFolder.instance(gateway, type); + const instance = UpdateFolder.instance(type, gateway); return instance.execute(params); }, [type, gateway] From 1b8b210051ee148d93c64fd252a0f2e3b6ae4a91 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Mon, 21 Oct 2024 13:43:56 +0200 Subject: [PATCH 19/28] refactor: introduce GetFolderLevelPermission feature --- .../CreateFolder.test.ts => Folder.test.ts} | 18 +++++------ .../GetCanManagePermissions.ts | 18 ----------- .../GetCanManagePermissionsRepository.ts | 20 ------------ .../GetCanManagePermissionsUseCase.ts | 7 ---- .../GetCanManagePermissionsWithFlpUseCase.ts | 14 -------- .../IGetCanManagePermissionsRepository.ts | 3 -- .../IGetCanManagePermissionsUseCase.ts | 3 -- .../folder/getCanManagePermissions/index.ts | 1 - .../useGetCanManagePermissions.ts | 32 ------------------- .../GetCanManageStructure.ts | 20 ------------ .../GetCanManageStructureRepository.ts | 20 ------------ .../GetCanManageStructureUseCase.ts | 7 ---- .../GetCanManageStructureWithFlpUseCase.ts | 14 -------- .../IGetCanManageStructureRepository.ts | 3 -- .../IGetCanManageStructureUseCase.ts | 3 -- .../folder/getCanManageStructure/index.ts | 1 - .../useGetCanManageStructure.ts | 32 ------------------- .../FolderPermissionName.ts | 4 +++ .../useGetFolderLevelPermission.ts} | 15 ++++++--- packages/app-aco/src/features/folder/index.ts | 6 ++-- packages/app-aco/src/hooks/useFolders.ts | 13 ++++---- 21 files changed, 32 insertions(+), 222 deletions(-) rename packages/app-aco/src/features/folder/{createFolder/CreateFolder.test.ts => Folder.test.ts} (88%) delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/index.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/index.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/FolderPermissionName.ts rename packages/app-aco/src/features/folder/{getCanManageContent/useGetCanManageContent.ts => getFolderLevelPermission/useGetFolderLevelPermission.ts} (58%) diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts b/packages/app-aco/src/features/folder/Folder.test.ts similarity index 88% rename from packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts rename to packages/app-aco/src/features/folder/Folder.test.ts index c18f145450f..2619ca735f0 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts +++ b/packages/app-aco/src/features/folder/Folder.test.ts @@ -1,12 +1,8 @@ -import { ICreateFolderGateway } from "~/features/folder/createFolder/ICreateFolderGateway"; -import { FolderGqlDto } from "~/features/folder/createFolder/FolderGqlDto"; -import { CmsIdentity } from "~/types"; import pick from "lodash/pick"; -import { CreateFolder } from "./CreateFolder"; - -const createFolderGateway = ({ execute }: ICreateFolderGateway): ICreateFolderGateway => ({ - execute -}); +import { CmsIdentity } from "@webiny/app-headless-cms-common/types"; +import { FolderGqlDto } from "~/features/folder/createFolder/FolderGqlDto"; +import { ICreateFolderGateway } from "~/features/folder/createFolder/ICreateFolderGateway"; +import { CreateFolder } from "~/features/folder/createFolder/CreateFolder"; const user1: CmsIdentity = { id: "user-1", @@ -35,7 +31,11 @@ const folder1: FolderGqlDto = { modifiedOn: null }; -describe("CreateFolder", () => { +const createFolderGateway = ({ execute }: ICreateFolderGateway): ICreateFolderGateway => ({ + execute +}); + +describe("Folder features", () => { it("should be able to create a folder", async () => { const gateway = createFolderGateway({ execute: jest.fn().mockImplementation(() => { diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts deleted file mode 100644 index 83f01f6cc62..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissions.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; -import { GetCanManagePermissionsRepository } from "./GetCanManagePermissionsRepository"; -import { GetCanManagePermissionsWithFlpUseCase } from "./GetCanManagePermissionsWithFlpUseCase"; -import { GetCanManagePermissionsUseCase } from "./GetCanManagePermissionsUseCase"; -import { folderCacheFactory } from "~/features/folder"; - -export class GetCanManagePermissions { - public static instance(type: string, canUseFlp: boolean): IGetCanManagePermissionsUseCase { - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetCanManagePermissionsRepository(foldersCache); - - if (canUseFlp) { - return new GetCanManagePermissionsWithFlpUseCase(repository); - } - - return new GetCanManagePermissionsUseCase(); - } -} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts deleted file mode 100644 index 6fb7a160aeb..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsRepository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FoldersCache } from "../cache"; -import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRepository"; - -export class GetCanManagePermissionsRepository implements IGetCanManagePermissionsRepository { - private cache: FoldersCache; - - constructor(cache: FoldersCache) { - this.cache = cache; - } - - execute(id: string) { - const folder = this.cache.getItem(id); - - if (!folder) { - return false; - } - - return folder.canManagePermissions ?? false; - } -} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts deleted file mode 100644 index 38cd627d143..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsUseCase.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; - -export class GetCanManagePermissionsUseCase implements IGetCanManagePermissionsUseCase { - execute() { - return true; - } -} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts deleted file mode 100644 index ba34911471e..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/GetCanManagePermissionsWithFlpUseCase.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IGetCanManagePermissionsUseCase } from "./IGetCanManagePermissionsUseCase"; -import { IGetCanManagePermissionsRepository } from "./IGetCanManagePermissionsRepository"; - -export class GetCanManagePermissionsWithFlpUseCase implements IGetCanManagePermissionsUseCase { - private repository: IGetCanManagePermissionsRepository; - - constructor(repository: IGetCanManagePermissionsRepository) { - this.repository = repository; - } - - execute(id: string) { - return this.repository.execute(id); - } -} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts deleted file mode 100644 index a158522c9a1..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsRepository.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetCanManagePermissionsRepository { - execute: (id: string) => boolean; -} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts deleted file mode 100644 index 735a3424afc..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/IGetCanManagePermissionsUseCase.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetCanManagePermissionsUseCase { - execute: (id: string) => boolean; -} diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/index.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/index.ts deleted file mode 100644 index 1886a775b37..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./useGetCanManagePermissions"; diff --git a/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts b/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts deleted file mode 100644 index a984d616c22..00000000000 --- a/packages/app-aco/src/features/folder/getCanManagePermissions/useGetCanManagePermissions.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useCallback, useContext } from "react"; -import { useWcp } from "@webiny/app-wcp"; -import { FoldersContext } from "~/contexts/folders"; -import { GetCanManagePermissions } from "./GetCanManagePermissions"; - -export const useGetCanManagePermissions = () => { - const { canUseFolderLevelPermissions } = useWcp(); - - const foldersContext = useContext(FoldersContext); - - if (!foldersContext) { - throw new Error("useGetCanManagePermissions must be used within a FoldersProvider"); - } - - const { type } = foldersContext; - - if (!type) { - throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); - } - - const canManagePermissions = useCallback( - (id: string) => { - const instance = GetCanManagePermissions.instance(type, canUseFolderLevelPermissions()); - return instance.execute(id); - }, - [type, canUseFolderLevelPermissions] - ); - - return { - canManagePermissions - }; -}; diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts deleted file mode 100644 index 2c960032748..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructure.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; -import { GetCanManageStructureRepository } from "./GetCanManageStructureRepository"; -import { GetCanManageStructureWithFlpUseCase } from "./GetCanManageStructureWithFlpUseCase"; -import { GetCanManageStructureUseCase } from "./GetCanManageStructureUseCase"; -import { folderCacheFactory } from "../cache"; - -export class GetCanManageStructure { - static cache: Map = new Map(); - - public static instance(type: string, canUseFlp: boolean): IGetCanManageStructureUseCase { - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetCanManageStructureRepository(foldersCache); - - if (canUseFlp) { - return new GetCanManageStructureWithFlpUseCase(repository); - } - - return new GetCanManageStructureUseCase(); - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts deleted file mode 100644 index bc92f12c0cd..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureRepository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FoldersCache } from "../cache"; -import { IGetCanManageStructureRepository } from "./IGetCanManageStructureRepository"; - -export class GetCanManageStructureRepository implements IGetCanManageStructureRepository { - private cache: FoldersCache; - - constructor(cache: FoldersCache) { - this.cache = cache; - } - - execute(id: string) { - const folder = this.cache.getItem(id); - - if (!folder) { - return false; - } - - return folder.canManageStructure ?? false; - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts deleted file mode 100644 index 70cc57cdf64..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureUseCase.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; - -export class GetCanManageStructureUseCase implements IGetCanManageStructureUseCase { - execute() { - return true; - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts deleted file mode 100644 index 1e4dc63aa00..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/GetCanManageStructureWithFlpUseCase.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IGetCanManageStructureUseCase } from "./IGetCanManageStructureUseCase"; -import { IGetCanManageStructureRepository } from "./IGetCanManageStructureRepository"; - -export class GetCanManageStructureWithFlpUseCase implements IGetCanManageStructureUseCase { - private repository: IGetCanManageStructureRepository; - - constructor(repository: IGetCanManageStructureRepository) { - this.repository = repository; - } - - execute(id: string) { - return this.repository.execute(id); - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts b/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts deleted file mode 100644 index dd792ff2d85..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureRepository.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetCanManageStructureRepository { - execute: (id: string) => boolean; -} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts b/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts deleted file mode 100644 index 6d49f9c4048..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/IGetCanManageStructureUseCase.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetCanManageStructureUseCase { - execute: (id: string) => boolean; -} diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/index.ts b/packages/app-aco/src/features/folder/getCanManageStructure/index.ts deleted file mode 100644 index 7223c9c3e60..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./useGetCanManageStructure"; diff --git a/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts b/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts deleted file mode 100644 index eba471678a0..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageStructure/useGetCanManageStructure.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useCallback, useContext } from "react"; -import { useWcp } from "@webiny/app-wcp"; -import { FoldersContext } from "~/contexts/folders"; -import { GetCanManageStructure } from "./GetCanManageStructure"; - -export const useGetCanManageStructure = () => { - const { canUseFolderLevelPermissions } = useWcp(); - - const foldersContext = useContext(FoldersContext); - - if (!foldersContext) { - throw new Error("useGetCanManageContent must be used within a FoldersProvider"); - } - - const { type } = foldersContext; - - if (!type) { - throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); - } - - const canManageStructure = useCallback( - (id: string) => { - const instance = GetCanManageStructure.instance(type, canUseFolderLevelPermissions()); - return instance.execute(id); - }, - [type, canUseFolderLevelPermissions] - ); - - return { - canManageStructure - }; -}; diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/FolderPermissionName.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/FolderPermissionName.ts new file mode 100644 index 00000000000..a9483befe9b --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/FolderPermissionName.ts @@ -0,0 +1,4 @@ +export type FolderPermissionName = + | "canManagePermissions" + | "canManageStructure" + | "canManageContent"; diff --git a/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts similarity index 58% rename from packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts rename to packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts index 84e269cf29a..092aa8bf524 100644 --- a/packages/app-aco/src/features/folder/getCanManageContent/useGetCanManageContent.ts +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts @@ -1,9 +1,10 @@ import { useCallback, useContext } from "react"; import { useWcp } from "@webiny/app-wcp"; import { FoldersContext } from "~/contexts/folders"; -import { GetCanManageContent } from "./GetCanManageContent"; +import { GetFolderLevelPermission } from "./GetFolderLevelPermission"; +import { FolderPermissionName } from "./FolderPermissionName"; -export const useGetCanManageContent = () => { +export const useGetFolderLevelPermission = (permissionName: FolderPermissionName) => { const { canUseFolderLevelPermissions } = useWcp(); const foldersContext = useContext(FoldersContext); @@ -18,15 +19,19 @@ export const useGetCanManageContent = () => { throw Error(`FoldersProvider requires a "type" prop or an AcoAppContext to be available!`); } - const canManageContent = useCallback( + const getFolderLevelPermission = useCallback( (id: string) => { - const instance = GetCanManageContent.instance(type, canUseFolderLevelPermissions()); + const instance = GetFolderLevelPermission.instance( + type, + permissionName, + canUseFolderLevelPermissions() + ); return instance.execute(id); }, [type, canUseFolderLevelPermissions] ); return { - canManageContent + getFolderLevelPermission }; }; diff --git a/packages/app-aco/src/features/folder/index.ts b/packages/app-aco/src/features/folder/index.ts index 9605ca1e3e5..fc6678906ca 100644 --- a/packages/app-aco/src/features/folder/index.ts +++ b/packages/app-aco/src/features/folder/index.ts @@ -1,11 +1,9 @@ +export * from "./Folder"; export * from "./cache"; export * from "./createFolder"; export * from "./deleteFolder"; -export * from "./getCanManageStructure"; -export * from "./getCanManagePermissions"; -export * from "./getCanManageContent"; export * from "./getDescendantFolders"; export * from "./getFolder"; +export * from "./getFolderLevelPermission"; export * from "./listFolders"; export * from "./updateFolder"; -export * from "./Folder"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 092c34f0a1d..1a0a6c7e9ee 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -1,11 +1,9 @@ import { useCreateFolder, useDeleteFolder, - useGetCanManageContent, - useGetCanManagePermissions, - useGetCanManageStructure, useGetDescendantFolders, useGetFolder, + useGetFolderLevelPermission, useListFolders, useUpdateFolder } from "~/features/folder"; @@ -17,9 +15,12 @@ export const useFolders = () => { const { updateFolder } = useUpdateFolder(); const { getDescendantFolders } = useGetDescendantFolders(); const { getFolder } = useGetFolder(); - const { canManageStructure } = useGetCanManageStructure(); - const { canManagePermissions } = useGetCanManagePermissions(); - const { canManageContent } = useGetCanManageContent(); + const { getFolderLevelPermission: canManageStructure } = + useGetFolderLevelPermission("canManageStructure"); + const { getFolderLevelPermission: canManagePermissions } = + useGetFolderLevelPermission("canManagePermissions"); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); return { folders, From 0c5b524c2313bfa0c2aec7b017d1c2bcb10d3f31 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Mon, 21 Oct 2024 13:51:28 +0200 Subject: [PATCH 20/28] refactor: introduce GetFolderLevelPermission feature --- .../GetCanManageContent.ts | 18 --------------- .../GetCanManageContentRepository.ts | 20 ---------------- .../GetCanManageContentUseCase.ts | 7 ------ .../GetCanManageContentWithFlpUseCase.ts | 14 ----------- .../IGetCanManageContentRepository.ts | 3 --- .../IGetCanManageContentUseCase.ts | 3 --- .../folder/getCanManageContent/index.ts | 1 - .../GetFolderLevelPermission.ts | 23 +++++++++++++++++++ .../GetFolderLevelPermissionRepository.ts | 23 +++++++++++++++++++ .../GetFolderLevelPermissionUseCase.ts | 7 ++++++ .../GetFolderLevelPermissionWithFlpUseCase.ts | 14 +++++++++++ .../IGetFolderLevelPermissionRepository.ts | 3 +++ .../IGetFolderLevelPermissionUseCase.ts | 3 +++ .../folder/getFolderLevelPermission/index.ts | 1 + 14 files changed, 74 insertions(+), 66 deletions(-) delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts delete mode 100644 packages/app-aco/src/features/folder/getCanManageContent/index.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionRepository.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/index.ts diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts deleted file mode 100644 index d4e34b8b2eb..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContent.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; -import { GetCanManageContentRepository } from "./GetCanManageContentRepository"; -import { GetCanManageContentWithFlpUseCase } from "./GetCanManageContentWithFlpUseCase"; -import { GetCanManageContentUseCase } from "./GetCanManageContentUseCase"; -import { folderCacheFactory } from "../cache"; - -export class GetCanManageContent { - public static instance(type: string, canUseFlp: boolean): IGetCanManageContentUseCase { - const foldersCache = folderCacheFactory.getCache(type); - const repository = new GetCanManageContentRepository(foldersCache); - - if (canUseFlp) { - return new GetCanManageContentWithFlpUseCase(repository); - } - - return new GetCanManageContentUseCase(); - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts deleted file mode 100644 index 94ca30ce47b..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentRepository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FoldersCache } from "../cache"; -import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository"; - -export class GetCanManageContentRepository implements IGetCanManageContentRepository { - private cache: FoldersCache; - - constructor(cache: FoldersCache) { - this.cache = cache; - } - - execute(id: string) { - const folder = this.cache.getItem(id); - - if (!folder) { - return false; - } - - return folder.canManageContent ?? false; - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts deleted file mode 100644 index 877e72e8510..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentUseCase.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; - -export class GetCanManageContentUseCase implements IGetCanManageContentUseCase { - execute() { - return true; - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts deleted file mode 100644 index ad9a0ed4176..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/GetCanManageContentWithFlpUseCase.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IGetCanManageContentUseCase } from "./IGetCanManageContentUseCase"; -import { IGetCanManageContentRepository } from "./IGetCanManageContentRepository"; - -export class GetCanManageContentWithFlpUseCase implements IGetCanManageContentUseCase { - private repository: IGetCanManageContentRepository; - - constructor(repository: IGetCanManageContentRepository) { - this.repository = repository; - } - - execute(id: string) { - return this.repository.execute(id); - } -} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts b/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts deleted file mode 100644 index 54752ef9362..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentRepository.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetCanManageContentRepository { - execute: (id: string) => boolean; -} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts b/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts deleted file mode 100644 index 79228e7b053..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/IGetCanManageContentUseCase.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IGetCanManageContentUseCase { - execute: (id: string) => boolean; -} diff --git a/packages/app-aco/src/features/folder/getCanManageContent/index.ts b/packages/app-aco/src/features/folder/getCanManageContent/index.ts deleted file mode 100644 index 17ccf4b067a..00000000000 --- a/packages/app-aco/src/features/folder/getCanManageContent/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./useGetCanManageContent"; diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.ts new file mode 100644 index 00000000000..eb7d50c208d --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.ts @@ -0,0 +1,23 @@ +import { IGetFolderLevelPermissionUseCase } from "./IGetFolderLevelPermissionUseCase"; +import { GetFolderLevelPermissionRepository } from "./GetFolderLevelPermissionRepository"; +import { GetFolderLevelPermissionWithFlpUseCase } from "./GetFolderLevelPermissionWithFlpUseCase"; +import { GetFolderLevelPermissionUseCase } from "./GetFolderLevelPermissionUseCase"; +import { FolderPermissionName } from "./FolderPermissionName"; +import { folderCacheFactory } from "../cache"; + +export class GetFolderLevelPermission { + public static instance( + type: string, + permissionName: FolderPermissionName, + canUseFlp: boolean + ): IGetFolderLevelPermissionUseCase { + const foldersCache = folderCacheFactory.getCache(type); + const repository = new GetFolderLevelPermissionRepository(foldersCache, permissionName); + + if (canUseFlp) { + return new GetFolderLevelPermissionWithFlpUseCase(repository); + } + + return new GetFolderLevelPermissionUseCase(); + } +} diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts new file mode 100644 index 00000000000..e140985f6e1 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts @@ -0,0 +1,23 @@ +import { FoldersCache } from "../cache"; +import { IGetFolderLevelPermissionRepository } from "./IGetFolderLevelPermissionRepository"; +import { FolderPermissionName } from "./FolderPermissionName"; + +export class GetFolderLevelPermissionRepository implements IGetFolderLevelPermissionRepository { + private cache: FoldersCache; + private permissionName: FolderPermissionName; + + constructor(cache: FoldersCache, permissionName: FolderPermissionName) { + this.cache = cache; + this.permissionName = permissionName; + } + + execute(id: string) { + const folder = this.cache.getItem(id); + + if (!folder) { + return false; + } + + return folder[this.permissionName] ?? false; + } +} diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionUseCase.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionUseCase.ts new file mode 100644 index 00000000000..982a2d1a442 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionUseCase.ts @@ -0,0 +1,7 @@ +import { IGetFolderLevelPermissionUseCase } from "./IGetFolderLevelPermissionUseCase"; + +export class GetFolderLevelPermissionUseCase implements IGetFolderLevelPermissionUseCase { + execute() { + return true; + } +} diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts new file mode 100644 index 00000000000..0479cfbbd37 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts @@ -0,0 +1,14 @@ +import { IGetFolderLevelPermissionUseCase } from "./IGetFolderLevelPermissionUseCase"; +import { IGetFolderLevelPermissionRepository } from "./IGetFolderLevelPermissionRepository"; + +export class GetFolderLevelPermissionWithFlpUseCase implements IGetFolderLevelPermissionUseCase { + private repository: IGetFolderLevelPermissionRepository; + + constructor(repository: IGetFolderLevelPermissionRepository) { + this.repository = repository; + } + + execute(id: string) { + return this.repository.execute(id); + } +} diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionRepository.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionRepository.ts new file mode 100644 index 00000000000..69585a37ed3 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionRepository.ts @@ -0,0 +1,3 @@ +export interface IGetFolderLevelPermissionRepository { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts new file mode 100644 index 00000000000..9ae5dd13cc8 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts @@ -0,0 +1,3 @@ +export interface IGetFolderLevelPermissionUseCase { + execute: (id: string) => boolean; +} diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/index.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/index.ts new file mode 100644 index 00000000000..ad2572bc388 --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/index.ts @@ -0,0 +1 @@ +export * from "./useGetFolderLevelPermission"; From 603aa5e100e654037ae3d898b3e4ef5b084b9b31 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Mon, 21 Oct 2024 14:19:28 +0200 Subject: [PATCH 21/28] refactor: add loading namespace --- .../folder/createFolder/CreateFolder.ts | 2 +- .../folder/deleteFolder/DeleteFolder.ts | 2 +- .../features/folder/getFolder/GetFolder.ts | 2 +- .../folder/listFolders/ListFolders.ts | 38 ++++--------------- .../folder/updateFolder/UpdateFolder.ts | 2 +- .../Loading/LoadingRepositoryFactory.ts | 8 ++-- 6 files changed, 16 insertions(+), 38 deletions(-) diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts index 5ca40f5aebf..1182098d6d4 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolder.ts @@ -9,7 +9,7 @@ import { folderCacheFactory } from "../cache"; export class CreateFolder { public static instance(type: string, gateway: ICreateFolderGateway): ICreateFolderUseCase { const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); + const loadingRepository = loadingRepositoryFactory.getRepository(type); const repository = new CreateFolderRepository(foldersCache, gateway, type); const useCase = new CreateFolderUseCase(repository); return new CreateFolderUseCaseWithLoading(loadingRepository, useCase); diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts index 920d5bcfa87..41aebf02144 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.ts @@ -9,7 +9,7 @@ import { folderCacheFactory } from "../cache"; export class DeleteFolder { public static instance(type: string, gateway: IDeleteFolderGateway): IDeleteFolderUseCase { const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); + const loadingRepository = loadingRepositoryFactory.getRepository(type); const repository = new DeleteFolderRepository(foldersCache, gateway); const useCase = new DeleteFolderUseCase(repository); return new DeleteFolderUseCaseWithLoading(loadingRepository, useCase); diff --git a/packages/app-aco/src/features/folder/getFolder/GetFolder.ts b/packages/app-aco/src/features/folder/getFolder/GetFolder.ts index e74b7662ab3..ef82ff0841f 100644 --- a/packages/app-aco/src/features/folder/getFolder/GetFolder.ts +++ b/packages/app-aco/src/features/folder/getFolder/GetFolder.ts @@ -9,7 +9,7 @@ import { folderCacheFactory } from "../cache"; export class GetFolder { public static instance(type: string, gateway: IGetFolderGateway): IGetFolderUseCase { const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); + const loadingRepository = loadingRepositoryFactory.getRepository(type); const repository = new GetFolderRepository(foldersCache, gateway); const useCase = new GetFolderUseCase(repository); return new GetFolderUseCaseWithLoading(loadingRepository, useCase); diff --git a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts index da9003366be..71f8153e290 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts @@ -13,39 +13,17 @@ interface IListFoldersInstance { } export class ListFolders { - static useCaseCache: Map = new Map(); - static foldersCache: Map = new Map(); - static loadingCache: Map = new Map(); - public static instance(type: string, gateway: IListFoldersGateway): IListFoldersInstance { - if (!this.foldersCache.has(type)) { - this.foldersCache.set(type, folderCacheFactory.getCache(type)); - } - - if (!this.loadingCache.has(type)) { - this.loadingCache.set(type, loadingRepositoryFactory.getRepository()); - } - - if (!this.useCaseCache.has(type)) { - // Create a new instance if not cached - const foldersCache = this.foldersCache.get(type)!; - const loadingRepository = this.loadingCache.get(type)!; - const repository = new ListFoldersRepository(foldersCache, gateway, type); - const useCase = new ListFoldersUseCase(repository); - const useCaseWithLoading = new ListFoldersUseCaseWithLoading( - loadingRepository, - useCase - ); - - // Store in cache - this.useCaseCache.set(type, useCaseWithLoading); - } + const foldersCache = folderCacheFactory.getCache(type); + const loadingRepository = loadingRepositoryFactory.getRepository(type); + const repository = new ListFoldersRepository(foldersCache, gateway, type); + const useCase = new ListFoldersUseCase(repository); + const useCaseWithLoading = new ListFoldersUseCaseWithLoading(loadingRepository, useCase); - // Return the cached instance return { - useCase: this.useCaseCache.get(type)!, - folders: this.foldersCache.get(type)!, - loading: this.loadingCache.get(type)! + useCase: useCaseWithLoading, + folders: foldersCache, + loading: loadingRepository }; } } diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts index 731a5563805..294eee74b15 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts @@ -9,7 +9,7 @@ import { folderCacheFactory } from "~/features/folder"; export class UpdateFolder { public static instance(type: string, gateway: IUpdateFolderGateway): IUpdateFolderUseCase { const foldersCache = folderCacheFactory.getCache(type); - const loadingRepository = loadingRepositoryFactory.getRepository(); + const loadingRepository = loadingRepositoryFactory.getRepository(type); const repository = new UpdateFolderRepository(foldersCache, gateway); const useCase = new UpdateFolderUseCase(repository); return new UpdateFolderUseCaseWithLoading(loadingRepository, useCase); diff --git a/packages/app-utils/src/fta/Domain/Repositories/Loading/LoadingRepositoryFactory.ts b/packages/app-utils/src/fta/Domain/Repositories/Loading/LoadingRepositoryFactory.ts index e761c3768ae..de631f0bb14 100644 --- a/packages/app-utils/src/fta/Domain/Repositories/Loading/LoadingRepositoryFactory.ts +++ b/packages/app-utils/src/fta/Domain/Repositories/Loading/LoadingRepositoryFactory.ts @@ -3,8 +3,8 @@ import { LoadingRepository } from "./LoadingRepository"; export class LoadingRepositoryFactory { private cache: Map = new Map(); - getRepository() { - const cacheKey = this.getCacheKey(); + getRepository(namespace?: string) { + const cacheKey = this.getCacheKey(namespace); if (!this.cache.has(cacheKey)) { this.cache.set(cacheKey, new LoadingRepository()); @@ -13,8 +13,8 @@ export class LoadingRepositoryFactory { return this.cache.get(cacheKey) as LoadingRepository; } - private getCacheKey() { - return Date.now().toString(); + private getCacheKey(namespace?: string) { + return namespace ?? Date.now().toString(); } } From 22c5c9cdadd9327688b2eec0e11ec8c46fb4a662 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Mon, 21 Oct 2024 15:52:14 +0200 Subject: [PATCH 22/28] chore: run adio --- packages/app-serverless-cms/package.json | 1 - packages/app-serverless-cms/tsconfig.build.json | 1 - packages/app-serverless-cms/tsconfig.json | 3 --- yarn.lock | 1 - 4 files changed, 6 deletions(-) diff --git a/packages/app-serverless-cms/package.json b/packages/app-serverless-cms/package.json index aa229371b54..b2a4f323cc4 100644 --- a/packages/app-serverless-cms/package.json +++ b/packages/app-serverless-cms/package.json @@ -11,7 +11,6 @@ "dependencies": { "@emotion/react": "^11.10.6", "@webiny/app": "0.0.0", - "@webiny/app-aco": "0.0.0", "@webiny/app-admin": "0.0.0", "@webiny/app-admin-rmwc": "0.0.0", "@webiny/app-apw": "0.0.0", diff --git a/packages/app-serverless-cms/tsconfig.build.json b/packages/app-serverless-cms/tsconfig.build.json index 804755f3d06..7901e5895b5 100644 --- a/packages/app-serverless-cms/tsconfig.build.json +++ b/packages/app-serverless-cms/tsconfig.build.json @@ -3,7 +3,6 @@ "include": ["src"], "references": [ { "path": "../app/tsconfig.build.json" }, - { "path": "../app-aco/tsconfig.build.json" }, { "path": "../app-admin/tsconfig.build.json" }, { "path": "../app-admin-rmwc/tsconfig.build.json" }, { "path": "../app-apw/tsconfig.build.json" }, diff --git a/packages/app-serverless-cms/tsconfig.json b/packages/app-serverless-cms/tsconfig.json index ac59a189557..46906b9d9f9 100644 --- a/packages/app-serverless-cms/tsconfig.json +++ b/packages/app-serverless-cms/tsconfig.json @@ -3,7 +3,6 @@ "include": ["src", "__tests__"], "references": [ { "path": "../app" }, - { "path": "../app-aco" }, { "path": "../app-admin" }, { "path": "../app-admin-rmwc" }, { "path": "../app-apw" }, @@ -37,8 +36,6 @@ "~tests/*": ["./__tests__/*"], "@webiny/app/*": ["../app/src/*"], "@webiny/app": ["../app/src"], - "@webiny/app-aco/*": ["../app-aco/src/*"], - "@webiny/app-aco": ["../app-aco/src"], "@webiny/app-admin/*": ["../app-admin/src/*"], "@webiny/app-admin": ["../app-admin/src"], "@webiny/app-admin-rmwc/*": ["../app-admin-rmwc/src/*"], diff --git a/yarn.lock b/yarn.lock index f88a476385b..d2a8e98a3f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15975,7 +15975,6 @@ __metadata: "@emotion/babel-plugin": ^11.11.0 "@emotion/react": ^11.10.6 "@webiny/app": 0.0.0 - "@webiny/app-aco": 0.0.0 "@webiny/app-admin": 0.0.0 "@webiny/app-admin-rmwc": 0.0.0 "@webiny/app-apw": 0.0.0 From 7e638362aac07f063ac4066726d0b0751a82f018 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 9 Jan 2025 16:41:58 +0100 Subject: [PATCH 23/28] refactor: replace FolderCache with generic ListCache --- .../src/features/folder/cache/FoldersCache.ts | 47 ------------ .../folder/cache/FoldersCacheFactory.ts | 9 ++- .../src/features/folder/cache/ICache.ts | 9 --- .../src/features/folder/cache/ListCache.ts | 74 +++++++++++++++++++ .../src/features/folder/cache/index.ts | 3 +- .../createFolder/CreateFolderRepository.ts | 10 +-- .../deleteFolder/DeleteFolderRepository.ts | 8 +- .../GetDescendantFoldersRepository.ts | 6 +- .../folder/getFolder/GetFolderRepository.ts | 8 +- .../GetFolderLevelPermissionRepository.ts | 11 +-- .../folder/listFolders/ListFolders.ts | 5 +- .../listFolders/ListFoldersRepository.ts | 9 ++- .../updateFolder/UpdateFolderRepository.ts | 14 +++- 13 files changed, 120 insertions(+), 93 deletions(-) delete mode 100644 packages/app-aco/src/features/folder/cache/FoldersCache.ts delete mode 100644 packages/app-aco/src/features/folder/cache/ICache.ts create mode 100644 packages/app-aco/src/features/folder/cache/ListCache.ts diff --git a/packages/app-aco/src/features/folder/cache/FoldersCache.ts b/packages/app-aco/src/features/folder/cache/FoldersCache.ts deleted file mode 100644 index b0cc7da79f9..00000000000 --- a/packages/app-aco/src/features/folder/cache/FoldersCache.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { makeAutoObservable } from "mobx"; -import { ICache } from "./ICache"; -import { Folder } from "../Folder"; - -export class FoldersCache implements ICache { - private folders: Folder[]; - - constructor() { - this.folders = []; - makeAutoObservable(this); - } - - hasItems() { - return this.folders.length > 0; - } - - getItems() { - return this.folders; - } - - getItem(id: string) { - return this.folders.find(f => f.id === id); - } - - async set(item: Folder): Promise { - this.folders.push(item); - } - - async setMultiple(items: Folder[]): Promise { - this.folders = items; - } - - async update(id: string, item: Folder): Promise { - const folderIndex = this.folders.findIndex(f => f.id === id); - - if (folderIndex > -1) { - this.folders[folderIndex] = { - ...this.folders[folderIndex], - ...item - }; - } - } - - async remove(id: string): Promise { - this.folders = this.folders.filter(folder => folder.id !== id); - } -} diff --git a/packages/app-aco/src/features/folder/cache/FoldersCacheFactory.ts b/packages/app-aco/src/features/folder/cache/FoldersCacheFactory.ts index dfda95e49df..581b8e67790 100644 --- a/packages/app-aco/src/features/folder/cache/FoldersCacheFactory.ts +++ b/packages/app-aco/src/features/folder/cache/FoldersCacheFactory.ts @@ -1,16 +1,17 @@ -import { FoldersCache } from "./FoldersCache"; +import { Folder } from "../Folder"; +import { ListCache } from "~/features/folder/cache/ListCache"; export class FoldersCacheFactory { - private cache: Map = new Map(); + private cache: Map> = new Map(); getCache(namespace: string) { const cacheKey = this.getCacheKey(namespace); if (!this.cache.has(cacheKey)) { - this.cache.set(cacheKey, new FoldersCache()); + this.cache.set(cacheKey, new ListCache()); } - return this.cache.get(cacheKey) as FoldersCache; + return this.cache.get(cacheKey) as ListCache; } private getCacheKey(namespace: string) { diff --git a/packages/app-aco/src/features/folder/cache/ICache.ts b/packages/app-aco/src/features/folder/cache/ICache.ts deleted file mode 100644 index 5818456bfe5..00000000000 --- a/packages/app-aco/src/features/folder/cache/ICache.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface ICache { - hasItems: () => boolean; - getItems: () => TItem[]; - getItem: (id: string) => TItem | undefined; - set: (item: TItem) => Promise; - setMultiple: (items: TItem[]) => Promise; - update: (id: string, item: TItem) => Promise; - remove: (id: string) => Promise; -} diff --git a/packages/app-aco/src/features/folder/cache/ListCache.ts b/packages/app-aco/src/features/folder/cache/ListCache.ts new file mode 100644 index 00000000000..b45475794cb --- /dev/null +++ b/packages/app-aco/src/features/folder/cache/ListCache.ts @@ -0,0 +1,74 @@ +import { makeAutoObservable, runInAction, toJS } from "mobx"; + +export type Constructor = new (...args: any[]) => T; + +export interface IListCachePredicate { + (item: T): boolean; +} + +export interface IListCacheItemUpdater { + (item: T): T; +} + +export interface IListCache { + count(): number; + clear(): void; + hasItems(): boolean; + getItems(): T[]; + getItem(predicate: IListCachePredicate): T | undefined; + addItems(items: T[]): void; + updateItems(updater: IListCacheItemUpdater): void; + removeItems(predicate: IListCachePredicate): void; +} + +export class ListCache implements IListCache { + private state: T[]; + + constructor() { + this.state = []; + + makeAutoObservable(this); + } + + count() { + return this.state.length; + } + + clear() { + runInAction(() => { + this.state = []; + }); + } + + hasItems() { + return this.state.length > 0; + } + + getItems() { + return [...this.state.map(item => toJS(item))]; + } + + getItem(predicate: IListCachePredicate): T | undefined { + const item = this.state.find(item => predicate(item)); + + return item ? toJS(item) : undefined; + } + + addItems(items: T[]) { + runInAction(() => { + this.state = [...this.state, ...items]; + }); + } + + updateItems(updater: IListCacheItemUpdater) { + runInAction(() => { + this.state = [...this.state.map(item => updater(item))]; + }); + } + + removeItems(predicate: IListCachePredicate) { + runInAction(() => { + this.state = this.state.filter(item => !predicate(item)); + }); + } +} diff --git a/packages/app-aco/src/features/folder/cache/index.ts b/packages/app-aco/src/features/folder/cache/index.ts index bc66ba6e954..ecb9ffa44c9 100644 --- a/packages/app-aco/src/features/folder/cache/index.ts +++ b/packages/app-aco/src/features/folder/cache/index.ts @@ -1,3 +1,2 @@ -export * from "./FoldersCache"; export * from "./FoldersCacheFactory"; -export * from "./ICache"; +export * from "./ListCache"; diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts index b3398b03b58..5bfa1449296 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts @@ -1,16 +1,16 @@ import { makeAutoObservable } from "mobx"; import { ICreateFolderRepository } from "./ICreateFolderRepository"; +import { ListCache } from "../cache"; import { Folder } from "../Folder"; -import { FoldersCache } from "../cache"; import { ICreateFolderGateway } from "./ICreateFolderGateway"; import { FolderDto } from "./FolderDto"; export class CreateFolderRepository implements ICreateFolderRepository { - private cache: FoldersCache; + private cache: ListCache; private gateway: ICreateFolderGateway; - private type: string; + private readonly type: string; - constructor(cache: FoldersCache, gateway: ICreateFolderGateway, type: string) { + constructor(cache: ListCache, gateway: ICreateFolderGateway, type: string) { this.cache = cache; this.gateway = gateway; this.type = type; @@ -27,6 +27,6 @@ export class CreateFolderRepository implements ICreateFolderRepository { }; const result = await this.gateway.execute(dto); - await this.cache.set(Folder.create(result)); + this.cache.addItems([Folder.create(result)]); } } diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts index 6b6c898b5db..bc4e07b28a2 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts @@ -1,14 +1,14 @@ import { makeAutoObservable } from "mobx"; import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; -import { FoldersCache } from "../cache"; +import { ListCache } from "../cache"; import { Folder } from "../Folder"; import { IDeleteFolderGateway } from "./IDeleteFolderGateway"; export class DeleteFolderRepository implements IDeleteFolderRepository { - private cache: FoldersCache; + private cache: ListCache; private gateway: IDeleteFolderGateway; - constructor(cache: FoldersCache, gateway: IDeleteFolderGateway) { + constructor(cache: ListCache, gateway: IDeleteFolderGateway) { this.cache = cache; this.gateway = gateway; makeAutoObservable(this); @@ -16,6 +16,6 @@ export class DeleteFolderRepository implements IDeleteFolderRepository { async execute(folder: Folder) { await this.gateway.execute(folder.id); - await this.cache.remove(folder.id); + this.cache.removeItems(f => f.id === folder.id); } } diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts index 5c4fb977a81..2b39b34f54b 100644 --- a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts @@ -1,13 +1,13 @@ import { makeAutoObservable } from "mobx"; import { IGetDescendantFoldersRepository } from "./IGetDescendantFoldersRepository"; -import { FoldersCache } from "../cache"; +import { ListCache } from "../cache"; import { Folder } from "../Folder"; import { ROOT_FOLDER } from "~/constants"; export class GetDescendantFoldersRepository implements IGetDescendantFoldersRepository { - private readonly cache: FoldersCache; + private readonly cache: ListCache; - constructor(cache: FoldersCache) { + constructor(cache: ListCache) { this.cache = cache; makeAutoObservable(this); } diff --git a/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts b/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts index 5e863b8eef5..729f53b8ac4 100644 --- a/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts +++ b/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts @@ -1,14 +1,14 @@ import { makeAutoObservable } from "mobx"; import { Folder } from "../Folder"; -import { FoldersCache } from "../cache"; +import { ListCache } from "../cache"; import { IGetFolderRepository } from "./IGetFolderRepository"; import { IGetFolderGateway } from "./IGetFolderGateway"; export class GetFolderRepository implements IGetFolderRepository { - private cache: FoldersCache; + private cache: ListCache; private gateway: IGetFolderGateway; - constructor(cache: FoldersCache, gateway: IGetFolderGateway) { + constructor(cache: ListCache, gateway: IGetFolderGateway) { this.cache = cache; this.gateway = gateway; makeAutoObservable(this); @@ -16,6 +16,6 @@ export class GetFolderRepository implements IGetFolderRepository { async execute(id: string) { const response = await this.gateway.execute(id); - await this.cache.set(Folder.create(response)); + this.cache.addItems([Folder.create(response)]); } } diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts index e140985f6e1..c3d9e2b9940 100644 --- a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionRepository.ts @@ -1,18 +1,19 @@ -import { FoldersCache } from "../cache"; +import { ListCache } from "../cache"; import { IGetFolderLevelPermissionRepository } from "./IGetFolderLevelPermissionRepository"; import { FolderPermissionName } from "./FolderPermissionName"; +import { Folder } from "~/features/folder"; export class GetFolderLevelPermissionRepository implements IGetFolderLevelPermissionRepository { - private cache: FoldersCache; - private permissionName: FolderPermissionName; + private cache: ListCache; + private readonly permissionName: FolderPermissionName; - constructor(cache: FoldersCache, permissionName: FolderPermissionName) { + constructor(cache: ListCache, permissionName: FolderPermissionName) { this.cache = cache; this.permissionName = permissionName; } execute(id: string) { - const folder = this.cache.getItem(id); + const folder = this.cache.getItem(folder => folder.id === id); if (!folder) { return false; diff --git a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts index 71f8153e290..3623c849fae 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFolders.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFolders.ts @@ -4,11 +4,12 @@ import { IListFoldersGateway } from "./IListFoldersGateway"; import { ListFoldersRepository } from "./ListFoldersRepository"; import { ListFoldersUseCaseWithLoading } from "./ListFoldersUseCaseWithLoading"; import { ListFoldersUseCase } from "./ListFoldersUseCase"; -import { folderCacheFactory, FoldersCache } from "../cache"; +import { folderCacheFactory, ListCache } from "../cache"; +import { Folder } from "~/features/folder"; interface IListFoldersInstance { useCase: IListFoldersUseCase; - folders: FoldersCache; + folders: ListCache; loading: LoadingRepository; } diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts index 1afe0c9536e..635b1b2752a 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts @@ -1,15 +1,15 @@ import { makeAutoObservable } from "mobx"; -import { FoldersCache } from "../cache"; +import { ListCache } from "../cache"; import { Folder } from "../Folder"; import { IListFoldersGateway } from "./IListFoldersGateway"; import { IListFoldersRepository } from "./IListFoldersRepository"; export class ListFoldersRepository implements IListFoldersRepository { - private cache: FoldersCache; + private cache: ListCache; private gateway: IListFoldersGateway; private type: string; - constructor(cache: FoldersCache, gateway: IListFoldersGateway, type: string) { + constructor(cache: ListCache, gateway: IListFoldersGateway, type: string) { this.cache = cache; this.gateway = gateway; this.type = type; @@ -18,6 +18,7 @@ export class ListFoldersRepository implements IListFoldersRepository { async execute() { const items = await this.gateway.execute(this.type); - await this.cache.setMultiple(items.map(item => Folder.create(item))); + this.cache.clear(); + this.cache.addItems(items.map(item => Folder.create(item))); } } diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts index 7c620a5a005..48241fc533e 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts @@ -1,15 +1,15 @@ import { makeAutoObservable } from "mobx"; import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; -import { FoldersCache } from "../cache"; +import { ListCache } from "../cache"; import { Folder } from "../Folder"; import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; import { FolderDto } from "./FolderDto"; export class UpdateFolderRepository implements IUpdateFolderRepository { - private cache: FoldersCache; + private cache: ListCache; private gateway: IUpdateFolderGateway; - constructor(cache: FoldersCache, gateway: IUpdateFolderGateway) { + constructor(cache: ListCache, gateway: IUpdateFolderGateway) { this.cache = cache; this.gateway = gateway; makeAutoObservable(this); @@ -25,6 +25,12 @@ export class UpdateFolderRepository implements IUpdateFolderRepository { }; const result = await this.gateway.execute(dto); - await this.cache.update(folder.id, Folder.create(result)); + this.cache.updateItems(f => { + if (f.id === folder.id) { + return Folder.create(result); + } + + return Folder.create(f); + }); } } From b963e3ad8c4b6fdce4da9338c5dca5a86b409c7c Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Thu, 9 Jan 2025 16:51:01 +0100 Subject: [PATCH 24/28] refactor: remove unused makeAutoObservable --- .../src/features/folder/Folder.test.ts | 55 ------------------- .../createFolder/CreateFolderRepository.ts | 2 - .../deleteFolder/DeleteFolderRepository.ts | 2 - .../GetDescendantFoldersRepository.ts | 2 - .../folder/getFolder/GetFolderRepository.ts | 2 - .../listFolders/ListFoldersRepository.ts | 2 - .../updateFolder/UpdateFolderRepository.ts | 2 - 7 files changed, 67 deletions(-) delete mode 100644 packages/app-aco/src/features/folder/Folder.test.ts diff --git a/packages/app-aco/src/features/folder/Folder.test.ts b/packages/app-aco/src/features/folder/Folder.test.ts deleted file mode 100644 index 2619ca735f0..00000000000 --- a/packages/app-aco/src/features/folder/Folder.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import pick from "lodash/pick"; -import { CmsIdentity } from "@webiny/app-headless-cms-common/types"; -import { FolderGqlDto } from "~/features/folder/createFolder/FolderGqlDto"; -import { ICreateFolderGateway } from "~/features/folder/createFolder/ICreateFolderGateway"; -import { CreateFolder } from "~/features/folder/createFolder/CreateFolder"; - -const user1: CmsIdentity = { - id: "user-1", - type: "admin", - displayName: "User 1" -}; - -const type = "demo-type"; - -const folder1: FolderGqlDto = { - id: "folder-1", - title: "Folder 1", - slug: "folder-1", - permissions: [], - hasNonInheritedPermissions: true, - canManageContent: true, - canManagePermissions: true, - canManageStructure: true, - type, - parentId: null, - createdBy: user1, - createdOn: new Date().toString(), - savedBy: user1, - savedOn: new Date().toString(), - modifiedBy: null, - modifiedOn: null -}; - -const createFolderGateway = ({ execute }: ICreateFolderGateway): ICreateFolderGateway => ({ - execute -}); - -describe("Folder features", () => { - it("should be able to create a folder", async () => { - const gateway = createFolderGateway({ - execute: jest.fn().mockImplementation(() => { - return Promise.resolve(folder1); - }) - }); - - const createFolder = CreateFolder.instance(type, gateway); - - const createPromise = createFolder.execute( - pick(folder1, ["title", "slug", "type", "parentId", "permissions"]) - ); - - await createPromise; - expect(gateway.execute).toHaveBeenCalledTimes(1); - }); -}); diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts index 5bfa1449296..1166f4f86b8 100644 --- a/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolderRepository.ts @@ -1,4 +1,3 @@ -import { makeAutoObservable } from "mobx"; import { ICreateFolderRepository } from "./ICreateFolderRepository"; import { ListCache } from "../cache"; import { Folder } from "../Folder"; @@ -14,7 +13,6 @@ export class CreateFolderRepository implements ICreateFolderRepository { this.cache = cache; this.gateway = gateway; this.type = type; - makeAutoObservable(this); } async execute(folder: Folder) { diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts index bc4e07b28a2..9192780de14 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolderRepository.ts @@ -1,4 +1,3 @@ -import { makeAutoObservable } from "mobx"; import { IDeleteFolderRepository } from "./IDeleteFolderRepository"; import { ListCache } from "../cache"; import { Folder } from "../Folder"; @@ -11,7 +10,6 @@ export class DeleteFolderRepository implements IDeleteFolderRepository { constructor(cache: ListCache, gateway: IDeleteFolderGateway) { this.cache = cache; this.gateway = gateway; - makeAutoObservable(this); } async execute(folder: Folder) { diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts index 2b39b34f54b..6dc2268b71b 100644 --- a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFoldersRepository.ts @@ -1,4 +1,3 @@ -import { makeAutoObservable } from "mobx"; import { IGetDescendantFoldersRepository } from "./IGetDescendantFoldersRepository"; import { ListCache } from "../cache"; import { Folder } from "../Folder"; @@ -9,7 +8,6 @@ export class GetDescendantFoldersRepository implements IGetDescendantFoldersRepo constructor(cache: ListCache) { this.cache = cache; - makeAutoObservable(this); } execute(id: string): Folder[] { diff --git a/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts b/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts index 729f53b8ac4..37750d1f1a1 100644 --- a/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts +++ b/packages/app-aco/src/features/folder/getFolder/GetFolderRepository.ts @@ -1,4 +1,3 @@ -import { makeAutoObservable } from "mobx"; import { Folder } from "../Folder"; import { ListCache } from "../cache"; import { IGetFolderRepository } from "./IGetFolderRepository"; @@ -11,7 +10,6 @@ export class GetFolderRepository implements IGetFolderRepository { constructor(cache: ListCache, gateway: IGetFolderGateway) { this.cache = cache; this.gateway = gateway; - makeAutoObservable(this); } async execute(id: string) { diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts index 635b1b2752a..2b41cc5943d 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts @@ -1,4 +1,3 @@ -import { makeAutoObservable } from "mobx"; import { ListCache } from "../cache"; import { Folder } from "../Folder"; import { IListFoldersGateway } from "./IListFoldersGateway"; @@ -13,7 +12,6 @@ export class ListFoldersRepository implements IListFoldersRepository { this.cache = cache; this.gateway = gateway; this.type = type; - makeAutoObservable(this); } async execute() { diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts index 48241fc533e..e30b7523761 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderRepository.ts @@ -1,4 +1,3 @@ -import { makeAutoObservable } from "mobx"; import { IUpdateFolderRepository } from "./IUpdateFolderRepository"; import { ListCache } from "../cache"; import { Folder } from "../Folder"; @@ -12,7 +11,6 @@ export class UpdateFolderRepository implements IUpdateFolderRepository { constructor(cache: ListCache, gateway: IUpdateFolderGateway) { this.cache = cache; this.gateway = gateway; - makeAutoObservable(this); } async execute(folder: Folder) { From c04bfeac7950d2a4e248ec80357c4f4fbab17d18 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 10 Jan 2025 09:29:36 +0100 Subject: [PATCH 25/28] test: add tests --- .../folder/createFolder/CreateFolder.test.ts | 44 ++++ .../folder/deleteFolder/DeleteFolder.test.ts | 38 +++ .../deleteFolder/IDeleteFolderUseCase.ts | 7 - .../GetDescendantFolders.test.ts | 110 +++++++++ .../GetFolderLevelPermission.test.ts | 225 ++++++++++++++++++ .../GetFolderLevelPermissionWithFlpUseCase.ts | 9 +- .../IGetFolderLevelPermissionUseCase.ts | 6 +- .../useGetFolderLevelPermission.ts | 2 +- .../folder/listFolders/ListFolders.test.ts | 119 +++++++++ .../folder/updateFolder/UpdateFolder.test.ts | 111 +++++++++ .../folder/updateFolder/UpdateFolder.ts | 2 +- 11 files changed, 660 insertions(+), 13 deletions(-) create mode 100644 packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts create mode 100644 packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts create mode 100644 packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.test.ts create mode 100644 packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.test.ts create mode 100644 packages/app-aco/src/features/folder/listFolders/ListFolders.test.ts create mode 100644 packages/app-aco/src/features/folder/updateFolder/UpdateFolder.test.ts diff --git a/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts b/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts new file mode 100644 index 00000000000..ecdcdced489 --- /dev/null +++ b/packages/app-aco/src/features/folder/createFolder/CreateFolder.test.ts @@ -0,0 +1,44 @@ +import { CreateFolder } from "./CreateFolder"; +import { folderCacheFactory } from "../cache/FoldersCacheFactory"; + +describe("CreateFolder", () => { + const type = "abc"; + const gateway = { + execute: jest.fn().mockResolvedValue({ + id: "any-folder-id", + title: "New Folder", + slug: "new-folder", + type + }) + }; + const foldersCache = folderCacheFactory.getCache(type); + + beforeEach(() => { + foldersCache.clear(); + }); + + it("should be able to create a new folder", async () => { + const createFolder = CreateFolder.instance(type, gateway); + + expect(foldersCache.hasItems()).toBeFalse(); + + await createFolder.execute({ + title: "New Folder", + slug: "new-folder", + parentId: null, + permissions: [], + type + }); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeTrue(); + + const item = foldersCache.getItem(folder => folder.slug === "new-folder"); + + expect(item).toBeDefined(); + expect(item?.id).toEqual("any-folder-id"); + expect(item?.type).toEqual(type); + expect(item?.title).toEqual("New Folder"); + expect(item?.slug).toEqual("new-folder"); + }); +}); diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts new file mode 100644 index 00000000000..fe7c3db797b --- /dev/null +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts @@ -0,0 +1,38 @@ +import { DeleteFolder } from "./DeleteFolder"; +import { folderCacheFactory } from "../cache/FoldersCacheFactory"; +import { Folder } from "../Folder"; + +describe("DeleteFolder", () => { + const type = "abc"; + const gateway = { + execute: jest.fn().mockResolvedValue(true) + }; + const foldersCache = folderCacheFactory.getCache(type); + + beforeEach(() => { + foldersCache.clear(); + foldersCache.addItems([ + Folder.create({ + id: "any-folder-id", + title: "New Folder", + slug: "new-folder", + parentId: null, + permissions: [], + type + }) + ]); + }); + + it("should be able to delete a folder", async () => { + const deleteFolder = DeleteFolder.instance(type, gateway); + + expect(foldersCache.hasItems()).toBeTrue(); + const item = foldersCache.getItem(folder => folder.id === "any-folder-id"); + expect(item?.id).toEqual("any-folder-id"); + + await deleteFolder.execute({ id: "any-folder-id" }); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeFalse(); + }); +}); diff --git a/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts index a257dd5b0e0..c4963f82922 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts @@ -1,12 +1,5 @@ -import { FolderPermission } from "~/types"; - export interface DeleteFolderParams { id: string; - title: string; - slug: string; - type: string; - parentId: string | null; - permissions: FolderPermission[]; } export interface IDeleteFolderUseCase { diff --git a/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.test.ts b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.test.ts new file mode 100644 index 00000000000..c4fb3a4a4a6 --- /dev/null +++ b/packages/app-aco/src/features/folder/getDescendantFolders/GetDescendantFolders.test.ts @@ -0,0 +1,110 @@ +import { GetDescendantFolders } from "./GetDescendantFolders"; +import { folderCacheFactory } from "../cache/FoldersCacheFactory"; +import { Folder } from "../Folder"; + +describe("GetDescendantFolders", () => { + const type = "abc"; + const foldersCache = folderCacheFactory.getCache(type); + + beforeEach(() => { + foldersCache.clear(); + foldersCache.addItems([ + Folder.create({ + id: "folder-1", + title: "Folder 1", + slug: "folder-1", + parentId: null, + permissions: [], + type + }), + Folder.create({ + id: "folder-2", + title: "Folder 2", + slug: "folder-2", + parentId: null, + permissions: [], + type + }), + Folder.create({ + id: "folder-3", + title: "Folder 3", + slug: "folder-3", + parentId: "folder-2", + permissions: [], + type + }), + Folder.create({ + id: "folder-4", + title: "Folder 4", + slug: "folder-4", + parentId: "folder-3", + permissions: [], + type + }) + ]); + }); + + it("should return all descendants of a folder", async () => { + const getDescendantFolders = GetDescendantFolders.instance(type); + + const descendants = getDescendantFolders.execute({ + id: "folder-2" + }); + + expect(descendants).toEqual([ + { + id: "folder-2", + title: "Folder 2", + slug: "folder-2", + parentId: null, + permissions: [], + type + }, + { + id: "folder-3", + title: "Folder 3", + slug: "folder-3", + parentId: "folder-2", + permissions: [], + type + }, + { + id: "folder-4", + title: "Folder 4", + slug: "folder-4", + parentId: "folder-3", + permissions: [], + type + } + ]); + }); + + it("should return the folder it self in case no descendants are found", async () => { + const getDescendantFolders = GetDescendantFolders.instance(type); + + const descendants = getDescendantFolders.execute({ + id: "folder-1" + }); + + expect(descendants).toEqual([ + { + id: "folder-1", + title: "Folder 1", + slug: "folder-1", + parentId: null, + permissions: [], + type + } + ]); + }); + + it("should return empty array if folder does not exist", async () => { + const getDescendantFolders = GetDescendantFolders.instance(type); + + const descendants = getDescendantFolders.execute({ + id: "non-existent-folder" + }); + + expect(descendants).toEqual([]); + }); +}); diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.test.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.test.ts new file mode 100644 index 00000000000..9d8a8c1e7ee --- /dev/null +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermission.test.ts @@ -0,0 +1,225 @@ +import { GetFolderLevelPermission } from "./GetFolderLevelPermission"; +import { folderCacheFactory } from "../cache/FoldersCacheFactory"; +import { Folder } from "../Folder"; + +describe("GetFolderLevelPermission", () => { + const type = "abc"; + const foldersCache = folderCacheFactory.getCache(type); + + beforeEach(() => { + foldersCache.clear(); + foldersCache.addItems([ + Folder.create({ + id: "folder-canManageContent", + title: "Folder canManageContent", + slug: "folder-canManageContent", + parentId: null, + permissions: [], + canManageContent: true, + type + }), + Folder.create({ + id: "folder-canManageStructure", + title: "Folder canManageStructure", + slug: "folder-canManageStructure", + parentId: null, + permissions: [], + canManageStructure: true, + type + }), + Folder.create({ + id: "folder-canManagePermissions", + title: "Folder canManagePermissions3", + slug: "folder-canManagePermissions", + parentId: null, + permissions: [], + canManagePermissions: true, + type + }), + Folder.create({ + id: "folder-no-permissions", + title: "Folder No Permissions", + slug: "folder-no-permissions", + parentId: null, + permissions: [], + type + }) + ]); + }); + + it("should return true in case a specific permission is set at folder level and FLP is enabled", async () => { + // canManagePermissions + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManagePermissions", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-canManagePermissions" + }); + expect(result).toBeTrue(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageStructure", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-canManageStructure" + }); + expect(result).toBeTrue(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageContent", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-canManageContent" + }); + expect(result).toBeTrue(); + } + }); + + it("should return false in case a specific permission is not set at folder level and FLP is enabled", async () => { + // canManagePermissions + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManagePermissions", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-no-permissions" + }); + expect(result).toBeFalse(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageStructure", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-no-permissions" + }); + expect(result).toBeFalse(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageContent", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-no-permissions" + }); + expect(result).toBeFalse(); + } + }); + + it("should return always false in case the folder is not found", async () => { + // canManagePermissions + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManagePermissions", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "not-existing-folder" + }); + expect(result).toBeFalse(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageStructure", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "not-existing-folder" + }); + expect(result).toBeFalse(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageContent", + true + ); + + const result = getFolderLevelPermission.execute({ + id: "not-existing-folder" + }); + expect(result).toBeFalse(); + } + }); + + it("should return always true in case FLP is not enabled", async () => { + // canManagePermissions + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManagePermissions", + false + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-no-permissions" + }); + expect(result).toBeTrue(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageStructure", + false + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-no-permissions" + }); + expect(result).toBeTrue(); + } + + // canManageStructure + { + const getFolderLevelPermission = GetFolderLevelPermission.instance( + type, + "canManageContent", + false + ); + + const result = getFolderLevelPermission.execute({ + id: "folder-no-permissions" + }); + expect(result).toBeTrue(); + } + }); +}); diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts index 0479cfbbd37..351aad0167e 100644 --- a/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/GetFolderLevelPermissionWithFlpUseCase.ts @@ -1,4 +1,7 @@ -import { IGetFolderLevelPermissionUseCase } from "./IGetFolderLevelPermissionUseCase"; +import { + GetFolderLevelPermissionParams, + IGetFolderLevelPermissionUseCase +} from "./IGetFolderLevelPermissionUseCase"; import { IGetFolderLevelPermissionRepository } from "./IGetFolderLevelPermissionRepository"; export class GetFolderLevelPermissionWithFlpUseCase implements IGetFolderLevelPermissionUseCase { @@ -8,7 +11,7 @@ export class GetFolderLevelPermissionWithFlpUseCase implements IGetFolderLevelPe this.repository = repository; } - execute(id: string) { - return this.repository.execute(id); + execute(params: GetFolderLevelPermissionParams) { + return this.repository.execute(params.id); } } diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts index 9ae5dd13cc8..443205e3c38 100644 --- a/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/IGetFolderLevelPermissionUseCase.ts @@ -1,3 +1,7 @@ +export interface GetFolderLevelPermissionParams { + id: string; +} + export interface IGetFolderLevelPermissionUseCase { - execute: (id: string) => boolean; + execute: (params: GetFolderLevelPermissionParams) => boolean; } diff --git a/packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts b/packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts index 092aa8bf524..de1dab3dc07 100644 --- a/packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts +++ b/packages/app-aco/src/features/folder/getFolderLevelPermission/useGetFolderLevelPermission.ts @@ -26,7 +26,7 @@ export const useGetFolderLevelPermission = (permissionName: FolderPermissionName permissionName, canUseFolderLevelPermissions() ); - return instance.execute(id); + return instance.execute({ id }); }, [type, canUseFolderLevelPermissions] ); diff --git a/packages/app-aco/src/features/folder/listFolders/ListFolders.test.ts b/packages/app-aco/src/features/folder/listFolders/ListFolders.test.ts new file mode 100644 index 00000000000..519c01cc587 --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/ListFolders.test.ts @@ -0,0 +1,119 @@ +import { ListFolders } from "./ListFolders"; +import { folderCacheFactory } from "../cache/FoldersCacheFactory"; + +describe("ListFolders", () => { + const type = "abc"; + const gateway = { + execute: jest.fn().mockResolvedValue([ + { + id: "folder-1", + title: "Folder 1", + slug: "folder-1", + type + }, + { + id: "folder-2", + title: "Folder 2", + slug: "folder-1", + type + }, + { + id: "folder-3", + title: "Folder 3", + slug: "folder-3", + type + } + ]) + }; + const foldersCache = folderCacheFactory.getCache(type); + + beforeEach(() => { + foldersCache.clear(); + jest.clearAllMocks(); + }); + + it("should be able to list folders", async () => { + const listFolders = ListFolders.instance(type, gateway); + + expect(foldersCache.hasItems()).toBeFalse(); + + await listFolders.useCase.execute(); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeTrue(); + + const items = foldersCache.getItems(); + expect(items.length).toEqual(3); + }); + + it("should return empty array if no folders are found", async () => { + const emptyGateway = { + execute: jest.fn().mockResolvedValue([]) + }; + const listFolders = ListFolders.instance(type, emptyGateway); + + expect(foldersCache.hasItems()).toBeFalse(); + + await listFolders.useCase.execute(); + + expect(emptyGateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeFalse(); + + const items = foldersCache.getItems(); + expect(items.length).toEqual(0); + }); + + it("should handle gateway errors gracefully", async () => { + const errorGateway = { + execute: jest.fn().mockRejectedValue(new Error("Gateway error")) + }; + const listFolders = ListFolders.instance(type, errorGateway); + + expect(foldersCache.hasItems()).toBeFalse(); + + await expect(listFolders.useCase.execute()).rejects.toThrow("Gateway error"); + + expect(errorGateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeFalse(); + }); + + it("should NOT cache folders after listing", async () => { + const listFolders = ListFolders.instance(type, gateway); + + expect(foldersCache.hasItems()).toBeFalse(); + + await listFolders.useCase.execute(); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeTrue(); + + const items = foldersCache.getItems(); + expect(items.length).toEqual(3); + + // Execute again, it should execute the gateway again + await listFolders.useCase.execute(); + expect(gateway.execute).toHaveBeenCalledTimes(2); + }); + + it("should clear cache when type changes", async () => { + const listFolders = ListFolders.instance(type, gateway); + + expect(foldersCache.hasItems()).toBeFalse(); + + await listFolders.useCase.execute(); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + expect(foldersCache.hasItems()).toBeTrue(); + + const newType = "xyz"; + const newFoldersCache = folderCacheFactory.getCache(newType); + const newListFolders = ListFolders.instance(newType, gateway); + + expect(newFoldersCache.hasItems()).toBeFalse(); + + await newListFolders.useCase.execute(); + + expect(gateway.execute).toHaveBeenCalledTimes(2); + expect(newFoldersCache.hasItems()).toBeTrue(); + }); +}); diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.test.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.test.ts new file mode 100644 index 00000000000..1ad82996072 --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.test.ts @@ -0,0 +1,111 @@ +import { UpdateFolder } from "./UpdateFolder"; +import { folderCacheFactory } from "../cache/FoldersCacheFactory"; +import { Folder } from "../Folder"; + +describe("UpdateFolder", () => { + const type = "abc"; + + const foldersCache = folderCacheFactory.getCache(type); + + beforeEach(() => { + jest.clearAllMocks(); + foldersCache.clear(); + foldersCache.addItems([ + Folder.create({ + id: "any-folder-id", + title: "Any Folder", + slug: "any-folder", + parentId: null, + permissions: [], + type + }) + ]); + }); + + it("should be able to update a folder", async () => { + const gateway = { + execute: jest.fn().mockResolvedValue({ + id: "any-folder-id", + title: "Updated Folder", + slug: "updated-folder", + parentId: "another-id", + permissions: [], + type + }) + }; + + const updateFolder = UpdateFolder.instance(type, gateway); + + expect(foldersCache.hasItems()).toBeTrue(); + const item = foldersCache.getItem(folder => folder.id === "any-folder-id"); + expect(item?.id).toEqual("any-folder-id"); + expect(item?.title).toEqual("Any Folder"); + + await updateFolder.execute({ + id: "any-folder-id", + title: "Updated Folder", + slug: "updated-folder", + parentId: "another-id", + permissions: [], + type + }); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + const updatedItem = foldersCache.getItem(folder => folder.id === "any-folder-id"); + + expect(updatedItem).toBeDefined(); + expect(updatedItem?.id).toEqual("any-folder-id"); + expect(updatedItem?.type).toEqual(type); + expect(updatedItem?.title).toEqual("Updated Folder"); + expect(updatedItem?.slug).toEqual("updated-folder"); + expect(updatedItem?.parentId).toEqual("another-id"); + }); + + it("should not update a folder if id is missing", async () => { + const gateway = { + execute: jest.fn().mockResolvedValue(null) + }; + + const updateFolder = UpdateFolder.instance(type, gateway); + + await updateFolder.execute({ + id: "", + title: "Updated Folder", + slug: "updated-folder", + parentId: "another-id", + permissions: [], + type + }); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + const updatedItem = foldersCache.getItem(folder => folder.id === "any-folder-id"); + + expect(updatedItem).toBeDefined(); + expect(updatedItem?.id).toEqual("any-folder-id"); + expect(updatedItem?.type).toEqual(type); + expect(updatedItem?.title).toEqual("Any Folder"); + expect(updatedItem?.slug).toEqual("any-folder"); + expect(updatedItem?.parentId).toEqual(null); + }); + + it("should handle gateway errors gracefully", async () => { + const gateway = { + execute: jest.fn().mockRejectedValue(new Error("Gateway error")) + }; + + const updateFolder = UpdateFolder.instance(type, gateway); + + await expect( + updateFolder.execute({ + id: "any-folder-id", + title: "Updated Folder", + slug: "updated-folder", + parentId: "another-id", + permissions: [], + type + }) + ).rejects.toThrow("Gateway error"); + + expect(gateway.execute).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts index 294eee74b15..de17042b002 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts @@ -4,7 +4,7 @@ import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; import { UpdateFolderRepository } from "./UpdateFolderRepository"; import { UpdateFolderUseCase } from "./UpdateFolderUseCase"; import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading"; -import { folderCacheFactory } from "~/features/folder"; +import { folderCacheFactory } from "../cache"; export class UpdateFolder { public static instance(type: string, gateway: IUpdateFolderGateway): IUpdateFolderUseCase { From b3770d18c4caf2744f45d6d4c569488755f86efa Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 10 Jan 2025 11:12:11 +0100 Subject: [PATCH 26/28] refactor: remove useFolders --- .../src/components/FolderTree/List/index.tsx | 10 ++++++---- .../src/components/FolderTree/List/utils.ts | 6 +++--- .../app-aco/src/components/FolderTree/index.tsx | 9 ++++++--- packages/app-aco/src/contexts/acoList.tsx | 10 ++++------ packages/app-aco/src/dialogs/useCreateDialog.tsx | 4 ++-- packages/app-aco/src/dialogs/useDeleteDialog.tsx | 4 ++-- packages/app-aco/src/dialogs/useEditDialog.tsx | 4 ++-- .../src/dialogs/useSetPermissionsDialog.tsx | 4 ++-- .../folder/deleteFolder/DeleteFolder.test.ts | 9 ++++++++- .../folder/deleteFolder/IDeleteFolderUseCase.ts | 7 +++++++ .../folder/deleteFolder/useDeleteFolder.ts | 2 +- packages/app-aco/src/features/index.ts | 1 + packages/app-aco/src/hooks/useFolders.ts | 7 ++++++- packages/app-aco/src/index.ts | 1 + .../FileManagerViewContext.tsx | 4 ++-- .../FileManagerViewProvider/useListFiles.ts | 4 ++-- .../src/admin/views/contentEntries/Table/Main.tsx | 15 +++++++++------ .../components/BulkActions/SecureActionDelete.tsx | 11 +++++------ .../BulkActions/SecureActionDuplicate.tsx | 9 +++++---- .../components/BulkActions/SecureActionMove.tsx | 9 +++++---- .../BulkActions/SecureActionPublish.tsx | 9 +++++---- .../BulkActions/SecureActionUnpublish.tsx | 9 +++++---- .../Table/Actions/SecureChangePageStatus.tsx | 7 ++++--- .../Table/Table/Actions/SecureDeletePage.tsx | 9 +++++---- .../Table/Table/Actions/SecureDuplicatePage.tsx | 9 +++++---- .../Table/Table/Actions/SecureEditPage.tsx | 9 +++++---- .../Table/Table/Actions/SecureMovePage.tsx | 10 +++++----- .../pageDetails/header/deletePage/DeletePage.tsx | 9 +++++---- .../header/editRevision/EditRevision.tsx | 9 +++++---- .../DuplicatePage/SecureDuplicatePage.tsx | 10 +++++----- .../header/pageOptionsMenu/PageOptionsMenu.tsx | 7 ++++--- .../header/publishRevision/PublishRevision.tsx | 7 ++++--- .../SecureDeleteRevisionMenuOption.tsx | 10 +++++----- .../MenuOptions/SecureEditRevisionMenuOption.tsx | 10 +++++----- .../MenuOptions/SecureNewRevisionFromCurrent.tsx | 9 +++++---- .../MenuOptions/SecurePublishPageMenuOption.tsx | 9 +++++---- .../MenuOptions/SecureUnpublishPageMenuOption.tsx | 9 +++++---- .../src/admin/views/Pages/Table/Main.tsx | 15 +++++++++------ 38 files changed, 170 insertions(+), 126 deletions(-) create mode 100644 packages/app-aco/src/features/index.ts diff --git a/packages/app-aco/src/components/FolderTree/List/index.tsx b/packages/app-aco/src/components/FolderTree/List/index.tsx index 11fa30881cb..97dd3d9c5df 100644 --- a/packages/app-aco/src/components/FolderTree/List/index.tsx +++ b/packages/app-aco/src/components/FolderTree/List/index.tsx @@ -13,7 +13,7 @@ import { Node } from "../Node"; import { NodePreview } from "../NodePreview"; import { Placeholder } from "../Placeholder"; import { createInitialOpenList, createTreeData } from "./utils"; -import { useFolders } from "~/hooks"; +import { useGetFolderLevelPermission, useUpdateFolder } from "~/features"; import { ROOT_FOLDER } from "~/constants"; import { DndFolderItemData, FolderItem } from "~/types"; import { FolderProvider } from "~/contexts/folder"; @@ -33,7 +33,9 @@ export const List = ({ hiddenFolderIds, enableActions }: ListProps) => { - const { updateFolder, folderLevelPermissions: flp } = useFolders(); + const { updateFolder } = useUpdateFolder(); + const { getFolderLevelPermission: canManageStructure } = + useGetFolderLevelPermission("canManageStructure"); const { showSnackbar } = useSnackbar(); const [treeData, setTreeData] = useState[]>([]); const [initialOpenList, setInitialOpenList] = useState(); @@ -95,9 +97,9 @@ export const List = ({ const canDrag = useCallback( (folderId: string) => { const isRootFolder = folderId === ROOT_FOLDER; - return !isRootFolder && flp.canManageStructure(folderId); + return !isRootFolder && canManageStructure(folderId); }, - [flp.canManageStructure] + [canManageStructure] ); return ( diff --git a/packages/app-aco/src/components/FolderTree/List/utils.ts b/packages/app-aco/src/components/FolderTree/List/utils.ts index 4659211a1e5..d3b7010315c 100644 --- a/packages/app-aco/src/components/FolderTree/List/utils.ts +++ b/packages/app-aco/src/components/FolderTree/List/utils.ts @@ -3,9 +3,9 @@ import { DndFolderItemData, FolderItem } from "~/types"; import { ROOT_FOLDER } from "~/constants"; /** - * Transform an array of folders returned by useFolders hook into an array of elements for the tree component. + * Transform an array of folders returned by folders cache into an array of elements for the tree component. * - * @param folders list of folders returned by useFolders hook. + * @param folders list of folders returned by folders cache. * @param focusedNodeId id of the current folder selected/focused. * @param hiddenFolderIds list ids of the folder you don't want to show within the list. * @return array of elements to render the tree component. @@ -37,7 +37,7 @@ export const createTreeData = ( * Return an array of ids of open folders, based on the current focused folder id, its parent folders and the folders * opened by user interaction. * - * @param folders list of folders returned by useFolders hook. + * @param folders list of folders returned by folders cache. * @param openIds list of open folders ids. * @param focusedId id of the current folder selected/focused. * @return array of ids of open folders. diff --git a/packages/app-aco/src/components/FolderTree/index.tsx b/packages/app-aco/src/components/FolderTree/index.tsx index 2bbbbc73a36..b874066ae59 100644 --- a/packages/app-aco/src/components/FolderTree/index.tsx +++ b/packages/app-aco/src/components/FolderTree/index.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { Tooltip } from "@webiny/ui/Tooltip"; -import { useFolders } from "~/hooks/useFolders"; +import { useGetFolderLevelPermission, useListFolders } from "~/features"; import { CreateButton } from "./ButtonCreate"; import { Empty } from "./Empty"; import { Loader } from "./Loader"; @@ -29,7 +29,10 @@ export const FolderTree = ({ onFolderClick, rootFolderLabel }: FolderTreeProps) => { - const { folders, folderLevelPermissions: flp, loading } = useFolders(); + const { loading, folders } = useListFolders(); + const { getFolderLevelPermission: canManageStructure } = + useGetFolderLevelPermission("canManageStructure"); + const localFolders = useMemo(() => { if (!folders) { return []; @@ -50,7 +53,7 @@ export const FolderTree = ({ let createButton = null; if (enableCreate) { - const canCreate = flp.canManageStructure(focusedFolderId!); + const canCreate = canManageStructure(focusedFolderId!); createButton = ; diff --git a/packages/app-aco/src/contexts/acoList.tsx b/packages/app-aco/src/contexts/acoList.tsx index 2695295319a..53f4709a91b 100644 --- a/packages/app-aco/src/contexts/acoList.tsx +++ b/packages/app-aco/src/contexts/acoList.tsx @@ -11,7 +11,8 @@ import { ListSearchRecordsSort, SearchRecordItem } from "~/types"; -import { useAcoApp, useFolders, useNavigateFolder } from "~/hooks"; +import { useAcoApp, useNavigateFolder } from "~/hooks"; +import { useGetDescendantFolders, useListFolders } from "~/features"; import { FoldersContext } from "~/contexts/folders"; import { SearchRecordsContext } from "~/contexts/records"; import { sortTableItems, validateOrGetDefaultDbSort } from "~/sorting"; @@ -120,11 +121,8 @@ export const AcoListProvider = ({ children, ...props }: AcoListProviderProps) => const { identity } = useSecurity(); const { currentFolderId } = useNavigateFolder(); const { folderIdPath, folderIdInPath } = useAcoApp(); - const { - folders: originalFolders, - loading: foldersLoading, - getDescendantFolders - } = useFolders(); + const { folders: originalFolders, loading: foldersLoading } = useListFolders(); + const { getDescendantFolders } = useGetDescendantFolders(); const folderContext = useContext(FoldersContext); const searchContext = useContext(SearchRecordsContext); diff --git a/packages/app-aco/src/dialogs/useCreateDialog.tsx b/packages/app-aco/src/dialogs/useCreateDialog.tsx index 1920abe3593..c3194deabb2 100644 --- a/packages/app-aco/src/dialogs/useCreateDialog.tsx +++ b/packages/app-aco/src/dialogs/useCreateDialog.tsx @@ -10,7 +10,7 @@ import { validation } from "@webiny/validation"; import { FolderTree } from "~/components"; import { useDialogs } from "@webiny/app-admin"; import { DialogFoldersContainer } from "~/dialogs/styled"; -import { useFolders } from "~/hooks"; +import { useCreateFolder } from "~/features"; import { ROOT_FOLDER } from "~/constants"; import { FolderItem } from "~/types"; @@ -81,7 +81,7 @@ const FormComponent = ({ currentParentId = null }: FormComponentProps) => { export const useCreateDialog = (): UseCreateDialogResponse => { const dialogs = useDialogs(); - const { createFolder } = useFolders(); + const { createFolder } = useCreateFolder(); const { showSnackbar } = useSnackbar(); const onAccept = useCallback(async (data: FolderItem) => { diff --git a/packages/app-aco/src/dialogs/useDeleteDialog.tsx b/packages/app-aco/src/dialogs/useDeleteDialog.tsx index a8dd8e65bf5..54f8f643f6e 100644 --- a/packages/app-aco/src/dialogs/useDeleteDialog.tsx +++ b/packages/app-aco/src/dialogs/useDeleteDialog.tsx @@ -1,7 +1,7 @@ import { useSnackbar } from "@webiny/app-admin"; import { useDialogs } from "@webiny/app-admin"; -import { useFolders } from "~/hooks"; +import { useDeleteFolder } from "~/features"; import { FolderItem } from "~/types"; import { useCallback } from "react"; @@ -15,7 +15,7 @@ interface UseDeleteDialogResponse { export const useDeleteDialog = (): UseDeleteDialogResponse => { const dialogs = useDialogs(); - const { deleteFolder } = useFolders(); + const { deleteFolder } = useDeleteFolder(); const { showSnackbar } = useSnackbar(); const onAccept = useCallback(async (folder: FolderItem) => { diff --git a/packages/app-aco/src/dialogs/useEditDialog.tsx b/packages/app-aco/src/dialogs/useEditDialog.tsx index da03f9575ae..e9027d28832 100644 --- a/packages/app-aco/src/dialogs/useEditDialog.tsx +++ b/packages/app-aco/src/dialogs/useEditDialog.tsx @@ -10,7 +10,7 @@ import { FolderTree } from "~/components"; import { ROOT_FOLDER } from "~/constants"; import { useDialogs } from "@webiny/app-admin"; import { DialogFoldersContainer } from "~/dialogs/styled"; -import { useFolders } from "~/hooks"; +import { useUpdateFolder } from "~/features"; import { FolderItem } from "~/types"; interface ShowDialogParams { @@ -72,7 +72,7 @@ const FormComponent = ({ folder }: FormComponentProps) => { export const useEditDialog = (): UseEditDialogResponse => { const dialog = useDialogs(); - const { updateFolder } = useFolders(); + const { updateFolder } = useUpdateFolder(); const { showSnackbar } = useSnackbar(); const onAccept = useCallback(async (folder: FolderItem, data: GenericFormData) => { diff --git a/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx b/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx index 8758d00bc74..9505cdd4139 100644 --- a/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx +++ b/packages/app-aco/src/dialogs/useSetPermissionsDialog.tsx @@ -9,7 +9,7 @@ import { UsersTeamsSelection } from "./DialogSetPermissions/UsersTeamsSelection" import { LIST_FOLDER_LEVEL_PERMISSIONS_TARGETS } from "./DialogSetPermissions/graphql"; import { useDialogs } from "@webiny/app-admin"; -import { useFolders } from "~/hooks"; +import { useUpdateFolder } from "~/features"; import { FolderItem, FolderLevelPermissionsTarget, FolderPermission } from "~/types"; interface ShowDialogParams { @@ -115,7 +115,7 @@ const FormComponent = ({ folder }: FormComponentProps) => { export const useSetPermissionsDialog = (): UseSetPermissionsDialogResponse => { const dialogs = useDialogs(); - const { updateFolder } = useFolders(); + const { updateFolder } = useUpdateFolder(); const { showSnackbar } = useSnackbar(); const onAccept = useCallback(async (folder: FolderItem, data: Partial) => { diff --git a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts index fe7c3db797b..d587c352579 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/DeleteFolder.test.ts @@ -30,7 +30,14 @@ describe("DeleteFolder", () => { const item = foldersCache.getItem(folder => folder.id === "any-folder-id"); expect(item?.id).toEqual("any-folder-id"); - await deleteFolder.execute({ id: "any-folder-id" }); + await deleteFolder.execute({ + id: "any-folder-id", + title: "New Folder", + slug: "new-folder", + parentId: null, + permissions: [], + type + }); expect(gateway.execute).toHaveBeenCalledTimes(1); expect(foldersCache.hasItems()).toBeFalse(); diff --git a/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts index c4963f82922..a257dd5b0e0 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/IDeleteFolderUseCase.ts @@ -1,5 +1,12 @@ +import { FolderPermission } from "~/types"; + export interface DeleteFolderParams { id: string; + title: string; + slug: string; + type: string; + parentId: string | null; + permissions: FolderPermission[]; } export interface IDeleteFolderUseCase { diff --git a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts index 5f36f3fb893..e0344e7be1f 100644 --- a/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts +++ b/packages/app-aco/src/features/folder/deleteFolder/useDeleteFolder.ts @@ -12,7 +12,7 @@ export const useDeleteFolder = () => { const foldersContext = useContext(FoldersContext); if (!foldersContext) { - throw new Error("useFolders must be used within a FoldersProvider"); + throw new Error("useDeleteFolder must be used within a FoldersProvider"); } const { type } = foldersContext; diff --git a/packages/app-aco/src/features/index.ts b/packages/app-aco/src/features/index.ts new file mode 100644 index 00000000000..40d34a8d6d6 --- /dev/null +++ b/packages/app-aco/src/features/index.ts @@ -0,0 +1 @@ +export * from "./folder"; diff --git a/packages/app-aco/src/hooks/useFolders.ts b/packages/app-aco/src/hooks/useFolders.ts index 1a0a6c7e9ee..a493b1c546e 100644 --- a/packages/app-aco/src/hooks/useFolders.ts +++ b/packages/app-aco/src/hooks/useFolders.ts @@ -6,8 +6,13 @@ import { useGetFolderLevelPermission, useListFolders, useUpdateFolder -} from "~/features/folder"; +} from "~/features"; +/** + * Custom hook to manage folder operations. + * + * @deprecated This hook is deprecated. Use the individual hooks directly from "~/features" instead. + */ export const useFolders = () => { const { createFolder } = useCreateFolder(); const { deleteFolder } = useDeleteFolder(); diff --git a/packages/app-aco/src/index.ts b/packages/app-aco/src/index.ts index 1c69c067f52..34b2023afd9 100644 --- a/packages/app-aco/src/index.ts +++ b/packages/app-aco/src/index.ts @@ -2,5 +2,6 @@ export * from "./components"; export * from "./config"; export * from "./contexts"; export * from "./hooks"; +export * from "./features"; export * from "./dialogs"; export * from "./sorting"; diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/FileManagerViewContext.tsx b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/FileManagerViewContext.tsx index dc034cefd22..89d876e4245 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/FileManagerViewContext.tsx +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/FileManagerViewContext.tsx @@ -8,7 +8,7 @@ import { initializeState, State } from "./state"; import { FolderItem, ListMeta, ListSearchRecordsSort } from "@webiny/app-aco/types"; import { UploadOptions } from "@webiny/app/types"; import { sortTableItems } from "@webiny/app-aco/sorting"; -import { useFolders, useNavigateFolder } from "@webiny/app-aco"; +import { useListFolders, useNavigateFolder } from "@webiny/app-aco"; import { ListFilesQueryVariables } from "~/modules/FileManagerApiProvider/graphql"; import { useListFiles } from "./useListFiles"; import { useTags } from "./useTags"; @@ -106,7 +106,7 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP const shiftKeyPressed = useShiftKey(); const modifiers = { scope: props.scope, own: props.own, accept: props.accept }; const fileManager = useFileManagerApi(); - const { folders: originalFolders, loading: foldersLoading } = useFolders(); + const { folders: originalFolders, loading: foldersLoading } = useListFolders(); const { currentFolderId = ROOT_FOLDER, navigateToFolder } = useNavigateFolder(); const tags = useTags(modifiers); const [state, setState] = useStateIfMounted(initializeState()); diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts index a28a45b6629..3d6811e76c4 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts @@ -1,6 +1,6 @@ import isEqual from "lodash/isEqual"; import { validateOrGetDefaultDbSort } from "@webiny/app-aco/sorting"; -import { useFolders } from "@webiny/app-aco"; +import { useGetDescendantFolders } from "@webiny/app-aco"; import { ListMeta } from "@webiny/app-aco/types"; import { useSecurity } from "@webiny/app-security"; import { FileItem } from "@webiny/app-admin/types"; @@ -41,7 +41,7 @@ interface UseListFilesParams { export function useListFiles({ modifiers, folderId, state }: UseListFilesParams) { const { identity } = useSecurity(); const fileManager = useFileManagerApi(); - const { getDescendantFolders } = useFolders(); + const { getDescendantFolders } = useGetDescendantFolders(); const [meta, setMeta] = useStateIfMounted(undefined); const [files, setFiles] = useStateIfMounted([]); const [loading, setLoading] = useStateIfMounted>({}); diff --git a/packages/app-headless-cms/src/admin/views/contentEntries/Table/Main.tsx b/packages/app-headless-cms/src/admin/views/contentEntries/Table/Main.tsx index af6797906a2..6e6488ea02d 100644 --- a/packages/app-headless-cms/src/admin/views/contentEntries/Table/Main.tsx +++ b/packages/app-headless-cms/src/admin/views/contentEntries/Table/Main.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import debounce from "lodash/debounce"; -import { useCreateDialog, useFolders } from "@webiny/app-aco"; +import { useCreateDialog, useGetFolderLevelPermission } from "@webiny/app-aco"; import { Scrollbar } from "@webiny/ui/Scrollbar"; import { Empty } from "~/admin/components/ContentEntries/Empty"; import { Filters } from "~/admin/components/ContentEntries/Filters"; @@ -29,15 +29,18 @@ export const Main = ({ folderId: initialFolderId }: MainProps) => { // We check permissions on two layers - security and folder level permissions. const { canCreate, contentModel } = useContentEntry(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); + const { getFolderLevelPermission: canManageStructure } = + useGetFolderLevelPermission("canManageStructure"); const canCreateFolder = useMemo(() => { - return flp.canManageStructure(folderId); - }, [flp, folderId]); + return canManageStructure(folderId); + }, [canManageStructure, folderId]); const canCreateContent = useMemo(() => { - return canCreate && flp.canManageContent(folderId); - }, [flp, folderId]); + return canCreate && canManageContent(folderId); + }, [canManageContent, folderId]); const createEntry = useCallback(() => { const folder = folderId ? `&folderId=${encodeURIComponent(folderId)}` : ""; diff --git a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDelete.tsx b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDelete.tsx index 8af05ee53f3..225683e4aba 100644 --- a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDelete.tsx +++ b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDelete.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { observer } from "mobx-react-lite"; import { PageListConfig } from "~/admin/config/pages"; import { usePagesPermissions } from "~/hooks/permissions"; @@ -7,18 +7,17 @@ import { ActionDelete as ActionDeleteBase } from "~/admin/components/BulkActions export const SecureActionDelete = observer(() => { const { canDelete } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { useWorker } = PageListConfig.Browser.BulkAction; const worker = useWorker(); const canDeleteAll = useMemo(() => { return worker.items.every(item => { - return ( - canDelete(item.data.createdBy.id) && flp.canManageContent(item.location?.folderId) - ); + return canDelete(item.data.createdBy.id) && canManageContent(item.location?.folderId); }); - }, [worker.items]); + }, [worker.items, canManageContent]); if (!canDeleteAll) { console.log("You don't have permissions to delete pages."); diff --git a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDuplicate.tsx b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDuplicate.tsx index 527d7f2903d..2e333ddac8d 100644 --- a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDuplicate.tsx +++ b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionDuplicate.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { observer } from "mobx-react-lite"; import { PageListConfig } from "~/admin/config/pages"; import { usePagesPermissions } from "~/hooks/permissions"; @@ -8,7 +8,8 @@ import { ActionDuplicate } from "~/admin/components/BulkActions/ActionDuplicate" export const SecureActionDuplicate = ActionDuplicate.createDecorator(Original => { return observer(() => { const { canWrite: pagesCanWrite } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { useWorker } = PageListConfig.Browser.BulkAction; const worker = useWorker(); @@ -17,10 +18,10 @@ export const SecureActionDuplicate = ActionDuplicate.createDecorator(Original => return worker.items.every(item => { return ( pagesCanWrite(item.data.createdBy.id) && - flp.canManageContent(item.location?.folderId) + canManageContent(item.location?.folderId) ); }); - }, [worker.items]); + }, [worker.items, canManageContent]); if (!canDuplicateAll) { console.log("You don't have permissions to duplicate pages."); diff --git a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionMove.tsx b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionMove.tsx index 733d0ca65e1..0e12c532ed8 100644 --- a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionMove.tsx +++ b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionMove.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { observer } from "mobx-react-lite"; import { PageListConfig } from "~/admin/config/pages"; import { ActionMove as ActionMoveBase } from "~/admin/components/BulkActions"; @@ -7,13 +7,14 @@ import { ActionMove as ActionMoveBase } from "~/admin/components/BulkActions"; export const SecureActionMove = observer(() => { const { useWorker } = PageListConfig.Browser.BulkAction; const worker = useWorker(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const canMoveAll = useMemo(() => { return worker.items.every(item => { - return flp.canManageContent(item.location?.folderId); + return canManageContent(item.location?.folderId); }); - }, [worker.items]); + }, [worker.items, canManageContent]); if (!canMoveAll) { return null; diff --git a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionPublish.tsx b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionPublish.tsx index 051d25e6d8d..80dc43dbd92 100644 --- a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionPublish.tsx +++ b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionPublish.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { observer } from "mobx-react-lite"; import { PageListConfig } from "~/admin/config/pages"; import { usePagesPermissions } from "~/hooks/permissions"; @@ -8,16 +8,17 @@ import { ActionPublish as ActionPublishBase } from "~/admin/components/BulkActio export const SecureActionPublish = observer(() => { const { canPublish } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { useWorker } = PageListConfig.Browser.BulkAction; const worker = useWorker(); const canPublishAll = useMemo(() => { return worker.items.every(item => { - return canPublish() && flp.canManageContent(item.location?.folderId); + return canPublish() && canManageContent(item.location?.folderId); }); - }, [worker.items]); + }, [worker.items, canManageContent]); if (!canPublishAll) { console.log("You don't have permissions to publish pages."); diff --git a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionUnpublish.tsx b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionUnpublish.tsx index 9683f12a73f..6025b05b730 100644 --- a/packages/app-page-builder/src/admin/components/BulkActions/SecureActionUnpublish.tsx +++ b/packages/app-page-builder/src/admin/components/BulkActions/SecureActionUnpublish.tsx @@ -1,13 +1,14 @@ import React, { useMemo } from "react"; import { observer } from "mobx-react-lite"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { PageListConfig } from "~/admin/config/pages"; import { usePagesPermissions } from "~/hooks/permissions"; import { ActionUnpublish as ActionUnpublishBase } from "~/admin/components/BulkActions"; export const SecureActionUnpublish = observer(() => { const { canUnpublish } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { useWorker } = PageListConfig.Browser.BulkAction; @@ -15,9 +16,9 @@ export const SecureActionUnpublish = observer(() => { const canUnpublishAll = useMemo(() => { return worker.items.every(item => { - return canUnpublish() && flp.canManageContent(item.location?.folderId); + return canUnpublish() && canManageContent(item.location?.folderId); }); - }, [worker.items]); + }, [worker.items, canManageContent]); if (!canUnpublishAll) { console.log("You don't have permissions to unpublish pages."); diff --git a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureChangePageStatus.tsx b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureChangePageStatus.tsx index 13a2ba0618e..46cc3d4e423 100644 --- a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureChangePageStatus.tsx +++ b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureChangePageStatus.tsx @@ -1,12 +1,13 @@ import React from "react"; import { usePage } from "~/admin/views/Pages/hooks/usePage"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { ChangePageStatus } from "./ChangePageStatus"; export const SecureChangePageStatus = () => { const { page } = usePage(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { hasPermissions, canPublish, canUnpublish } = usePagesPermissions(); if (!hasPermissions()) { @@ -14,7 +15,7 @@ export const SecureChangePageStatus = () => { } const { folderId } = page.location; - if (!flp.canManageContent(folderId)) { + if (!canManageContent(folderId)) { return null; } diff --git a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDeletePage.tsx b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDeletePage.tsx index e06a04da33e..fc1672a286f 100644 --- a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDeletePage.tsx +++ b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDeletePage.tsx @@ -1,18 +1,19 @@ import React, { useMemo } from "react"; import { usePage } from "~/admin/views/Pages/hooks/usePage"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { DeletePage } from "./DeletePage"; export const SecureDeletePage = () => { const { page } = usePage(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { canDelete: pagesCanDelete } = usePagesPermissions(); const { folderId } = page.location; const canDelete = useMemo(() => { - return pagesCanDelete(page.data.createdBy.id) && flp.canManageContent(folderId); - }, [flp, folderId]); + return pagesCanDelete(page.data.createdBy.id) && canManageContent(folderId); + }, [canManageContent, folderId]); if (!canDelete) { return null; diff --git a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDuplicatePage.tsx b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDuplicatePage.tsx index 9af2fdbcbe0..c894783d806 100644 --- a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDuplicatePage.tsx +++ b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureDuplicatePage.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { usePagesPermissions } from "~/hooks/permissions"; import { usePage } from "~/admin/views/Pages/hooks/usePage"; import { DuplicatePage } from "./DuplicatePage"; @@ -7,14 +7,15 @@ import { DuplicatePage } from "./DuplicatePage"; export const SecureDuplicatePage = DuplicatePage.createDecorator(Original => { return function SecureDuplicatePageRenderer() { const { page } = usePage(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { canWrite: pagesCanWrite } = usePagesPermissions(); const { folderId } = page.location; const canDuplicate = useMemo(() => { - return pagesCanWrite(page.data.createdBy.id) && flp.canManageContent(folderId); - }, [flp, folderId]); + return pagesCanWrite(page.data.createdBy.id) && canManageContent(folderId); + }, [canManageContent, folderId]); if (!canDuplicate) { return null; diff --git a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureEditPage.tsx b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureEditPage.tsx index e6a342f059e..79a4a7127d4 100644 --- a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureEditPage.tsx +++ b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureEditPage.tsx @@ -1,18 +1,19 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { usePage } from "~/admin/views/Pages/hooks/usePage"; import { usePagesPermissions } from "~/hooks/permissions"; import { EditPage } from "./EditPage"; export const SecureEditPage = () => { const { page } = usePage(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { canUpdate: pagesCanUpdate } = usePagesPermissions(); const { folderId } = page.location; const canEdit = useMemo(() => { - return pagesCanUpdate(page.data.createdBy.id) && flp.canManageContent(folderId); - }, [flp, folderId]); + return pagesCanUpdate(page.data.createdBy.id) && canManageContent(folderId); + }, [canManageContent, folderId]); if (!canEdit) { return null; diff --git a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureMovePage.tsx b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureMovePage.tsx index eece9aa980a..515a1c3bfeb 100644 --- a/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureMovePage.tsx +++ b/packages/app-page-builder/src/admin/components/Table/Table/Actions/SecureMovePage.tsx @@ -1,17 +1,17 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { usePage } from "~/admin/views/Pages/hooks/usePage"; import { MovePage } from "./MovePage"; export const SecureMovePage = () => { const { page } = usePage(); - - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { folderId } = page.location; const canMove = useMemo(() => { - return flp.canManageContent(folderId); - }, [flp, folderId]); + return canManageContent(folderId); + }, [canManageContent, folderId]); if (!canMove) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/header/deletePage/DeletePage.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/header/deletePage/DeletePage.tsx index 089fa129c45..7c7578f3b41 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/header/deletePage/DeletePage.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/header/deletePage/DeletePage.tsx @@ -4,7 +4,7 @@ import { Tooltip } from "@webiny/ui/Tooltip"; import { ReactComponent as DeleteIcon } from "~/admin/assets/delete.svg"; import { usePagesPermissions } from "~/hooks/permissions"; import { useDeletePage } from "~/admin/views/Pages/hooks/useDeletePage"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { makeDecoratable } from "@webiny/react-composition"; import { usePage } from "~/admin/views/Pages/PageDetails"; @@ -15,14 +15,15 @@ export interface DeletePageProps { const DeletePage = makeDecoratable("DeletePage", (props: DeletePageProps) => { const { onDelete } = props; const { page } = usePage(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { canDelete: pagesCanDelete } = usePagesPermissions(); const { openDialogDeletePage } = useDeletePage({ page, onDelete }); const folderId = page.wbyAco_location?.folderId; const canDelete = useMemo(() => { - return pagesCanDelete(page.createdBy?.id) && flp.canManageContent(folderId); - }, [flp, folderId]); + return pagesCanDelete(page.createdBy?.id) && canManageContent(folderId); + }, [canManageContent, folderId]); if (!canDelete) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/header/editRevision/EditRevision.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/header/editRevision/EditRevision.tsx index 889ada66ccf..f88a42b88d8 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/header/editRevision/EditRevision.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/header/editRevision/EditRevision.tsx @@ -9,7 +9,7 @@ import { i18n } from "@webiny/app/i18n"; import { useMutation } from "@apollo/react-hooks"; import { usePagesPermissions } from "~/hooks/permissions"; import { useNavigatePage } from "~/admin/hooks/useNavigatePage"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { usePage } from "~/admin/views/Pages/PageDetails"; import { makeDecoratable } from "@webiny/react-composition"; @@ -17,7 +17,8 @@ const t = i18n.ns("app-headless-cms/app-page-builder/page-details/header/edit"); const EditRevision = makeDecoratable("EditRevision", () => { const { canUpdate: pagesCanUpdate } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const [inProgress, setInProgress] = useState(); const { showSnackbar } = useSnackbar(); const [createPageFrom] = useMutation(CREATE_PAGE); @@ -46,8 +47,8 @@ const EditRevision = makeDecoratable("EditRevision", () => { const folderId = page.wbyAco_location?.folderId; const canEdit = useMemo(() => { - return pagesCanUpdate(page.createdBy?.id) && flp.canManageContent(folderId); - }, [flp, folderId]); + return pagesCanUpdate(page.createdBy?.id) && canManageContent(folderId); + }, [canManageContent, folderId]); if (!canEdit) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/DuplicatePage/SecureDuplicatePage.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/DuplicatePage/SecureDuplicatePage.tsx index 855a1d4b5ab..77245349ea4 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/DuplicatePage/SecureDuplicatePage.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/DuplicatePage/SecureDuplicatePage.tsx @@ -1,5 +1,5 @@ import React, { useMemo } from "react"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { usePage } from "~/admin/views/Pages/PageDetails"; import { usePagesPermissions } from "~/hooks/permissions"; import { DuplicatePage } from "./DuplicatePage"; @@ -7,7 +7,8 @@ import { DuplicatePage } from "./DuplicatePage"; export const SecureDuplicatePage = DuplicatePage.createDecorator(Original => { return function SecurePageDetailsDuplicatePageRenderer() { const { page } = usePage(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { canWrite: pagesCanWrite } = usePagesPermissions(); const canDuplicate = useMemo(() => { @@ -17,10 +18,9 @@ export const SecureDuplicatePage = DuplicatePage.createDecorator(Original => { } return ( - pagesCanWrite(page.createdBy.id) && - flp.canManageContent(page.wbyAco_location.folderId) + pagesCanWrite(page.createdBy.id) && canManageContent(page.wbyAco_location.folderId) ); - }, [flp, page]); + }, [canManageContent, page]); if (!canDuplicate) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/PageOptionsMenu.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/PageOptionsMenu.tsx index 7fddcdaab67..0a55b4db39a 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/PageOptionsMenu.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/header/pageOptionsMenu/PageOptionsMenu.tsx @@ -21,7 +21,7 @@ import { plugins } from "@webiny/plugins"; import { PbPageData, PbPageDetailsHeaderRightOptionsMenuItemPlugin, PbPageTemplate } from "~/types"; import { SecureView } from "@webiny/app-security"; import { useAdminPageBuilder } from "~/admin/hooks/useAdminPageBuilder"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { useTemplatesPermissions } from "~/hooks/permissions"; import { PreviewPage } from "./PreviewPage"; import { DuplicatePage } from "./DuplicatePage"; @@ -84,13 +84,14 @@ const PageOptionsMenu = (props: PageOptionsMenuProps) => { [page] ); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { canCreate: templatesCanCreate } = useTemplatesPermissions(); const canCreateTemplate = templatesCanCreate(); const folderId = page.wbyAco_location?.folderId; - const flpCanManageContent = flp.canManageContent(folderId); + const flpCanManageContent = canManageContent(folderId); const isTemplatePage = page.content?.data?.template; return ( diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/header/publishRevision/PublishRevision.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/header/publishRevision/PublishRevision.tsx index 6c1b1c70926..73f7988a011 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/header/publishRevision/PublishRevision.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/header/publishRevision/PublishRevision.tsx @@ -7,7 +7,7 @@ import { ReactComponent as PublishIcon } from "@material-design-icons/svg/round/ import { ReactComponent as UnpublishIcon } from "@material-design-icons/svg/round/settings_backup_restore.svg"; import { makeDecoratable } from "@webiny/app-admin"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { usePage } from "~/admin/views/Pages/PageDetails"; import { usePublishRevisionHandler } from "../../pageRevisions/usePublishRevisionHandler"; @@ -15,7 +15,8 @@ const t = i18n.ns("app-headless-cms/app-page-builder/page-details/header/publish const PublishRevision = () => { const { canPublish, canUnpublish, hasPermissions } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const { page } = usePage(); const { publishRevision, unpublishRevision } = usePublishRevisionHandler(); @@ -45,7 +46,7 @@ const PublishRevision = () => { }); const folderId = page.wbyAco_location?.folderId; - if (!hasPermissions() || !flp.canManageContent(folderId)) { + if (!hasPermissions() || !canManageContent(folderId)) { return null; } diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureDeleteRevisionMenuOption.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureDeleteRevisionMenuOption.tsx index cf50324561c..646a7e4fb44 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureDeleteRevisionMenuOption.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureDeleteRevisionMenuOption.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { DeleteRevisionMenuOption, @@ -10,14 +10,14 @@ import { export const SecureDeleteRevisionMenuOption = (props: DeleteRevisionMenuOptionProps) => { const { page } = props; const { canDelete: pagesCanDelete } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const hasAccess = useMemo(() => { return ( - pagesCanDelete(page?.createdBy?.id) && - flp.canManageContent(page.wbyAco_location?.folderId) + pagesCanDelete(page?.createdBy?.id) && canManageContent(page.wbyAco_location?.folderId) ); - }, [page]); + }, [page, canManageContent]); if (!hasAccess) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureEditRevisionMenuOption.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureEditRevisionMenuOption.tsx index 0e6bccc1f44..193e4de88a5 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureEditRevisionMenuOption.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureEditRevisionMenuOption.tsx @@ -1,20 +1,20 @@ import React, { useMemo } from "react"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { EditRevisionMenuOption, EditRevisionMenuOptionProps } from "./EditRevisionMenuOption"; export const SecureEditRevisionMenuOption = (props: EditRevisionMenuOptionProps) => { const { page } = props; const { canUpdate: pagesCanUpdate } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const hasAccess = useMemo(() => { return ( - pagesCanUpdate(page?.createdBy?.id) && - flp.canManageContent(page.wbyAco_location?.folderId) + pagesCanUpdate(page?.createdBy?.id) && canManageContent(page.wbyAco_location?.folderId) ); - }, [page]); + }, [page, canManageContent]); if (!hasAccess) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureNewRevisionFromCurrent.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureNewRevisionFromCurrent.tsx index 409fa88e58b..b0b02da0fb9 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureNewRevisionFromCurrent.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureNewRevisionFromCurrent.tsx @@ -1,17 +1,18 @@ import React, { useMemo } from "react"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { NewRevisionFromCurrent, NewRevisionFromCurrentProps } from "./NewRevisionFromCurrent"; export const SecureNewRevisionFromCurrent = (props: NewRevisionFromCurrentProps) => { const { page } = props; const { canCreate: pagesCanCreate } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const hasAccess = useMemo(() => { - return pagesCanCreate() && flp.canManageContent(page.wbyAco_location?.folderId); - }, [page]); + return pagesCanCreate() && canManageContent(page.wbyAco_location?.folderId); + }, [page, canManageContent]); if (!hasAccess) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecurePublishPageMenuOption.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecurePublishPageMenuOption.tsx index 90646e2cb29..9310ee05826 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecurePublishPageMenuOption.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecurePublishPageMenuOption.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { PublishPageMenuOptionProps, PublishPageMenuOption } from "./PublishPageMenuOption"; import { usePage } from "~/admin/views/Pages/PageDetails"; @@ -8,11 +8,12 @@ import { usePage } from "~/admin/views/Pages/PageDetails"; export const SecurePublishPageMenuOption = (props: PublishPageMenuOptionProps) => { const { page } = usePage(); const { canPublish: pagesCanPublish } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const hasAccess = useMemo(() => { - return pagesCanPublish() && flp.canManageContent(page.wbyAco_location?.folderId); - }, [page]); + return pagesCanPublish() && canManageContent(page.wbyAco_location?.folderId); + }, [page, canManageContent]); if (!hasAccess) { return null; diff --git a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureUnpublishPageMenuOption.tsx b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureUnpublishPageMenuOption.tsx index e5bd121e5a3..6e130ca81ce 100644 --- a/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureUnpublishPageMenuOption.tsx +++ b/packages/app-page-builder/src/admin/plugins/pageDetails/pageRevisions/MenuOptions/SecureUnpublishPageMenuOption.tsx @@ -1,17 +1,18 @@ import React, { useMemo } from "react"; import { usePagesPermissions } from "~/hooks/permissions"; -import { useFolders } from "@webiny/app-aco"; +import { useGetFolderLevelPermission } from "@webiny/app-aco"; import { UnpublishPageMenuOption, UnpublishPageMenuOptionProps } from "./UnpublishPageMenuOption"; export const SecureUnpublishPageMenuOption = (props: UnpublishPageMenuOptionProps) => { const { page } = props; const { canUnpublish: pagesCanUnpublish } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const hasAccess = useMemo(() => { - return pagesCanUnpublish() && flp.canManageContent(page.wbyAco_location?.folderId); - }, [page]); + return pagesCanUnpublish() && canManageContent(page.wbyAco_location?.folderId); + }, [page, canManageContent]); if (!hasAccess) { return null; diff --git a/packages/app-page-builder/src/admin/views/Pages/Table/Main.tsx b/packages/app-page-builder/src/admin/views/Pages/Table/Main.tsx index 4b87fa7c569..064b859e4fd 100644 --- a/packages/app-page-builder/src/admin/views/Pages/Table/Main.tsx +++ b/packages/app-page-builder/src/admin/views/Pages/Table/Main.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import debounce from "lodash/debounce"; import { i18n } from "@webiny/app/i18n"; -import { useCreateDialog, useFolders } from "@webiny/app-aco"; +import { useCreateDialog, useGetFolderLevelPermission } from "@webiny/app-aco"; import { CircularProgress } from "@webiny/ui/Progress"; import { Scrollbar } from "@webiny/ui/Scrollbar"; import CategoriesDialog from "~/admin/views/Categories/CategoriesDialog"; @@ -45,15 +45,18 @@ export const Main = ({ folderId: initialFolderId }: Props) => { // We check permissions on two layers - security and folder level permissions. const { canCreate } = usePagesPermissions(); - const { folderLevelPermissions: flp } = useFolders(); + const { getFolderLevelPermission: canManageStructure } = + useGetFolderLevelPermission("canManageStructure"); + const { getFolderLevelPermission: canManageContent } = + useGetFolderLevelPermission("canManageContent"); const canCreateFolder = useMemo(() => { - return flp.canManageStructure(folderId); - }, [flp, folderId]); + return canManageStructure(folderId); + }, [canManageStructure, folderId]); const canCreateContent = useMemo(() => { - return canCreate() && flp.canManageContent(folderId); - }, [flp, folderId]); + return canCreate() && canManageContent(folderId); + }, [canManageContent, folderId]); const { innerHeight: windowHeight } = window; const [tableHeight, setTableHeight] = useState(0); From 226af4d507c7e36acb145992c5b21d112b0d5ba1 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 10 Jan 2025 16:06:50 +0100 Subject: [PATCH 27/28] fix: omit all inherited permissions --- .../folder/updateFolder/UpdateFolder.ts | 8 +++++++- ...olderUseCaseWithoutInheritedPermissions.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithoutInheritedPermissions.ts diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts index de17042b002..fec60dc8be8 100644 --- a/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolder.ts @@ -4,6 +4,7 @@ import { IUpdateFolderGateway } from "./IUpdateFolderGateway"; import { UpdateFolderRepository } from "./UpdateFolderRepository"; import { UpdateFolderUseCase } from "./UpdateFolderUseCase"; import { UpdateFolderUseCaseWithLoading } from "./UpdateFolderUseCaseWithLoading"; +import { UpdateFolderUseCaseWithoutInheritedPermissions } from "./UpdateFolderUseCaseWithoutInheritedPermissions"; import { folderCacheFactory } from "../cache"; export class UpdateFolder { @@ -12,6 +13,11 @@ export class UpdateFolder { const loadingRepository = loadingRepositoryFactory.getRepository(type); const repository = new UpdateFolderRepository(foldersCache, gateway); const useCase = new UpdateFolderUseCase(repository); - return new UpdateFolderUseCaseWithLoading(loadingRepository, useCase); + const useCaseWithoutInheritedPermissions = + new UpdateFolderUseCaseWithoutInheritedPermissions(useCase); + return new UpdateFolderUseCaseWithLoading( + loadingRepository, + useCaseWithoutInheritedPermissions + ); } } diff --git a/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithoutInheritedPermissions.ts b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithoutInheritedPermissions.ts new file mode 100644 index 00000000000..02b75e371f3 --- /dev/null +++ b/packages/app-aco/src/features/folder/updateFolder/UpdateFolderUseCaseWithoutInheritedPermissions.ts @@ -0,0 +1,19 @@ +import { IUpdateFolderUseCase, UpdateFolderParams } from "./IUpdateFolderUseCase"; + +export class UpdateFolderUseCaseWithoutInheritedPermissions implements IUpdateFolderUseCase { + private useCase: IUpdateFolderUseCase; + + constructor(useCase: IUpdateFolderUseCase) { + this.useCase = useCase; + } + + async execute(params: UpdateFolderParams) { + // We must omit all inherited permissions. + const permissions = params.permissions.filter(p => !p.inheritedFrom); + + await this.useCase.execute({ + ...params, + permissions + }); + } +} From 40a483d5a21a6a8c4951c7ca70eba2276e2adb60 Mon Sep 17 00:00:00 2001 From: Leonardo Giacone Date: Fri, 10 Jan 2025 16:54:35 +0100 Subject: [PATCH 28/28] refactor: add listing params --- .../folder/listFolders/FolderGqlDto.ts | 20 ++++++++++++++++++ .../folder/listFolders/IListFoldersGateway.ts | 21 +++---------------- .../listFolders/ListFoldersGqlGateway.ts | 6 +++--- .../listFolders/ListFoldersRepository.ts | 2 +- 4 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 packages/app-aco/src/features/folder/listFolders/FolderGqlDto.ts diff --git a/packages/app-aco/src/features/folder/listFolders/FolderGqlDto.ts b/packages/app-aco/src/features/folder/listFolders/FolderGqlDto.ts new file mode 100644 index 00000000000..0d2ff62504c --- /dev/null +++ b/packages/app-aco/src/features/folder/listFolders/FolderGqlDto.ts @@ -0,0 +1,20 @@ +import { CmsIdentity, FolderPermission } from "~/types"; + +export interface FolderGqlDto { + id: string; + title: string; + slug: string; + permissions: FolderPermission[]; + hasNonInheritedPermissions: boolean; + canManagePermissions: boolean; + canManageStructure: boolean; + canManageContent: boolean; + type: string; + parentId: string | null; + createdBy: CmsIdentity; + createdOn: string; + savedBy: CmsIdentity; + savedOn: string; + modifiedBy: CmsIdentity | null; + modifiedOn: string | null; +} diff --git a/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts b/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts index 7e010d72607..f3806afb4aa 100644 --- a/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts +++ b/packages/app-aco/src/features/folder/listFolders/IListFoldersGateway.ts @@ -1,24 +1,9 @@ -import { CmsIdentity, FolderPermission } from "~/types"; +import { FolderGqlDto } from "./FolderGqlDto"; -export interface FolderDto { - id: string; - title: string; - slug: string; - permissions: FolderPermission[]; - hasNonInheritedPermissions: boolean; - canManagePermissions: boolean; - canManageStructure: boolean; - canManageContent: boolean; +export interface ListFoldersGatewayParams { type: string; - parentId: string | null; - createdBy: CmsIdentity; - createdOn: string; - savedBy: CmsIdentity; - savedOn: string; - modifiedBy: CmsIdentity | null; - modifiedOn: string | null; } export interface IListFoldersGateway { - execute: (type: string) => Promise; + execute: (params: ListFoldersGatewayParams) => Promise; } diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts index 5a301622a9e..7bfba60a75c 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersGqlGateway.ts @@ -1,6 +1,6 @@ import ApolloClient from "apollo-client"; import gql from "graphql-tag"; -import { IListFoldersGateway } from "./IListFoldersGateway"; +import { IListFoldersGateway, ListFoldersGatewayParams } from "./IListFoldersGateway"; import { AcoError, FolderItem } from "~/types"; import { ROOT_FOLDER } from "~/constants"; @@ -72,14 +72,14 @@ export class ListFoldersGqlGateway implements IListFoldersGateway { this.client = client; } - async execute(type: string) { + async execute(params: ListFoldersGatewayParams) { const { data: response } = await this.client.query< ListFoldersResponse, ListFoldersQueryVariables >({ query: LIST_FOLDERS, variables: { - type, + ...params, limit: 10000 }, fetchPolicy: "network-only" diff --git a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts index 2b41cc5943d..ddec23543e5 100644 --- a/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts +++ b/packages/app-aco/src/features/folder/listFolders/ListFoldersRepository.ts @@ -15,7 +15,7 @@ export class ListFoldersRepository implements IListFoldersRepository { } async execute() { - const items = await this.gateway.execute(this.type); + const items = await this.gateway.execute({ type: this.type }); this.cache.clear(); this.cache.addItems(items.map(item => Folder.create(item))); }