@plumile/backoffice-react 0.1.200 → 0.1.201
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js.map +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/buildBreadcrumbs.js.map +1 -1
- package/lib/esm/components/backoffice/layout/sidebarUtils.js.map +1 -1
- package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js +1 -1
- package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js +1 -1
- package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailPage.helpers.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailPage.js +169 -169
- package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityListDataPage.js +1 -1
- package/lib/esm/pages/BackofficeEntityListDataPage.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityListPage.helpers.js.map +1 -1
- package/lib/esm/provider/entityRegistry.js +39 -36
- package/lib/esm/provider/entityRegistry.js.map +1 -1
- package/lib/esm/provider/useBackofficeAuthRouteGate.js +7 -7
- package/lib/esm/provider/useBackofficeAuthRouteGate.js.map +1 -1
- package/lib/esm/relay/createInlineReader.js.map +1 -1
- package/lib/esm/relay/envHelpers.js +30 -22
- package/lib/esm/relay/envHelpers.js.map +1 -1
- package/lib/esm/relay/typedRelayHooks.js +11 -2
- package/lib/esm/relay/typedRelayHooks.js.map +1 -1
- package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
- package/lib/types/components/backoffice/actions/BackofficeEntityActionFormDialog.d.ts +2 -2
- package/lib/types/components/backoffice/actions/BackofficeEntityActionFormDialog.d.ts.map +1 -1
- package/lib/types/components/backoffice/layout/sidebarUtils.d.ts.map +1 -1
- package/lib/types/components/backoffice/pickers/EntityIdPickerDialog.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityDetailPage.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityDetailPage.helpers.d.ts +3 -3
- package/lib/types/pages/BackofficeEntityDetailPage.helpers.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityListPage.helpers.d.ts +2 -2
- package/lib/types/pages/BackofficeEntityListPage.helpers.d.ts.map +1 -1
- package/lib/types/provider/entityRegistry.d.ts.map +1 -1
- package/lib/types/provider/types.d.ts +1 -1
- package/lib/types/provider/types.d.ts.map +1 -1
- package/lib/types/provider/useBackofficeAuthRouteGate.d.ts.map +1 -1
- package/lib/types/relay/createInlineReader.d.ts +4 -1
- package/lib/types/relay/createInlineReader.d.ts.map +1 -1
- package/lib/types/relay/envHelpers.d.ts.map +1 -1
- package/lib/types/relay/typedRelayHooks.d.ts +15 -5
- package/lib/types/relay/typedRelayHooks.d.ts.map +1 -1
- package/lib/types/router/createBackofficeRoutes.d.ts +1 -1
- package/lib/types/router/createBackofficeRoutes.d.ts.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeEntityDetailPage.js","names":[],"sources":["../../../src/pages/BackofficeEntityDetailPage.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { type JSX, type ReactNode, useContext, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n commitMutation,\n type PreloadedQuery,\n usePreloadedQuery,\n} from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\nimport { resolveMutationOutcome } from '../relay/mutationResult.js';\n\nimport { BACKOFFICE_DATE_TIME_OPTIONS } from '@plumile/backoffice-core/constants.js';\nimport type {\n BackofficePreparedDetailPageDataRoute,\n BackofficeResolvedDetailPageFacetConfig,\n} from '@plumile/backoffice-core/types.js';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { LinkButton } from '@plumile/ui/atomic/atoms/button/LinkButton.js';\nimport { FormattedDate } from '@plumile/ui/atomic/atoms/formatted-date/FormattedDate.js';\nimport { useToast } from '@plumile/ui/atomic/molecules/toast/ToastProvider.js';\nimport { Tag } from '@plumile/ui/backoffice/atoms/tag/Tag.js';\nimport { BackofficeDetailSection } from '@plumile/ui/backoffice/molecules/backoffice_detail_section/BackofficeDetailSection.js';\nimport { BackofficeKeyValueList } from '@plumile/ui/backoffice/molecules/backoffice_key_value_list/BackofficeKeyValueList.js';\nimport { BackofficePayloadViewer } from '@plumile/ui/backoffice/molecules/backoffice_payload_viewer/BackofficePayloadViewer.js';\nimport { BackofficeScopeStack } from '@plumile/ui/backoffice/molecules/backoffice_scope_stack/BackofficeScopeStack.js';\nimport { AuditTimeline } from '@plumile/ui/backoffice/organisms/audit_timeline/AuditTimeline.js';\nimport { MetricCard } from '@plumile/ui/components/dashboard/metric_card/MetricCard.js';\nimport { MetricTileGroup } from '@plumile/ui/components/dashboard/metric_tile_group/MetricTileGroup.js';\nimport { DataTable } from '@plumile/ui/components/data-table/DataTable.js';\nimport { ChatCheckSvg } from '@plumile/ui/icons/ChatCheckSvg.js';\nimport { KeyOffSvg } from '@plumile/ui/icons/KeyOffSvg.js';\nimport { KeySvg } from '@plumile/ui/icons/KeySvg.js';\nimport { LockOpenSvg } from '@plumile/ui/icons/LockOpenSvg.js';\nimport { LockSvg } from '@plumile/ui/icons/LockSvg.js';\nimport { RobotCheckSvg } from '@plumile/ui/icons/RobotCheckSvg.js';\nimport { RobotXSvg } from '@plumile/ui/icons/RobotXSvg.js';\nimport { RocketOffSvg } from '@plumile/ui/icons/RocketOffSvg.js';\nimport { RocketSvg } from '@plumile/ui/icons/RocketSvg.js';\nimport { SettingsCheckSvg } from '@plumile/ui/icons/SettingsCheckSvg.js';\nimport { SettingsXSvg } from '@plumile/ui/icons/SettingsXSvg.js';\nimport { ShieldLockSvg } from '@plumile/ui/icons/ShieldLockSvg.js';\nimport { ShieldOffSvg } from '@plumile/ui/icons/ShieldOffSvg.js';\nimport { XBadgeSvg } from '@plumile/ui/icons/XBadgeSvg.js';\nimport Link from '@plumile/router/routing/Link.js';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\n\nimport { buildDataTableColumns } from '../components/backoffice/columns/buildDataTableColumns.js';\nimport { BackofficeEntityDetailScaffold } from '../components/backoffice/scaffolds/BackofficeEntityDetailScaffold.js';\nimport { useBackofficeEntityDetailNotFoundState } from '../components/backoffice/scaffolds/BackofficeEntityDetailNotFound.js';\nimport { BackofficeDetailBadgeRow } from '../components/backoffice/detail/BackofficeDetailBadgeRow.js';\nimport { BackofficeDetailFlagTag } from '../components/backoffice/detail/BackofficeDetailFlagTag.js';\nimport { BackofficeDetailTaggedValue } from '../components/backoffice/detail/BackofficeDetailTaggedValue.js';\nimport { BackofficeLifecycleTimelineSection } from '../components/backoffice/detail/BackofficeLifecycleTimelineSection.js';\nimport { BackofficeRelationsSummaryGrid } from '../components/backoffice/detail/BackofficeRelationsSummaryGrid.js';\nimport * as detailLayoutStyles from '../components/backoffice/detail/backofficeDetailLayout.css.js';\nimport { LazyBackofficeEntityActionFormDialog } from '../components/backoffice/actions/LazyBackofficeEntityActionFormDialog.js';\nimport {\n resolveToastSpec,\n resolveToastViewActions,\n} from '../components/backoffice/actions/toastViewAction.js';\nimport * as pageStyles from './backofficeEntityDetailPage.css.js';\nimport { useBackofficeFormats } from '../i18n/useBackofficeFormats.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeFragment } from '../relay/typedRelayHooks.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport {\n extractMutationPayload,\n isFormMutationAction,\n isMutationAction,\n isRouteAction,\n resolveLabel,\n} from './BackofficeEntityDetailPage.helpers.js';\nimport {\n buildFieldItems,\n renderBlocks,\n type FlagIconName,\n} from './BackofficeEntityDetailPage.view-helpers.js';\n\nexport type BackofficeEntityDetailPageProps = {\n prepared: BackofficePreparedDetailPageDataRoute;\n};\n\nconst renderFlagIcon = (iconName: FlagIconName): JSX.Element => {\n const iconSize = 14;\n switch (iconName) {\n case 'shield-lock':\n return (\n <ShieldLockSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'shield-off':\n return (\n <ShieldOffSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'settings-check':\n return (\n <SettingsCheckSvg\n width={iconSize}\n height={iconSize}\n aria-hidden=\"true\"\n />\n );\n case 'settings-x':\n return (\n <SettingsXSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'x-badge':\n return (\n <XBadgeSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'chat-check':\n return (\n <ChatCheckSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'key':\n return <KeySvg width={iconSize} height={iconSize} aria-hidden=\"true\" />;\n case 'key-off':\n return (\n <KeyOffSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'lock':\n return <LockSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />;\n case 'lock-open':\n return (\n <LockOpenSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'robot-check':\n return (\n <RobotCheckSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'robot-x':\n return (\n <RobotXSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'rocket':\n return (\n <RocketSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'rocket-off':\n return (\n <RocketOffSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n default:\n throw new Error(`Unsupported flag icon: ${String(iconName)}`);\n }\n};\n\nconst resolveDetailPlacement = (item: {\n placement?: 'primary' | 'secondary' | 'main' | 'side' | 'fullWidth';\n presentation?: {\n group?: string;\n desktop?: 'primary' | 'secondary' | 'fullWidth';\n };\n kind?: string;\n fields?: readonly {\n presentation?: {\n group?: string;\n desktop?: 'primary' | 'secondary' | 'fullWidth';\n };\n }[];\n}): 'primary' | 'secondary' => {\n if (item.presentation?.desktop === 'secondary') {\n return 'secondary';\n }\n if (\n item.presentation?.group === 'scope' ||\n item.presentation?.group === 'status'\n ) {\n return 'secondary';\n }\n const fieldGroups =\n item.fields?.map((field) => {\n return field.presentation?.group;\n }) ?? [];\n if (\n fieldGroups.length > 0 &&\n fieldGroups.every((group) => {\n return group === 'scope' || group === 'status';\n })\n ) {\n return 'secondary';\n }\n if (item.placement === 'side') {\n return 'secondary';\n }\n if (item.placement === 'secondary') {\n return 'secondary';\n }\n return 'primary';\n};\n\nconst BackofficeEntityDetailPageContent = ({\n config,\n prepared,\n}: {\n config: BackofficeResolvedDetailPageFacetConfig;\n prepared: {\n pageQuery: PreloadedQuery<OperationType>;\n id: string;\n detailId?: string;\n pageId: string;\n pagePath: string;\n };\n}): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { formatNumber, formatCurrency, formatCurrencyTitle, formatPercent } =\n useBackofficeFormats();\n const { entities } = useBackofficeConfig();\n const routing = useContext(RoutingContext);\n const environment = useRelayEnvironment();\n const toast = useToast();\n const [actionState, setActionState] = useState<Record<string, boolean>>({});\n const [activeFormActionId, setActiveFormActionId] = useState<string | null>(\n null,\n );\n const setActionLoading = (actionId: string, isLoading: boolean) => {\n setActionState((prev) => {\n if (prev[actionId] === isLoading) {\n return prev;\n }\n return { ...prev, [actionId]: isLoading };\n });\n };\n\n const { page } = config;\n const notFound = useBackofficeEntityDetailNotFoundState({\n listHref: config.routes.list,\n });\n\n const pageQueryData = usePreloadedQuery(page.query, prepared.pageQuery);\n const pageNodeRef = page.resolveNode(pageQueryData, {\n id: prepared.id,\n detailId: prepared.detailId,\n });\n const resolvedNode = useBackofficeFragment<\n unknown,\n { __typename: string } | null | undefined\n >(page.fragment, pageNodeRef);\n return (\n <BackofficeEntityDetailScaffold\n node={resolvedNode}\n notFound={notFound}\n render={(node) => {\n const view = page.toView(node);\n const resolveEntityHref = (entityId: string, refId: string) => {\n const entityConfig = entities[entityId];\n if (entityConfig == null) {\n return null;\n }\n return entityConfig.routes.detail(refId);\n };\n const actions = page.actions ?? [];\n let headerActionButtons: ReactNode[] = [];\n if (actions.length > 0) {\n const visibleActions = actions.filter((action) => {\n if (action.isVisible == null) {\n return true;\n }\n return action.isVisible(view);\n });\n\n if (visibleActions.length > 0) {\n headerActionButtons = visibleActions.map((action) => {\n const label = resolveLabel(action.label, tApp);\n const ariaLabel =\n action.ariaLabel != null\n ? resolveLabel(action.ariaLabel, tApp)\n : label;\n const variant = action.variant ?? 'secondary';\n const size = action.size ?? 'small';\n const isLoading = actionState[action.id] ?? false;\n const isDisabled =\n isLoading || action.isDisabled?.(view) === true;\n\n if (isRouteAction(action)) {\n const href = action.to(view);\n return (\n <LinkButton\n key={action.id}\n to={href}\n variant={variant}\n size={size}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n preloadOnHover=\"code-and-data\"\n >\n {label}\n </LinkButton>\n );\n }\n\n if (isFormMutationAction(action)) {\n return (\n <Button\n key={action.id}\n type=\"button\"\n variant={variant}\n size={size}\n isLoading={false}\n disabled={isDisabled}\n onClick={() => {\n setActiveFormActionId(action.id);\n }}\n aria-label={ariaLabel}\n >\n {label}\n </Button>\n );\n }\n\n if (isMutationAction(action)) {\n const handleClick = () => {\n if (isLoading) {\n return;\n }\n const variables = action.getVariables(view);\n setActionLoading(action.id, true);\n commitMutation(environment, {\n mutation: action.mutation,\n variables,\n updater: (store) => {\n action.updater?.(store, view);\n },\n onCompleted: (response) => {\n setActionLoading(action.id, false);\n const mutationPayload = extractMutationPayload(response);\n if (mutationPayload != null) {\n let defaultErrorMessage = t(\n 'actions.form.errors.invalidPayload',\n );\n if (action.toasts?.error?.message != null) {\n defaultErrorMessage = resolveLabel(\n action.toasts.error.message,\n tApp,\n );\n } else if (action.toasts?.error?.title != null) {\n defaultErrorMessage = resolveLabel(\n action.toasts.error.title,\n tApp,\n );\n }\n\n const outcome = resolveMutationOutcome(\n mutationPayload,\n {\n defaultErrorMessage,\n mapReason: (reason) => {\n const mapped = action.mapErrorReason?.(\n reason,\n view,\n );\n if (mapped == null) {\n return null;\n }\n if (typeof mapped === 'function') {\n return resolveLabel(mapped, tApp);\n }\n return String(mapped);\n },\n },\n );\n if (!outcome.ok) {\n const error = new Error(outcome.message);\n action.onError?.(error, view);\n if (action.toasts?.error != null) {\n const toastSpec = resolveToastSpec(\n action.toasts.error,\n tApp,\n );\n toast.error(toastSpec.title, toastSpec.message);\n }\n return;\n }\n }\n\n action.onCompleted?.(response, view);\n if (action.toasts?.success != null) {\n const toastSpec = resolveToastSpec(\n action.toasts.success,\n tApp,\n );\n const toastActions = resolveToastViewActions({\n toast: action.toasts.success,\n response,\n node: view,\n tApp,\n entities,\n defaultLabel: t('actions.view'),\n navigateTo: (to) => {\n routing?.history.push({ pathname: to });\n },\n });\n toast.push({\n kind: 'info',\n title: toastSpec.title,\n message: toastSpec.message,\n actions: toastActions,\n });\n }\n },\n onError: (error) => {\n setActionLoading(action.id, false);\n action.onError?.(error, view);\n if (action.toasts?.error != null) {\n const toastSpec = resolveToastSpec(\n action.toasts.error,\n tApp,\n );\n toast.error(toastSpec.title, toastSpec.message);\n }\n },\n });\n };\n\n return (\n <Button\n key={action.id}\n type=\"button\"\n variant={variant}\n size={size}\n isLoading={isLoading}\n disabled={isDisabled}\n onClick={handleClick}\n aria-label={ariaLabel}\n >\n {label}\n </Button>\n );\n }\n\n return null;\n });\n }\n }\n\n const activeFormAction = actions.find((action) => {\n return action.id === activeFormActionId;\n });\n\n const { content } = page;\n\n const primaryNodes: ReactNode[] = [];\n const secondaryNodes: ReactNode[] = [];\n content.forEach((item, index) => {\n const placement = resolveDetailPlacement(item);\n const targetNodes =\n placement === 'secondary' ? secondaryNodes : primaryNodes;\n\n if (item.kind === 'fieldSet') {\n const sectionLabel = resolveLabel(item.title, tApp);\n const description =\n item.description != null\n ? resolveLabel(item.description, tApp)\n : undefined;\n const { items, customNodes } = buildFieldItems(item.fields, view, {\n tApp,\n t,\n resolveEntityHref,\n formatNumber,\n formatCurrency,\n formatCurrencyTitle,\n formatPercent,\n renderTag: (tone, label) => {\n return <Tag tone={tone}>{label}</Tag>;\n },\n renderBadgeRow: (items) => {\n return <BackofficeDetailBadgeRow items={items} />;\n },\n renderDate: (value, fallback) => {\n return (\n <FormattedDate\n value={value}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n fallback={fallback}\n />\n );\n },\n renderFlagTag: (tag) => {\n return (\n <BackofficeDetailFlagTag\n tone={tag.tone}\n icon={\n tag.iconName != null\n ? renderFlagIcon(tag.iconName)\n : undefined\n }\n label={tag.label}\n />\n );\n },\n renderLink: (href, label) => {\n return (\n <Link to={href} preloadOnHover=\"code-and-data\">\n {label}\n </Link>\n );\n },\n renderTaggedValue: (tag, value) => {\n return <BackofficeDetailTaggedValue tag={tag} value={value} />;\n },\n wrapCustomNode: (id, custom) => {\n return <div key={id}>{custom}</div>;\n },\n });\n\n const hasContent = items.length > 0 || customNodes.length > 0;\n\n if (!hasContent) {\n return;\n }\n\n targetNodes.push(\n <BackofficeDetailSection\n key={`${sectionLabel}-${index}`}\n title={sectionLabel}\n description={description}\n items={items.length > 0 ? items : undefined}\n >\n {customNodes}\n </BackofficeDetailSection>,\n );\n return;\n }\n\n const rendered = renderBlocks([item], view, {\n tApp,\n t,\n resolveEntityHref,\n keyPrefix: String(index),\n renderLink: (href, label) => {\n return (\n <Link to={href} preloadOnHover=\"code-and-data\">\n {label}\n </Link>\n );\n },\n renderDate: (value, fallback) => {\n return (\n <FormattedDate\n value={value}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n fallback={fallback}\n />\n );\n },\n renderTag: (tone, label) => {\n return <Tag tone={tone}>{label}</Tag>;\n },\n renderMetricGroup: ({\n key,\n title,\n description,\n density,\n items,\n }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n {items.length > 0 && (\n <MetricTileGroup\n density={density ?? 'comfortable'}\n minColumn=\"180\"\n >\n {items.map((metric) => {\n return (\n <MetricCard\n key={metric.id}\n label={metric.label}\n value={metric.value}\n hint={metric.hint}\n tone={metric.tone ?? 'neutral'}\n density={density ?? 'comfortable'}\n copyValue={metric.copyValue}\n copyLabel={t('common.actions.copy')}\n copiedLabel={t('common.actions.copied')}\n />\n );\n })}\n </MetricTileGroup>\n )}\n </BackofficeDetailSection>\n );\n },\n renderTimeline: ({ key, title, description, events }) => {\n return (\n <BackofficeLifecycleTimelineSection\n key={key}\n title={title}\n description={description}\n events={events}\n />\n );\n },\n renderAuditTimeline: ({ key, title, description, events }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <AuditTimeline events={events} />\n </BackofficeDetailSection>\n );\n },\n renderRelations: ({ key, title, items }) => {\n return (\n <BackofficeRelationsSummaryGrid\n key={key}\n title={title}\n items={items}\n />\n );\n },\n renderContextStack: ({ key, title, items }) => {\n return (\n <BackofficeScopeStack key={key} title={title} items={items} />\n );\n },\n renderCustomSection: (key, title, child) => {\n return (\n <BackofficeDetailSection key={key} title={title}>\n {child}\n </BackofficeDetailSection>\n );\n },\n wrapCustomNode: (key, custom) => {\n return <div key={key}>{custom}</div>;\n },\n resolveTableColumns: (columns) => {\n return buildDataTableColumns(columns, {\n tApp,\n t,\n });\n },\n renderTable: ({ key, title, description, columns, rows }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(row, rowIndex) => {\n if (row != null && typeof row === 'object') {\n const record = row as Record<string, unknown>;\n const maybeId = record.id;\n if (\n typeof maybeId === 'string' &&\n maybeId.trim() !== ''\n ) {\n return maybeId;\n }\n }\n return String(rowIndex);\n }}\n />\n </BackofficeDetailSection>\n );\n },\n renderPayload: ({ key, title, description, content, format }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <BackofficePayloadViewer\n content={content}\n format={format}\n emptyState={t('common.notAvailable')}\n />\n </BackofficeDetailSection>\n );\n },\n renderKeyValueListSection: ({ key, title, description, items }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <BackofficeKeyValueList items={items} />\n </BackofficeDetailSection>\n );\n },\n });\n const blockNode = rendered[0];\n if (blockNode != null) {\n targetNodes.push(blockNode);\n }\n });\n\n const tabActionsNode =\n headerActionButtons.length > 0 ? (\n <div className={pageStyles.headerActions}>\n <div className={pageStyles.headerActionGroup}>\n {headerActionButtons}\n </div>\n </div>\n ) : null;\n\n const hasAside = secondaryNodes.length > 0;\n const contentNode = hasAside ? (\n <div className={detailLayoutStyles.layout}>\n <div className={detailLayoutStyles.primary}>{primaryNodes}</div>\n <aside className={detailLayoutStyles.secondary}>\n {secondaryNodes}\n </aside>\n </div>\n ) : (\n <div className={detailLayoutStyles.stacked}>{primaryNodes}</div>\n );\n\n return (\n <>\n {tabActionsNode}\n {contentNode}\n {activeFormAction != null &&\n isFormMutationAction(activeFormAction) && (\n <LazyBackofficeEntityActionFormDialog\n isOpen\n action={activeFormAction}\n node={view}\n onClose={() => {\n setActiveFormActionId(null);\n }}\n />\n )}\n </>\n );\n }}\n />\n );\n};\n\nexport const BackofficeEntityDetailPage = ({\n prepared,\n}: BackofficeEntityDetailPageProps): JSX.Element => {\n return (\n <BackofficeEntityDetailPageContent\n config={prepared.pageConfig}\n prepared={prepared}\n />\n );\n};\n\nexport default BackofficeEntityDetailPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BackofficeEntityDetailPage.js","names":[],"sources":["../../../src/pages/BackofficeEntityDetailPage.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { type JSX, type ReactNode, useContext, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n commitMutation,\n type PreloadedQuery,\n usePreloadedQuery,\n} from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\nimport { resolveMutationOutcome } from '../relay/mutationResult.js';\n\nimport { BACKOFFICE_DATE_TIME_OPTIONS } from '@plumile/backoffice-core/constants.js';\nimport type {\n BackofficePreparedDetailPageDataRoute,\n BackofficeResolvedDetailPageFacetConfig,\n} from '@plumile/backoffice-core/types.js';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { LinkButton } from '@plumile/ui/atomic/atoms/button/LinkButton.js';\nimport { FormattedDate } from '@plumile/ui/atomic/atoms/formatted-date/FormattedDate.js';\nimport { useToast } from '@plumile/ui/atomic/molecules/toast/ToastProvider.js';\nimport { Tag } from '@plumile/ui/backoffice/atoms/tag/Tag.js';\nimport { BackofficeDetailSection } from '@plumile/ui/backoffice/molecules/backoffice_detail_section/BackofficeDetailSection.js';\nimport { BackofficeKeyValueList } from '@plumile/ui/backoffice/molecules/backoffice_key_value_list/BackofficeKeyValueList.js';\nimport { BackofficePayloadViewer } from '@plumile/ui/backoffice/molecules/backoffice_payload_viewer/BackofficePayloadViewer.js';\nimport { BackofficeScopeStack } from '@plumile/ui/backoffice/molecules/backoffice_scope_stack/BackofficeScopeStack.js';\nimport { AuditTimeline } from '@plumile/ui/backoffice/organisms/audit_timeline/AuditTimeline.js';\nimport { MetricCard } from '@plumile/ui/components/dashboard/metric_card/MetricCard.js';\nimport { MetricTileGroup } from '@plumile/ui/components/dashboard/metric_tile_group/MetricTileGroup.js';\nimport { DataTable } from '@plumile/ui/components/data-table/DataTable.js';\nimport { ChatCheckSvg } from '@plumile/ui/icons/ChatCheckSvg.js';\nimport { KeyOffSvg } from '@plumile/ui/icons/KeyOffSvg.js';\nimport { KeySvg } from '@plumile/ui/icons/KeySvg.js';\nimport { LockOpenSvg } from '@plumile/ui/icons/LockOpenSvg.js';\nimport { LockSvg } from '@plumile/ui/icons/LockSvg.js';\nimport { RobotCheckSvg } from '@plumile/ui/icons/RobotCheckSvg.js';\nimport { RobotXSvg } from '@plumile/ui/icons/RobotXSvg.js';\nimport { RocketOffSvg } from '@plumile/ui/icons/RocketOffSvg.js';\nimport { RocketSvg } from '@plumile/ui/icons/RocketSvg.js';\nimport { SettingsCheckSvg } from '@plumile/ui/icons/SettingsCheckSvg.js';\nimport { SettingsXSvg } from '@plumile/ui/icons/SettingsXSvg.js';\nimport { ShieldLockSvg } from '@plumile/ui/icons/ShieldLockSvg.js';\nimport { ShieldOffSvg } from '@plumile/ui/icons/ShieldOffSvg.js';\nimport { XBadgeSvg } from '@plumile/ui/icons/XBadgeSvg.js';\nimport Link from '@plumile/router/routing/Link.js';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\n\nimport { buildDataTableColumns } from '../components/backoffice/columns/buildDataTableColumns.js';\nimport { BackofficeEntityDetailScaffold } from '../components/backoffice/scaffolds/BackofficeEntityDetailScaffold.js';\nimport { useBackofficeEntityDetailNotFoundState } from '../components/backoffice/scaffolds/BackofficeEntityDetailNotFound.js';\nimport { BackofficeDetailBadgeRow } from '../components/backoffice/detail/BackofficeDetailBadgeRow.js';\nimport { BackofficeDetailFlagTag } from '../components/backoffice/detail/BackofficeDetailFlagTag.js';\nimport { BackofficeDetailTaggedValue } from '../components/backoffice/detail/BackofficeDetailTaggedValue.js';\nimport { BackofficeLifecycleTimelineSection } from '../components/backoffice/detail/BackofficeLifecycleTimelineSection.js';\nimport { BackofficeRelationsSummaryGrid } from '../components/backoffice/detail/BackofficeRelationsSummaryGrid.js';\nimport * as detailLayoutStyles from '../components/backoffice/detail/backofficeDetailLayout.css.js';\nimport { LazyBackofficeEntityActionFormDialog } from '../components/backoffice/actions/LazyBackofficeEntityActionFormDialog.js';\nimport {\n resolveToastSpec,\n resolveToastViewActions,\n} from '../components/backoffice/actions/toastViewAction.js';\nimport * as pageStyles from './backofficeEntityDetailPage.css.js';\nimport { useBackofficeFormats } from '../i18n/useBackofficeFormats.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeRuntimeFragment } from '../relay/typedRelayHooks.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport {\n extractMutationPayload,\n isFormMutationAction,\n isMutationAction,\n isRouteAction,\n resolveLabel,\n} from './BackofficeEntityDetailPage.helpers.js';\nimport {\n buildFieldItems,\n renderBlocks,\n type FlagIconName,\n} from './BackofficeEntityDetailPage.view-helpers.js';\n\nexport type BackofficeEntityDetailPageProps = {\n prepared: BackofficePreparedDetailPageDataRoute;\n};\n\nconst isBackofficeRelayNode = (\n value: unknown,\n): value is { readonly __typename: string } => {\n if (value == null || typeof value !== 'object') {\n return false;\n }\n const typename = Reflect.get(value, '__typename');\n return typeof typename === 'string';\n};\n\nconst renderFlagIcon = (iconName: FlagIconName): JSX.Element => {\n const iconSize = 14;\n switch (iconName) {\n case 'shield-lock':\n return (\n <ShieldLockSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'shield-off':\n return (\n <ShieldOffSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'settings-check':\n return (\n <SettingsCheckSvg\n width={iconSize}\n height={iconSize}\n aria-hidden=\"true\"\n />\n );\n case 'settings-x':\n return (\n <SettingsXSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'x-badge':\n return (\n <XBadgeSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'chat-check':\n return (\n <ChatCheckSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'key':\n return <KeySvg width={iconSize} height={iconSize} aria-hidden=\"true\" />;\n case 'key-off':\n return (\n <KeyOffSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'lock':\n return <LockSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />;\n case 'lock-open':\n return (\n <LockOpenSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'robot-check':\n return (\n <RobotCheckSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'robot-x':\n return (\n <RobotXSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'rocket':\n return (\n <RocketSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n case 'rocket-off':\n return (\n <RocketOffSvg width={iconSize} height={iconSize} aria-hidden=\"true\" />\n );\n default:\n throw new Error(`Unsupported flag icon: ${String(iconName)}`);\n }\n};\n\nconst resolveDetailPlacement = (item: {\n placement?: 'primary' | 'secondary' | 'main' | 'side' | 'fullWidth';\n presentation?: {\n group?: string;\n desktop?: 'primary' | 'secondary' | 'fullWidth';\n };\n kind?: string;\n fields?: readonly {\n presentation?: {\n group?: string;\n desktop?: 'primary' | 'secondary' | 'fullWidth';\n };\n }[];\n}): 'primary' | 'secondary' => {\n if (item.presentation?.desktop === 'secondary') {\n return 'secondary';\n }\n if (\n item.presentation?.group === 'scope' ||\n item.presentation?.group === 'status'\n ) {\n return 'secondary';\n }\n const fieldGroups =\n item.fields?.map((field) => {\n return field.presentation?.group;\n }) ?? [];\n if (\n fieldGroups.length > 0 &&\n fieldGroups.every((group) => {\n return group === 'scope' || group === 'status';\n })\n ) {\n return 'secondary';\n }\n if (item.placement === 'side') {\n return 'secondary';\n }\n if (item.placement === 'secondary') {\n return 'secondary';\n }\n return 'primary';\n};\n\nconst BackofficeEntityDetailPageContent = ({\n config,\n prepared,\n}: {\n config: BackofficeResolvedDetailPageFacetConfig;\n prepared: {\n pageQuery: PreloadedQuery<OperationType>;\n id: string;\n detailId?: string;\n pageId: string;\n pagePath: string;\n };\n}): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { formatNumber, formatCurrency, formatCurrencyTitle, formatPercent } =\n useBackofficeFormats();\n const { entities } = useBackofficeConfig();\n const routing = useContext(RoutingContext);\n const environment = useRelayEnvironment();\n const toast = useToast();\n const [actionState, setActionState] = useState<Record<string, boolean>>({});\n const [activeFormActionId, setActiveFormActionId] = useState<string | null>(\n null,\n );\n const setActionLoading = (actionId: string, isLoading: boolean) => {\n setActionState((prev) => {\n if (prev[actionId] === isLoading) {\n return prev;\n }\n return { ...prev, [actionId]: isLoading };\n });\n };\n\n const { page } = config;\n const notFound = useBackofficeEntityDetailNotFoundState({\n listHref: config.routes.list,\n });\n\n const pageQueryData = usePreloadedQuery(page.query, prepared.pageQuery);\n const pageNodeRef = page.resolveNode(pageQueryData, {\n id: prepared.id,\n detailId: prepared.detailId,\n });\n const fragmentNode = useBackofficeRuntimeFragment(page.fragment, pageNodeRef);\n const resolvedNode = isBackofficeRelayNode(fragmentNode)\n ? fragmentNode\n : null;\n return (\n <BackofficeEntityDetailScaffold\n node={resolvedNode}\n notFound={notFound}\n render={(node) => {\n const view = page.toView(node);\n const resolveEntityHref = (entityId: string, refId: string) => {\n const entityConfig = entities[entityId];\n if (entityConfig == null) {\n return null;\n }\n return entityConfig.routes.detail(refId);\n };\n const actions = page.actions ?? [];\n let headerActionButtons: ReactNode[] = [];\n if (actions.length > 0) {\n const visibleActions = actions.filter((action) => {\n if (action.isVisible == null) {\n return true;\n }\n return action.isVisible(view);\n });\n\n if (visibleActions.length > 0) {\n headerActionButtons = visibleActions.map((action) => {\n const label = resolveLabel(action.label, tApp);\n const ariaLabel =\n action.ariaLabel != null\n ? resolveLabel(action.ariaLabel, tApp)\n : label;\n const variant = action.variant ?? 'secondary';\n const size = action.size ?? 'small';\n const isLoading = actionState[action.id] ?? false;\n const isDisabled =\n isLoading || action.isDisabled?.(view) === true;\n\n if (isRouteAction(action)) {\n const href = action.to(view);\n return (\n <LinkButton\n key={action.id}\n to={href}\n variant={variant}\n size={size}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n preloadOnHover=\"code-and-data\"\n >\n {label}\n </LinkButton>\n );\n }\n\n if (isFormMutationAction(action)) {\n return (\n <Button\n key={action.id}\n type=\"button\"\n variant={variant}\n size={size}\n isLoading={false}\n disabled={isDisabled}\n onClick={() => {\n setActiveFormActionId(action.id);\n }}\n aria-label={ariaLabel}\n >\n {label}\n </Button>\n );\n }\n\n if (isMutationAction(action)) {\n const handleClick = () => {\n if (isLoading) {\n return;\n }\n const variables = action.getVariables(view);\n setActionLoading(action.id, true);\n commitMutation(environment, {\n mutation: action.mutation,\n variables,\n updater: (store) => {\n action.updater?.(store, view);\n },\n onCompleted: (response) => {\n setActionLoading(action.id, false);\n const mutationPayload = extractMutationPayload(response);\n if (mutationPayload != null) {\n let defaultErrorMessage = t(\n 'actions.form.errors.invalidPayload',\n );\n if (action.toasts?.error?.message != null) {\n defaultErrorMessage = resolveLabel(\n action.toasts.error.message,\n tApp,\n );\n } else if (action.toasts?.error?.title != null) {\n defaultErrorMessage = resolveLabel(\n action.toasts.error.title,\n tApp,\n );\n }\n\n const outcome = resolveMutationOutcome(\n mutationPayload,\n {\n defaultErrorMessage,\n mapReason: (reason) => {\n const mapped = action.mapErrorReason?.(\n reason,\n view,\n );\n if (mapped == null) {\n return null;\n }\n if (typeof mapped === 'function') {\n return resolveLabel(mapped, tApp);\n }\n return String(mapped);\n },\n },\n );\n if (!outcome.ok) {\n const error = new Error(outcome.message);\n action.onError?.(error, view);\n if (action.toasts?.error != null) {\n const toastSpec = resolveToastSpec(\n action.toasts.error,\n tApp,\n );\n toast.error(toastSpec.title, toastSpec.message);\n }\n return;\n }\n }\n\n action.onCompleted?.(response, view);\n if (action.toasts?.success != null) {\n const toastSpec = resolveToastSpec(\n action.toasts.success,\n tApp,\n );\n const toastActions = resolveToastViewActions({\n toast: action.toasts.success,\n response,\n node: view,\n tApp,\n entities,\n defaultLabel: t('actions.view'),\n navigateTo: (to) => {\n routing?.history.push({ pathname: to });\n },\n });\n toast.push({\n kind: 'info',\n title: toastSpec.title,\n message: toastSpec.message,\n actions: toastActions,\n });\n }\n },\n onError: (error) => {\n setActionLoading(action.id, false);\n action.onError?.(error, view);\n if (action.toasts?.error != null) {\n const toastSpec = resolveToastSpec(\n action.toasts.error,\n tApp,\n );\n toast.error(toastSpec.title, toastSpec.message);\n }\n },\n });\n };\n\n return (\n <Button\n key={action.id}\n type=\"button\"\n variant={variant}\n size={size}\n isLoading={isLoading}\n disabled={isDisabled}\n onClick={handleClick}\n aria-label={ariaLabel}\n >\n {label}\n </Button>\n );\n }\n\n return null;\n });\n }\n }\n\n const activeFormAction = actions.find((action) => {\n return action.id === activeFormActionId;\n });\n\n const { content } = page;\n\n const primaryNodes: ReactNode[] = [];\n const secondaryNodes: ReactNode[] = [];\n content.forEach((item, index) => {\n const placement = resolveDetailPlacement(item);\n const targetNodes =\n placement === 'secondary' ? secondaryNodes : primaryNodes;\n\n if (item.kind === 'fieldSet') {\n const sectionLabel = resolveLabel(item.title, tApp);\n const description =\n item.description != null\n ? resolveLabel(item.description, tApp)\n : undefined;\n const { items, customNodes } = buildFieldItems(item.fields, view, {\n tApp,\n t,\n resolveEntityHref,\n formatNumber,\n formatCurrency,\n formatCurrencyTitle,\n formatPercent,\n renderTag: (tone, label) => {\n return <Tag tone={tone}>{label}</Tag>;\n },\n renderBadgeRow: (items) => {\n return <BackofficeDetailBadgeRow items={items} />;\n },\n renderDate: (value, fallback) => {\n return (\n <FormattedDate\n value={value}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n fallback={fallback}\n />\n );\n },\n renderFlagTag: (tag) => {\n return (\n <BackofficeDetailFlagTag\n tone={tag.tone}\n icon={\n tag.iconName != null\n ? renderFlagIcon(tag.iconName)\n : undefined\n }\n label={tag.label}\n />\n );\n },\n renderLink: (href, label) => {\n return (\n <Link to={href} preloadOnHover=\"code-and-data\">\n {label}\n </Link>\n );\n },\n renderTaggedValue: (tag, value) => {\n return <BackofficeDetailTaggedValue tag={tag} value={value} />;\n },\n wrapCustomNode: (id, custom) => {\n return <div key={id}>{custom}</div>;\n },\n });\n\n const hasContent = items.length > 0 || customNodes.length > 0;\n\n if (!hasContent) {\n return;\n }\n\n targetNodes.push(\n <BackofficeDetailSection\n key={`${sectionLabel}-${index}`}\n title={sectionLabel}\n description={description}\n items={items.length > 0 ? items : undefined}\n >\n {customNodes}\n </BackofficeDetailSection>,\n );\n return;\n }\n\n const rendered = renderBlocks([item], view, {\n tApp,\n t,\n resolveEntityHref,\n keyPrefix: String(index),\n renderLink: (href, label) => {\n return (\n <Link to={href} preloadOnHover=\"code-and-data\">\n {label}\n </Link>\n );\n },\n renderDate: (value, fallback) => {\n return (\n <FormattedDate\n value={value}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n fallback={fallback}\n />\n );\n },\n renderTag: (tone, label) => {\n return <Tag tone={tone}>{label}</Tag>;\n },\n renderMetricGroup: ({\n key,\n title,\n description,\n density,\n items,\n }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n {items.length > 0 && (\n <MetricTileGroup\n density={density ?? 'comfortable'}\n minColumn=\"180\"\n >\n {items.map((metric) => {\n return (\n <MetricCard\n key={metric.id}\n label={metric.label}\n value={metric.value}\n hint={metric.hint}\n tone={metric.tone ?? 'neutral'}\n density={density ?? 'comfortable'}\n copyValue={metric.copyValue}\n copyLabel={t('common.actions.copy')}\n copiedLabel={t('common.actions.copied')}\n />\n );\n })}\n </MetricTileGroup>\n )}\n </BackofficeDetailSection>\n );\n },\n renderTimeline: ({ key, title, description, events }) => {\n return (\n <BackofficeLifecycleTimelineSection\n key={key}\n title={title}\n description={description}\n events={events}\n />\n );\n },\n renderAuditTimeline: ({ key, title, description, events }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <AuditTimeline events={events} />\n </BackofficeDetailSection>\n );\n },\n renderRelations: ({ key, title, items }) => {\n return (\n <BackofficeRelationsSummaryGrid\n key={key}\n title={title}\n items={items}\n />\n );\n },\n renderContextStack: ({ key, title, items }) => {\n return (\n <BackofficeScopeStack key={key} title={title} items={items} />\n );\n },\n renderCustomSection: (key, title, child) => {\n return (\n <BackofficeDetailSection key={key} title={title}>\n {child}\n </BackofficeDetailSection>\n );\n },\n wrapCustomNode: (key, custom) => {\n return <div key={key}>{custom}</div>;\n },\n resolveTableColumns: (columns) => {\n return buildDataTableColumns(columns, {\n tApp,\n t,\n });\n },\n renderTable: ({ key, title, description, columns, rows }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <DataTable\n columns={columns}\n rows={rows}\n getRowId={(row, rowIndex) => {\n if (row != null && typeof row === 'object') {\n const record = row as Record<string, unknown>;\n const maybeId = record.id;\n if (\n typeof maybeId === 'string' &&\n maybeId.trim() !== ''\n ) {\n return maybeId;\n }\n }\n return String(rowIndex);\n }}\n />\n </BackofficeDetailSection>\n );\n },\n renderPayload: ({ key, title, description, content, format }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <BackofficePayloadViewer\n content={content}\n format={format}\n emptyState={t('common.notAvailable')}\n />\n </BackofficeDetailSection>\n );\n },\n renderKeyValueListSection: ({ key, title, description, items }) => {\n return (\n <BackofficeDetailSection\n key={key}\n title={title}\n description={description}\n >\n <BackofficeKeyValueList items={items} />\n </BackofficeDetailSection>\n );\n },\n });\n const blockNode = rendered[0];\n if (blockNode != null) {\n targetNodes.push(blockNode);\n }\n });\n\n const tabActionsNode =\n headerActionButtons.length > 0 ? (\n <div className={pageStyles.headerActions}>\n <div className={pageStyles.headerActionGroup}>\n {headerActionButtons}\n </div>\n </div>\n ) : null;\n\n const hasAside = secondaryNodes.length > 0;\n const contentNode = hasAside ? (\n <div className={detailLayoutStyles.layout}>\n <div className={detailLayoutStyles.primary}>{primaryNodes}</div>\n <aside className={detailLayoutStyles.secondary}>\n {secondaryNodes}\n </aside>\n </div>\n ) : (\n <div className={detailLayoutStyles.stacked}>{primaryNodes}</div>\n );\n\n return (\n <>\n {tabActionsNode}\n {contentNode}\n {activeFormAction != null &&\n isFormMutationAction(activeFormAction) && (\n <LazyBackofficeEntityActionFormDialog\n isOpen\n action={activeFormAction}\n node={view}\n onClose={() => {\n setActiveFormActionId(null);\n }}\n />\n )}\n </>\n );\n }}\n />\n );\n};\n\nexport const BackofficeEntityDetailPage = ({\n prepared,\n}: BackofficeEntityDetailPageProps): JSX.Element => {\n return (\n <BackofficeEntityDetailPageContent\n config={prepared.pageConfig}\n prepared={prepared}\n />\n );\n};\n\nexport default BackofficeEntityDetailPage;\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useBackofficeReactTranslation as e } from "../i18n/useBackofficeReactTranslation.js";
|
|
2
2
|
import { BackofficeErrorBoundary as t } from "../components/backoffice/errors/BackofficeErrorBoundary.js";
|
|
3
|
-
import {
|
|
3
|
+
import { useBackofficeRuntimePaginationFragment as n } from "../relay/typedRelayHooks.js";
|
|
4
4
|
import { BackofficeLazyEntityCountLabel as r } from "../components/backoffice/refs/BackofficeLazyEntityCount.js";
|
|
5
5
|
import { BackofficeEntityListScaffold as i } from "../components/backoffice/scaffolds/BackofficeEntityListScaffold.js";
|
|
6
6
|
import { useRelayEnvironment as a } from "../relay/useRelayEnvironment.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeEntityListDataPage.js","names":[],"sources":["../../../src/pages/BackofficeEntityListDataPage.tsx"],"sourcesContent":["import {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { loadQuery, usePreloadedQuery } from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\nimport {\n BACKOFFICE_LIST_DEFAULTS,\n BACKOFFICE_LIST_REFETCH_POLICY,\n} from '@plumile/backoffice-core/constants.js';\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficePreparedListDataRoute } from '@plumile/backoffice-core/types.js';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\n\nimport { BackofficeErrorBoundary } from '../components/backoffice/errors/BackofficeErrorBoundary.js';\nimport { BackofficeEntityListScaffold } from '../components/backoffice/scaffolds/BackofficeEntityListScaffold.js';\nimport { BackofficeLazyEntityCountLabel } from '../components/backoffice/refs/BackofficeLazyEntityCount.js';\nimport { useBackofficeLoadMore } from '../hooks/useBackofficeLoadMore.js';\nimport { useBackofficeListRefetch } from '../hooks/useBackofficeListRefetch.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficePaginationFragment } from '../relay/typedRelayHooks.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport { useBackofficeEntityListRouteContext } from './BackofficeEntityListRouteContext.js';\n\nexport type BackofficeEntityListDataPageProps = {\n prepared: BackofficePreparedListDataRoute;\n};\n\ntype BackofficeEntityConnectionListDataProps = {\n queryRef: BackofficePreparedListDataRoute['query'];\n};\n\n/**\n * Renders the Relay-backed row data under the list layout route boundary.\n */\nfunction BackofficeEntityConnectionListData({\n queryRef,\n}: BackofficeEntityConnectionListDataProps): JSX.Element | null {\n const {\n config,\n state,\n pushState,\n headerActions,\n columns,\n gridTemplateColumns,\n getRowId,\n countFetchKey,\n bumpCountFetchKey,\n filterDrawerState,\n registerRefresh,\n } = useBackofficeEntityListRouteContext();\n const listConfig = config.list;\n const { t } = useBackofficeReactTranslation();\n\n const queryData = usePreloadedQuery(listConfig.query, queryRef);\n const {\n data: fragmentData,\n loadNext,\n hasNext,\n isLoadingNext,\n refetch,\n } = useBackofficePaginationFragment<OperationType, unknown, unknown>(\n listConfig.fragment,\n queryData,\n );\n\n const connection = listConfig.getConnection(fragmentData);\n\n const rows = useMemo(() => {\n return connection.edges.map((edge) => {\n return listConfig.toRow(edge.node);\n });\n }, [connection.edges, listConfig]);\n\n const { listDefaults } = config;\n const resolvedSort = state.sort ?? listDefaults.sort;\n const { pageSize } = BACKOFFICE_LIST_DEFAULTS;\n\n const baseVariables = useMemo(() => {\n return {\n where: state.where,\n sort: resolvedSort,\n count: pageSize,\n cursor: null,\n };\n }, [pageSize, resolvedSort, state.where]);\n const countVariablesKey = useMemo(() => {\n return stableListVariablesKey(baseVariables);\n }, [baseVariables]);\n const previousCountVariablesKeyRef = useRef(countVariablesKey);\n\n const { isRefreshing, onRefresh } = useBackofficeListRefetch({\n refetch,\n variables: baseVariables,\n defaults: {\n where: listDefaults.where,\n sort: listDefaults.sort,\n count: pageSize,\n cursor: null,\n },\n fetchPolicy: BACKOFFICE_LIST_REFETCH_POLICY,\n buildQueryVariables: listConfig.buildQueryVariables,\n });\n\n useEffect(() => {\n if (previousCountVariablesKeyRef.current === countVariablesKey) {\n return;\n }\n previousCountVariablesKeyRef.current = countVariablesKey;\n bumpCountFetchKey();\n }, [bumpCountFetchKey, countVariablesKey]);\n\n const handleRefresh = useCallback(() => {\n bumpCountFetchKey();\n onRefresh();\n }, [bumpCountFetchKey, onRefresh]);\n\n useEffect(() => {\n registerRefresh(handleRefresh);\n return () => {\n registerRefresh(null);\n };\n }, [handleRefresh, registerRefresh]);\n\n const handleLoadMore = useBackofficeLoadMore({\n hasNext,\n isLoadingNext,\n loadNext,\n count: pageSize,\n });\n\n let loadedCountFallback: JSX.Element = <span>{t('common.loading')}</span>;\n if (rows.length > 0) {\n loadedCountFallback = (\n <span>\n {t('list.loaded', {\n count: rows.length,\n })}\n </span>\n );\n }\n const loadedCountLabel = (\n <BackofficeLazyEntityCountLabel\n count={listConfig.count}\n where={state.where}\n fetchKey={countFetchKey}\n loadingFallback={loadedCountFallback}\n >\n {(totalCount) => {\n return (\n <span>\n {t('list.showing', {\n shown: rows.length,\n total: totalCount,\n })}\n </span>\n );\n }}\n </BackofficeLazyEntityCountLabel>\n );\n\n return (\n <BackofficeEntityListScaffold\n config={config}\n state={state}\n pushState={pushState}\n headerActions={headerActions}\n rows={rows}\n columns={columns}\n gridTemplateColumns={gridTemplateColumns}\n getRowId={getRowId}\n hasNextPage={hasNext}\n isLoadingMore={isLoadingNext}\n isRefreshing={isRefreshing}\n onLoadMore={handleLoadMore}\n onRefresh={handleRefresh}\n totalCount={null}\n loadedCountLabel={loadedCountLabel}\n filterDrawerState={filterDrawerState}\n />\n );\n}\n\nexport const BackofficeEntityListDataPage = ({\n prepared,\n}: BackofficeEntityListDataPageProps): JSX.Element | null => {\n const {\n config,\n state,\n pushState,\n headerActions,\n columns,\n gridTemplateColumns,\n getRowId,\n filterDrawerState,\n } = useBackofficeEntityListRouteContext();\n const relayEnvironment = useRelayEnvironment();\n const { t } = useBackofficeReactTranslation();\n const [queryRef, setQueryRef] = useState(() => {\n return prepared.query;\n });\n const ownedQueryRef = useRef<BackofficePreparedListDataRoute['query'] | null>(\n null,\n );\n\n const disposeOwnedQueryRef = useCallback(() => {\n ownedQueryRef.current?.dispose();\n ownedQueryRef.current = null;\n }, []);\n\n useEffect(() => {\n disposeOwnedQueryRef();\n setQueryRef(prepared.query);\n }, [disposeOwnedQueryRef, prepared.query]);\n\n useEffect(() => {\n return () => {\n disposeOwnedQueryRef();\n };\n }, [disposeOwnedQueryRef]);\n\n const reloadInitialQuery = useCallback(() => {\n const listConfig = config.list;\n const { listDefaults } = config;\n const { pageSize } = BACKOFFICE_LIST_DEFAULTS;\n const variablesBase = {\n where: state.where,\n sort: state.sort ?? listDefaults.sort,\n count: pageSize,\n cursor: null,\n };\n const variables = listConfig.buildQueryVariables(variablesBase);\n const nextQueryRef = loadQuery<OperationType>(\n relayEnvironment,\n listConfig.query,\n variables,\n {\n fetchPolicy: 'network-only',\n },\n );\n disposeOwnedQueryRef();\n ownedQueryRef.current = nextQueryRef;\n setQueryRef(nextQueryRef);\n }, [config, disposeOwnedQueryRef, relayEnvironment, state.sort, state.where]);\n\n return (\n <BackofficeErrorBoundary\n fallback={({ reset }) => {\n return (\n <BackofficeEntityListScaffold\n config={config}\n state={state}\n pushState={pushState}\n headerActions={headerActions}\n rows={[]}\n columns={columns}\n gridTemplateColumns={gridTemplateColumns}\n getRowId={getRowId}\n hasNextPage={false}\n isLoadingMore={false}\n isRefreshing={false}\n onLoadMore={() => {}}\n onRefresh={() => {\n reset();\n reloadInitialQuery();\n }}\n totalCount={null}\n filterDrawerState={filterDrawerState}\n emptyState={\n <InlineBanner\n tone=\"danger\"\n title={t('list.errors.title')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={() => {\n reset();\n reloadInitialQuery();\n }}\n >\n {t('list.actions.retry')}\n </Button>\n }\n >\n {t('list.errors.tableFailed')}\n </InlineBanner>\n }\n />\n );\n }}\n >\n <BackofficeEntityConnectionListData queryRef={queryRef} />\n </BackofficeErrorBoundary>\n );\n};\n\nexport default BackofficeEntityListDataPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BackofficeEntityListDataPage.js","names":[],"sources":["../../../src/pages/BackofficeEntityListDataPage.tsx"],"sourcesContent":["import {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { loadQuery, usePreloadedQuery } from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\nimport {\n BACKOFFICE_LIST_DEFAULTS,\n BACKOFFICE_LIST_REFETCH_POLICY,\n} from '@plumile/backoffice-core/constants.js';\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficePreparedListDataRoute } from '@plumile/backoffice-core/types.js';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\n\nimport { BackofficeErrorBoundary } from '../components/backoffice/errors/BackofficeErrorBoundary.js';\nimport { BackofficeEntityListScaffold } from '../components/backoffice/scaffolds/BackofficeEntityListScaffold.js';\nimport { BackofficeLazyEntityCountLabel } from '../components/backoffice/refs/BackofficeLazyEntityCount.js';\nimport { useBackofficeLoadMore } from '../hooks/useBackofficeLoadMore.js';\nimport { useBackofficeListRefetch } from '../hooks/useBackofficeListRefetch.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeRuntimePaginationFragment } from '../relay/typedRelayHooks.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport { useBackofficeEntityListRouteContext } from './BackofficeEntityListRouteContext.js';\n\nexport type BackofficeEntityListDataPageProps = {\n prepared: BackofficePreparedListDataRoute;\n};\n\ntype BackofficeEntityConnectionListDataProps = {\n queryRef: BackofficePreparedListDataRoute['query'];\n};\n\n/**\n * Renders the Relay-backed row data under the list layout route boundary.\n */\nfunction BackofficeEntityConnectionListData({\n queryRef,\n}: BackofficeEntityConnectionListDataProps): JSX.Element | null {\n const {\n config,\n state,\n pushState,\n headerActions,\n columns,\n gridTemplateColumns,\n getRowId,\n countFetchKey,\n bumpCountFetchKey,\n filterDrawerState,\n registerRefresh,\n } = useBackofficeEntityListRouteContext();\n const listConfig = config.list;\n const { t } = useBackofficeReactTranslation();\n\n const queryData = usePreloadedQuery(listConfig.query, queryRef);\n const {\n data: fragmentData,\n loadNext,\n hasNext,\n isLoadingNext,\n refetch,\n } = useBackofficeRuntimePaginationFragment<OperationType>(\n listConfig.fragment,\n queryData,\n );\n\n const connection = listConfig.getConnection(fragmentData);\n\n const rows = useMemo(() => {\n return connection.edges.map((edge) => {\n return listConfig.toRow(edge.node);\n });\n }, [connection.edges, listConfig]);\n\n const { listDefaults } = config;\n const resolvedSort = state.sort ?? listDefaults.sort;\n const { pageSize } = BACKOFFICE_LIST_DEFAULTS;\n\n const baseVariables = useMemo(() => {\n return {\n where: state.where,\n sort: resolvedSort,\n count: pageSize,\n cursor: null,\n };\n }, [pageSize, resolvedSort, state.where]);\n const countVariablesKey = useMemo(() => {\n return stableListVariablesKey(baseVariables);\n }, [baseVariables]);\n const previousCountVariablesKeyRef = useRef(countVariablesKey);\n\n const { isRefreshing, onRefresh } = useBackofficeListRefetch({\n refetch,\n variables: baseVariables,\n defaults: {\n where: listDefaults.where,\n sort: listDefaults.sort,\n count: pageSize,\n cursor: null,\n },\n fetchPolicy: BACKOFFICE_LIST_REFETCH_POLICY,\n buildQueryVariables: listConfig.buildQueryVariables,\n });\n\n useEffect(() => {\n if (previousCountVariablesKeyRef.current === countVariablesKey) {\n return;\n }\n previousCountVariablesKeyRef.current = countVariablesKey;\n bumpCountFetchKey();\n }, [bumpCountFetchKey, countVariablesKey]);\n\n const handleRefresh = useCallback(() => {\n bumpCountFetchKey();\n onRefresh();\n }, [bumpCountFetchKey, onRefresh]);\n\n useEffect(() => {\n registerRefresh(handleRefresh);\n return () => {\n registerRefresh(null);\n };\n }, [handleRefresh, registerRefresh]);\n\n const handleLoadMore = useBackofficeLoadMore({\n hasNext,\n isLoadingNext,\n loadNext,\n count: pageSize,\n });\n\n let loadedCountFallback: JSX.Element = <span>{t('common.loading')}</span>;\n if (rows.length > 0) {\n loadedCountFallback = (\n <span>\n {t('list.loaded', {\n count: rows.length,\n })}\n </span>\n );\n }\n const loadedCountLabel = (\n <BackofficeLazyEntityCountLabel\n count={listConfig.count}\n where={state.where}\n fetchKey={countFetchKey}\n loadingFallback={loadedCountFallback}\n >\n {(totalCount) => {\n return (\n <span>\n {t('list.showing', {\n shown: rows.length,\n total: totalCount,\n })}\n </span>\n );\n }}\n </BackofficeLazyEntityCountLabel>\n );\n\n return (\n <BackofficeEntityListScaffold\n config={config}\n state={state}\n pushState={pushState}\n headerActions={headerActions}\n rows={rows}\n columns={columns}\n gridTemplateColumns={gridTemplateColumns}\n getRowId={getRowId}\n hasNextPage={hasNext}\n isLoadingMore={isLoadingNext}\n isRefreshing={isRefreshing}\n onLoadMore={handleLoadMore}\n onRefresh={handleRefresh}\n totalCount={null}\n loadedCountLabel={loadedCountLabel}\n filterDrawerState={filterDrawerState}\n />\n );\n}\n\nexport const BackofficeEntityListDataPage = ({\n prepared,\n}: BackofficeEntityListDataPageProps): JSX.Element | null => {\n const {\n config,\n state,\n pushState,\n headerActions,\n columns,\n gridTemplateColumns,\n getRowId,\n filterDrawerState,\n } = useBackofficeEntityListRouteContext();\n const relayEnvironment = useRelayEnvironment();\n const { t } = useBackofficeReactTranslation();\n const [queryRef, setQueryRef] = useState(() => {\n return prepared.query;\n });\n const ownedQueryRef = useRef<BackofficePreparedListDataRoute['query'] | null>(\n null,\n );\n\n const disposeOwnedQueryRef = useCallback(() => {\n ownedQueryRef.current?.dispose();\n ownedQueryRef.current = null;\n }, []);\n\n useEffect(() => {\n disposeOwnedQueryRef();\n setQueryRef(prepared.query);\n }, [disposeOwnedQueryRef, prepared.query]);\n\n useEffect(() => {\n return () => {\n disposeOwnedQueryRef();\n };\n }, [disposeOwnedQueryRef]);\n\n const reloadInitialQuery = useCallback(() => {\n const listConfig = config.list;\n const { listDefaults } = config;\n const { pageSize } = BACKOFFICE_LIST_DEFAULTS;\n const variablesBase = {\n where: state.where,\n sort: state.sort ?? listDefaults.sort,\n count: pageSize,\n cursor: null,\n };\n const variables = listConfig.buildQueryVariables(variablesBase);\n const nextQueryRef = loadQuery<OperationType>(\n relayEnvironment,\n listConfig.query,\n variables,\n {\n fetchPolicy: 'network-only',\n },\n );\n disposeOwnedQueryRef();\n ownedQueryRef.current = nextQueryRef;\n setQueryRef(nextQueryRef);\n }, [config, disposeOwnedQueryRef, relayEnvironment, state.sort, state.where]);\n\n return (\n <BackofficeErrorBoundary\n fallback={({ reset }) => {\n return (\n <BackofficeEntityListScaffold\n config={config}\n state={state}\n pushState={pushState}\n headerActions={headerActions}\n rows={[]}\n columns={columns}\n gridTemplateColumns={gridTemplateColumns}\n getRowId={getRowId}\n hasNextPage={false}\n isLoadingMore={false}\n isRefreshing={false}\n onLoadMore={() => {}}\n onRefresh={() => {\n reset();\n reloadInitialQuery();\n }}\n totalCount={null}\n filterDrawerState={filterDrawerState}\n emptyState={\n <InlineBanner\n tone=\"danger\"\n title={t('list.errors.title')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={() => {\n reset();\n reloadInitialQuery();\n }}\n >\n {t('list.actions.retry')}\n </Button>\n }\n >\n {t('list.errors.tableFailed')}\n </InlineBanner>\n }\n />\n );\n }}\n >\n <BackofficeEntityConnectionListData queryRef={queryRef} />\n </BackofficeErrorBoundary>\n );\n};\n\nexport default BackofficeEntityListDataPage;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeEntityListPage.helpers.js","names":[],"sources":["../../../src/pages/BackofficeEntityListPage.helpers.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'react';\n\nimport type {\n
|
|
1
|
+
{"version":3,"file":"BackofficeEntityListPage.helpers.js","names":[],"sources":["../../../src/pages/BackofficeEntityListPage.helpers.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'react';\n\nimport type {\n BackofficeRuntimeEntityFormMutationActionSpec,\n BackofficeEntityRouteActionSpec,\n BackofficeListActionSpec,\n BackofficeRuntimeConnectionListConfig,\n BackofficeRuntimeResolvedListFacetConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport type { DataTableColumn } from '@plumile/ui/components/data-table/DataTable.js';\nimport type { TFunction } from 'i18next';\n\nimport type { BackofficeSizedDataTableColumn } from '../components/backoffice/columns/buildDataTableColumns.js';\n\ntype ButtonVariant = ComponentProps<typeof Button>['variant'];\n\nconst ROW_FLAGS_SLOT_PX = 24;\nconst ROW_FLAGS_GAP_PX = 6;\nconst ROW_FLAGS_PADDING_X_PX = 4;\n\nconst ACTIONS_SLOT_PX = 32;\nconst ACTIONS_GAP_PX = 8;\nconst ACTIONS_PADDING_X_PX = 12;\nconst ACTIONS_SAFETY_PX = 4;\n\nconst listColumnTrackBySize: Record<\n BackofficeSizedDataTableColumn<unknown>['size'],\n string\n> = {\n xs: 'minmax(3.5rem, 7rem)',\n s: 'minmax(5rem, 10rem)',\n statusAction: 'minmax(7rem, 12rem)',\n m: 'minmax(7rem, 14rem)',\n l: 'minmax(9rem, 18rem)',\n xl: 'minmax(11rem, 24rem)',\n fluid: 'minmax(0, 1fr)',\n};\n\nexport const computeRowFlagsColumnWidthPx = (flagCount: number): number => {\n if (flagCount <= 0) {\n return 0;\n }\n return (\n ROW_FLAGS_PADDING_X_PX * 2 +\n ROW_FLAGS_SLOT_PX * flagCount +\n ROW_FLAGS_GAP_PX * Math.max(0, flagCount - 1)\n );\n};\n\nexport const computeActionsColumnWidthPx = (actionCount: number): number => {\n if (actionCount <= 0) {\n return 0;\n }\n return (\n ACTIONS_SAFETY_PX +\n ACTIONS_PADDING_X_PX * 2 +\n ACTIONS_SLOT_PX * actionCount +\n ACTIONS_GAP_PX * Math.max(0, actionCount - 1)\n );\n};\n\nexport const resolveTrackBySize = (\n column: DataTableColumn<unknown>,\n fallback: string,\n): string => {\n if (column.mobileRole === 'action') {\n return '60px';\n }\n if (column.isPrimary === true) {\n return 'minmax(0, 1.4fr)';\n }\n if ('size' in column && typeof column.size === 'string') {\n return listColumnTrackBySize[\n column.size as BackofficeSizedDataTableColumn<unknown>['size']\n ];\n }\n return fallback;\n};\n\nexport const isRouteAction = (\n action: BackofficeListActionSpec,\n): action is BackofficeEntityRouteActionSpec<null> => {\n return action.kind === 'route';\n};\n\nexport const isFormMutationAction = (\n action: BackofficeListActionSpec,\n): action is BackofficeRuntimeEntityFormMutationActionSpec<null> => {\n return action.kind === 'formMutation';\n};\n\nexport const resolveActionVariant = (\n actionVariant: ButtonVariant | undefined,\n index: number,\n): Exclude<ButtonVariant, undefined> => {\n if (actionVariant != null) {\n return actionVariant;\n }\n if (index === 0) {\n return 'primary';\n }\n return 'secondary';\n};\n\nexport const resolveRowId = (row: unknown): string | null => {\n if (row == null || typeof row !== 'object') {\n return null;\n }\n if (!('id' in row)) {\n return null;\n }\n const value = (row as { id?: unknown }).id;\n if (typeof value !== 'string') {\n return null;\n }\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n return trimmed;\n};\n\nexport type ConnectionListConfig = BackofficeRuntimeResolvedListFacetConfig & {\n list: BackofficeRuntimeConnectionListConfig;\n};\n\nexport const resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nexport const buildActionsColumn = (options: {\n ariaLabel: string;\n fallback: string;\n resolveDetailHref: (id: string) => string | null;\n className?: string;\n renderAction: (input: { href: string; ariaLabel: string }) => JSX.Element;\n}): DataTableColumn<unknown> => {\n const { ariaLabel, fallback, resolveDetailHref, className, renderAction } =\n options;\n\n return {\n id: 'actions',\n header: '',\n className,\n mobileRole: 'action',\n cell: (row) => {\n const id = resolveRowId(row);\n if (id == null) {\n return fallback;\n }\n const href = resolveDetailHref(id);\n if (href == null) {\n return fallback;\n }\n return renderAction({ href, ariaLabel });\n },\n };\n};\n"],"mappings":";AAkBA,IASM,IAGF;CACF,IAAI;CACJ,GAAG;CACH,cAAc;CACd,GAAG;CACH,GAAG;CACH,IAAI;CACJ,OAAO;AACT,GAEa,KAAgC,MACvC,KAAa,IACR,IAGP,IACA,KAAoB,IACpB,IAAmB,KAAK,IAAI,GAAG,IAAY,CAAC,GAInC,KAA+B,MACtC,KAAe,IACV,IAGP,KAEA,KAAkB,IAClB,IAAiB,KAAK,IAAI,GAAG,IAAc,CAAC,GAInC,KACX,GACA,MAEI,EAAO,eAAe,WACjB,SAEL,EAAO,cAAc,KAChB,qBAEL,UAAU,KAAU,OAAO,EAAO,QAAS,WACtC,EACL,EAAO,QAGJ,GAGI,KACX,MAEO,EAAO,SAAS,SAGZ,KACX,MAEO,EAAO,SAAS,gBAGZ,KACX,GACA,MAEI,MAGA,MAAU,IACL,YAEF,cAGI,KAAgB,MAAgC;CAI3D,IAHmB,OAAO,KAAQ,aAA9B,KAGA,EAAE,QAAQ,IACZ,OAAO;CAET,IAAM,IAAS,EAAyB;CACxC,IAAI,OAAO,KAAU,UACnB,OAAO;CAET,IAAM,IAAU,EAAM,KAAK;CAI3B,OAHI,MAAY,KACP,OAEF;AACT,GAMa,KAAgB,GAAkB,MACtC,EAAM,CAAI,GAGN,KAAsB,MAMH;CAC9B,IAAM,EAAE,cAAW,aAAU,sBAAmB,cAAW,oBACzD;CAEF,OAAO;EACL,IAAI;EACJ,QAAQ;EACR;EACA,YAAY;EACZ,OAAO,MAAQ;GACb,IAAM,IAAK,EAAa,CAAG;GAC3B,IAAI,KAAM,MACR,OAAO;GAET,IAAM,IAAO,EAAkB,CAAE;GAIjC,OAHI,KAAQ,OACH,IAEF,EAAa;IAAE;IAAM;GAAU,CAAC;EACzC;CACF;AACF"}
|
|
@@ -1,95 +1,98 @@
|
|
|
1
1
|
import { resolveBackofficeLoadedFacetModule as e } from "@plumile/backoffice-core/resolve.js";
|
|
2
2
|
//#region src/provider/entityRegistry.ts
|
|
3
|
-
var t = "cache-first", n = "detail-page", r = "detail-layout", i = "list", a = "picker", o = "tool", s = (e) => e.kind === "list-detail", c = (e) => e.kind === "tool", l = (e, t, r) => t === n ? `${e}:${t}:${r ?? ""}` : `${e}:${t}`, u = (e) => e instanceof Error ? e : Error(String(e)), d = (e) => e?.status !== "loaded" || e.module == null ? null : e.module,
|
|
3
|
+
var t = "cache-first", n = "detail-page", r = "detail-layout", i = "list", a = "picker", o = "tool", s = (e) => e.kind === "list-detail", c = (e) => e.kind === "tool", l = (e, t, r) => t === n ? `${e}:${t}:${r ?? ""}` : `${e}:${t}`, u = (e) => e instanceof Error ? e : Error(String(e)), d = (e, t) => e.kind === t, f = (e, t) => e?.status !== "loaded" || e.module == null ? null : d(e.module, t) ? e.module : null, p = (e, t) => {
|
|
4
4
|
let n = e[t];
|
|
5
5
|
if (n == null) throw Error(`Unknown backoffice entity: ${t}`);
|
|
6
6
|
return n;
|
|
7
|
-
},
|
|
8
|
-
let
|
|
9
|
-
if ((
|
|
10
|
-
let t =
|
|
7
|
+
}, m = (m, h) => {
|
|
8
|
+
let g = /* @__PURE__ */ new Map(), _ = (e) => m[e] ?? null, v = async (e, n, r, i) => {
|
|
9
|
+
if ((r?.mode ?? t) === "cache-first") {
|
|
10
|
+
let t = f(g.get(e), n);
|
|
11
11
|
if (t != null) return t;
|
|
12
|
-
let
|
|
13
|
-
if (
|
|
12
|
+
let r = g.get(e);
|
|
13
|
+
if (r?.status === "loading" && r.promise != null) return r.promise.then((e) => {
|
|
14
|
+
if (!d(e, n)) throw Error(`Cached backoffice facet kind mismatch: ${n}`);
|
|
15
|
+
return e;
|
|
16
|
+
});
|
|
14
17
|
}
|
|
15
|
-
let
|
|
18
|
+
let a = i().then((t) => (g.set(e, {
|
|
16
19
|
status: "loaded",
|
|
17
20
|
module: t
|
|
18
21
|
}), t)).catch((t) => {
|
|
19
22
|
let n = u(t);
|
|
20
|
-
throw
|
|
23
|
+
throw g.set(e, {
|
|
21
24
|
status: "error",
|
|
22
25
|
error: n
|
|
23
26
|
}), n;
|
|
24
27
|
});
|
|
25
|
-
return
|
|
28
|
+
return g.set(e, {
|
|
26
29
|
status: "loading",
|
|
27
|
-
promise:
|
|
28
|
-
}),
|
|
30
|
+
promise: a
|
|
31
|
+
}), a;
|
|
29
32
|
};
|
|
30
33
|
return {
|
|
31
|
-
getManifest:
|
|
32
|
-
getLoadedListEntity: (e) =>
|
|
33
|
-
getLoadedPickerEntity: (e) =>
|
|
34
|
-
getLoadedDetailLayoutEntity: (e) =>
|
|
35
|
-
getLoadedDetailPageEntity: (e, t) =>
|
|
36
|
-
getLoadedToolEntity: (e) =>
|
|
34
|
+
getManifest: _,
|
|
35
|
+
getLoadedListEntity: (e) => f(g.get(l(e, i)), i),
|
|
36
|
+
getLoadedPickerEntity: (e) => f(g.get(l(e, a)), a),
|
|
37
|
+
getLoadedDetailLayoutEntity: (e) => f(g.get(l(e, r)), r),
|
|
38
|
+
getLoadedDetailPageEntity: (e, t) => f(g.get(l(e, n, t)), n),
|
|
39
|
+
getLoadedToolEntity: (e) => f(g.get(l(e, o)), o),
|
|
37
40
|
loadListEntity: async (t, n) => {
|
|
38
|
-
let r =
|
|
41
|
+
let r = p(m, t);
|
|
39
42
|
if (!s(r)) throw Error(`Backoffice entity ${t} does not expose a list facet.`);
|
|
40
43
|
let a = r.facets.list;
|
|
41
44
|
if (a == null) throw Error(`Backoffice entity ${t} does not expose a list facet.`);
|
|
42
|
-
return
|
|
43
|
-
let n = await a(), o = e(r, n,
|
|
45
|
+
return v(l(t, i), i, n, async () => {
|
|
46
|
+
let n = await a(), o = e(r, n, h);
|
|
44
47
|
if (o.kind !== i) throw Error(`Backoffice entity ${t} did not resolve to a list facet.`);
|
|
45
48
|
return o;
|
|
46
49
|
});
|
|
47
50
|
},
|
|
48
51
|
loadPickerEntity: async (t, n) => {
|
|
49
|
-
let r =
|
|
52
|
+
let r = p(m, t);
|
|
50
53
|
if (!s(r)) throw Error(`Backoffice entity ${t} does not expose a picker facet.`);
|
|
51
54
|
let i = r.facets.picker;
|
|
52
55
|
if (i == null) throw Error(`Backoffice entity ${t} does not expose a picker facet.`);
|
|
53
|
-
return
|
|
54
|
-
let n = await i(), o = e(r, n,
|
|
56
|
+
return v(l(t, a), a, n, async () => {
|
|
57
|
+
let n = await i(), o = e(r, n, h);
|
|
55
58
|
if (o.kind !== a) throw Error(`Backoffice entity ${t} did not resolve to a picker facet.`);
|
|
56
59
|
return o;
|
|
57
60
|
});
|
|
58
61
|
},
|
|
59
62
|
loadDetailLayoutEntity: async (t, n) => {
|
|
60
|
-
let i =
|
|
63
|
+
let i = p(m, t);
|
|
61
64
|
if (!s(i)) throw Error(`Backoffice entity ${t} does not expose a detail-layout facet.`);
|
|
62
|
-
return
|
|
63
|
-
let n = await i.facets.detailLayout(), a = e(i, n,
|
|
65
|
+
return v(l(t, r), r, n, async () => {
|
|
66
|
+
let n = await i.facets.detailLayout(), a = e(i, n, h);
|
|
64
67
|
if (a.kind !== r) throw Error(`Backoffice entity ${t} did not resolve to a detail-layout facet.`);
|
|
65
68
|
return a;
|
|
66
69
|
});
|
|
67
70
|
},
|
|
68
71
|
loadDetailPageEntity: async (t, r, i) => {
|
|
69
|
-
let a =
|
|
72
|
+
let a = p(m, t);
|
|
70
73
|
if (!s(a)) throw Error(`Backoffice entity ${t} does not expose a detail-page facet.`);
|
|
71
|
-
return
|
|
72
|
-
let i = await a.facets.detailPage(r), o = e(a, i,
|
|
74
|
+
return v(l(t, n, r), n, i, async () => {
|
|
75
|
+
let i = await a.facets.detailPage(r), o = e(a, i, h);
|
|
73
76
|
if (o.kind !== n) throw Error(`Backoffice entity ${t} did not resolve to a detail-page facet.`);
|
|
74
77
|
return o;
|
|
75
78
|
});
|
|
76
79
|
},
|
|
77
80
|
loadToolEntity: async (t, n) => {
|
|
78
|
-
let r =
|
|
81
|
+
let r = p(m, t);
|
|
79
82
|
if (!c(r)) throw Error(`Backoffice entity ${t} does not expose a tool facet.`);
|
|
80
|
-
return
|
|
81
|
-
let n = await r.facets.tool(), i = e(r, n,
|
|
83
|
+
return v(l(t, o), o, n, async () => {
|
|
84
|
+
let n = await r.facets.tool(), i = e(r, n, h);
|
|
82
85
|
if (i.kind !== o) throw Error(`Backoffice entity ${t} did not resolve to a tool facet.`);
|
|
83
86
|
return i;
|
|
84
87
|
});
|
|
85
88
|
}
|
|
86
89
|
};
|
|
87
|
-
},
|
|
90
|
+
}, h = {
|
|
88
91
|
buildFacetCacheKey: l,
|
|
89
|
-
resolveManifest:
|
|
92
|
+
resolveManifest: p,
|
|
90
93
|
toError: u
|
|
91
94
|
};
|
|
92
95
|
//#endregion
|
|
93
|
-
export {
|
|
96
|
+
export { h as __test, m as createBackofficeEntityRegistry, m as default };
|
|
94
97
|
|
|
95
98
|
//# sourceMappingURL=entityRegistry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entityRegistry.js","names":[],"sources":["../../../src/provider/entityRegistry.ts"],"sourcesContent":["import {\n resolveBackofficeLoadedFacetModule,\n type ResolveBackofficeEntityOptions,\n} from '@plumile/backoffice-core/resolve.js';\nimport type {\n BackofficeEntityFacetModuleCacheEntry,\n BackofficeEntityLoadMode,\n BackofficeEntityManifestMap,\n BackofficeResolvedEntityFacetModule,\n BackofficeListDetailFacetLoaderMap,\n BackofficeToolFacetLoaderMap,\n BackofficeResolvedDetailLayoutFacetModule,\n BackofficeResolvedDetailPageFacetModule,\n BackofficeResolvedListFacetModule,\n BackofficeResolvedPickerFacetModule,\n BackofficeResolvedToolFacetModule,\n} from '@plumile/backoffice-core/types.js';\n\nexport type BackofficeEntityRegistry = {\n getManifest: (entityId: string) => BackofficeEntityManifestMap[string] | null;\n getLoadedListEntity: (\n entityId: string,\n ) => BackofficeResolvedListFacetModule | null;\n getLoadedPickerEntity: (\n entityId: string,\n ) => BackofficeResolvedPickerFacetModule | null;\n getLoadedDetailLayoutEntity: (\n entityId: string,\n ) => BackofficeResolvedDetailLayoutFacetModule | null;\n getLoadedDetailPageEntity: (\n entityId: string,\n pageId: string,\n ) => BackofficeResolvedDetailPageFacetModule | null;\n getLoadedToolEntity: (\n entityId: string,\n ) => BackofficeResolvedToolFacetModule | null;\n loadListEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedListFacetModule>;\n loadPickerEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedPickerFacetModule>;\n loadDetailLayoutEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedDetailLayoutFacetModule>;\n loadDetailPageEntity: (\n entityId: string,\n pageId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedDetailPageFacetModule>;\n loadToolEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedToolFacetModule>;\n};\n\nconst DEFAULT_LOAD_MODE: BackofficeEntityLoadMode = 'cache-first';\nconst DETAIL_PAGE_FACET_KIND = 'detail-page';\nconst DETAIL_LAYOUT_FACET_KIND = 'detail-layout';\nconst LIST_FACET_KIND = 'list';\nconst PICKER_FACET_KIND = 'picker';\nconst TOOL_FACET_KIND = 'tool';\n\nconst hasListFacets = (\n manifestItem: BackofficeEntityManifestMap[string],\n): manifestItem is BackofficeEntityManifestMap[string] & {\n facets: BackofficeListDetailFacetLoaderMap;\n} => {\n return manifestItem.kind === 'list-detail';\n};\n\nconst hasToolFacet = (\n manifestItem: BackofficeEntityManifestMap[string],\n): manifestItem is BackofficeEntityManifestMap[string] & {\n facets: BackofficeToolFacetLoaderMap;\n} => {\n return manifestItem.kind === 'tool';\n};\n\nconst buildFacetCacheKey = (\n entityId: string,\n kind: 'list' | 'picker' | 'detail-layout' | 'detail-page' | 'tool',\n pageId?: string,\n): string => {\n if (kind === DETAIL_PAGE_FACET_KIND) {\n return `${entityId}:${kind}:${pageId ?? ''}`;\n }\n return `${entityId}:${kind}`;\n};\n\nconst toError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error(String(error));\n};\n\nconst getLoadedModule = <TModule>(\n entry: BackofficeEntityFacetModuleCacheEntry | undefined,\n): TModule | null => {\n if (entry?.status !== 'loaded' || entry.module == null) {\n return null;\n }\n return entry.module as TModule;\n};\n\nconst resolveManifest = (\n manifest: BackofficeEntityManifestMap,\n entityId: string,\n): BackofficeEntityManifestMap[string] => {\n const manifestItem = manifest[entityId];\n if (manifestItem == null) {\n throw new Error(`Unknown backoffice entity: ${entityId}`);\n }\n return manifestItem;\n};\n\nexport const createBackofficeEntityRegistry = (\n manifest: BackofficeEntityManifestMap,\n options: ResolveBackofficeEntityOptions,\n): BackofficeEntityRegistry => {\n const cache = new Map<string, BackofficeEntityFacetModuleCacheEntry>();\n\n const getManifest: BackofficeEntityRegistry['getManifest'] = (entityId) => {\n return manifest[entityId] ?? null;\n };\n\n const loadFacet = async <TModule>(\n cacheKey: string,\n loadOptions: { mode?: BackofficeEntityLoadMode } | undefined,\n loader: () => Promise<TModule>,\n ): Promise<TModule> => {\n const resolvedMode = loadOptions?.mode ?? DEFAULT_LOAD_MODE;\n\n if (resolvedMode === 'cache-first') {\n const loadedModule = getLoadedModule<TModule>(cache.get(cacheKey));\n if (loadedModule != null) {\n return loadedModule;\n }\n\n const existing = cache.get(cacheKey);\n if (existing?.status === 'loading' && existing.promise != null) {\n return existing.promise as Promise<TModule>;\n }\n }\n\n const promise = loader()\n .then((module) => {\n cache.set(cacheKey, {\n status: 'loaded',\n module: module as unknown as BackofficeResolvedEntityFacetModule,\n });\n return module;\n })\n .catch((error: unknown) => {\n const resolvedError = toError(error);\n cache.set(cacheKey, {\n status: 'error',\n error: resolvedError,\n });\n throw resolvedError;\n });\n\n cache.set(cacheKey, {\n status: 'loading',\n promise: promise as Promise<BackofficeResolvedEntityFacetModule>,\n });\n\n return promise;\n };\n\n const getLoadedListEntity: BackofficeEntityRegistry['getLoadedListEntity'] = (\n entityId,\n ) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, LIST_FACET_KIND)),\n );\n };\n\n const getLoadedPickerEntity: BackofficeEntityRegistry['getLoadedPickerEntity'] =\n (entityId) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, PICKER_FACET_KIND)),\n );\n };\n\n const getLoadedDetailLayoutEntity: BackofficeEntityRegistry['getLoadedDetailLayoutEntity'] =\n (entityId) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, DETAIL_LAYOUT_FACET_KIND)),\n );\n };\n\n const getLoadedDetailPageEntity: BackofficeEntityRegistry['getLoadedDetailPageEntity'] =\n (entityId, pageId) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, DETAIL_PAGE_FACET_KIND, pageId)),\n );\n };\n\n const getLoadedToolEntity: BackofficeEntityRegistry['getLoadedToolEntity'] = (\n entityId,\n ) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, TOOL_FACET_KIND)),\n );\n };\n\n const loadListEntity: BackofficeEntityRegistry['loadListEntity'] = async (\n entityId,\n loadOptions,\n ) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a list facet.`,\n );\n }\n const facetLoader = manifestItem.facets.list;\n if (facetLoader == null) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a list facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, LIST_FACET_KIND),\n loadOptions,\n async () => {\n const loaded = await facetLoader();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== LIST_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a list facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadPickerEntity: BackofficeEntityRegistry['loadPickerEntity'] = async (\n entityId,\n loadOptions,\n ) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a picker facet.`,\n );\n }\n const facetLoader = manifestItem.facets.picker;\n if (facetLoader == null) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a picker facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, PICKER_FACET_KIND),\n loadOptions,\n async () => {\n const loaded = await facetLoader();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== PICKER_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a picker facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadDetailLayoutEntity: BackofficeEntityRegistry['loadDetailLayoutEntity'] =\n async (entityId, loadOptions) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a detail-layout facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, DETAIL_LAYOUT_FACET_KIND),\n loadOptions,\n async () => {\n const loaded = await manifestItem.facets.detailLayout();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== DETAIL_LAYOUT_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a detail-layout facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadDetailPageEntity: BackofficeEntityRegistry['loadDetailPageEntity'] =\n async (entityId, pageId, loadOptions) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a detail-page facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, DETAIL_PAGE_FACET_KIND, pageId),\n loadOptions,\n async () => {\n const loaded = await manifestItem.facets.detailPage(pageId);\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== DETAIL_PAGE_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a detail-page facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadToolEntity: BackofficeEntityRegistry['loadToolEntity'] = async (\n entityId,\n loadOptions,\n ) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasToolFacet(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a tool facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, TOOL_FACET_KIND),\n loadOptions,\n async () => {\n const loaded = await manifestItem.facets.tool();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== TOOL_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a tool facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n return {\n getManifest,\n getLoadedListEntity,\n getLoadedPickerEntity,\n getLoadedDetailLayoutEntity,\n getLoadedDetailPageEntity,\n getLoadedToolEntity,\n loadListEntity,\n loadPickerEntity,\n loadDetailLayoutEntity,\n loadDetailPageEntity,\n loadToolEntity,\n };\n};\n\nexport const __test = {\n buildFacetCacheKey,\n resolveManifest,\n toError,\n};\n\nexport default createBackofficeEntityRegistry;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entityRegistry.js","names":[],"sources":["../../../src/provider/entityRegistry.ts"],"sourcesContent":["import {\n resolveBackofficeLoadedFacetModule,\n type ResolveBackofficeEntityOptions,\n} from '@plumile/backoffice-core/resolve.js';\nimport type {\n BackofficeEntityFacetModuleCacheEntry,\n BackofficeEntityLoadMode,\n BackofficeEntityManifestMap,\n BackofficeResolvedEntityFacetModule,\n BackofficeListDetailFacetLoaderMap,\n BackofficeToolFacetLoaderMap,\n BackofficeResolvedDetailLayoutFacetModule,\n BackofficeResolvedDetailPageFacetModule,\n BackofficeResolvedListFacetModule,\n BackofficeResolvedPickerFacetModule,\n BackofficeResolvedToolFacetModule,\n} from '@plumile/backoffice-core/types.js';\n\nexport type BackofficeEntityRegistry = {\n getManifest: (entityId: string) => BackofficeEntityManifestMap[string] | null;\n getLoadedListEntity: (\n entityId: string,\n ) => BackofficeResolvedListFacetModule | null;\n getLoadedPickerEntity: (\n entityId: string,\n ) => BackofficeResolvedPickerFacetModule | null;\n getLoadedDetailLayoutEntity: (\n entityId: string,\n ) => BackofficeResolvedDetailLayoutFacetModule | null;\n getLoadedDetailPageEntity: (\n entityId: string,\n pageId: string,\n ) => BackofficeResolvedDetailPageFacetModule | null;\n getLoadedToolEntity: (\n entityId: string,\n ) => BackofficeResolvedToolFacetModule | null;\n loadListEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedListFacetModule>;\n loadPickerEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedPickerFacetModule>;\n loadDetailLayoutEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedDetailLayoutFacetModule>;\n loadDetailPageEntity: (\n entityId: string,\n pageId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedDetailPageFacetModule>;\n loadToolEntity: (\n entityId: string,\n options?: { mode?: BackofficeEntityLoadMode },\n ) => Promise<BackofficeResolvedToolFacetModule>;\n};\n\nconst DEFAULT_LOAD_MODE: BackofficeEntityLoadMode = 'cache-first';\nconst DETAIL_PAGE_FACET_KIND = 'detail-page';\nconst DETAIL_LAYOUT_FACET_KIND = 'detail-layout';\nconst LIST_FACET_KIND = 'list';\nconst PICKER_FACET_KIND = 'picker';\nconst TOOL_FACET_KIND = 'tool';\n\nconst hasListFacets = (\n manifestItem: BackofficeEntityManifestMap[string],\n): manifestItem is BackofficeEntityManifestMap[string] & {\n facets: BackofficeListDetailFacetLoaderMap;\n} => {\n return manifestItem.kind === 'list-detail';\n};\n\nconst hasToolFacet = (\n manifestItem: BackofficeEntityManifestMap[string],\n): manifestItem is BackofficeEntityManifestMap[string] & {\n facets: BackofficeToolFacetLoaderMap;\n} => {\n return manifestItem.kind === 'tool';\n};\n\nconst buildFacetCacheKey = (\n entityId: string,\n kind: 'list' | 'picker' | 'detail-layout' | 'detail-page' | 'tool',\n pageId?: string,\n): string => {\n if (kind === DETAIL_PAGE_FACET_KIND) {\n return `${entityId}:${kind}:${pageId ?? ''}`;\n }\n return `${entityId}:${kind}`;\n};\n\nconst toError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error(String(error));\n};\n\ntype BackofficeResolvedFacetKind = BackofficeResolvedEntityFacetModule['kind'];\ntype BackofficeResolvedFacetModule<Kind extends BackofficeResolvedFacetKind> =\n Extract<BackofficeResolvedEntityFacetModule, { kind: Kind }>;\n\nconst isResolvedFacetKind = <Kind extends BackofficeResolvedFacetKind>(\n module: BackofficeResolvedEntityFacetModule,\n kind: Kind,\n): module is BackofficeResolvedFacetModule<Kind> => {\n return module.kind === kind;\n};\n\nconst getLoadedModule = <Kind extends BackofficeResolvedFacetKind>(\n entry: BackofficeEntityFacetModuleCacheEntry | undefined,\n kind: Kind,\n): BackofficeResolvedFacetModule<Kind> | null => {\n if (entry?.status !== 'loaded' || entry.module == null) {\n return null;\n }\n if (isResolvedFacetKind(entry.module, kind)) {\n return entry.module;\n }\n return null;\n};\n\nconst resolveManifest = (\n manifest: BackofficeEntityManifestMap,\n entityId: string,\n): BackofficeEntityManifestMap[string] => {\n const manifestItem = manifest[entityId];\n if (manifestItem == null) {\n throw new Error(`Unknown backoffice entity: ${entityId}`);\n }\n return manifestItem;\n};\n\nexport const createBackofficeEntityRegistry = (\n manifest: BackofficeEntityManifestMap,\n options: ResolveBackofficeEntityOptions,\n): BackofficeEntityRegistry => {\n const cache = new Map<string, BackofficeEntityFacetModuleCacheEntry>();\n\n const getManifest: BackofficeEntityRegistry['getManifest'] = (entityId) => {\n return manifest[entityId] ?? null;\n };\n\n const loadFacet = async <Kind extends BackofficeResolvedFacetKind>(\n cacheKey: string,\n kind: Kind,\n loadOptions: { mode?: BackofficeEntityLoadMode } | undefined,\n loader: () => Promise<BackofficeResolvedFacetModule<Kind>>,\n ): Promise<BackofficeResolvedFacetModule<Kind>> => {\n const resolvedMode = loadOptions?.mode ?? DEFAULT_LOAD_MODE;\n\n if (resolvedMode === 'cache-first') {\n const loadedModule = getLoadedModule(cache.get(cacheKey), kind);\n if (loadedModule != null) {\n return loadedModule;\n }\n\n const existing = cache.get(cacheKey);\n if (existing?.status === 'loading' && existing.promise != null) {\n return existing.promise.then((module) => {\n if (!isResolvedFacetKind(module, kind)) {\n throw new Error(`Cached backoffice facet kind mismatch: ${kind}`);\n }\n return module;\n });\n }\n }\n\n const promise = loader()\n .then((module) => {\n cache.set(cacheKey, {\n status: 'loaded',\n module,\n });\n return module;\n })\n .catch((error: unknown) => {\n const resolvedError = toError(error);\n cache.set(cacheKey, {\n status: 'error',\n error: resolvedError,\n });\n throw resolvedError;\n });\n\n cache.set(cacheKey, {\n status: 'loading',\n promise,\n });\n\n return promise;\n };\n\n const getLoadedListEntity: BackofficeEntityRegistry['getLoadedListEntity'] = (\n entityId,\n ) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, LIST_FACET_KIND)),\n LIST_FACET_KIND,\n );\n };\n\n const getLoadedPickerEntity: BackofficeEntityRegistry['getLoadedPickerEntity'] =\n (entityId) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, PICKER_FACET_KIND)),\n PICKER_FACET_KIND,\n );\n };\n\n const getLoadedDetailLayoutEntity: BackofficeEntityRegistry['getLoadedDetailLayoutEntity'] =\n (entityId) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, DETAIL_LAYOUT_FACET_KIND)),\n DETAIL_LAYOUT_FACET_KIND,\n );\n };\n\n const getLoadedDetailPageEntity: BackofficeEntityRegistry['getLoadedDetailPageEntity'] =\n (entityId, pageId) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, DETAIL_PAGE_FACET_KIND, pageId)),\n DETAIL_PAGE_FACET_KIND,\n );\n };\n\n const getLoadedToolEntity: BackofficeEntityRegistry['getLoadedToolEntity'] = (\n entityId,\n ) => {\n return getLoadedModule(\n cache.get(buildFacetCacheKey(entityId, TOOL_FACET_KIND)),\n TOOL_FACET_KIND,\n );\n };\n\n const loadListEntity: BackofficeEntityRegistry['loadListEntity'] = async (\n entityId,\n loadOptions,\n ) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a list facet.`,\n );\n }\n const facetLoader = manifestItem.facets.list;\n if (facetLoader == null) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a list facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, LIST_FACET_KIND),\n LIST_FACET_KIND,\n loadOptions,\n async () => {\n const loaded = await facetLoader();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== LIST_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a list facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadPickerEntity: BackofficeEntityRegistry['loadPickerEntity'] = async (\n entityId,\n loadOptions,\n ) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a picker facet.`,\n );\n }\n const facetLoader = manifestItem.facets.picker;\n if (facetLoader == null) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a picker facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, PICKER_FACET_KIND),\n PICKER_FACET_KIND,\n loadOptions,\n async () => {\n const loaded = await facetLoader();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== PICKER_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a picker facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadDetailLayoutEntity: BackofficeEntityRegistry['loadDetailLayoutEntity'] =\n async (entityId, loadOptions) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a detail-layout facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, DETAIL_LAYOUT_FACET_KIND),\n DETAIL_LAYOUT_FACET_KIND,\n loadOptions,\n async () => {\n const loaded = await manifestItem.facets.detailLayout();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== DETAIL_LAYOUT_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a detail-layout facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadDetailPageEntity: BackofficeEntityRegistry['loadDetailPageEntity'] =\n async (entityId, pageId, loadOptions) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasListFacets(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a detail-page facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, DETAIL_PAGE_FACET_KIND, pageId),\n DETAIL_PAGE_FACET_KIND,\n loadOptions,\n async () => {\n const loaded = await manifestItem.facets.detailPage(pageId);\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== DETAIL_PAGE_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a detail-page facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n const loadToolEntity: BackofficeEntityRegistry['loadToolEntity'] = async (\n entityId,\n loadOptions,\n ) => {\n const manifestItem = resolveManifest(manifest, entityId);\n if (!hasToolFacet(manifestItem)) {\n throw new Error(\n `Backoffice entity ${entityId} does not expose a tool facet.`,\n );\n }\n return loadFacet(\n buildFacetCacheKey(entityId, TOOL_FACET_KIND),\n TOOL_FACET_KIND,\n loadOptions,\n async () => {\n const loaded = await manifestItem.facets.tool();\n const resolved = resolveBackofficeLoadedFacetModule(\n manifestItem,\n loaded,\n options,\n );\n if (resolved.kind !== TOOL_FACET_KIND) {\n throw new Error(\n `Backoffice entity ${entityId} did not resolve to a tool facet.`,\n );\n }\n return resolved;\n },\n );\n };\n\n return {\n getManifest,\n getLoadedListEntity,\n getLoadedPickerEntity,\n getLoadedDetailLayoutEntity,\n getLoadedDetailPageEntity,\n getLoadedToolEntity,\n loadListEntity,\n loadPickerEntity,\n loadDetailLayoutEntity,\n loadDetailPageEntity,\n loadToolEntity,\n };\n};\n\nexport const __test = {\n buildFacetCacheKey,\n resolveManifest,\n toError,\n};\n\nexport default createBackofficeEntityRegistry;\n"],"mappings":"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"}
|
|
@@ -2,14 +2,14 @@ import { getBackofficeLoginPath as e, isBackofficeAuthPath as t } from "../route
|
|
|
2
2
|
import { useEffect as n, useState as r, useSyncExternalStore as i } from "react";
|
|
3
3
|
import { addAuthRefreshStateListener as a, getAuthRefreshState as o, getShortAccessToken as s } from "@plumile/auth/shortAccessToken.js";
|
|
4
4
|
//#region src/provider/useBackofficeAuthRouteGate.ts
|
|
5
|
-
var c = (e) => a(e), l = () => o(), u = () => typeof window > "u" ? "/" : window.location.pathname, d = (a) => {
|
|
6
|
-
let o = i(c, l, l), [
|
|
5
|
+
var c = (e) => a(e), l = () => o(), u = () => typeof window > "u" ? "/" : window.location.pathname, d = (e) => e.status === "authenticated" ? !0 : e.status === "refreshing" || e.status === "temporarily_unavailable" ? e.previousExpiresAtMs != null : !1, f = (a) => {
|
|
6
|
+
let o = i(c, l, l), [f, p] = r(u), m = t(a, f);
|
|
7
7
|
return n(() => {
|
|
8
|
-
if (
|
|
8
|
+
if (m || o.status === "authenticated") return;
|
|
9
9
|
if (o.status === "session_expired") {
|
|
10
10
|
if (typeof window < "u") {
|
|
11
11
|
let t = e(a);
|
|
12
|
-
window.history.replaceState(window.history.state, "", t),
|
|
12
|
+
window.history.replaceState(window.history.state, "", t), p(t);
|
|
13
13
|
}
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
@@ -30,10 +30,10 @@ var c = (e) => a(e), l = () => o(), u = () => typeof window > "u" ? "/" : window
|
|
|
30
30
|
}, [
|
|
31
31
|
o,
|
|
32
32
|
a,
|
|
33
|
-
|
|
34
|
-
]),
|
|
33
|
+
m
|
|
34
|
+
]), m || d(o);
|
|
35
35
|
};
|
|
36
36
|
//#endregion
|
|
37
|
-
export {
|
|
37
|
+
export { f as useBackofficeAuthRouteGate };
|
|
38
38
|
|
|
39
39
|
//# sourceMappingURL=useBackofficeAuthRouteGate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeAuthRouteGate.js","names":[],"sources":["../../../src/provider/useBackofficeAuthRouteGate.ts"],"sourcesContent":["import { useEffect, useState, useSyncExternalStore } from 'react';\nimport {\n addAuthRefreshStateListener,\n getAuthRefreshState,\n getShortAccessToken,\n} from '@plumile/auth/shortAccessToken.js';\nimport type { AuthRefreshState } from '@plumile/auth/authRefreshState.js';\n\nimport {\n getBackofficeLoginPath,\n isBackofficeAuthPath,\n} from '../router/backofficeAuthPaths.js';\n\nconst subscribe = (onStoreChange: () => void): (() => void) => {\n return addAuthRefreshStateListener(onStoreChange);\n};\n\nconst getSnapshot = (): AuthRefreshState => {\n return getAuthRefreshState();\n};\n\nconst currentPathname = (): string => {\n if (typeof window === 'undefined') {\n return '/';\n }\n return window.location.pathname;\n};\n\nexport const useBackofficeAuthRouteGate = (basePath: string): boolean => {\n const authState = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const [pathname, setPathname] = useState(currentPathname);\n const isAuthPath = isBackofficeAuthPath(basePath, pathname);\n\n useEffect(() => {\n if (isAuthPath || authState.status === 'authenticated') {\n return undefined;\n }\n\n if (authState.status === 'session_expired') {\n if (typeof window !== 'undefined') {\n const loginPath = getBackofficeLoginPath(basePath);\n window.history.replaceState(window.history.state, '', loginPath);\n setPathname(loginPath);\n }\n return undefined;\n }\n\n if (authState.status === 'refreshing') {\n return undefined;\n }\n\n let cancelled = false;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n const authenticate = (): void => {\n getShortAccessToken().catch(() => {\n // The shared auth state carries the typed failure and drives the next render.\n });\n };\n\n if (authState.status === 'temporarily_unavailable') {\n const { retryAtMs } = authState;\n if (retryAtMs == null) {\n return undefined;\n }\n retryTimer = setTimeout(\n () => {\n if (!cancelled) {\n authenticate();\n }\n },\n Math.max(0, retryAtMs - Date.now()),\n );\n } else {\n authenticate();\n }\n\n return () => {\n cancelled = true;\n if (retryTimer != null) {\n clearTimeout(retryTimer);\n }\n };\n }, [authState, basePath, isAuthPath]);\n\n return isAuthPath || authState
|
|
1
|
+
{"version":3,"file":"useBackofficeAuthRouteGate.js","names":[],"sources":["../../../src/provider/useBackofficeAuthRouteGate.ts"],"sourcesContent":["import { useEffect, useState, useSyncExternalStore } from 'react';\nimport {\n addAuthRefreshStateListener,\n getAuthRefreshState,\n getShortAccessToken,\n} from '@plumile/auth/shortAccessToken.js';\nimport type { AuthRefreshState } from '@plumile/auth/authRefreshState.js';\n\nimport {\n getBackofficeLoginPath,\n isBackofficeAuthPath,\n} from '../router/backofficeAuthPaths.js';\n\nconst subscribe = (onStoreChange: () => void): (() => void) => {\n return addAuthRefreshStateListener(onStoreChange);\n};\n\nconst getSnapshot = (): AuthRefreshState => {\n return getAuthRefreshState();\n};\n\nconst currentPathname = (): string => {\n if (typeof window === 'undefined') {\n return '/';\n }\n return window.location.pathname;\n};\n\nconst hasEstablishedSession = (authState: AuthRefreshState): boolean => {\n if (authState.status === 'authenticated') {\n return true;\n }\n\n if (\n authState.status === 'refreshing' ||\n authState.status === 'temporarily_unavailable'\n ) {\n return authState.previousExpiresAtMs != null;\n }\n\n return false;\n};\n\nexport const useBackofficeAuthRouteGate = (basePath: string): boolean => {\n const authState = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const [pathname, setPathname] = useState(currentPathname);\n const isAuthPath = isBackofficeAuthPath(basePath, pathname);\n\n useEffect(() => {\n if (isAuthPath || authState.status === 'authenticated') {\n return undefined;\n }\n\n if (authState.status === 'session_expired') {\n if (typeof window !== 'undefined') {\n const loginPath = getBackofficeLoginPath(basePath);\n window.history.replaceState(window.history.state, '', loginPath);\n setPathname(loginPath);\n }\n return undefined;\n }\n\n if (authState.status === 'refreshing') {\n return undefined;\n }\n\n let cancelled = false;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n const authenticate = (): void => {\n getShortAccessToken().catch(() => {\n // The shared auth state carries the typed failure and drives the next render.\n });\n };\n\n if (authState.status === 'temporarily_unavailable') {\n const { retryAtMs } = authState;\n if (retryAtMs == null) {\n return undefined;\n }\n retryTimer = setTimeout(\n () => {\n if (!cancelled) {\n authenticate();\n }\n },\n Math.max(0, retryAtMs - Date.now()),\n );\n } else {\n authenticate();\n }\n\n return () => {\n cancelled = true;\n if (retryTimer != null) {\n clearTimeout(retryTimer);\n }\n };\n }, [authState, basePath, isAuthPath]);\n\n return isAuthPath || hasEstablishedSession(authState);\n};\n"],"mappings":";;;;AAaA,IAAM,KAAa,MACV,EAA4B,CAAa,GAG5C,UACG,EAAoB,GAGvB,UACA,OAAO,SAAW,MACb,MAEF,OAAO,SAAS,UAGnB,KAAyB,MACzB,EAAU,WAAW,kBAChB,KAIP,EAAU,WAAW,gBACrB,EAAU,WAAW,4BAEd,EAAU,uBAAuB,OAGnC,IAGI,KAA8B,MAA8B;CACvE,IAAM,IAAY,EAAqB,GAAW,GAAa,CAAW,GACpE,CAAC,GAAU,KAAe,EAAS,CAAe,GAClD,IAAa,EAAqB,GAAU,CAAQ;CAqD1D,OAnDA,QAAgB;EACd,IAAI,KAAc,EAAU,WAAW,iBACrC;EAGF,IAAI,EAAU,WAAW,mBAAmB;GAC1C,IAAI,OAAO,SAAW,KAAa;IACjC,IAAM,IAAY,EAAuB,CAAQ;IAEjD,AADA,OAAO,QAAQ,aAAa,OAAO,QAAQ,OAAO,IAAI,CAAS,GAC/D,EAAY,CAAS;GACvB;GACA;EACF;EAEA,IAAI,EAAU,WAAW,cACvB;EAGF,IAAI,IAAY,IACZ,GACE,UAA2B;GAC/B,EAAoB,CAAC,CAAC,YAAY,CAElC,CAAC;EACH;EAEA,IAAI,EAAU,WAAW,2BAA2B;GAClD,IAAM,EAAE,iBAAc;GACtB,IAAI,KAAa,MACf;GAEF,IAAa,iBACL;IACJ,AAAK,KACH,EAAa;GAEjB,GACA,KAAK,IAAI,GAAG,IAAY,KAAK,IAAI,CAAC,CACpC;EACF,OACE,EAAa;EAGf,aAAa;GAEX,AADA,IAAY,IACR,KAAc,QAChB,aAAa,CAAU;EAE3B;CACF,GAAG;EAAC;EAAW;EAAU;CAAU,CAAC,GAE7B,KAAc,EAAsB,CAAS;AACtD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createInlineReader.js","names":[],"sources":["../../../src/relay/createInlineReader.ts"],"sourcesContent":["import type { GraphQLTaggedNode } from 'relay-runtime';\nimport {
|
|
1
|
+
{"version":3,"file":"createInlineReader.js","names":[],"sources":["../../../src/relay/createInlineReader.ts"],"sourcesContent":["import type { GraphQLTaggedNode } from 'relay-runtime';\nimport {\n readBackofficeInlineData,\n type BackofficeRelayKey,\n type BackofficeRelayKeyData,\n} from './typedRelayHooks.js';\n\ntype ExactDataWitness<Actual, Expected> = [Actual] extends [Expected]\n ? [Expected] extends [Actual]\n ? unknown\n : never\n : never;\n\n// Reserved for non-React helpers that explicitly read `@inline` fragments.\nexport const createInlineDataReader = <\n TKey extends BackofficeRelayKey,\n TData extends BackofficeRelayKeyData<TKey> = BackofficeRelayKeyData<TKey>,\n>(\n fragment: GraphQLTaggedNode &\n ExactDataWitness<BackofficeRelayKeyData<TKey>, TData>,\n): ((ref: TKey) => BackofficeRelayKeyData<TKey>) => {\n return (ref: TKey) => {\n return readBackofficeInlineData(fragment, ref);\n };\n};\n"],"mappings":";;AAcA,IAAa,KAIX,OAGQ,MACC,EAAyB,GAAU,CAAG"}
|