diff --git a/src/backend/data/portal/main.ts b/src/backend/data/portal/main.ts index da5f37d74..31d90f871 100644 --- a/src/backend/data/portal/main.ts +++ b/src/backend/data/portal/main.ts @@ -94,7 +94,7 @@ export class PortalQueryImplementation { entity: string; implementation: () => Promise; }) { - noop(params); + await params.implementation(); } static async query( diff --git a/src/frontend/docs/scripts/form-scripts.tsx b/src/frontend/docs/scripts/form-scripts.tsx index 7b80a9bb0..2b76d4396 100644 --- a/src/frontend/docs/scripts/form-scripts.tsx +++ b/src/frontend/docs/scripts/form-scripts.tsx @@ -215,9 +215,7 @@ You can compute fields to save */ return { ...$.formValues, - slug: $.formValues.title - .replaceAll(" ", "-") - .toLowerCase() + slug: $.formValues.title?.replaceAll(" ", "-").toLowerCase() }`} /> diff --git a/src/frontend/hooks/data/constants.ts b/src/frontend/hooks/data/constants.ts index cd89086bf..d4cedf02b 100644 --- a/src/frontend/hooks/data/constants.ts +++ b/src/frontend/hooks/data/constants.ts @@ -1,4 +1,7 @@ -import { DATA_MUTATION_QUERY_ENDPOINTS } from "./portal"; +import { + DATA_MUTATION_QUERY_ENDPOINTS, + SINGLE_DATA_MUTATION_QUERY_ENDPOINTS, +} from "./portal"; export const ENTITY_TABLE_PATH = (entity: string) => `/api/data/${entity}/table`; @@ -6,12 +9,16 @@ export const ENTITY_TABLE_PATH = (entity: string) => export const ENTITY_COUNT_PATH = (entity: string) => `/api/data/${entity}/count`; -export const ENTITY_DETAILS_PATH = ( - entity: string, - id: string, - column?: string -) => { - const baseLink = `/api/data/${entity}/${id}`; +export const ENTITY_DETAILS_PATH = ({ + entity, + entityId, + column, +}: { + entity: string; + entityId: string; + column?: string; +}) => { + const baseLink = `/api/data/${entity}/${entityId}`; if (column) { return `${baseLink}?column=${column}`; @@ -19,11 +26,25 @@ export const ENTITY_DETAILS_PATH = ( return baseLink; }; -export const ENTITY_REFERENCE_PATH = (entity: string, id: string) => - `/api/data/${entity}/${id}/reference`; +export const ENTITY_REFERENCE_PATH = ({ + entity, + entityId, +}: { + entity: string; + entityId: string; +}) => `/api/data/${entity}/${entityId}/reference`; export const ENTITY_LIST_PATH = (entity: string) => `/api/data/${entity}/list`; +export const SINGLE_DATA_MUTATION_ENDPOINTS_TO_CLEAR = (params: { + entity: string; + entityId: string; +}) => [ + ENTITY_REFERENCE_PATH(params), + ENTITY_DETAILS_PATH(params), + ...SINGLE_DATA_MUTATION_QUERY_ENDPOINTS(params), +]; + export const DATA_MUTATION_ENDPOINTS_TO_CLEAR = (entity: string) => [ ENTITY_TABLE_PATH(entity), ENTITY_COUNT_PATH(entity), diff --git a/src/frontend/hooks/data/data.store.ts b/src/frontend/hooks/data/data.store.ts index 0f5186e51..92812590a 100644 --- a/src/frontend/hooks/data/data.store.ts +++ b/src/frontend/hooks/data/data.store.ts @@ -18,6 +18,7 @@ import { ENTITY_COUNT_PATH, ENTITY_DETAILS_PATH, ENTITY_REFERENCE_PATH, + SINGLE_DATA_MUTATION_ENDPOINTS_TO_CLEAR, } from "./constants"; export const useEntityDataDetails = ({ @@ -32,7 +33,7 @@ export const useEntityDataDetails = ({ const entityCrudConfig = useEntityCrudConfig(entity); return useApi>( - ENTITY_DETAILS_PATH(entity, entityId, column), + ENTITY_DETAILS_PATH({ entity, entityId, column }), { errorMessage: entityCrudConfig.TEXT_LANG.NOT_FOUND, enabled: @@ -126,10 +127,10 @@ export const useEntityReferenceCount = ( }); }; -export const useEntityDataReference = (entity: string, id: string) => { - return useApi(ENTITY_REFERENCE_PATH(entity, id), { +export const useEntityDataReference = (entity: string, entityId: string) => { + return useApi(ENTITY_REFERENCE_PATH({ entity, entityId }), { errorMessage: CRUD_CONFIG_NOT_FOUND("Reference data"), - enabled: isRouterParamEnabled(id) && isRouterParamEnabled(entity), + enabled: isRouterParamEnabled(entityId) && isRouterParamEnabled(entity), defaultData: "", }); }; @@ -156,13 +157,16 @@ export function useEntityDataCreationMutation(entity: string) { ); } -export function useEntityDataUpdationMutation(entity: string, id: string) { +export function useEntityDataUpdationMutation( + entity: string, + entityId: string +) { const entityCrudConfig = useEntityCrudConfig(); const apiMutateOptions = useWaitForResponseMutationOptions< Record >({ endpoints: [ - ENTITY_DETAILS_PATH(entity, id), + ...SINGLE_DATA_MUTATION_ENDPOINTS_TO_CLEAR({ entity, entityId }), ...DATA_MUTATION_ENDPOINTS_TO_CLEAR(entity), ], successMessage: entityCrudConfig.MUTATION_LANG.EDIT, @@ -170,13 +174,21 @@ export function useEntityDataUpdationMutation(entity: string, id: string) { return useMutation( async (data: Record) => - await makeActionRequest("PATCH", `/api/data/${entity}/${id}`, { data }), + await makeActionRequest("PATCH", `/api/data/${entity}/${entityId}`, { + data, + }), apiMutateOptions ); } export function useEntityDataDeletionMutation( - entity: string, + { + entity, + entityId, + }: { + entityId: string; + entity: string; + }, redirectTo?: string ) { const router = useRouter(); @@ -184,7 +196,10 @@ export function useEntityDataDeletionMutation( const apiMutateOptions = useWaitForResponseMutationOptions< Record >({ - endpoints: DATA_MUTATION_ENDPOINTS_TO_CLEAR(entity), + endpoints: [ + ...SINGLE_DATA_MUTATION_ENDPOINTS_TO_CLEAR({ entity, entityId }), + ...DATA_MUTATION_ENDPOINTS_TO_CLEAR(entity), + ], onSuccessActionWithFormData: () => { if (redirectTo) { router.replace(redirectTo); diff --git a/src/frontend/hooks/data/portal/index.ts b/src/frontend/hooks/data/portal/index.ts index a8454a19f..196806a72 100644 --- a/src/frontend/hooks/data/portal/index.ts +++ b/src/frontend/hooks/data/portal/index.ts @@ -1 +1,4 @@ -export { DATA_MUTATION_QUERY_ENDPOINTS } from "./main"; +export { + DATA_MUTATION_QUERY_ENDPOINTS, + SINGLE_DATA_MUTATION_QUERY_ENDPOINTS, +} from "./main"; diff --git a/src/frontend/hooks/data/portal/main.ts b/src/frontend/hooks/data/portal/main.ts index 0b0ff00cd..5921ca7a3 100644 --- a/src/frontend/hooks/data/portal/main.ts +++ b/src/frontend/hooks/data/portal/main.ts @@ -4,3 +4,11 @@ export const DATA_MUTATION_QUERY_ENDPOINTS = (entity: string) => { noop(entity); return []; }; + +export const SINGLE_DATA_MUTATION_QUERY_ENDPOINTS = (params: { + entity: string; + entityId: string; +}) => { + noop(params); + return []; +}; diff --git a/src/frontend/lib/toast/index.tsx b/src/frontend/lib/toast/index.tsx index 289ffbc23..178d2a563 100644 --- a/src/frontend/lib/toast/index.tsx +++ b/src/frontend/lib/toast/index.tsx @@ -49,6 +49,7 @@ export const ToastService = { toast.success((t) => , { style: toastStyle("success"), duration: 7000, + id: message, }); return; } @@ -88,16 +89,17 @@ export const ToastService = { { style: toastStyle("success"), duration: 7000, + id: message.message, } ); }, - error: (message: unknown) => - toast.error( - (t) => , - { - style: toastStyle("danger"), - duration: 7000, - } - ), + error: (message: unknown) => { + const errorMessage = getBestErrorMessage(message); + toast.error((t) => , { + style: toastStyle("danger"), + duration: 7000, + id: errorMessage, + }); + }, }; diff --git a/src/frontend/views/data/Details/RelationsDetails.tsx b/src/frontend/views/data/Details/RelationsDetails.tsx index e25175a15..d1e37935e 100644 --- a/src/frontend/views/data/Details/RelationsDetails.tsx +++ b/src/frontend/views/data/Details/RelationsDetails.tsx @@ -27,6 +27,7 @@ import { EntityDetailsView } from "./DetailsView"; import { DetailsLayout } from "./_Layout"; import { DetailsCanvas } from "../Table/_WholeEntityTable/DetailsCanvas"; import { useEntityActionButtons } from "../useEntityActionButtons"; +import { usePortalActionButtons } from "./portal"; export function EntityRelationDetails() { const childEntity = useRouteParam("childEntity"); @@ -80,10 +81,16 @@ export function EntityRelationDetails() { const actionButtons = useEntityActionButtons({ entity: childEntity, - id: idData, + entityId: idData, exclude: ["delete"], }); + const portalActionButtons = usePortalActionButtons({ + entity: childEntity, + entityId: idData, + baseActionButtons: actionButtons, + }); + return ( - + diff --git a/src/frontend/views/data/Table/useTableColumns.tsx b/src/frontend/views/data/Table/useTableColumns.tsx index cb633d2df..9ca3d3eee 100644 --- a/src/frontend/views/data/Table/useTableColumns.tsx +++ b/src/frontend/views/data/Table/useTableColumns.tsx @@ -46,7 +46,7 @@ function TableActionButtons({ const actionButtons = useEntityActionButtons({ entity, - id: idValue, + entityId: idValue, }); const portalActionButtons = usePortalActionButtons({ @@ -121,7 +121,7 @@ export const useTableColumns = ( const actionButtons = useEntityActionButtons({ entity, - id: "doesnt-matter-any-value-will-do-here", + entityId: "doesnt-matter-any-value-will-do-here", }); const columnsToShow = useMemo(() => { diff --git a/src/frontend/views/data/buildAppliedSchemaFormConfig.ts b/src/frontend/views/data/buildAppliedSchemaFormConfig.ts index 3c3e32138..590ab6886 100644 --- a/src/frontend/views/data/buildAppliedSchemaFormConfig.ts +++ b/src/frontend/views/data/buildAppliedSchemaFormConfig.ts @@ -41,10 +41,10 @@ export const buildAppliedSchemaFormConfig = ( ? { listUrl: ENTITY_LIST_PATH(entityToOneReferenceFields[field]), referenceUrl: (value: string) => - ENTITY_REFERENCE_PATH( - entityToOneReferenceFields[field], - value - ), + ENTITY_REFERENCE_PATH({ + entity: entityToOneReferenceFields[field], + entityId: value, + }), } : undefined, type: entityFieldTypes[field], diff --git a/src/frontend/views/data/useEntityActionButtons.ts b/src/frontend/views/data/useEntityActionButtons.ts index 0f4e233b0..3e18491a1 100644 --- a/src/frontend/views/data/useEntityActionButtons.ts +++ b/src/frontend/views/data/useEntityActionButtons.ts @@ -8,18 +8,21 @@ import { export const useEntityActionButtons = ({ entity, - id, + entityId, redirectAfterDelete, exclude = [], }: { exclude?: CrudActionData[]; entity: string; - id: string; + entityId: string; redirectAfterDelete?: string; }): IActionButton[] => { const canUserPerformCrudAction = useCanUserPerformCrudAction(entity); const entityDataDeletionMutation = useEntityDataDeletionMutation( - entity, + { + entity, + entityId, + }, redirectAfterDelete ); const actionButtons: IActionButton[] = []; @@ -28,7 +31,7 @@ export const useEntityActionButtons = ({ actionButtons.push({ _type: "normal", icon: "eye", - action: NAVIGATION_LINKS.ENTITY.DETAILS(entity, id), + action: NAVIGATION_LINKS.ENTITY.DETAILS(entity, entityId), label: "Details", order: 10, }); @@ -38,7 +41,7 @@ export const useEntityActionButtons = ({ actionButtons.push({ _type: "normal", icon: "edit", - action: NAVIGATION_LINKS.ENTITY.UPDATE(entity, id), + action: NAVIGATION_LINKS.ENTITY.UPDATE(entity, entityId), label: "Edit", order: 20, }); @@ -47,10 +50,10 @@ export const useEntityActionButtons = ({ if (canUserPerformCrudAction("delete") && !exclude.includes("delete")) { actionButtons.push({ _type: "delete", - action: () => entityDataDeletionMutation.mutate(id), + action: () => entityDataDeletionMutation.mutate(entityId), isMakingDeleteRequest: entityDataDeletionMutation.isLoading && - entityDataDeletionMutation.variables === id, + entityDataDeletionMutation.variables === entityId, shouldConfirmAlert: true, order: 30, }); diff --git a/src/frontend/views/entity/Form/index.tsx b/src/frontend/views/entity/Form/index.tsx index d50ef635b..d609103e5 100644 --- a/src/frontend/views/entity/Form/index.tsx +++ b/src/frontend/views/entity/Form/index.tsx @@ -81,7 +81,7 @@ function useEntityFormView() { return { ...$.formValues, - slug: $.formValues.title.replaceAll(" ", "-").toLowerCase(), + slug: $.formValues.title?.replaceAll(" ", "-").toLowerCase(), createdById: JSON.parse($.auth.systemProfile).userId, createdAt: new Date(), }