From 70fc7c9619a1aedbfd71e304a843d7ddec2e1820 Mon Sep 17 00:00:00 2001 From: Ayobami Akingbade Date: Sun, 17 Dec 2023 16:06:50 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(data):=20improve?= =?UTF-8?q?=20data=20CRUD=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/data/data.controller.ts | 2 +- src/backend/data/data.service.ts | 50 +++++++++++-------- src/backend/data/portal/index.ts | 2 +- src/backend/data/portal/main.ts | 19 +++++++ src/backend/data/types.ts | 6 +-- .../user-preferences.controller.ts | 7 ++- .../user-preferences.service.ts | 4 +- .../components/Button/ActionButtons/index.tsx | 1 + .../components/Button/ActionButtons/types.ts | 1 + src/frontend/hooks/auth/preferences.store.ts | 2 +- src/frontend/hooks/data/constants.ts | 2 +- src/frontend/hooks/data/data.store.ts | 18 ++----- .../views/account/Preferences/index.tsx | 2 + .../views/account/Preferences/portal/index.ts | 1 + .../views/account/Preferences/portal/main.tsx | 3 ++ .../views/data/Details/DetailsView.tsx | 6 +-- .../views/data/Details/RelationsDetails.tsx | 3 +- src/frontend/views/data/Details/index.tsx | 3 +- .../views/data/Details/portal/index.ts | 6 ++- .../views/data/Details/portal/main.ts | 15 +++++- .../views/data/Table/useTableColumns.tsx | 8 +-- src/frontend/views/data/Update/index.tsx | 4 ++ .../views/data/Update/portal/index.ts | 1 + src/frontend/views/data/Update/portal/main.ts | 11 ++++ src/shared/user-preferences/portal/main.ts | 7 +-- 25 files changed, 120 insertions(+), 64 deletions(-) create mode 100644 src/frontend/views/account/Preferences/portal/index.ts create mode 100644 src/frontend/views/account/Preferences/portal/main.tsx create mode 100644 src/frontend/views/data/Update/portal/index.ts create mode 100644 src/frontend/views/data/Update/portal/main.ts diff --git a/src/backend/data/data.controller.ts b/src/backend/data/data.controller.ts index 7cb628e73..873e61cdc 100644 --- a/src/backend/data/data.controller.ts +++ b/src/backend/data/data.controller.ts @@ -36,7 +36,7 @@ export class DataApiController { queryFilters: QueryFilterSchema ): Promise<{ count: number }> { return { - count: await this._dataApiService.count(entity, queryFilters), + count: await this._dataApiService.countData(entity, queryFilters), }; } diff --git a/src/backend/data/data.service.ts b/src/backend/data/data.service.ts index 929911248..8bb680505 100644 --- a/src/backend/data/data.service.ts +++ b/src/backend/data/data.service.ts @@ -23,7 +23,7 @@ import { EntitiesApiService, entitiesApiService, } from "../entities/entities.service"; -import { PortalDataHooksService } from "./portal"; +import { PortalDataHooksService, PortalQueryImplementation } from "./portal"; import { makeTableData } from "./utils"; const DEFAULT_LIST_LIMIT = 50; @@ -46,7 +46,7 @@ export class DataApiService implements IDataApiService { return this._rDBMSApiDataService; } - async list( + async fetchData( entity: string, select: string[], queryFilter: QueryFilterSchema, @@ -55,12 +55,22 @@ export class DataApiService implements IDataApiService { return await this.getDataAccessInstance().list( entity, select, - queryFilter, // + await PortalQueryImplementation.query(queryFilter, entity), paginationFilters ); } - async read( + async countData( + entity: string, + queryFilter: QueryFilterSchema + ): Promise { + return await this.getDataAccessInstance().count( + entity, + await PortalQueryImplementation.query(queryFilter, entity) + ); + } + + async readData( entity: string, select: string[], query: Record @@ -78,7 +88,7 @@ export class DataApiService implements IDataApiService { this._entitiesApiService.getEntityPrimaryField(entity), ]); - const data = await this.read>( + const data = await this.readData>( entity, relationshipSettings.fields, { @@ -98,12 +108,11 @@ export class DataApiService implements IDataApiService { this._entitiesApiService.getAllowedCrudsFieldsToShow(entity, "details"), column || this._entitiesApiService.getEntityPrimaryField(entity), ]); - const data = await this.read>( + const data = await this.readData>( entity, fieldsToShow, { [columnField]: id, - // } ); if (!data) { @@ -166,7 +175,7 @@ export class DataApiService implements IDataApiService { this._entitiesApiService.getEntityPrimaryField(entity), ]); - const data = await this.getDataAccessInstance().list( + const data = await this.fetchData( entity, [...relationshipSettings.fields, primaryField], { @@ -179,7 +188,6 @@ export class DataApiService implements IDataApiService { }, })), }, - // { take: DEFAULT_LIST_LIMIT, page: 1, @@ -188,7 +196,7 @@ export class DataApiService implements IDataApiService { return data.map((datum: Record) => { return { - value: datum[primaryField], + value: datum[primaryField] as string, label: compileTemplateString(relationshipSettings.format, datum), }; }); @@ -201,16 +209,16 @@ export class DataApiService implements IDataApiService { ): Promise>> { return makeTableData( await Promise.all([ - this.getDataAccessInstance().list( + this.fetchData( entity, await this._entitiesApiService.getAllowedCrudsFieldsToShow( entity, "table" ), - queryFilters, // + queryFilters, paginationFilters ), - this.getDataAccessInstance().count(entity, queryFilters), + this.countData(entity, queryFilters), ]), paginationFilters ); @@ -282,9 +290,15 @@ export class DataApiService implements IDataApiService { dataId: id, }); - await this.getDataAccessInstance().delete(entity, { - [await this._entitiesApiService.getEntityPrimaryField(entity)]: id, - }); // + await PortalQueryImplementation.delete({ + entity, + id, + implementation: async () => { + await this.getDataAccessInstance().delete(entity, { + [await this._entitiesApiService.getEntityPrimaryField(entity)]: id, + }); + }, + }); await PortalDataHooksService.afterDelete({ beforeData, @@ -294,10 +308,6 @@ export class DataApiService implements IDataApiService { }); } - async count(entity: string, queryFilter: QueryFilterSchema): Promise { - return await this.getDataAccessInstance().count(entity, queryFilter); // - } - private async getRelationshipSettings(entity: string): Promise<{ format: string; fields: string[]; diff --git a/src/backend/data/portal/index.ts b/src/backend/data/portal/index.ts index fb0ecbe18..09d1020d2 100644 --- a/src/backend/data/portal/index.ts +++ b/src/backend/data/portal/index.ts @@ -1 +1 @@ -export { PortalDataHooksService } from "./main"; +export { PortalDataHooksService, PortalQueryImplementation } from "./main"; diff --git a/src/backend/data/portal/main.ts b/src/backend/data/portal/main.ts index 6ba5e4f7e..da5f37d74 100644 --- a/src/backend/data/portal/main.ts +++ b/src/backend/data/portal/main.ts @@ -1,5 +1,6 @@ /* eslint-disable max-classes-per-file */ import { noop } from "shared/lib/noop"; +import { QueryFilterSchema } from "shared/types/data"; import { IDataApiService } from "../types"; export class PortalDataHooksService { @@ -86,3 +87,21 @@ export class PortalDataHooksService { noop(dataApiService, entity, dataId, beforeData); } } + +export class PortalQueryImplementation { + static async delete(params: { + id: string; + entity: string; + implementation: () => Promise; + }) { + noop(params); + } + + static async query( + queryFilter: QueryFilterSchema, + entity: string + ): Promise { + noop(entity); + return queryFilter; + } +} diff --git a/src/backend/data/types.ts b/src/backend/data/types.ts index a9f2e9e35..0ec2e0a60 100644 --- a/src/backend/data/types.ts +++ b/src/backend/data/types.ts @@ -12,20 +12,20 @@ export interface IPaginationFilters { export const FOR_CODE_COV = 1; export interface IDataApiService extends IApplicationService { - list( + fetchData( entity: string, select: string[], queryFilter: QueryFilterSchema, dataFetchingModifiers: IPaginationFilters ): Promise[]>; - read( + readData( entity: string, select: string[], query: Record ): Promise>; - count(entity: string, queryFilter: QueryFilterSchema): Promise; + countData(entity: string, queryFilter: QueryFilterSchema): Promise; create( entity: string, diff --git a/src/backend/user-preferences/user-preferences.controller.ts b/src/backend/user-preferences/user-preferences.controller.ts index dedd71704..b7f35d13d 100644 --- a/src/backend/user-preferences/user-preferences.controller.ts +++ b/src/backend/user-preferences/user-preferences.controller.ts @@ -1,6 +1,7 @@ import { USER_PREFERENCES_CONFIG, UserPreferencesKeys, + UserPreferencesValueType, } from "shared/user-preferences/constants"; import { BadRequestError } from "backend/lib/errors"; import { @@ -20,7 +21,11 @@ export class UserPreferenceApiController { }; } - async upsert(username: string, key: string, value: unknown) { + async upsert( + username: string, + key: T, + value: UserPreferencesValueType + ) { await this._userPreferencesApiService.upsert( username, this.validateUserPreferencesKeys(key), diff --git a/src/backend/user-preferences/user-preferences.service.ts b/src/backend/user-preferences/user-preferences.service.ts index 732adbd87..b121f5615 100644 --- a/src/backend/user-preferences/user-preferences.service.ts +++ b/src/backend/user-preferences/user-preferences.service.ts @@ -43,10 +43,10 @@ export class UserPreferencesApiService implements IApplicationService { ); if (value) { - return value as T; + return value as UserPreferencesValueType; } - return USER_PREFERENCES_CONFIG[key].defaultValue as T; + return USER_PREFERENCES_CONFIG[key].defaultValue; } async upsert( diff --git a/src/frontend/design-system/components/Button/ActionButtons/index.tsx b/src/frontend/design-system/components/Button/ActionButtons/index.tsx index 4261666b0..87f8f9a45 100644 --- a/src/frontend/design-system/components/Button/ActionButtons/index.tsx +++ b/src/frontend/design-system/components/Button/ActionButtons/index.tsx @@ -24,6 +24,7 @@ export function ActionButtons({ action={actionButton.action} label={actionButton.label} justIcon={justIcons} + isMakingActionRequest={actionButton.isMakingActionRequest} icon={actionButton.icon} /> ) : ( diff --git a/src/frontend/design-system/components/Button/ActionButtons/types.ts b/src/frontend/design-system/components/Button/ActionButtons/types.ts index c1f97c2b8..8f60dfa5f 100644 --- a/src/frontend/design-system/components/Button/ActionButtons/types.ts +++ b/src/frontend/design-system/components/Button/ActionButtons/types.ts @@ -5,6 +5,7 @@ export type IActionButton = _type: "normal"; action: string | (() => void); label: string; + isMakingActionRequest?: boolean; icon: ButtonIconTypes; order?: number; } diff --git a/src/frontend/hooks/auth/preferences.store.ts b/src/frontend/hooks/auth/preferences.store.ts index 0451baa55..0c2bf3fd5 100644 --- a/src/frontend/hooks/auth/preferences.store.ts +++ b/src/frontend/hooks/auth/preferences.store.ts @@ -34,7 +34,7 @@ export function useUserPreference(key: T) { enabled: isAuthenticated === true, returnUndefinedOnError: true, errorMessage: MAKE_USER_PREFERENCE_CRUD_CONFIG(key).TEXT_LANG.NOT_FOUND, - defaultData: USER_PREFERENCES_CONFIG[key].defaultValue as T, + defaultData: USER_PREFERENCES_CONFIG[key].defaultValue, selector: (data) => data.data, } ); diff --git a/src/frontend/hooks/data/constants.ts b/src/frontend/hooks/data/constants.ts index 355db9fd1..cd89086bf 100644 --- a/src/frontend/hooks/data/constants.ts +++ b/src/frontend/hooks/data/constants.ts @@ -24,7 +24,7 @@ export const ENTITY_REFERENCE_PATH = (entity: string, id: string) => export const ENTITY_LIST_PATH = (entity: string) => `/api/data/${entity}/list`; -export const CREATE_DATA_ENDPOINT_TO_CLEAR = (entity: string) => [ +export const DATA_MUTATION_ENDPOINTS_TO_CLEAR = (entity: string) => [ ENTITY_TABLE_PATH(entity), ENTITY_COUNT_PATH(entity), ENTITY_LIST_PATH(entity), diff --git a/src/frontend/hooks/data/data.store.ts b/src/frontend/hooks/data/data.store.ts index 61130dfef..0f5186e51 100644 --- a/src/frontend/hooks/data/data.store.ts +++ b/src/frontend/hooks/data/data.store.ts @@ -13,14 +13,11 @@ import { DataStates } from "frontend/lib/data/types"; import { useEntityCrudConfig } from "../entity/entity.config"; import { useMultipleEntityReferenceFields } from "../entity/entity.store"; import { isRouterParamEnabled } from ".."; -import { DATA_MUTATION_QUERY_ENDPOINTS } from "./portal"; import { - CREATE_DATA_ENDPOINT_TO_CLEAR, + DATA_MUTATION_ENDPOINTS_TO_CLEAR, ENTITY_COUNT_PATH, ENTITY_DETAILS_PATH, - ENTITY_LIST_PATH, ENTITY_REFERENCE_PATH, - ENTITY_TABLE_PATH, } from "./constants"; export const useEntityDataDetails = ({ @@ -142,7 +139,7 @@ export function useEntityDataCreationMutation(entity: string) { const apiMutateOptions = useWaitForResponseMutationOptions< Record >({ - endpoints: CREATE_DATA_ENDPOINT_TO_CLEAR(entity), + endpoints: DATA_MUTATION_ENDPOINTS_TO_CLEAR(entity), smartSuccessMessage: ({ id }) => ({ message: entityCrudConfig.MUTATION_LANG.CREATE, action: { @@ -165,10 +162,8 @@ export function useEntityDataUpdationMutation(entity: string, id: string) { Record >({ endpoints: [ - ENTITY_TABLE_PATH(entity), ENTITY_DETAILS_PATH(entity, id), - ENTITY_LIST_PATH(entity), - ...DATA_MUTATION_QUERY_ENDPOINTS(entity), + ...DATA_MUTATION_ENDPOINTS_TO_CLEAR(entity), ], successMessage: entityCrudConfig.MUTATION_LANG.EDIT, }); @@ -189,12 +184,7 @@ export function useEntityDataDeletionMutation( const apiMutateOptions = useWaitForResponseMutationOptions< Record >({ - endpoints: [ - ENTITY_TABLE_PATH(entity), - ENTITY_COUNT_PATH(entity), - ENTITY_LIST_PATH(entity), - ...DATA_MUTATION_QUERY_ENDPOINTS(entity), - ], + endpoints: DATA_MUTATION_ENDPOINTS_TO_CLEAR(entity), onSuccessActionWithFormData: () => { if (redirectTo) { router.replace(redirectTo); diff --git a/src/frontend/views/account/Preferences/index.tsx b/src/frontend/views/account/Preferences/index.tsx index a94d42323..907f90cad 100644 --- a/src/frontend/views/account/Preferences/index.tsx +++ b/src/frontend/views/account/Preferences/index.tsx @@ -23,6 +23,7 @@ import { UPDATE_USER_PREFERENCES_FORM_SCHEMA, } from "./constants"; import { IUserPreferences } from "./types"; +import { PortalUserPreferences } from "./portal"; export function UserPreferences() { const userPreferences = useUserPreference("theme"); @@ -68,6 +69,7 @@ export function UserPreferences() { /> + ); } diff --git a/src/frontend/views/account/Preferences/portal/index.ts b/src/frontend/views/account/Preferences/portal/index.ts new file mode 100644 index 000000000..fe12595a6 --- /dev/null +++ b/src/frontend/views/account/Preferences/portal/index.ts @@ -0,0 +1 @@ +export { PortalUserPreferences } from "./main"; diff --git a/src/frontend/views/account/Preferences/portal/main.tsx b/src/frontend/views/account/Preferences/portal/main.tsx new file mode 100644 index 000000000..6683aec0c --- /dev/null +++ b/src/frontend/views/account/Preferences/portal/main.tsx @@ -0,0 +1,3 @@ +export function PortalUserPreferences() { + return null; +} diff --git a/src/frontend/views/data/Details/DetailsView.tsx b/src/frontend/views/data/Details/DetailsView.tsx index 9d94ad0b6..2f5fcb440 100644 --- a/src/frontend/views/data/Details/DetailsView.tsx +++ b/src/frontend/views/data/Details/DetailsView.tsx @@ -25,6 +25,7 @@ import { filterOutHiddenScalarColumns } from "../utils"; import { useEntityViewStateMachine } from "../useEntityViewStateMachine"; import { viewSpecialDataTypes } from "../viewSpecialDataTypes"; import { evalutePresentationScript } from "../evaluatePresentationScript"; +import { PreDataDetails } from "./portal"; const ContentText = styled(Typo.SM)` overflow-wrap: anywhere; @@ -34,14 +35,12 @@ export function EntityDetailsView({ id, entity, displayFrom, - column, }: { id: string; entity: string; displayFrom: "details" | "canvas"; - column?: string; }) { - const dataDetails = useEntityDataDetails({ entity, entityId: id, column }); + const dataDetails = useEntityDataDetails({ entity, entityId: id }); const entityFields = useEntityFields(entity); const entityFieldTypes = useProcessedEntityFieldTypes(entity); const hiddenDetailsColumns = useHiddenEntityColumns("details", entity); @@ -96,6 +95,7 @@ export function EntityDetailsView({ } > +
{filterOutHiddenScalarColumns( entityFields.data, diff --git a/src/frontend/views/data/Details/RelationsDetails.tsx b/src/frontend/views/data/Details/RelationsDetails.tsx index 6609fcccf..e25175a15 100644 --- a/src/frontend/views/data/Details/RelationsDetails.tsx +++ b/src/frontend/views/data/Details/RelationsDetails.tsx @@ -133,9 +133,8 @@ export function EntityRelationDetails() { > )} diff --git a/src/frontend/views/data/Details/index.tsx b/src/frontend/views/data/Details/index.tsx index 1163f4ac2..f76dd5c6f 100644 --- a/src/frontend/views/data/Details/index.tsx +++ b/src/frontend/views/data/Details/index.tsx @@ -44,6 +44,7 @@ export function EntityDetails() { const portalActionButtons = usePortalActionButtons({ entity, entityId: id, + baseActionButtons: actionButtons, }); return ( @@ -55,7 +56,7 @@ export function EntityDetails() { diff --git a/src/frontend/views/data/Details/portal/index.ts b/src/frontend/views/data/Details/portal/index.ts index b4bcfa88d..1c249109c 100644 --- a/src/frontend/views/data/Details/portal/index.ts +++ b/src/frontend/views/data/Details/portal/index.ts @@ -1 +1,5 @@ -export { useDetailsViewMenuItems, usePortalActionButtons } from "./main"; +export { + useDetailsViewMenuItems, + usePortalActionButtons, + PreDataDetails, +} from "./main"; diff --git a/src/frontend/views/data/Details/portal/main.ts b/src/frontend/views/data/Details/portal/main.ts index 127b6561b..cba28d9b9 100644 --- a/src/frontend/views/data/Details/portal/main.ts +++ b/src/frontend/views/data/Details/portal/main.ts @@ -16,10 +16,23 @@ export const useDetailsViewMenuItems = ({ export const usePortalActionButtons = ({ entity, entityId, + baseActionButtons, }: { entity: string; entityId: string; + baseActionButtons: IActionButton[]; }): IActionButton[] => { noop(entity, entityId); - return []; + return baseActionButtons; }; + +export function PreDataDetails({ + entity, + entityId, +}: { + entity: string; + entityId: string; +}) { + noop(entity, entityId); + return null; +} diff --git a/src/frontend/views/data/Table/useTableColumns.tsx b/src/frontend/views/data/Table/useTableColumns.tsx index 21b48031b..cb633d2df 100644 --- a/src/frontend/views/data/Table/useTableColumns.tsx +++ b/src/frontend/views/data/Table/useTableColumns.tsx @@ -52,14 +52,10 @@ function TableActionButtons({ const portalActionButtons = usePortalActionButtons({ entity, entityId: idValue, + baseActionButtons: actionButtons, }); - return ( - - ); + return ; } const buildFilterConfigFromType = (prop: { diff --git a/src/frontend/views/data/Update/index.tsx b/src/frontend/views/data/Update/index.tsx index bfa6716c7..ba8784b7b 100644 --- a/src/frontend/views/data/Update/index.tsx +++ b/src/frontend/views/data/Update/index.tsx @@ -20,10 +20,14 @@ import { useEntityActionMenuItems, } from "../../entity/constants"; import { BaseEntityForm } from "../_BaseEntityForm"; +import { useDataUpdateActions } from "./portal"; export function EntityUpdate() { const entityId = useEntityId(); const entity = useEntitySlug(); + + useDataUpdateActions({ entity, entityId }); + const entityCrudConfig = useEntityCrudConfig(); const entityDataUpdationMutation = useEntityDataUpdationMutation( diff --git a/src/frontend/views/data/Update/portal/index.ts b/src/frontend/views/data/Update/portal/index.ts new file mode 100644 index 000000000..b39f5cacb --- /dev/null +++ b/src/frontend/views/data/Update/portal/index.ts @@ -0,0 +1 @@ +export { useDataUpdateActions } from "./main"; diff --git a/src/frontend/views/data/Update/portal/main.ts b/src/frontend/views/data/Update/portal/main.ts new file mode 100644 index 000000000..af6ec174a --- /dev/null +++ b/src/frontend/views/data/Update/portal/main.ts @@ -0,0 +1,11 @@ +import { noop } from "shared/lib/noop"; + +export function useDataUpdateActions({ + entity, + entityId, +}: { + entityId: string; + entity: string; +}) { + noop(entity, entityId); +} diff --git a/src/shared/user-preferences/portal/main.ts b/src/shared/user-preferences/portal/main.ts index 833f52b0d..225b93eff 100644 --- a/src/shared/user-preferences/portal/main.ts +++ b/src/shared/user-preferences/portal/main.ts @@ -1,11 +1,6 @@ -import { IUserPreferencesBag } from "../types"; - export type PortalUserPreferencesKeys = ""; -export const PORTAL_CONFIGURATION_KEYS: Record< - PortalUserPreferencesKeys, - IUserPreferencesBag -> = { +export const PORTAL_CONFIGURATION_KEYS = { "": { defaultValue: "", label: "",