@plumile/backoffice-react 0.1.193 → 0.1.195

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.
Files changed (117) hide show
  1. package/lib/esm/auth/AuthRefreshNotice.js.map +1 -1
  2. package/lib/esm/auth/TotpQrCode.js +8 -5
  3. package/lib/esm/auth/TotpQrCode.js.map +1 -1
  4. package/lib/esm/auth/login/AuthPanel.js.map +1 -1
  5. package/lib/esm/auth/login/EmailCapturePanel.js +4 -4
  6. package/lib/esm/auth/login/EmailCapturePanel.js.map +1 -1
  7. package/lib/esm/auth/login/LoginFlow.js.map +1 -1
  8. package/lib/esm/auth/login/MethodChooser.js.map +1 -1
  9. package/lib/esm/auth/login/MfaChallengeForm.js +4 -4
  10. package/lib/esm/auth/login/MfaChallengeForm.js.map +1 -1
  11. package/lib/esm/auth/login/OidcButtons.js.map +1 -1
  12. package/lib/esm/auth/login/PasskeyLoginForm.js +4 -4
  13. package/lib/esm/auth/login/PasskeyLoginForm.js.map +1 -1
  14. package/lib/esm/auth/login/PasswordLoginPanel.js.map +1 -1
  15. package/lib/esm/auth/pages/AcceptInvitationScreen.js.map +1 -1
  16. package/lib/esm/auth/pages/PasswordResetCompleteScreen.js.map +1 -1
  17. package/lib/esm/auth/pages/PasswordResetRequestScreen.js.map +1 -1
  18. package/lib/esm/auth/pages/VerifyEmailScreen.js.map +1 -1
  19. package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js +0 -1
  20. package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js.map +1 -1
  21. package/lib/esm/components/backoffice/actions/LazyBackofficeEntityActionFormDialog.js.map +1 -1
  22. package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js.map +1 -1
  23. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js +16 -11
  24. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js.map +1 -1
  25. package/lib/esm/components/backoffice/detail/BackofficeDetailBadgeRow.js.map +1 -1
  26. package/lib/esm/components/backoffice/detail/BackofficeDetailErrorList.js.map +1 -1
  27. package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js.map +1 -1
  28. package/lib/esm/components/backoffice/detail/BackofficeLifecycleTimelineSection.js.map +1 -1
  29. package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js.map +1 -1
  30. package/lib/esm/components/backoffice/detail/BackofficeTokenUsageBreakdown.js.map +1 -1
  31. package/lib/esm/components/backoffice/detail/BackofficeUsageCostBreakdown.js.map +1 -1
  32. package/lib/esm/components/backoffice/filters/BackofficeFilterAction.js +2 -2
  33. package/lib/esm/components/backoffice/filters/BackofficeFilterAction.js.map +1 -1
  34. package/lib/esm/components/backoffice/filters/DeferredFilterSearchInput.js.map +1 -1
  35. package/lib/esm/components/backoffice/filters/EntityFilterValue.js.map +1 -1
  36. package/lib/esm/components/backoffice/filters/EntityIdFilterField.js.map +1 -1
  37. package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js.map +1 -1
  38. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js +4 -1
  39. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js.map +1 -1
  40. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js.map +1 -1
  41. package/lib/esm/components/backoffice/layout/buildSidebarSections.js.map +1 -1
  42. package/lib/esm/components/backoffice/layout/sidebarUtils.js.map +1 -1
  43. package/lib/esm/components/backoffice/links/BackofficeInlineLink.js.map +1 -1
  44. package/lib/esm/components/backoffice/links/BackofficeLink.js.map +1 -1
  45. package/lib/esm/components/backoffice/links/BackofficeLinkContent.js.map +1 -1
  46. package/lib/esm/components/backoffice/links/BackofficeLinkLabel.js.map +1 -1
  47. package/lib/esm/components/backoffice/list/RowFlagsCell.js.map +1 -1
  48. package/lib/esm/components/backoffice/overview/BackofficeOverviewLayout.js.map +1 -1
  49. package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js +9 -9
  50. package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js.map +1 -1
  51. package/lib/esm/components/backoffice/refs/BackofficeEntityIdRef.js.map +1 -1
  52. package/lib/esm/components/backoffice/refs/BackofficeEntityLink.js.map +1 -1
  53. package/lib/esm/components/backoffice/refs/BackofficeLazyEntityCount.js.map +1 -1
  54. package/lib/esm/components/backoffice/refs/BackofficeRelatedCountLink.js +4 -4
  55. package/lib/esm/components/backoffice/refs/BackofficeRelatedCountLink.js.map +1 -1
  56. package/lib/esm/components/backoffice/routing/BackofficeContentBoundary.js.map +1 -1
  57. package/lib/esm/components/backoffice/routing/BackofficeContentError.js.map +1 -1
  58. package/lib/esm/components/backoffice/routing/BackofficeContentFallback.js.map +1 -1
  59. package/lib/esm/components/backoffice/routing/BackofficeRoutePendingBar.js.map +1 -1
  60. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityDetailNotFound.js +8 -5
  61. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityDetailNotFound.js.map +1 -1
  62. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js +306 -297
  63. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
  64. package/lib/esm/components/backoffice/scaffolds/BackofficeTabbedDetailShell.js.map +1 -1
  65. package/lib/esm/components/backoffice/shared/BackofficeFilterableCell.js.map +1 -1
  66. package/lib/esm/components/backoffice/shared/BackofficeFormattedCurrency.js.map +1 -1
  67. package/lib/esm/components/backoffice/shared/BackofficeFormattedNumber.js.map +1 -1
  68. package/lib/esm/components/backoffice/shared/BackofficeInlineFilterRow.js.map +1 -1
  69. package/lib/esm/components/backoffice/tools/BackofficeToolsDocPanel.js.map +1 -1
  70. package/lib/esm/components/backoffice/tools/BackofficeToolsErrorFallback.js.map +1 -1
  71. package/lib/esm/components/backoffice/tools/BackofficeToolsJsonForm.js.map +1 -1
  72. package/lib/esm/components/backoffice/tools/BackofficeToolsQueryBoundary.js +11 -11
  73. package/lib/esm/components/backoffice/tools/BackofficeToolsQueryBoundary.js.map +1 -1
  74. package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js +1 -1
  75. package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js.map +1 -1
  76. package/lib/esm/pages/BackofficeAcceptInvitationPage.js +8 -8
  77. package/lib/esm/pages/BackofficeAcceptInvitationPage.js.map +1 -1
  78. package/lib/esm/pages/BackofficeDashboardPage.js +4 -4
  79. package/lib/esm/pages/BackofficeDashboardPage.js.map +1 -1
  80. package/lib/esm/pages/BackofficeDashboardShellPage.js.map +1 -1
  81. package/lib/esm/pages/BackofficeDashboardWidgetContent.js +62 -43
  82. package/lib/esm/pages/BackofficeDashboardWidgetContent.js.map +1 -1
  83. package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js +4 -4
  84. package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js.map +1 -1
  85. package/lib/esm/pages/BackofficeEntityDetailPage.js +95 -89
  86. package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
  87. package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js +2 -2
  88. package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js.map +1 -1
  89. package/lib/esm/pages/BackofficeEntityDetailPageConfigPage.js.map +1 -1
  90. package/lib/esm/pages/BackofficeEntityListDataPage.js +13 -11
  91. package/lib/esm/pages/BackofficeEntityListDataPage.js.map +1 -1
  92. package/lib/esm/pages/BackofficeEntityListPage.js +80 -76
  93. package/lib/esm/pages/BackofficeEntityListPage.js.map +1 -1
  94. package/lib/esm/pages/BackofficeEntityListShellPage.js.map +1 -1
  95. package/lib/esm/pages/BackofficeHubPage.js.map +1 -1
  96. package/lib/esm/pages/BackofficeLayoutPage.js +56 -53
  97. package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
  98. package/lib/esm/pages/BackofficeLoginPage.js +26 -26
  99. package/lib/esm/pages/BackofficeLoginPage.js.map +1 -1
  100. package/lib/esm/pages/BackofficePasswordResetCompletePage.js +36 -36
  101. package/lib/esm/pages/BackofficePasswordResetCompletePage.js.map +1 -1
  102. package/lib/esm/pages/BackofficePasswordResetRequestPage.js +3 -3
  103. package/lib/esm/pages/BackofficePasswordResetRequestPage.js.map +1 -1
  104. package/lib/esm/pages/BackofficeToolShellPage.js.map +1 -1
  105. package/lib/esm/pages/BackofficeVerifyEmailPage.js +36 -36
  106. package/lib/esm/pages/BackofficeVerifyEmailPage.js.map +1 -1
  107. package/lib/esm/pages/detail/BackofficeEntityDetailManifestFallback.js.map +1 -1
  108. package/lib/esm/provider/BackofficeProvider.js +3 -2
  109. package/lib/esm/provider/BackofficeProvider.js.map +1 -1
  110. package/lib/esm/relay/envHelpers.js.map +1 -1
  111. package/lib/esm/router/createBackofficeRoutes.js +2 -2
  112. package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
  113. package/lib/esm/storybook/relay/RelayStory.js +4 -1
  114. package/lib/esm/storybook/relay/RelayStory.js.map +1 -1
  115. package/lib/esm/subscriptions/useCursorResumableSubscription.js +4 -4
  116. package/lib/esm/subscriptions/useCursorResumableSubscription.js.map +1 -1
  117. package/package.json +20 -20
@@ -1 +1 @@
1
- {"version":3,"file":"DeferredFilterSearchInput.js","names":[],"sources":["../../../../../src/components/backoffice/filters/DeferredFilterSearchInput.tsx"],"sourcesContent":["import {\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n type KeyboardEvent,\n} from 'react';\n\nimport { Input } from '@plumile/ui/atomic/atoms/input/Input.js';\nimport { CheckSvg } from '@plumile/ui/icons/CheckSvg.js';\nimport { ModalCloseSvg } from '@plumile/ui/icons/ModalCloseSvg.js';\nimport { SidebarSearchSvg } from '@plumile/ui/icons/SidebarSearchSvg.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './deferredFilterSearchInput.css.js';\n\nexport type DeferredFilterSearchInputProps = {\n value: string;\n placeholder: string;\n ariaLabel?: string;\n className?: string;\n inputMode?: 'search' | 'numeric' | 'decimal';\n type?: 'search' | 'text' | 'number' | 'datetime-local';\n onApply: (value: string) => void;\n};\n\nexport const DeferredFilterSearchInput = ({\n value,\n placeholder,\n ariaLabel,\n className,\n inputMode = 'search',\n type = 'text',\n onApply,\n}: DeferredFilterSearchInputProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [draftValue, setDraftValue] = useState(value);\n\n useEffect(() => {\n setDraftValue(value);\n }, [value]);\n\n const normalizedDraft = draftValue.trim();\n const normalizedValue = value.trim();\n const hasDraft = normalizedDraft !== '';\n const hasPendingValue = normalizedDraft !== normalizedValue;\n const canClear = hasDraft || normalizedValue !== '';\n const inputLabel = ariaLabel ?? placeholder;\n const clearLabel = t('filters.actions.clearFilter', { label: inputLabel });\n const applyLabel = t('filters.actions.applyFilter', { label: inputLabel });\n\n const applyDraft = () => {\n if (!hasPendingValue) {\n return;\n }\n onApply(normalizedDraft);\n };\n\n const clearValue = () => {\n setDraftValue('');\n if (normalizedValue !== '') {\n onApply('');\n }\n };\n\n let clearActionNode: JSX.Element = (\n <span className={styles.actionButtonSpacer} aria-hidden=\"true\" />\n );\n if (canClear) {\n clearActionNode = (\n <button\n type=\"button\"\n className={styles.actionButton}\n aria-label={clearLabel}\n title={clearLabel}\n onClick={clearValue}\n >\n <ModalCloseSvg width={16} height={16} aria-hidden=\"true\" />\n </button>\n );\n }\n\n return (\n <form\n className={className}\n onSubmit={(event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n applyDraft();\n }}\n >\n <div className={styles.container}>\n <Input\n type={type}\n inputMode={inputMode}\n value={draftValue}\n onInput={(event: FormEvent<HTMLInputElement>) => {\n setDraftValue(event.currentTarget.value);\n }}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n applyDraft();\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n setDraftValue(value);\n }\n }}\n placeholder={placeholder}\n aria-label={inputLabel}\n size=\"small\"\n fullWidth\n leftIcon={\n <SidebarSearchSvg width={18} height={18} aria-hidden=\"true\" />\n }\n rightIconIsInteractive\n rightIcon={\n <span className={styles.actions}>\n {clearActionNode}\n <button\n type=\"submit\"\n className={styles.actionButton}\n aria-label={applyLabel}\n title={applyLabel}\n disabled={!hasPendingValue}\n >\n <CheckSvg width={16} height={16} aria-hidden=\"true\" />\n </button>\n </span>\n }\n />\n </div>\n </form>\n );\n};\n\nexport default DeferredFilterSearchInput;\n"],"mappings":";;;;;;;;;AA2BA,IAAa,KAA6B,EACxC,UACA,gBACA,cACA,cACA,eAAY,UACZ,UAAO,QACP,iBACiD;CACjD,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAY,KAAiB,EAAS,CAAK;CAElD,QAAgB;EACd,EAAc,CAAK;CACrB,GAAG,CAAC,CAAK,CAAC;CAEV,IAAM,IAAkB,EAAW,KAAK,GAClC,IAAkB,EAAM,KAAK,GAC7B,IAAW,MAAoB,IAC/B,IAAkB,MAAoB,GACtC,IAAW,KAAY,MAAoB,IAC3C,IAAa,KAAa,GAC1B,IAAa,EAAE,+BAA+B,EAAE,OAAO,EAAW,CAAC,GACnE,IAAa,EAAE,+BAA+B,EAAE,OAAO,EAAW,CAAC,GAEnE,UAAmB;EAClB,KAGL,EAAQ,CAAe;CACzB,GAEM,UAAmB;EAEvB,AADA,EAAc,EAAE,GACZ,MAAoB,MACtB,EAAQ,EAAE;CAEd,GAEI,IACF,kBAAC,QAAD;EAAM,WAAW;EAA2B,eAAY;CAAQ,CAAA;CAgBlE,OAdI,MACF,IACE,kBAAC,UAAD;EACE,MAAK;EACL,WAAW;EACX,cAAY;EACZ,OAAO;EACP,SAAS;YAET,kBAAC,GAAD;GAAe,OAAO;GAAI,QAAQ;GAAI,eAAY;EAAQ,CAAA;CACpD,CAAA,IAKV,kBAAC,QAAD;EACa;EACX,WAAW,MAAsC;GAE/C,AADA,EAAM,eAAe,GACrB,EAAW;EACb;YAEA,kBAAC,OAAD;GAAK,WAAW;aACd,kBAAC,GAAD;IACQ;IACK;IACX,OAAO;IACP,UAAU,MAAuC;KAC/C,EAAc,EAAM,cAAc,KAAK;IACzC;IACA,YAAY,MAA2C;KAKrD,AAJI,EAAM,QAAQ,YAChB,EAAM,eAAe,GACrB,EAAW,IAET,EAAM,QAAQ,aAChB,EAAM,eAAe,GACrB,EAAc,CAAK;IAEvB;IACa;IACb,cAAY;IACZ,MAAK;IACL,WAAA;IACA,UACE,kBAAC,GAAD;KAAkB,OAAO;KAAI,QAAQ;KAAI,eAAY;IAAQ,CAAA;IAE/D,wBAAA;IACA,WACE,kBAAC,QAAD;KAAM,WAAW;eAAjB,CACG,GACD,kBAAC,UAAD;MACE,MAAK;MACL,WAAW;MACX,cAAY;MACZ,OAAO;MACP,UAAU,CAAC;gBAEX,kBAAC,GAAD;OAAU,OAAO;OAAI,QAAQ;OAAI,eAAY;MAAQ,CAAA;KAC/C,CAAA,CACJ;;GAET,CAAA;EACE,CAAA;CACD,CAAA;AAEV"}
1
+ {"version":3,"file":"DeferredFilterSearchInput.js","names":[],"sources":["../../../../../src/components/backoffice/filters/DeferredFilterSearchInput.tsx"],"sourcesContent":["import {\n useEffect,\n useState,\n type FormEvent,\n type JSX,\n type KeyboardEvent,\n} from 'react';\n\nimport { Input } from '@plumile/ui/atomic/atoms/input/Input.js';\nimport { CheckSvg } from '@plumile/ui/icons/CheckSvg.js';\nimport { ModalCloseSvg } from '@plumile/ui/icons/ModalCloseSvg.js';\nimport { SidebarSearchSvg } from '@plumile/ui/icons/SidebarSearchSvg.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './deferredFilterSearchInput.css.js';\n\nexport type DeferredFilterSearchInputProps = {\n value: string;\n placeholder: string;\n ariaLabel?: string;\n className?: string;\n inputMode?: 'search' | 'numeric' | 'decimal';\n type?: 'search' | 'text' | 'number' | 'datetime-local';\n onApply: (value: string) => void;\n};\n\nexport const DeferredFilterSearchInput = ({\n value,\n placeholder,\n ariaLabel,\n className,\n inputMode = 'search',\n type = 'text',\n onApply,\n}: DeferredFilterSearchInputProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const [draftValue, setDraftValue] = useState(value);\n\n useEffect(() => {\n setDraftValue(value);\n }, [value]);\n\n const normalizedDraft = draftValue.trim();\n const normalizedValue = value.trim();\n const hasDraft = normalizedDraft !== '';\n const hasPendingValue = normalizedDraft !== normalizedValue;\n const canClear = hasDraft || normalizedValue !== '';\n const inputLabel = ariaLabel ?? placeholder;\n const clearLabel = t('filters.actions.clearFilter', { label: inputLabel });\n const applyLabel = t('filters.actions.applyFilter', { label: inputLabel });\n\n const applyDraft = () => {\n if (!hasPendingValue) {\n return;\n }\n onApply(normalizedDraft);\n };\n\n const clearValue = () => {\n setDraftValue('');\n if (normalizedValue !== '') {\n onApply('');\n }\n };\n\n let clearActionNode: JSX.Element = (\n <span className={styles.actionButtonSpacer} aria-hidden=\"true\" />\n );\n if (canClear) {\n clearActionNode = (\n <button\n type=\"button\"\n className={styles.actionButton}\n aria-label={clearLabel}\n title={clearLabel}\n onClick={clearValue}\n >\n <ModalCloseSvg width={16} height={16} aria-hidden=\"true\" />\n </button>\n );\n }\n\n return (\n <form\n className={className}\n onSubmit={(event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n applyDraft();\n }}\n >\n <div className={styles.container}>\n <Input\n type={type}\n inputMode={inputMode}\n value={draftValue}\n onInput={(event: FormEvent<HTMLInputElement>) => {\n setDraftValue(event.currentTarget.value);\n }}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n applyDraft();\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n setDraftValue(value);\n }\n }}\n placeholder={placeholder}\n aria-label={inputLabel}\n size=\"small\"\n fullWidth\n leftIcon={\n <SidebarSearchSvg width={18} height={18} aria-hidden=\"true\" />\n }\n rightIconIsInteractive\n rightIcon={\n <span className={styles.actions}>\n {clearActionNode}\n <button\n type=\"submit\"\n className={styles.actionButton}\n aria-label={applyLabel}\n title={applyLabel}\n disabled={!hasPendingValue}\n >\n <CheckSvg width={16} height={16} aria-hidden=\"true\" />\n </button>\n </span>\n }\n />\n </div>\n </form>\n );\n};\n\nexport default DeferredFilterSearchInput;\n"],"mappings":";;;;;;;;;AA2BA,IAAa,KAA6B,EACxC,UACA,gBACA,cACA,cACA,eAAY,UACZ,UAAO,QACP,iBACiD;CACjD,IAAM,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAY,KAAiB,EAAS,CAAK;CAElD,QAAgB;EACd,EAAc,CAAK;CACrB,GAAG,CAAC,CAAK,CAAC;CAEV,IAAM,IAAkB,EAAW,KAAK,GAClC,IAAkB,EAAM,KAAK,GAC7B,IAAW,MAAoB,IAC/B,IAAkB,MAAoB,GACtC,IAAW,KAAY,MAAoB,IAC3C,IAAa,KAAa,GAC1B,IAAa,EAAE,+BAA+B,EAAE,OAAO,EAAW,CAAC,GACnE,IAAa,EAAE,+BAA+B,EAAE,OAAO,EAAW,CAAC,GAEnE,UAAmB;EAClB,KAGL,EAAQ,CAAe;CACzB,GAEM,UAAmB;EAEvB,AADA,EAAc,EAAE,GACZ,MAAoB,MACtB,EAAQ,EAAE;CAEd,GAEI,IACF,kBAAC,QAAD;EAAM,WAAW;EAA2B,eAAY;CAAQ,CAAA;CAgBlE,OAdI,MACF,IACE,kBAAC,UAAD;EACE,MAAK;EACL,WAAW;EACX,cAAY;EACZ,OAAO;EACP,SAAS;EAET,UAAA,kBAAC,GAAD;GAAe,OAAO;GAAI,QAAQ;GAAI,eAAY;EAAQ,CAAA;CACpD,CAAA,IAKV,kBAAC,QAAD;EACa;EACX,WAAW,MAAsC;GAE/C,AADA,EAAM,eAAe,GACrB,EAAW;EACb;EAEA,UAAA,kBAAC,OAAD;GAAK,WAAW;GACd,UAAA,kBAAC,GAAD;IACQ;IACK;IACX,OAAO;IACP,UAAU,MAAuC;KAC/C,EAAc,EAAM,cAAc,KAAK;IACzC;IACA,YAAY,MAA2C;KAKrD,AAJI,EAAM,QAAQ,YAChB,EAAM,eAAe,GACrB,EAAW,IAET,EAAM,QAAQ,aAChB,EAAM,eAAe,GACrB,EAAc,CAAK;IAEvB;IACa;IACb,cAAY;IACZ,MAAK;IACL,WAAA;IACA,UACE,kBAAC,GAAD;KAAkB,OAAO;KAAI,QAAQ;KAAI,eAAY;IAAQ,CAAA;IAE/D,wBAAA;IACA,WACE,kBAAC,QAAD;KAAM,WAAW;KAAjB,UAAA,CACG,GACD,kBAAC,UAAD;MACE,MAAK;MACL,WAAW;MACX,cAAY;MACZ,OAAO;MACP,UAAU,CAAC;MAEX,UAAA,kBAAC,GAAD;OAAU,OAAO;OAAI,QAAQ;OAAI,eAAY;MAAQ,CAAA;KAC/C,CAAA,CACJ;;GAET,CAAA;EACE,CAAA;CACD,CAAA;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityFilterValue.js","names":[],"sources":["../../../../../src/components/backoffice/filters/EntityFilterValue.tsx"],"sourcesContent":["import { Suspense, type JSX } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\n\nimport type {\n BackofficeAliasedPickerValueResponse,\n BackofficePickerValueConfig,\n} from '@plumile/backoffice-core/types.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficePickerEntityLoader } from '../../../provider/useBackofficeEntityLoader.js';\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\n\nconst { useLazyLoadQuery } = ReactRelay;\n\ntype EntityFilterValueContentProps<RowRef, RowView, ValueQueryData> = {\n valueConfig: BackofficePickerValueConfig<RowRef, RowView, ValueQueryData>;\n id: string;\n children: EntityFilterValueTextChildren;\n};\n\nconst resolveTitle = (value: unknown): string | null => {\n if (value == null || typeof value !== 'object') {\n return null;\n }\n const { title } = value as { title?: unknown };\n if (typeof title !== 'string') {\n return null;\n }\n const trimmed = title.trim();\n if (trimmed === '') {\n return null;\n }\n return trimmed;\n};\n\nconst EntityFilterValueContent = <RowRef, RowView, ValueQueryData>({\n valueConfig,\n id,\n children,\n}: EntityFilterValueContentProps<\n RowRef,\n RowView,\n ValueQueryData\n>): JSX.Element => {\n const data = useLazyLoadQuery<OperationType>(valueConfig.query, {\n id,\n }) as ValueQueryData;\n const rowRef = valueConfig.resolveRow(data);\n let row: RowView | null = null;\n if (rowRef != null) {\n row = valueConfig.toRow(rowRef);\n }\n const title = resolveTitle(row);\n let status: EntityFilterValueTextState['status'] = 'resolved';\n if (title == null) {\n status = 'unresolved';\n }\n\n return children(title, { status });\n};\n\nexport type EntityFilterValueTextState = {\n status: 'loading' | 'resolved' | 'unresolved' | 'unavailable' | 'error';\n};\n\nexport type EntityFilterValueTextChildren = (\n label: string | null,\n state?: EntityFilterValueTextState,\n) => JSX.Element;\n\nexport type EntityFilterValueTextProps = {\n entityId: string;\n id: string;\n children: EntityFilterValueTextChildren;\n};\n\nexport const EntityFilterValueText = ({\n entityId,\n id,\n children,\n}: EntityFilterValueTextProps): JSX.Element => {\n const resolvedId = id.trim();\n const pickerEntityState = useBackofficePickerEntityLoader(entityId, {\n enabled: resolvedId !== '',\n });\n\n if (resolvedId === '') {\n return children(null, { status: 'unavailable' });\n }\n\n let valueConfig: BackofficePickerValueConfig<\n unknown,\n unknown,\n BackofficeAliasedPickerValueResponse<string, unknown>\n > | null = null;\n if (pickerEntityState.status === 'loaded') {\n valueConfig = pickerEntityState.module.config.picker.value ?? null;\n }\n\n const loadingFallback = children(null, { status: 'loading' });\n if (pickerEntityState.status === 'loading') {\n return loadingFallback;\n }\n\n let unavailableStatus: EntityFilterValueTextState['status'] = 'unavailable';\n if (pickerEntityState.status === 'error') {\n unavailableStatus = 'error';\n }\n const unavailableFallback = children(null, {\n status: unavailableStatus,\n });\n if (valueConfig == null) {\n return unavailableFallback;\n }\n\n return (\n <BackofficeErrorBoundary\n fallback={() => {\n return children(null, { status: 'error' });\n }}\n >\n <Suspense fallback={loadingFallback}>\n <EntityFilterValueContent valueConfig={valueConfig} id={id}>\n {children}\n </EntityFilterValueContent>\n </Suspense>\n </BackofficeErrorBoundary>\n );\n};\n\nexport type EntityFilterValueProps = {\n entityId: string;\n id: string;\n};\n\nexport const EntityFilterValue = ({\n entityId,\n id,\n}: EntityFilterValueProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const resolvedId = id.trim();\n\n return (\n <EntityFilterValueText entityId={entityId} id={id}>\n {(label) => {\n let fallbackLabel = resolvedId;\n if (resolvedId === '') {\n fallbackLabel = t('filters.placeholders.unresolved');\n }\n return <span>{label ?? fallbackLabel}</span>;\n }}\n </EntityFilterValueText>\n );\n};\n\nexport default EntityFilterValue;\n"],"mappings":";;;;;;;AAaA,IAAM,EAAE,kBAAA,MAAqB,GAQvB,KAAgB,MAAkC;CACtD,IAAqB,OAAO,KAAU,aAAlC,GACF,OAAO;CAET,IAAM,EAAE,aAAU;CAClB,IAAI,OAAO,KAAU,UACnB,OAAO;CAET,IAAM,IAAU,EAAM,KAAK;CAI3B,OAHI,MAAY,KACP,OAEF;AACT,GAEM,KAA6D,EACjE,gBACA,OACA,kBAKiB;CACjB,IAAM,IAAO,EAAgC,EAAY,OAAO,EAC9D,MACF,CAAC,GACK,IAAS,EAAY,WAAW,CAAI,GACtC,IAAsB;CAC1B,AAAI,KAAU,SACZ,IAAM,EAAY,MAAM,CAAM;CAEhC,IAAM,IAAQ,EAAa,CAAG,GAC1B,IAA+C;CAKnD,OAJI,MACF,IAAS,eAGJ,EAAS,GAAO,EAAE,UAAO,CAAC;AACnC,GAiBa,KAAyB,EACpC,aACA,OACA,kBAC6C;CAC7C,IAAM,IAAa,EAAG,KAAK,GACrB,IAAoB,EAAgC,GAAU,EAClE,SAAS,MAAe,GAC1B,CAAC;CAED,IAAI,MAAe,IACjB,OAAO,EAAS,MAAM,EAAE,QAAQ,cAAc,CAAC;CAGjD,IAAI,IAIO;CACX,AAAI,EAAkB,WAAW,aAC/B,IAAc,EAAkB,OAAO,OAAO,OAAO,SAAS;CAGhE,IAAM,IAAkB,EAAS,MAAM,EAAE,QAAQ,UAAU,CAAC;CAC5D,IAAI,EAAkB,WAAW,WAC/B,OAAO;CAGT,IAAI,IAA0D;CAC9D,AAAI,EAAkB,WAAW,YAC/B,IAAoB;CAEtB,IAAM,IAAsB,EAAS,MAAM,EACzC,QAAQ,EACV,CAAC;CAKD,OAJI,KAAe,OACV,IAIP,kBAAC,GAAD;EACE,gBACS,EAAS,MAAM,EAAE,QAAQ,QAAQ,CAAC;YAG3C,kBAAC,GAAD;GAAU,UAAU;aAClB,kBAAC,GAAD;IAAuC;IAAiB;IACrD;GACuB,CAAA;EAClB,CAAA;CACa,CAAA;AAE7B,GAOa,KAAqB,EAChC,aACA,YACyC;CACzC,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAa,EAAG,KAAK;CAE3B,OACE,kBAAC,GAAD;EAAiC;EAAc;aAC3C,MAAU;GACV,IAAI,IAAgB;GAIpB,OAHI,MAAe,OACjB,IAAgB,EAAE,iCAAiC,IAE9C,kBAAC,QAAD,EAAA,UAAO,KAAS,EAAoB,CAAA;EAC7C;CACqB,CAAA;AAE3B"}
1
+ {"version":3,"file":"EntityFilterValue.js","names":[],"sources":["../../../../../src/components/backoffice/filters/EntityFilterValue.tsx"],"sourcesContent":["import { Suspense, type JSX } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { OperationType } from 'relay-runtime';\n\nimport type {\n BackofficeAliasedPickerValueResponse,\n BackofficePickerValueConfig,\n} from '@plumile/backoffice-core/types.js';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficePickerEntityLoader } from '../../../provider/useBackofficeEntityLoader.js';\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\n\nconst { useLazyLoadQuery } = ReactRelay;\n\ntype EntityFilterValueContentProps<RowRef, RowView, ValueQueryData> = {\n valueConfig: BackofficePickerValueConfig<RowRef, RowView, ValueQueryData>;\n id: string;\n children: EntityFilterValueTextChildren;\n};\n\nconst resolveTitle = (value: unknown): string | null => {\n if (value == null || typeof value !== 'object') {\n return null;\n }\n const { title } = value as { title?: unknown };\n if (typeof title !== 'string') {\n return null;\n }\n const trimmed = title.trim();\n if (trimmed === '') {\n return null;\n }\n return trimmed;\n};\n\nconst EntityFilterValueContent = <RowRef, RowView, ValueQueryData>({\n valueConfig,\n id,\n children,\n}: EntityFilterValueContentProps<\n RowRef,\n RowView,\n ValueQueryData\n>): JSX.Element => {\n const data = useLazyLoadQuery<OperationType>(valueConfig.query, {\n id,\n }) as ValueQueryData;\n const rowRef = valueConfig.resolveRow(data);\n let row: RowView | null = null;\n if (rowRef != null) {\n row = valueConfig.toRow(rowRef);\n }\n const title = resolveTitle(row);\n let status: EntityFilterValueTextState['status'] = 'resolved';\n if (title == null) {\n status = 'unresolved';\n }\n\n return children(title, { status });\n};\n\nexport type EntityFilterValueTextState = {\n status: 'loading' | 'resolved' | 'unresolved' | 'unavailable' | 'error';\n};\n\nexport type EntityFilterValueTextChildren = (\n label: string | null,\n state?: EntityFilterValueTextState,\n) => JSX.Element;\n\nexport type EntityFilterValueTextProps = {\n entityId: string;\n id: string;\n children: EntityFilterValueTextChildren;\n};\n\nexport const EntityFilterValueText = ({\n entityId,\n id,\n children,\n}: EntityFilterValueTextProps): JSX.Element => {\n const resolvedId = id.trim();\n const pickerEntityState = useBackofficePickerEntityLoader(entityId, {\n enabled: resolvedId !== '',\n });\n\n if (resolvedId === '') {\n return children(null, { status: 'unavailable' });\n }\n\n let valueConfig: BackofficePickerValueConfig<\n unknown,\n unknown,\n BackofficeAliasedPickerValueResponse<string, unknown>\n > | null = null;\n if (pickerEntityState.status === 'loaded') {\n valueConfig = pickerEntityState.module.config.picker.value ?? null;\n }\n\n const loadingFallback = children(null, { status: 'loading' });\n if (pickerEntityState.status === 'loading') {\n return loadingFallback;\n }\n\n let unavailableStatus: EntityFilterValueTextState['status'] = 'unavailable';\n if (pickerEntityState.status === 'error') {\n unavailableStatus = 'error';\n }\n const unavailableFallback = children(null, {\n status: unavailableStatus,\n });\n if (valueConfig == null) {\n return unavailableFallback;\n }\n\n return (\n <BackofficeErrorBoundary\n fallback={() => {\n return children(null, { status: 'error' });\n }}\n >\n <Suspense fallback={loadingFallback}>\n <EntityFilterValueContent valueConfig={valueConfig} id={id}>\n {children}\n </EntityFilterValueContent>\n </Suspense>\n </BackofficeErrorBoundary>\n );\n};\n\nexport type EntityFilterValueProps = {\n entityId: string;\n id: string;\n};\n\nexport const EntityFilterValue = ({\n entityId,\n id,\n}: EntityFilterValueProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const resolvedId = id.trim();\n\n return (\n <EntityFilterValueText entityId={entityId} id={id}>\n {(label) => {\n let fallbackLabel = resolvedId;\n if (resolvedId === '') {\n fallbackLabel = t('filters.placeholders.unresolved');\n }\n return <span>{label ?? fallbackLabel}</span>;\n }}\n </EntityFilterValueText>\n );\n};\n\nexport default EntityFilterValue;\n"],"mappings":";;;;;;;AAaA,IAAM,EAAE,kBAAA,MAAqB,GAQvB,KAAgB,MAAkC;CACtD,IAAqB,OAAO,KAAU,aAAlC,GACF,OAAO;CAET,IAAM,EAAE,aAAU;CAClB,IAAI,OAAO,KAAU,UACnB,OAAO;CAET,IAAM,IAAU,EAAM,KAAK;CAI3B,OAHI,MAAY,KACP,OAEF;AACT,GAEM,KAA6D,EACjE,gBACA,OACA,kBAKiB;CACjB,IAAM,IAAO,EAAgC,EAAY,OAAO,EAC9D,MACF,CAAC,GACK,IAAS,EAAY,WAAW,CAAI,GACtC,IAAsB;CAC1B,AAAI,KAAU,SACZ,IAAM,EAAY,MAAM,CAAM;CAEhC,IAAM,IAAQ,EAAa,CAAG,GAC1B,IAA+C;CAKnD,OAJI,MACF,IAAS,eAGJ,EAAS,GAAO,EAAE,UAAO,CAAC;AACnC,GAiBa,KAAyB,EACpC,aACA,OACA,kBAC6C;CAC7C,IAAM,IAAa,EAAG,KAAK,GACrB,IAAoB,EAAgC,GAAU,EAClE,SAAS,MAAe,GAC1B,CAAC;CAED,IAAI,MAAe,IACjB,OAAO,EAAS,MAAM,EAAE,QAAQ,cAAc,CAAC;CAGjD,IAAI,IAIO;CACX,AAAI,EAAkB,WAAW,aAC/B,IAAc,EAAkB,OAAO,OAAO,OAAO,SAAS;CAGhE,IAAM,IAAkB,EAAS,MAAM,EAAE,QAAQ,UAAU,CAAC;CAC5D,IAAI,EAAkB,WAAW,WAC/B,OAAO;CAGT,IAAI,IAA0D;CAC9D,AAAI,EAAkB,WAAW,YAC/B,IAAoB;CAEtB,IAAM,IAAsB,EAAS,MAAM,EACzC,QAAQ,EACV,CAAC;CAKD,OAJI,KAAe,OACV,IAIP,kBAAC,GAAD;EACE,gBACS,EAAS,MAAM,EAAE,QAAQ,QAAQ,CAAC;EAG3C,UAAA,kBAAC,GAAD;GAAU,UAAU;GAClB,UAAA,kBAAC,GAAD;IAAuC;IAAiB;IACrD;GACuB,CAAA;EAClB,CAAA;CACa,CAAA;AAE7B,GAOa,KAAqB,EAChC,aACA,YACyC;CACzC,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAa,EAAG,KAAK;CAE3B,OACE,kBAAC,GAAD;EAAiC;EAAc;EAC3C,WAAA,MAAU;GACV,IAAI,IAAgB;GAIpB,OAHI,MAAe,OACjB,IAAgB,EAAE,iCAAiC,IAE9C,kBAAC,QAAD,EAAA,UAAO,KAAS,EAAoB,CAAA;EAC7C;CACqB,CAAA;AAE3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityIdFilterField.js","names":[],"sources":["../../../../../src/components/backoffice/filters/EntityIdFilterField.tsx"],"sourcesContent":["import { type JSX } from 'react';\n\nimport { ModalCloseSvg } from '@plumile/ui/icons/ModalCloseSvg.js';\nimport { BackofficeSidebarPenToolSvg } from '@plumile/ui/icons/backoffice/BackofficeSidebarPenToolSvg.js';\nimport { BackofficeSidebarSearchSvg } from '@plumile/ui/icons/backoffice/BackofficeSidebarSearchSvg.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './entityIdFilterField.css.js';\n\nexport type EntityIdFilterFieldProps = {\n id?: string;\n label: string;\n value: string | null;\n displayValue?: string | null;\n placeholder?: string;\n ariaDescribedBy?: string;\n ariaInvalid?: boolean;\n isResolving?: boolean;\n onPick?: () => void;\n onClear?: () => void;\n disabled?: boolean;\n};\n\nexport const EntityIdFilterField = (\n props: EntityIdFilterFieldProps,\n): JSX.Element => {\n const {\n disabled = false,\n id,\n label,\n value,\n displayValue,\n placeholder,\n ariaDescribedBy,\n ariaInvalid,\n isResolving = false,\n onPick,\n onClear,\n } = props;\n const { t } = useBackofficeReactTranslation();\n const normalizedValue = value?.trim() ?? '';\n const normalizedDisplayValue = displayValue?.trim() ?? '';\n const hasValue = normalizedValue !== '';\n const hasDisplayValue = normalizedDisplayValue !== '';\n\n const resolvedPlaceholder =\n placeholder ?? t('filters.placeholders.anyEntity', { label });\n const unresolvedPlaceholder = t('filters.placeholders.unresolved');\n\n let displayNode: JSX.Element;\n if (hasDisplayValue) {\n displayNode = (\n <span className={styles.valueText}>{normalizedDisplayValue}</span>\n );\n } else if (hasValue) {\n displayNode = (\n <span className={styles.placeholder}>{unresolvedPlaceholder}</span>\n );\n } else {\n displayNode = (\n <span className={styles.placeholder}>{resolvedPlaceholder}</span>\n );\n }\n\n let pickLabel = t('common.actions.pick');\n if (hasValue) {\n pickLabel = t('filters.actions.changeFilterValue', { label });\n }\n let pickAriaLabel = t('filters.actions.filterBy', { label });\n if (hasValue) {\n pickAriaLabel = pickLabel;\n }\n const clearAriaLabel = t('filters.actions.clearFilter', { label });\n\n let clearNode: JSX.Element | null = null;\n if (hasValue && onClear != null) {\n clearNode = (\n <button\n type=\"button\"\n className={styles.clearButton}\n aria-label={clearAriaLabel}\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n onClear();\n }}\n >\n <ModalCloseSvg width={16} height={16} aria-hidden=\"true\" />\n </button>\n );\n }\n\n let pickerNode: JSX.Element | null = null;\n if (onPick != null) {\n let actionIcon = (\n <BackofficeSidebarSearchSvg\n className={styles.actionIcon}\n aria-hidden=\"true\"\n />\n );\n if (hasValue) {\n actionIcon = (\n <BackofficeSidebarPenToolSvg\n className={styles.actionIcon}\n aria-hidden=\"true\"\n />\n );\n }\n\n pickerNode = (\n <div className={styles.pickerControl}>\n <button\n id={id}\n type=\"button\"\n className={styles.pickerButton}\n aria-label={pickAriaLabel}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n aria-busy={isResolving || undefined}\n disabled={disabled}\n onClick={onPick}\n >\n <span className={styles.content}>\n <span className={styles.labelText}>{label}</span>\n {displayNode}\n </span>\n </button>\n <button\n type=\"button\"\n className={styles.pickActionButton}\n aria-label={pickAriaLabel}\n title={pickAriaLabel}\n disabled={disabled}\n onClick={onPick}\n >\n {actionIcon}\n </button>\n {clearNode}\n </div>\n );\n }\n\n return (\n <div className={styles.container}>\n {pickerNode ?? <div className={styles.valueBox}>{displayNode}</div>}\n </div>\n );\n};\n\nexport default EntityIdFilterField;\n"],"mappings":";;;;;;;AAuBA,IAAa,KACX,MACgB;CAChB,IAAM,EACJ,cAAW,IACX,OACA,UACA,UACA,iBACA,aAAA,GACA,oBACA,gBACA,iBAAc,IACd,WACA,eACE,GACE,EAAE,SAAM,EAA8B,GACtC,IAAkB,GAAO,KAAK,KAAK,IACnC,IAAyB,GAAc,KAAK,KAAK,IACjD,IAAW,MAAoB,IAC/B,IAAkB,MAA2B,IAE7C,IACJ,KAAe,EAAE,kCAAkC,EAAE,SAAM,CAAC,GACxD,IAAwB,EAAE,iCAAiC,GAE7D;CACJ,AASE,IATE,IAEA,kBAAC,QAAD;EAAM,WAAW;YAAmB;CAA6B,CAAA,IAE1D,IAEP,kBAAC,QAAD;EAAM,WAAW;YAAqB;CAA4B,CAAA,IAIlE,kBAAC,QAAD;EAAM,WAAW;YAAqB;CAA0B,CAAA;CAIpE,IAAI,IAAY,EAAE,qBAAqB;CACvC,AAAI,MACF,IAAY,EAAE,qCAAqC,EAAE,SAAM,CAAC;CAE9D,IAAI,IAAgB,EAAE,4BAA4B,EAAE,SAAM,CAAC;CAC3D,AAAI,MACF,IAAgB;CAElB,IAAM,IAAiB,EAAE,+BAA+B,EAAE,SAAM,CAAC,GAE7D,IAAgC;CACpC,AAAI,KAAY,KAAW,SACzB,IACE,kBAAC,UAAD;EACE,MAAK;EACL,WAAW;EACX,cAAY;EACF;EACV,UAAU,MAAU;GAElB,AADA,EAAM,gBAAgB,GACtB,EAAQ;EACV;YAEA,kBAAC,GAAD;GAAe,OAAO;GAAI,QAAQ;GAAI,eAAY;EAAQ,CAAA;CACpD,CAAA;CAIZ,IAAI,IAAiC;CACrC,IAAI,KAAU,MAAM;EAClB,IAAI,IACF,kBAAC,GAAD;GACE,WAAW;GACX,eAAY;EACb,CAAA;EAWH,AATI,MACF,IACE,kBAAC,GAAD;GACE,WAAW;GACX,eAAY;EACb,CAAA,IAIL,IACE,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,kBAAC,UAAD;KACM;KACJ,MAAK;KACL,WAAW;KACX,cAAY;KACZ,oBAAkB;KAClB,gBAAc;KACd,aAAW,KAAe,KAAA;KAChB;KACV,SAAS;eAET,kBAAC,QAAD;MAAM,WAAW;gBAAjB,CACE,kBAAC,QAAD;OAAM,WAAW;iBAAmB;MAAY,CAAA,GAC/C,CACG;;IACA,CAAA;IACR,kBAAC,UAAD;KACE,MAAK;KACL,WAAW;KACX,cAAY;KACZ,OAAO;KACG;KACV,SAAS;eAER;IACK,CAAA;IACP;GACE;;CAET;CAEA,OACE,kBAAC,OAAD;EAAK,WAAW;YACb,KAAc,kBAAC,OAAD;GAAK,WAAW;aAAkB;EAAiB,CAAA;CAC/D,CAAA;AAET"}
1
+ {"version":3,"file":"EntityIdFilterField.js","names":[],"sources":["../../../../../src/components/backoffice/filters/EntityIdFilterField.tsx"],"sourcesContent":["import { type JSX } from 'react';\n\nimport { ModalCloseSvg } from '@plumile/ui/icons/ModalCloseSvg.js';\nimport { BackofficeSidebarPenToolSvg } from '@plumile/ui/icons/backoffice/BackofficeSidebarPenToolSvg.js';\nimport { BackofficeSidebarSearchSvg } from '@plumile/ui/icons/backoffice/BackofficeSidebarSearchSvg.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './entityIdFilterField.css.js';\n\nexport type EntityIdFilterFieldProps = {\n id?: string;\n label: string;\n value: string | null;\n displayValue?: string | null;\n placeholder?: string;\n ariaDescribedBy?: string;\n ariaInvalid?: boolean;\n isResolving?: boolean;\n onPick?: () => void;\n onClear?: () => void;\n disabled?: boolean;\n};\n\nexport const EntityIdFilterField = (\n props: EntityIdFilterFieldProps,\n): JSX.Element => {\n const {\n disabled = false,\n id,\n label,\n value,\n displayValue,\n placeholder,\n ariaDescribedBy,\n ariaInvalid,\n isResolving = false,\n onPick,\n onClear,\n } = props;\n const { t } = useBackofficeReactTranslation();\n const normalizedValue = value?.trim() ?? '';\n const normalizedDisplayValue = displayValue?.trim() ?? '';\n const hasValue = normalizedValue !== '';\n const hasDisplayValue = normalizedDisplayValue !== '';\n\n const resolvedPlaceholder =\n placeholder ?? t('filters.placeholders.anyEntity', { label });\n const unresolvedPlaceholder = t('filters.placeholders.unresolved');\n\n let displayNode: JSX.Element;\n if (hasDisplayValue) {\n displayNode = (\n <span className={styles.valueText}>{normalizedDisplayValue}</span>\n );\n } else if (hasValue) {\n displayNode = (\n <span className={styles.placeholder}>{unresolvedPlaceholder}</span>\n );\n } else {\n displayNode = (\n <span className={styles.placeholder}>{resolvedPlaceholder}</span>\n );\n }\n\n let pickLabel = t('common.actions.pick');\n if (hasValue) {\n pickLabel = t('filters.actions.changeFilterValue', { label });\n }\n let pickAriaLabel = t('filters.actions.filterBy', { label });\n if (hasValue) {\n pickAriaLabel = pickLabel;\n }\n const clearAriaLabel = t('filters.actions.clearFilter', { label });\n\n let clearNode: JSX.Element | null = null;\n if (hasValue && onClear != null) {\n clearNode = (\n <button\n type=\"button\"\n className={styles.clearButton}\n aria-label={clearAriaLabel}\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n onClear();\n }}\n >\n <ModalCloseSvg width={16} height={16} aria-hidden=\"true\" />\n </button>\n );\n }\n\n let pickerNode: JSX.Element | null = null;\n if (onPick != null) {\n let actionIcon = (\n <BackofficeSidebarSearchSvg\n className={styles.actionIcon}\n aria-hidden=\"true\"\n />\n );\n if (hasValue) {\n actionIcon = (\n <BackofficeSidebarPenToolSvg\n className={styles.actionIcon}\n aria-hidden=\"true\"\n />\n );\n }\n\n pickerNode = (\n <div className={styles.pickerControl}>\n <button\n id={id}\n type=\"button\"\n className={styles.pickerButton}\n aria-label={pickAriaLabel}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n aria-busy={isResolving || undefined}\n disabled={disabled}\n onClick={onPick}\n >\n <span className={styles.content}>\n <span className={styles.labelText}>{label}</span>\n {displayNode}\n </span>\n </button>\n <button\n type=\"button\"\n className={styles.pickActionButton}\n aria-label={pickAriaLabel}\n title={pickAriaLabel}\n disabled={disabled}\n onClick={onPick}\n >\n {actionIcon}\n </button>\n {clearNode}\n </div>\n );\n }\n\n return (\n <div className={styles.container}>\n {pickerNode ?? <div className={styles.valueBox}>{displayNode}</div>}\n </div>\n );\n};\n\nexport default EntityIdFilterField;\n"],"mappings":";;;;;;;AAuBA,IAAa,KACX,MACgB;CAChB,IAAM,EACJ,cAAW,IACX,OACA,UACA,UACA,iBACA,aAAA,GACA,oBACA,gBACA,iBAAc,IACd,WACA,eACE,GACE,EAAE,SAAM,EAA8B,GACtC,IAAkB,GAAO,KAAK,KAAK,IACnC,IAAyB,GAAc,KAAK,KAAK,IACjD,IAAW,MAAoB,IAC/B,IAAkB,MAA2B,IAE7C,IACJ,KAAe,EAAE,kCAAkC,EAAE,SAAM,CAAC,GACxD,IAAwB,EAAE,iCAAiC,GAE7D;CACJ,AASE,IATE,IAEA,kBAAC,QAAD;EAAM,WAAW;EAAmB,UAAA;CAA6B,CAAA,IAE1D,IAEP,kBAAC,QAAD;EAAM,WAAW;EAAqB,UAAA;CAA4B,CAAA,IAIlE,kBAAC,QAAD;EAAM,WAAW;EAAqB,UAAA;CAA0B,CAAA;CAIpE,IAAI,IAAY,EAAE,qBAAqB;CACvC,AAAI,MACF,IAAY,EAAE,qCAAqC,EAAE,SAAM,CAAC;CAE9D,IAAI,IAAgB,EAAE,4BAA4B,EAAE,SAAM,CAAC;CAC3D,AAAI,MACF,IAAgB;CAElB,IAAM,IAAiB,EAAE,+BAA+B,EAAE,SAAM,CAAC,GAE7D,IAAgC;CACpC,AAAI,KAAY,KAAW,SACzB,IACE,kBAAC,UAAD;EACE,MAAK;EACL,WAAW;EACX,cAAY;EACF;EACV,UAAU,MAAU;GAElB,AADA,EAAM,gBAAgB,GACtB,EAAQ;EACV;EAEA,UAAA,kBAAC,GAAD;GAAe,OAAO;GAAI,QAAQ;GAAI,eAAY;EAAQ,CAAA;CACpD,CAAA;CAIZ,IAAI,IAAiC;CACrC,IAAI,KAAU,MAAM;EAClB,IAAI,IACF,kBAAC,GAAD;GACE,WAAW;GACX,eAAY;EACb,CAAA;EAWH,AATI,MACF,IACE,kBAAC,GAAD;GACE,WAAW;GACX,eAAY;EACb,CAAA,IAIL,IACE,kBAAC,OAAD;GAAK,WAAW;GAAhB,UAAA;IACE,kBAAC,UAAD;KACM;KACJ,MAAK;KACL,WAAW;KACX,cAAY;KACZ,oBAAkB;KAClB,gBAAc;KACd,aAAW,KAAe,KAAA;KAChB;KACV,SAAS;KAET,UAAA,kBAAC,QAAD;MAAM,WAAW;MAAjB,UAAA,CACE,kBAAC,QAAD;OAAM,WAAW;OAAmB,UAAA;MAAY,CAAA,GAC/C,CACG;;IACA,CAAA;IACR,kBAAC,UAAD;KACE,MAAK;KACL,WAAW;KACX,cAAY;KACZ,OAAO;KACG;KACV,SAAS;KAER,UAAA;IACK,CAAA;IACP;GACE;;CAET;CAEA,OACE,kBAAC,OAAD;EAAK,WAAW;EACb,UAAA,KAAc,kBAAC,OAAD;GAAK,WAAW;GAAkB,UAAA;EAAiB,CAAA;CAC/D,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeHubTemplate.js","names":[],"sources":["../../../../../src/components/backoffice/hub/BackofficeHubTemplate.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport Link from '@plumile/router/routing/Link.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { SidebarTasksSvg } from '@plumile/ui/icons/SidebarTasksSvg.js';\n\nimport * as styles from './backofficeHubTemplate.css.js';\n\nexport type BackofficeHubTemplateItemKind = 'entity' | 'tool';\n\nexport type BackofficeHubTemplateItem = {\n id: string;\n kind: BackofficeHubTemplateItemKind;\n label: string;\n href: string;\n icon?: ReactNode;\n description?: string | null;\n metaLabel?: string | null;\n};\n\nexport type BackofficeHubTemplateGroup = {\n id: string;\n title: string;\n description?: string | null;\n icon?: ReactNode;\n items: readonly BackofficeHubTemplateItem[];\n};\n\nexport type BackofficeHubTemplateEmptyState = {\n title: string;\n description: string;\n icon?: ReactNode;\n};\n\nexport type BackofficeHubTemplateSearch = {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n};\n\nexport type BackofficeHubTemplateProps = {\n groups: readonly BackofficeHubTemplateGroup[];\n search?: BackofficeHubTemplateSearch;\n emptyState: BackofficeHubTemplateEmptyState;\n};\n\nconst fallbackIcon = (\n <SidebarTasksSvg width={20} height={20} aria-hidden=\"true\" />\n);\n\nexport const BackofficeHubTemplate = ({\n groups,\n search,\n emptyState,\n}: BackofficeHubTemplateProps): JSX.Element => {\n let body: JSX.Element;\n\n if (groups.length === 0) {\n body = (\n <BackofficeEmptyState\n title={emptyState.title}\n description={emptyState.description}\n icon={emptyState.icon ?? fallbackIcon}\n />\n );\n } else {\n body = (\n <div className={styles.groups}>\n {groups.map((group) => {\n return (\n <section key={group.id} className={styles.group}>\n <div className={styles.groupHeader}>\n {group.icon != null && (\n <span className={styles.groupIcon} aria-hidden=\"true\">\n {group.icon}\n </span>\n )}\n <span className={styles.groupHeading}>\n <h2 className={styles.groupTitle}>{group.title}</h2>\n {group.description != null && (\n <span className={styles.groupDescription}>\n {group.description}\n </span>\n )}\n </span>\n </div>\n <div className={styles.grid}>\n {group.items.map((item) => {\n const icon = item.icon ?? fallbackIcon;\n const hasDescription =\n item.description != null && item.description !== '';\n const hasMetaLabel =\n item.metaLabel != null && item.metaLabel !== '';\n\n return (\n <Link\n key={`${item.kind}-${item.id}`}\n to={item.href}\n className={styles.item}\n preloadOnHover=\"code-and-data\"\n >\n <span className={styles.itemIcon} aria-hidden=\"true\">\n {icon}\n </span>\n <span className={styles.itemContent}>\n <span className={styles.itemTitle}>{item.label}</span>\n {hasDescription && (\n <span className={styles.itemDescription}>\n {item.description}\n </span>\n )}\n {hasMetaLabel && (\n <span className={styles.itemMeta}>\n {item.metaLabel}\n </span>\n )}\n </span>\n </Link>\n );\n })}\n </div>\n </section>\n );\n })}\n </div>\n );\n }\n\n return (\n <div className={styles.content}>\n {search != null && (\n <div className={styles.search}>\n <GlobalSearchInput\n value={search.value}\n onChange={search.onChange}\n placeholder={search.placeholder}\n />\n </div>\n )}\n {body}\n </div>\n );\n};\n\nexport default BackofficeHubTemplate;\n"],"mappings":";;;;;;;AA8CA,IAAM,IACJ,kBAAC,GAAD;CAAiB,OAAO;CAAI,QAAQ;CAAI,eAAY;AAAQ,CAAA,GAGjD,KAAyB,EACpC,QAAA,GACA,QAAA,GACA,oBAC6C;CAC7C,IAAI;CAyEJ,OAvEA,AASE,IATE,EAAO,WAAW,IAElB,kBAAC,GAAD;EACE,OAAO,EAAW;EAClB,aAAa,EAAW;EACxB,MAAM,EAAW,QAAQ;CAC1B,CAAA,IAID,kBAAC,OAAD;EAAK,WAAW;YACb,EAAO,KAAK,MAET,kBAAC,WAAD;GAAwB,WAAW;aAAnC,CACE,kBAAC,OAAD;IAAK,WAAW;cAAhB,CACG,EAAM,QAAQ,QACb,kBAAC,QAAD;KAAM,WAAW;KAAkB,eAAY;eAC5C,EAAM;IACH,CAAA,GAER,kBAAC,QAAD;KAAM,WAAW;eAAjB,CACE,kBAAC,MAAD;MAAI,WAAW;gBAAoB,EAAM;KAAU,CAAA,GAClD,EAAM,eAAe,QACpB,kBAAC,QAAD;MAAM,WAAW;gBACd,EAAM;KACH,CAAA,CAEJ;MACH;OACL,kBAAC,OAAD;IAAK,WAAW;cACb,EAAM,MAAM,KAAK,MAAS;KACzB,IAAM,IAAO,EAAK,QAAQ,GACpB,IACJ,EAAK,eAAe,QAAQ,EAAK,gBAAgB,IAC7C,IACJ,EAAK,aAAa,QAAQ,EAAK,cAAc;KAE/C,OACE,kBAAC,GAAD;MAEE,IAAI,EAAK;MACT,WAAW;MACX,gBAAe;gBAJjB,CAME,kBAAC,QAAD;OAAM,WAAW;OAAiB,eAAY;iBAC3C;MACG,CAAA,GACN,kBAAC,QAAD;OAAM,WAAW;iBAAjB;QACE,kBAAC,QAAD;SAAM,WAAW;mBAAmB,EAAK;QAAY,CAAA;QACpD,KACC,kBAAC,QAAD;SAAM,WAAW;mBACd,EAAK;QACF,CAAA;QAEP,KACC,kBAAC,QAAD;SAAM,WAAW;mBACd,EAAK;QACF,CAAA;OAEJ;QACF;QArBC,GAAG,EAAK,KAAK,GAAG,EAAK,IAqBtB;IAEV,CAAC;GACE,CAAA,CACE;KAnDK,EAAM,EAmDX,CAEZ;CACE,CAAA,GAKP,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,KAAU,QACT,kBAAC,OAAD;GAAK,WAAW;aACd,kBAAC,GAAD;IACE,OAAO,EAAO;IACd,UAAU,EAAO;IACjB,aAAa,EAAO;GACrB,CAAA;EACE,CAAA,GAEN,CACE;;AAET"}
1
+ {"version":3,"file":"BackofficeHubTemplate.js","names":[],"sources":["../../../../../src/components/backoffice/hub/BackofficeHubTemplate.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport Link from '@plumile/router/routing/Link.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { SidebarTasksSvg } from '@plumile/ui/icons/SidebarTasksSvg.js';\n\nimport * as styles from './backofficeHubTemplate.css.js';\n\nexport type BackofficeHubTemplateItemKind = 'entity' | 'tool';\n\nexport type BackofficeHubTemplateItem = {\n id: string;\n kind: BackofficeHubTemplateItemKind;\n label: string;\n href: string;\n icon?: ReactNode;\n description?: string | null;\n metaLabel?: string | null;\n};\n\nexport type BackofficeHubTemplateGroup = {\n id: string;\n title: string;\n description?: string | null;\n icon?: ReactNode;\n items: readonly BackofficeHubTemplateItem[];\n};\n\nexport type BackofficeHubTemplateEmptyState = {\n title: string;\n description: string;\n icon?: ReactNode;\n};\n\nexport type BackofficeHubTemplateSearch = {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n};\n\nexport type BackofficeHubTemplateProps = {\n groups: readonly BackofficeHubTemplateGroup[];\n search?: BackofficeHubTemplateSearch;\n emptyState: BackofficeHubTemplateEmptyState;\n};\n\nconst fallbackIcon = (\n <SidebarTasksSvg width={20} height={20} aria-hidden=\"true\" />\n);\n\nexport const BackofficeHubTemplate = ({\n groups,\n search,\n emptyState,\n}: BackofficeHubTemplateProps): JSX.Element => {\n let body: JSX.Element;\n\n if (groups.length === 0) {\n body = (\n <BackofficeEmptyState\n title={emptyState.title}\n description={emptyState.description}\n icon={emptyState.icon ?? fallbackIcon}\n />\n );\n } else {\n body = (\n <div className={styles.groups}>\n {groups.map((group) => {\n return (\n <section key={group.id} className={styles.group}>\n <div className={styles.groupHeader}>\n {group.icon != null && (\n <span className={styles.groupIcon} aria-hidden=\"true\">\n {group.icon}\n </span>\n )}\n <span className={styles.groupHeading}>\n <h2 className={styles.groupTitle}>{group.title}</h2>\n {group.description != null && (\n <span className={styles.groupDescription}>\n {group.description}\n </span>\n )}\n </span>\n </div>\n <div className={styles.grid}>\n {group.items.map((item) => {\n const icon = item.icon ?? fallbackIcon;\n const hasDescription =\n item.description != null && item.description !== '';\n const hasMetaLabel =\n item.metaLabel != null && item.metaLabel !== '';\n\n return (\n <Link\n key={`${item.kind}-${item.id}`}\n to={item.href}\n className={styles.item}\n preloadOnHover=\"code-and-data\"\n >\n <span className={styles.itemIcon} aria-hidden=\"true\">\n {icon}\n </span>\n <span className={styles.itemContent}>\n <span className={styles.itemTitle}>{item.label}</span>\n {hasDescription && (\n <span className={styles.itemDescription}>\n {item.description}\n </span>\n )}\n {hasMetaLabel && (\n <span className={styles.itemMeta}>\n {item.metaLabel}\n </span>\n )}\n </span>\n </Link>\n );\n })}\n </div>\n </section>\n );\n })}\n </div>\n );\n }\n\n return (\n <div className={styles.content}>\n {search != null && (\n <div className={styles.search}>\n <GlobalSearchInput\n value={search.value}\n onChange={search.onChange}\n placeholder={search.placeholder}\n />\n </div>\n )}\n {body}\n </div>\n );\n};\n\nexport default BackofficeHubTemplate;\n"],"mappings":";;;;;;;AA8CA,IAAM,IACJ,kBAAC,GAAD;CAAiB,OAAO;CAAI,QAAQ;CAAI,eAAY;AAAQ,CAAA,GAGjD,KAAyB,EACpC,QAAA,GACA,QAAA,GACA,oBAC6C;CAC7C,IAAI;CAyEJ,OAvEA,AASE,IATE,EAAO,WAAW,IAElB,kBAAC,GAAD;EACE,OAAO,EAAW;EAClB,aAAa,EAAW;EACxB,MAAM,EAAW,QAAQ;CAC1B,CAAA,IAID,kBAAC,OAAD;EAAK,WAAW;EACb,UAAA,EAAO,KAAK,MAET,kBAAC,WAAD;GAAwB,WAAW;GAAnC,UAAA,CACE,kBAAC,OAAD;IAAK,WAAW;IAAhB,UAAA,CACG,EAAM,QAAQ,QACb,kBAAC,QAAD;KAAM,WAAW;KAAkB,eAAY;KAC5C,UAAA,EAAM;IACH,CAAA,GAER,kBAAC,QAAD;KAAM,WAAW;KAAjB,UAAA,CACE,kBAAC,MAAD;MAAI,WAAW;MAAoB,UAAA,EAAM;KAAU,CAAA,GAClD,EAAM,eAAe,QACpB,kBAAC,QAAD;MAAM,WAAW;MACd,UAAA,EAAM;KACH,CAAA,CAEJ;IACH,CAAA,CAAA;GACL,CAAA,GAAA,kBAAC,OAAD;IAAK,WAAW;IACb,UAAA,EAAM,MAAM,KAAK,MAAS;KACzB,IAAM,IAAO,EAAK,QAAQ,GACpB,IACJ,EAAK,eAAe,QAAQ,EAAK,gBAAgB,IAC7C,IACJ,EAAK,aAAa,QAAQ,EAAK,cAAc;KAE/C,OACE,kBAAC,GAAD;MAEE,IAAI,EAAK;MACT,WAAW;MACX,gBAAe;MAJjB,UAAA,CAME,kBAAC,QAAD;OAAM,WAAW;OAAiB,eAAY;OAC3C,UAAA;MACG,CAAA,GACN,kBAAC,QAAD;OAAM,WAAW;OAAjB,UAAA;QACE,kBAAC,QAAD;SAAM,WAAW;SAAmB,UAAA,EAAK;QAAY,CAAA;QACpD,KACC,kBAAC,QAAD;SAAM,WAAW;SACd,UAAA,EAAK;QACF,CAAA;QAEP,KACC,kBAAC,QAAD;SAAM,WAAW;SACd,UAAA,EAAK;QACF,CAAA;OAEJ;MACF,CAAA,CAAA;KArBC,GAAA,GAAG,EAAK,KAAK,GAAG,EAAK,IAqBtB;IAEV,CAAC;GACE,CAAA,CACE;EAnDK,GAAA,EAAM,EAmDX,CAEZ;CACE,CAAA,GAKP,kBAAC,OAAD;EAAK,WAAW;EAAhB,UAAA,CACG,KAAU,QACT,kBAAC,OAAD;GAAK,WAAW;GACd,UAAA,kBAAC,GAAD;IACE,OAAO,EAAO;IACd,UAAU,EAAO;IACjB,aAAa,EAAO;GACrB,CAAA;EACE,CAAA,GAEN,CACE;;AAET"}
@@ -3,7 +3,10 @@ import { BackofficeTopbarPortal as t } from "./BackofficeTopbarPortal.js";
3
3
  import { BackofficeTopbarBreadcrumb as n } from "./BackofficeTopbarBreadcrumb.js";
4
4
  import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
5
5
  //#region src/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.tsx
6
- var o = ({ breadcrumb: o, children: s }) => /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i(t, { children: /* @__PURE__ */ i(n, { items: e(o) }) }), /* @__PURE__ */ i(r, { children: s })] });
6
+ var o = ({ breadcrumb: o, children: s }) => {
7
+ let c = e(o);
8
+ return /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i(t, { children: /* @__PURE__ */ i(n, { items: c }) }), /* @__PURE__ */ i(r, { children: s })] });
9
+ };
7
10
  //#endregion
8
11
  export { o as BackofficeRightPageLayout, o as default };
9
12
 
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeRightPageLayout.js","names":[],"sources":["../../../../../../src/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport { assertValidBreadcrumb } from './assertValidBreadcrumb.js';\nimport { BackofficeTopbarPortal } from './BackofficeTopbarPortal.js';\nimport { BackofficeTopbarBreadcrumb } from './BackofficeTopbarBreadcrumb.js';\nimport type { BackofficeTopbarBreadcrumbItem } from './types.js';\n\nexport type BackofficeRightPageLayoutProps = {\n breadcrumb: readonly BackofficeTopbarBreadcrumbItem[];\n children: ReactNode;\n};\n\nexport const BackofficeRightPageLayout = ({\n breadcrumb,\n children,\n}: BackofficeRightPageLayoutProps): JSX.Element => {\n const items = assertValidBreadcrumb(breadcrumb);\n\n return (\n <>\n <BackofficeTopbarPortal>\n <BackofficeTopbarBreadcrumb items={items} />\n </BackofficeTopbarPortal>\n <>{children}</>\n </>\n );\n};\n\nexport default BackofficeRightPageLayout;\n"],"mappings":";;;;;AAYA,IAAa,KAA6B,EACxC,eACA,kBAKE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAmC,OAL3B,EAAsB,CAKK,EAAQ,CAAA,EACrB,CAAA,GACxB,kBAAA,GAAA,EAAG,YAAW,CAAA,CACd,EAAA,CAAA"}
1
+ {"version":3,"file":"BackofficeRightPageLayout.js","names":[],"sources":["../../../../../../src/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport { assertValidBreadcrumb } from './assertValidBreadcrumb.js';\nimport { BackofficeTopbarPortal } from './BackofficeTopbarPortal.js';\nimport { BackofficeTopbarBreadcrumb } from './BackofficeTopbarBreadcrumb.js';\nimport type { BackofficeTopbarBreadcrumbItem } from './types.js';\n\nexport type BackofficeRightPageLayoutProps = {\n breadcrumb: readonly BackofficeTopbarBreadcrumbItem[];\n children: ReactNode;\n};\n\nexport const BackofficeRightPageLayout = ({\n breadcrumb,\n children,\n}: BackofficeRightPageLayoutProps): JSX.Element => {\n const items = assertValidBreadcrumb(breadcrumb);\n\n return (\n <>\n <BackofficeTopbarPortal>\n <BackofficeTopbarBreadcrumb items={items} />\n </BackofficeTopbarPortal>\n <>{children}</>\n </>\n );\n};\n\nexport default BackofficeRightPageLayout;\n"],"mappings":";;;;;AAYA,IAAa,KAA6B,EACxC,eACA,kBACiD;CACjD,IAAM,IAAQ,EAAsB,CAAU;CAE9C,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAmC,SAAQ,CAAA,EACrB,CAAA,GACxB,kBAAA,GAAA,EAAG,YAAW,CAAA,CACd,EAAA,CAAA;AAEN"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeTopbarBreadcrumb.js","names":[],"sources":["../../../../../../src/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.tsx"],"sourcesContent":["import { type JSX } from 'react';\nimport Link from '@plumile/router/routing/Link.js';\nimport { SidebarHomeSvg } from '@plumile/ui/icons/SidebarHomeSvg.js';\n\nimport { BackofficeLink } from '../../links/BackofficeLink.js';\nimport { BackofficeLinkLabel } from '../../links/BackofficeLinkLabel.js';\nimport { useBackofficeReactTranslation } from '../../../../i18n/useBackofficeReactTranslation.js';\nimport type { BackofficeTopbarBreadcrumbItem } from './types.js';\nimport { useBackofficeTopbarPortalContext } from './BackofficeTopbarPortalContext.js';\nimport * as styles from './backofficeTopbarBreadcrumb.css.js';\n\nexport type BackofficeTopbarBreadcrumbProps = {\n items: readonly BackofficeTopbarBreadcrumbItem[];\n};\n\nconst getBreadcrumbItemKey = (item: BackofficeTopbarBreadcrumbItem): string => {\n const { target } = item;\n if (target.kind === 'dashboard') {\n return `${item.kind}-dashboard`;\n }\n if (target.kind === 'entity-list') {\n return `${item.kind}-entity-list-${target.entityId}`;\n }\n if (target.kind === 'entity-detail') {\n return `${item.kind}-entity-detail-${target.entityId}-${target.id}`;\n }\n if (target.kind === 'entity-detail-page') {\n return `${item.kind}-entity-detail-page-${target.entityId}-${target.id}-${target.pageId}`;\n }\n if (target.kind === 'tool') {\n return `${item.kind}-tool-${target.toolId}`;\n }\n if (target.kind === 'hub') {\n return `${item.kind}-hub-${target.hubId}`;\n }\n return `${item.kind}-href-${target.href}`;\n};\n\nexport const BackofficeTopbarBreadcrumb = ({\n items,\n}: BackofficeTopbarBreadcrumbProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const { dashboardHref, dashboardLabel } = useBackofficeTopbarPortalContext();\n let isDashboardCurrent = false;\n const [firstItem] = items;\n if (items.length === 1 && firstItem != null) {\n isDashboardCurrent =\n firstItem.target.kind === 'dashboard' && firstItem.kind === 'current';\n }\n let visibleItems: readonly BackofficeTopbarBreadcrumbItem[] = items;\n if (isDashboardCurrent) {\n visibleItems = [];\n }\n\n const homeContent = (\n <>\n <SidebarHomeSvg width={16} height={16} aria-hidden=\"true\" />\n <span className={styles.homeLabel}>{dashboardLabel}</span>\n </>\n );\n\n return (\n <nav className={styles.nav} aria-label={t('common.breadcrumb')}>\n <ol className={styles.list}>\n <li className={styles.item}>\n {isDashboardCurrent && (\n <span\n className={styles.homeCurrent}\n aria-current=\"page\"\n title={dashboardLabel}\n >\n {homeContent}\n </span>\n )}\n {!isDashboardCurrent && (\n <Link\n to={dashboardHref}\n className={styles.homeLink}\n aria-label={dashboardLabel}\n title={dashboardLabel}\n preloadOnHover=\"code-and-data\"\n >\n {homeContent}\n </Link>\n )}\n </li>\n {visibleItems.map((item, index) => {\n const isCurrent = item.kind === 'current';\n const key = getBreadcrumbItemKey(item);\n let icon: 'auto' | 'none' = 'none';\n if (index === 0) {\n icon = 'auto';\n }\n let content: JSX.Element;\n\n if (!isCurrent) {\n content = (\n <BackofficeLink\n target={item.target}\n label={item.label}\n className={styles.link}\n icon={icon}\n />\n );\n } else {\n content = (\n <BackofficeLinkLabel\n target={item.target}\n label={item.label}\n className={styles.current}\n icon={icon}\n />\n );\n }\n\n return (\n <li key={key} className={styles.item}>\n <span className={styles.separator} aria-hidden=\"true\">\n /\n </span>\n {content}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BackofficeTopbarBreadcrumb;\n"],"mappings":";;;;;;;;;AAeA,IAAM,KAAwB,MAAiD;CAC7E,IAAM,EAAE,cAAW;CAmBnB,OAlBI,EAAO,SAAS,cACX,GAAG,EAAK,KAAK,cAElB,EAAO,SAAS,gBACX,GAAG,EAAK,KAAK,eAAe,EAAO,aAExC,EAAO,SAAS,kBACX,GAAG,EAAK,KAAK,iBAAiB,EAAO,SAAS,GAAG,EAAO,OAE7D,EAAO,SAAS,uBACX,GAAG,EAAK,KAAK,sBAAsB,EAAO,SAAS,GAAG,EAAO,GAAG,GAAG,EAAO,WAE/E,EAAO,SAAS,SACX,GAAG,EAAK,KAAK,QAAQ,EAAO,WAEjC,EAAO,SAAS,QACX,GAAG,EAAK,KAAK,OAAO,EAAO,UAE7B,GAAG,EAAK,KAAK,QAAQ,EAAO;AACrC,GAEa,KAA8B,EACzC,eACkD;CAClD,IAAM,EAAE,SAAM,EAA8B,GACtC,EAAE,kBAAe,sBAAmB,EAAiC,GACvE,IAAqB,IACnB,CAAC,KAAa;CACpB,AAAI,EAAM,WAAW,KAAK,KAAa,SACrC,IACE,EAAU,OAAO,SAAS,eAAe,EAAU,SAAS;CAEhE,IAAI,IAA0D;CAC9D,AAAI,MACF,IAAe,CAAC;CAGlB,IAAM,IACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAgB,OAAO;EAAI,QAAQ;EAAI,eAAY;CAAQ,CAAA,GAC3D,kBAAC,QAAD;EAAM,WAAW;YAAmB;CAAqB,CAAA,CACzD,EAAA,CAAA;CAGJ,OACE,kBAAC,OAAD;EAAK,WAAW;EAAY,cAAY,EAAE,mBAAmB;YAC3D,kBAAC,MAAD;GAAI,WAAW;aAAf,CACE,kBAAC,MAAD;IAAI,WAAW;cAAf,CACG,KACC,kBAAC,QAAD;KACE,WAAW;KACX,gBAAa;KACb,OAAO;eAEN;IACG,CAAA,GAEP,CAAC,KACA,kBAAC,GAAD;KACE,IAAI;KACJ,WAAW;KACX,cAAY;KACZ,OAAO;KACP,gBAAe;eAEd;IACG,CAAA,CAEN;OACH,EAAa,KAAK,GAAM,MAAU;IACjC,IAAM,IAAY,EAAK,SAAS,WAC1B,IAAM,EAAqB,CAAI,GACjC,IAAwB;IAC5B,AAAI,MAAU,MACZ,IAAO;IAET,IAAI;IAsBJ,OApBA,AACE,IADG,IAWD,kBAAC,GAAD;KACE,QAAQ,EAAK;KACb,OAAO,EAAK;KACZ,WAAW;KACL;IACP,CAAA,IAdD,kBAAC,GAAD;KACE,QAAQ,EAAK;KACb,OAAO,EAAK;KACZ,WAAW;KACL;IACP,CAAA,GAcH,kBAAC,MAAD;KAAc,WAAW;eAAzB,CACE,kBAAC,QAAD;MAAM,WAAW;MAAkB,eAAY;gBAAO;KAEhD,CAAA,GACL,CACC;OALK,CAKL;GAER,CAAC,CACC;;CACD,CAAA;AAET"}
1
+ {"version":3,"file":"BackofficeTopbarBreadcrumb.js","names":[],"sources":["../../../../../../src/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.tsx"],"sourcesContent":["import { type JSX } from 'react';\nimport Link from '@plumile/router/routing/Link.js';\nimport { SidebarHomeSvg } from '@plumile/ui/icons/SidebarHomeSvg.js';\n\nimport { BackofficeLink } from '../../links/BackofficeLink.js';\nimport { BackofficeLinkLabel } from '../../links/BackofficeLinkLabel.js';\nimport { useBackofficeReactTranslation } from '../../../../i18n/useBackofficeReactTranslation.js';\nimport type { BackofficeTopbarBreadcrumbItem } from './types.js';\nimport { useBackofficeTopbarPortalContext } from './BackofficeTopbarPortalContext.js';\nimport * as styles from './backofficeTopbarBreadcrumb.css.js';\n\nexport type BackofficeTopbarBreadcrumbProps = {\n items: readonly BackofficeTopbarBreadcrumbItem[];\n};\n\nconst getBreadcrumbItemKey = (item: BackofficeTopbarBreadcrumbItem): string => {\n const { target } = item;\n if (target.kind === 'dashboard') {\n return `${item.kind}-dashboard`;\n }\n if (target.kind === 'entity-list') {\n return `${item.kind}-entity-list-${target.entityId}`;\n }\n if (target.kind === 'entity-detail') {\n return `${item.kind}-entity-detail-${target.entityId}-${target.id}`;\n }\n if (target.kind === 'entity-detail-page') {\n return `${item.kind}-entity-detail-page-${target.entityId}-${target.id}-${target.pageId}`;\n }\n if (target.kind === 'tool') {\n return `${item.kind}-tool-${target.toolId}`;\n }\n if (target.kind === 'hub') {\n return `${item.kind}-hub-${target.hubId}`;\n }\n return `${item.kind}-href-${target.href}`;\n};\n\nexport const BackofficeTopbarBreadcrumb = ({\n items,\n}: BackofficeTopbarBreadcrumbProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const { dashboardHref, dashboardLabel } = useBackofficeTopbarPortalContext();\n let isDashboardCurrent = false;\n const [firstItem] = items;\n if (items.length === 1 && firstItem != null) {\n isDashboardCurrent =\n firstItem.target.kind === 'dashboard' && firstItem.kind === 'current';\n }\n let visibleItems: readonly BackofficeTopbarBreadcrumbItem[] = items;\n if (isDashboardCurrent) {\n visibleItems = [];\n }\n\n const homeContent = (\n <>\n <SidebarHomeSvg width={16} height={16} aria-hidden=\"true\" />\n <span className={styles.homeLabel}>{dashboardLabel}</span>\n </>\n );\n\n return (\n <nav className={styles.nav} aria-label={t('common.breadcrumb')}>\n <ol className={styles.list}>\n <li className={styles.item}>\n {isDashboardCurrent && (\n <span\n className={styles.homeCurrent}\n aria-current=\"page\"\n title={dashboardLabel}\n >\n {homeContent}\n </span>\n )}\n {!isDashboardCurrent && (\n <Link\n to={dashboardHref}\n className={styles.homeLink}\n aria-label={dashboardLabel}\n title={dashboardLabel}\n preloadOnHover=\"code-and-data\"\n >\n {homeContent}\n </Link>\n )}\n </li>\n {visibleItems.map((item, index) => {\n const isCurrent = item.kind === 'current';\n const key = getBreadcrumbItemKey(item);\n let icon: 'auto' | 'none' = 'none';\n if (index === 0) {\n icon = 'auto';\n }\n let content: JSX.Element;\n\n if (!isCurrent) {\n content = (\n <BackofficeLink\n target={item.target}\n label={item.label}\n className={styles.link}\n icon={icon}\n />\n );\n } else {\n content = (\n <BackofficeLinkLabel\n target={item.target}\n label={item.label}\n className={styles.current}\n icon={icon}\n />\n );\n }\n\n return (\n <li key={key} className={styles.item}>\n <span className={styles.separator} aria-hidden=\"true\">\n /\n </span>\n {content}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BackofficeTopbarBreadcrumb;\n"],"mappings":";;;;;;;;;AAeA,IAAM,KAAwB,MAAiD;CAC7E,IAAM,EAAE,cAAW;CAmBnB,OAlBI,EAAO,SAAS,cACX,GAAG,EAAK,KAAK,cAElB,EAAO,SAAS,gBACX,GAAG,EAAK,KAAK,eAAe,EAAO,aAExC,EAAO,SAAS,kBACX,GAAG,EAAK,KAAK,iBAAiB,EAAO,SAAS,GAAG,EAAO,OAE7D,EAAO,SAAS,uBACX,GAAG,EAAK,KAAK,sBAAsB,EAAO,SAAS,GAAG,EAAO,GAAG,GAAG,EAAO,WAE/E,EAAO,SAAS,SACX,GAAG,EAAK,KAAK,QAAQ,EAAO,WAEjC,EAAO,SAAS,QACX,GAAG,EAAK,KAAK,OAAO,EAAO,UAE7B,GAAG,EAAK,KAAK,QAAQ,EAAO;AACrC,GAEa,KAA8B,EACzC,eACkD;CAClD,IAAM,EAAE,SAAM,EAA8B,GACtC,EAAE,kBAAe,sBAAmB,EAAiC,GACvE,IAAqB,IACnB,CAAC,KAAa;CACpB,AAAI,EAAM,WAAW,KAAK,KAAa,SACrC,IACE,EAAU,OAAO,SAAS,eAAe,EAAU,SAAS;CAEhE,IAAI,IAA0D;CAC9D,AAAI,MACF,IAAe,CAAC;CAGlB,IAAM,IACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAgB,OAAO;EAAI,QAAQ;EAAI,eAAY;CAAQ,CAAA,GAC3D,kBAAC,QAAD;EAAM,WAAW;EAAmB,UAAA;CAAqB,CAAA,CACzD,EAAA,CAAA;CAGJ,OACE,kBAAC,OAAD;EAAK,WAAW;EAAY,cAAY,EAAE,mBAAmB;EAC3D,UAAA,kBAAC,MAAD;GAAI,WAAW;GAAf,UAAA,CACE,kBAAC,MAAD;IAAI,WAAW;IAAf,UAAA,CACG,KACC,kBAAC,QAAD;KACE,WAAW;KACX,gBAAa;KACb,OAAO;KAEN,UAAA;IACG,CAAA,GAEP,CAAC,KACA,kBAAC,GAAD;KACE,IAAI;KACJ,WAAW;KACX,cAAY;KACZ,OAAO;KACP,gBAAe;KAEd,UAAA;IACG,CAAA,CAEN;GACH,CAAA,GAAA,EAAa,KAAK,GAAM,MAAU;IACjC,IAAM,IAAY,EAAK,SAAS,WAC1B,IAAM,EAAqB,CAAI,GACjC,IAAwB;IAC5B,AAAI,MAAU,MACZ,IAAO;IAET,IAAI;IAsBJ,OApBA,AACE,IADG,IAWD,kBAAC,GAAD;KACE,QAAQ,EAAK;KACb,OAAO,EAAK;KACZ,WAAW;KACL;IACP,CAAA,IAdD,kBAAC,GAAD;KACE,QAAQ,EAAK;KACb,OAAO,EAAK;KACZ,WAAW;KACL;IACP,CAAA,GAcH,kBAAC,MAAD;KAAc,WAAW;KAAzB,UAAA,CACE,kBAAC,QAAD;MAAM,WAAW;MAAkB,eAAY;MAAO,UAAA;KAEhD,CAAA,GACL,CACC;IALK,GAAA,CAKL;GAER,CAAC,CACC;;CACD,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"buildSidebarSections.js","names":[],"sources":["../../../../../src/components/backoffice/layout/buildSidebarSections.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\nimport type {\n BackofficeSidebarConfig,\n BackofficeDashboardRegistration,\n BackofficeSidebarItemDescriptor,\n BackofficeIconComponent,\n BackofficeSidebarRecentItem,\n} from '../../../provider/types.js';\nimport type {\n SidebarNavigationItem,\n SidebarNavigationSection,\n} from '@plumile/ui/components/navigation/sidebar/SidebarNavigation.js';\nimport { BackofficeSidebarHistorySvg } from '@plumile/ui/icons/backoffice/BackofficeSidebarHistorySvg.js';\nimport { GripDotsSvg } from '@plumile/ui/icons/GripDotsSvg.js';\nimport { PinFilledSvg } from '@plumile/ui/icons/PinFilledSvg.js';\nimport { PinSvg } from '@plumile/ui/icons/PinSvg.js';\nimport { SidebarHomeSvg } from '@plumile/ui/icons/SidebarHomeSvg.js';\nimport { SidebarTasksSvg } from '@plumile/ui/icons/SidebarTasksSvg.js';\nimport type { SidebarGroupCollapseState } from '../../../hooks/useSidebarGroupCollapse.js';\nimport { findBackofficeDashboardRegistration } from '../../../provider/dashboardRegistrations.js';\nimport * as styles from './backofficeSidebarActions.css.js';\nimport {\n buildEntityGroupLookup,\n isActivePath,\n joinBackofficePath,\n resolveLabel,\n resolveGroupItems,\n resolveHubEntityIds,\n resolveSidebarHub,\n resolveSidebarGroups,\n} from './sidebarUtils.js';\n\nconst renderIcon = (\n Icon?: BackofficeIconComponent,\n fallback?: ReactNode,\n size = 18,\n): ReactNode => {\n if (Icon != null) {\n return <Icon width={size} height={size} aria-hidden=\"true\" />;\n }\n return fallback ?? null;\n};\n\nexport type BuildSidebarSectionsInput = {\n basePath: string;\n pathname: string;\n entities: BackofficeEntityManifestMap;\n dashboards?: readonly BackofficeDashboardRegistration[];\n sidebar?: BackofficeSidebarConfig;\n permissions: unknown;\n searchQuery?: string;\n tApp: TFunction;\n t: TFunction;\n pinnedEntityIds?: readonly string[];\n recentItems?: readonly BackofficeSidebarRecentItem[];\n onTogglePin?: (entityId: string) => void;\n onReorderPin?: (fromId: string, toId: string) => void;\n collapsedByGroupId?: SidebarGroupCollapseState;\n onGroupCollapsedChange?: (groupId: string, collapsed: boolean) => void;\n sidebarCollapsed?: boolean;\n};\n\n/**\n * Builds the sidebar sections for the backoffice layout.\n */\nexport function buildSidebarSections(\n input: BuildSidebarSectionsInput,\n): readonly SidebarNavigationSection[] {\n const {\n basePath,\n pathname,\n entities,\n dashboards = [],\n sidebar,\n permissions,\n searchQuery,\n tApp,\n t,\n pinnedEntityIds = [],\n recentItems = [],\n onTogglePin,\n onReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange,\n sidebarCollapsed = false,\n } = input;\n\n const groups = resolveSidebarGroups(entities, sidebar);\n const entries = Object.entries(groups);\n const pinnedSet = new Set(pinnedEntityIds);\n const pinLabel = t('sidebar.actions.pin');\n const unpinLabel = t('sidebar.actions.unpin');\n const reorderLabel = t('sidebar.actions.reorder');\n const entityGroupLookup = buildEntityGroupLookup(groups, sidebar);\n const normalizedQuery = searchQuery?.trim().toLowerCase() ?? '';\n\n const labelMatchesQuery = (label: string): boolean => {\n return (\n normalizedQuery === '' || label.toLowerCase().includes(normalizedQuery)\n );\n };\n\n const renderPinAction = (entityId: string): ReactNode | null => {\n if (onTogglePin == null) {\n return null;\n }\n const isPinned = pinnedSet.has(entityId);\n let label = pinLabel;\n let Icon = PinSvg;\n if (isPinned) {\n label = unpinLabel;\n Icon = PinFilledSvg;\n }\n\n return (\n <button\n type=\"button\"\n className={styles.actionButton}\n aria-pressed={isPinned}\n aria-label={label}\n title={label}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onTogglePin(entityId);\n }}\n >\n <Icon width={14} height={14} aria-hidden=\"true\" />\n </button>\n );\n };\n\n const buildDashboardItem = (\n inputItem?: {\n id?: string;\n icon?: BackofficeIconComponent;\n label?: string;\n },\n groupId?: string,\n ): SidebarNavigationItem | null => {\n const dashboardId = inputItem?.id ?? 'dashboard';\n const dashboardDescriptor: BackofficeSidebarItemDescriptor = {\n kind: 'dashboard',\n id: dashboardId,\n };\n const isDashboardVisible = sidebar?.isItemVisible?.(\n dashboardDescriptor,\n permissions,\n );\n if (isDashboardVisible === false) {\n return null;\n }\n\n const registration = findBackofficeDashboardRegistration(\n dashboards,\n dashboardId,\n );\n let label = inputItem?.label;\n if (label == null && registration != null) {\n label = resolveLabel(registration.label, tApp);\n }\n label ??= t('sidebar.items.dashboard');\n if (!labelMatchesQuery(label)) {\n return null;\n }\n\n let href = basePath;\n let id = 'dashboard';\n if (dashboardId !== 'dashboard') {\n href = joinBackofficePath(basePath, `dashboard/${dashboardId}`);\n id = `dashboard-${dashboardId}`;\n }\n\n let isActive = isActivePath(pathname, href);\n if (dashboardId === 'dashboard') {\n isActive = pathname === basePath || pathname === `${basePath}/dashboard`;\n }\n\n return {\n id,\n data: {\n kind: 'dashboard',\n id: dashboardId,\n groupId,\n },\n label,\n href,\n icon: renderIcon(\n inputItem?.icon ?? registration?.icon,\n <SidebarHomeSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive,\n ariaLabel: label,\n };\n };\n\n const buildEntityItem = (inputItem: {\n entityId: string;\n groupId?: string;\n groupIcon?: BackofficeIconComponent;\n itemIcon?: BackofficeIconComponent;\n itemLabel?: string;\n enableReorder?: boolean;\n sectionId?: string;\n }): SidebarNavigationItem | null => {\n const {\n entityId,\n groupId,\n groupIcon,\n itemIcon,\n itemLabel,\n enableReorder,\n sectionId,\n } = inputItem;\n const config = entities[entityId];\n if (config == null) {\n return null;\n }\n\n let descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'entity',\n id: entityId,\n };\n if (config.kind === 'tool') {\n descriptor = { kind: 'tool', id: entityId };\n }\n const isEntityVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isEntityVisible === false) {\n return null;\n }\n\n if (config.kind === 'tool') {\n const label = itemLabel ?? resolveLabel(config.label, tApp);\n if (\n normalizedQuery !== '' &&\n !label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n\n let actionsVisibility: SidebarNavigationItem['actionsVisibility'];\n if (sectionId !== 'pinned' && pinnedSet.has(entityId)) {\n actionsVisibility = 'always';\n }\n\n return {\n id: `tool-${entityId}`,\n data: {\n kind: 'tool',\n id: entityId,\n groupId,\n },\n label,\n href: config.routes.list,\n icon: renderIcon(\n itemIcon ?? groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, config.routes.list),\n ariaLabel: label,\n actionSlot: renderPinAction(entityId),\n actionsVisibility,\n };\n }\n\n if (!config.hasList) {\n return null;\n }\n\n const label = itemLabel ?? resolveLabel(config.label, tApp);\n if (\n normalizedQuery !== '' &&\n !label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n\n let dragHandleSlot: ReactNode | undefined;\n if (enableReorder === true && onReorderPin != null) {\n dragHandleSlot = (\n <GripDotsSvg width={14} height={14} aria-hidden=\"true\" />\n );\n }\n\n let dragHandleLabel: string | undefined;\n if (dragHandleSlot != null) {\n dragHandleLabel = reorderLabel;\n }\n\n let actionsVisibility: SidebarNavigationItem['actionsVisibility'];\n if (sectionId !== 'pinned' && pinnedSet.has(entityId)) {\n actionsVisibility = 'always';\n }\n\n return {\n id: entityId,\n data: {\n kind: 'entity',\n id: entityId,\n groupId,\n },\n label,\n href: config.routes.list,\n icon: renderIcon(\n itemIcon ?? groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, config.routes.list),\n ariaLabel: label,\n actionSlot: renderPinAction(entityId),\n actionsVisibility,\n dragHandleSlot,\n dragHandleLabel,\n };\n };\n\n const buildHubItem = (inputItem: {\n hub: ReturnType<typeof resolveSidebarHub>;\n groupId?: string;\n icon?: BackofficeIconComponent;\n }): SidebarNavigationItem | null => {\n const { hub, groupId, icon } = inputItem;\n const descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'hub',\n id: hub.id,\n };\n const isVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isVisible === false) {\n return null;\n }\n const childEntityIds = resolveHubEntityIds(hub);\n const visibleChildConfigs = childEntityIds\n .map((entityId) => {\n return entities[entityId] ?? null;\n })\n .filter((config): config is BackofficeEntityManifestMap[string] => {\n if (config == null) {\n return false;\n }\n let childKind: BackofficeSidebarItemDescriptor['kind'] = 'entity';\n if (config.kind === 'tool') {\n childKind = 'tool';\n }\n const childDescriptor: BackofficeSidebarItemDescriptor = {\n kind: childKind,\n id: config.id,\n };\n const isChildVisible = sidebar?.isItemVisible?.(\n childDescriptor,\n permissions,\n );\n if (isChildVisible === false) {\n return false;\n }\n if (config.kind !== 'tool' && !config.hasList) {\n return false;\n }\n return true;\n });\n if (childEntityIds.length > 0 && visibleChildConfigs.length === 0) {\n return null;\n }\n const label = resolveLabel(hub.title, tApp);\n const matchesHub = labelMatchesQuery(label);\n const matchesChild = visibleChildConfigs.some((config) => {\n return labelMatchesQuery(resolveLabel(config.label, tApp));\n });\n if (!matchesHub && !matchesChild) {\n return null;\n }\n const isActive =\n isActivePath(pathname, hub.href) ||\n visibleChildConfigs.some((config) => {\n return isActivePath(pathname, config.routes.list);\n });\n return {\n id: `hub-${hub.id}`,\n data: {\n kind: 'hub',\n id: hub.id,\n groupId,\n },\n label,\n href: hub.href,\n icon: renderIcon(\n icon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive,\n ariaLabel: label,\n };\n };\n\n const sections: SidebarNavigationSection[] = [];\n\n const primaryItems = sidebar?.primaryItems ?? [];\n if (primaryItems.length > 0) {\n const primarySectionItems = primaryItems\n .map((primaryItem): SidebarNavigationItem | null => {\n if (primaryItem.kind === 'dashboard') {\n let itemLabel: string | undefined;\n if (primaryItem.label != null) {\n itemLabel = resolveLabel(primaryItem.label, tApp);\n }\n return buildDashboardItem({\n id: primaryItem.id,\n icon: primaryItem.icon,\n label: itemLabel,\n });\n }\n if (primaryItem.kind === 'hub') {\n const hub = resolveSidebarHub(primaryItem, sidebar);\n return buildHubItem({\n hub,\n icon: primaryItem.icon,\n });\n }\n let itemLabel: string | undefined;\n if (primaryItem.label != null) {\n itemLabel = resolveLabel(primaryItem.label, tApp);\n }\n return buildEntityItem({\n entityId: primaryItem.id,\n itemIcon: primaryItem.icon,\n itemLabel,\n sectionId: 'primary',\n });\n })\n .filter((item): item is SidebarNavigationItem => {\n return item != null;\n });\n\n if (primarySectionItems.length > 0) {\n sections.push({\n id: 'primary',\n items: primarySectionItems,\n collapsible: false,\n });\n }\n }\n\n if (pinnedEntityIds.length > 0) {\n const pinnedItems = pinnedEntityIds\n .map((entityId) => {\n const groupMeta = entityGroupLookup.get(entityId);\n return buildEntityItem({\n entityId,\n groupId: groupMeta?.groupId,\n groupIcon: groupMeta?.groupIcon,\n itemIcon: groupMeta?.itemIcon,\n enableReorder: true,\n sectionId: 'pinned',\n });\n })\n .filter((item): item is SidebarNavigationItem => {\n return item != null;\n });\n\n if (pinnedItems.length > 0) {\n let reorder: SidebarNavigationSection['reorder'];\n if (onReorderPin != null && pinnedItems.length > 1) {\n reorder = {\n enabled: true,\n onReorder: onReorderPin,\n };\n }\n let sectionItems = pinnedItems;\n if (reorder == null) {\n sectionItems = pinnedItems.map((item) => {\n const { dragHandleSlot, dragHandleLabel, ...rest } = item;\n return rest;\n });\n }\n\n sections.push({\n id: 'pinned',\n title: t('sidebar.sections.pinned'),\n icon: renderIcon(\n undefined,\n <PinSvg width={16} height={16} aria-hidden=\"true\" />,\n ),\n items: sectionItems,\n collapsible: false,\n reorder,\n });\n }\n }\n\n if (recentItems.length > 0) {\n const recentSectionItems = recentItems\n .map((recentItem): SidebarNavigationItem | null => {\n const config = entities[recentItem.id];\n if (config == null) {\n return null;\n }\n const descriptor: BackofficeSidebarItemDescriptor = {\n kind: recentItem.kind,\n id: recentItem.id,\n };\n const isVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isVisible === false) {\n return null;\n }\n if (\n normalizedQuery !== '' &&\n !recentItem.label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n const groupMeta = entityGroupLookup.get(recentItem.id);\n return {\n id: `recent-${recentItem.kind}-${recentItem.id}`,\n data: {\n kind: recentItem.kind,\n id: recentItem.id,\n groupId: groupMeta?.groupId,\n },\n label: recentItem.label,\n href: recentItem.href,\n icon: renderIcon(\n groupMeta?.itemIcon ?? groupMeta?.groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, recentItem.href),\n ariaLabel: recentItem.label,\n } satisfies SidebarNavigationItem;\n })\n .filter((item): item is SidebarNavigationItem => {\n return item != null;\n });\n\n if (recentSectionItems.length > 0) {\n sections.push({\n id: 'recent',\n title: t('sidebar.sections.recent'),\n icon: renderIcon(\n undefined,\n <BackofficeSidebarHistorySvg\n width={16}\n height={16}\n aria-hidden=\"true\"\n />,\n ),\n items: recentSectionItems,\n collapsible: false,\n });\n }\n }\n\n entries.forEach(([groupId, group]) => {\n if (group.isVisible != null && !group.isVisible(permissions)) {\n return;\n }\n\n const items: SidebarNavigationItem[] = [];\n\n const groupItems = resolveGroupItems(group);\n if (groupItems.length > 0) {\n groupItems.forEach((groupItem) => {\n if (groupItem.kind === 'dashboard') {\n let itemLabel: string | undefined;\n if (groupItem.label != null) {\n itemLabel = resolveLabel(groupItem.label, tApp);\n }\n const item = buildDashboardItem(\n {\n id: groupItem.id,\n icon: groupItem.icon ?? group.icon,\n label: itemLabel,\n },\n groupId,\n );\n if (item != null) {\n items.push(item);\n }\n return;\n }\n if (groupItem.kind === 'hub') {\n const hub = resolveSidebarHub(groupItem, sidebar);\n const item = buildHubItem({\n hub,\n groupId,\n icon: groupItem.icon ?? group.icon,\n });\n if (item != null) {\n items.push(item);\n }\n return;\n }\n let itemLabel: string | undefined;\n if (groupItem.label != null) {\n itemLabel = resolveLabel(groupItem.label, tApp);\n }\n const item = buildEntityItem({\n entityId: groupItem.id,\n groupId,\n groupIcon: group.icon,\n itemIcon: groupItem.icon,\n itemLabel,\n sectionId: groupId,\n });\n if (item != null) {\n items.push(item);\n }\n });\n }\n\n let sectionItems: SidebarNavigationItem[] = items;\n if (sidebarCollapsed && group.behavior?.showInCollapsedRail !== true) {\n sectionItems = items.filter((item) => {\n return item.data?.kind === 'dashboard' || item.isActive === true;\n });\n }\n\n if (sectionItems.length === 0) {\n return;\n }\n\n let title: string | undefined;\n if (group.title != null) {\n title = resolveLabel(group.title, tApp);\n }\n\n const isCollapsed = collapsedByGroupId?.[groupId];\n let onCollapsedChange: ((collapsed: boolean) => void) | undefined;\n if (onGroupCollapsedChange != null) {\n onCollapsedChange = (collapsed: boolean) => {\n onGroupCollapsedChange(groupId, collapsed);\n };\n }\n\n sections.push({\n id: groupId,\n title,\n icon: renderIcon(group.icon, undefined, 16),\n items: sectionItems,\n collapsible: group.behavior?.collapsible ?? true,\n defaultCollapsed: group.behavior?.defaultCollapsed ?? true,\n isCollapsed,\n onCollapsedChange,\n });\n });\n\n return sections;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"buildSidebarSections.js","names":[],"sources":["../../../../../src/components/backoffice/layout/buildSidebarSections.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\nimport type {\n BackofficeSidebarConfig,\n BackofficeDashboardRegistration,\n BackofficeSidebarItemDescriptor,\n BackofficeIconComponent,\n BackofficeSidebarRecentItem,\n} from '../../../provider/types.js';\nimport type {\n SidebarNavigationItem,\n SidebarNavigationSection,\n} from '@plumile/ui/components/navigation/sidebar/SidebarNavigation.js';\nimport { BackofficeSidebarHistorySvg } from '@plumile/ui/icons/backoffice/BackofficeSidebarHistorySvg.js';\nimport { GripDotsSvg } from '@plumile/ui/icons/GripDotsSvg.js';\nimport { PinFilledSvg } from '@plumile/ui/icons/PinFilledSvg.js';\nimport { PinSvg } from '@plumile/ui/icons/PinSvg.js';\nimport { SidebarHomeSvg } from '@plumile/ui/icons/SidebarHomeSvg.js';\nimport { SidebarTasksSvg } from '@plumile/ui/icons/SidebarTasksSvg.js';\nimport type { SidebarGroupCollapseState } from '../../../hooks/useSidebarGroupCollapse.js';\nimport { findBackofficeDashboardRegistration } from '../../../provider/dashboardRegistrations.js';\nimport * as styles from './backofficeSidebarActions.css.js';\nimport {\n buildEntityGroupLookup,\n isActivePath,\n joinBackofficePath,\n resolveLabel,\n resolveGroupItems,\n resolveHubEntityIds,\n resolveSidebarHub,\n resolveSidebarGroups,\n} from './sidebarUtils.js';\n\nconst renderIcon = (\n Icon?: BackofficeIconComponent,\n fallback?: ReactNode,\n size = 18,\n): ReactNode => {\n if (Icon != null) {\n return <Icon width={size} height={size} aria-hidden=\"true\" />;\n }\n return fallback ?? null;\n};\n\nexport type BuildSidebarSectionsInput = {\n basePath: string;\n pathname: string;\n entities: BackofficeEntityManifestMap;\n dashboards?: readonly BackofficeDashboardRegistration[];\n sidebar?: BackofficeSidebarConfig;\n permissions: unknown;\n searchQuery?: string;\n tApp: TFunction;\n t: TFunction;\n pinnedEntityIds?: readonly string[];\n recentItems?: readonly BackofficeSidebarRecentItem[];\n onTogglePin?: (entityId: string) => void;\n onReorderPin?: (fromId: string, toId: string) => void;\n collapsedByGroupId?: SidebarGroupCollapseState;\n onGroupCollapsedChange?: (groupId: string, collapsed: boolean) => void;\n sidebarCollapsed?: boolean;\n};\n\n/**\n * Builds the sidebar sections for the backoffice layout.\n */\nexport function buildSidebarSections(\n input: BuildSidebarSectionsInput,\n): readonly SidebarNavigationSection[] {\n const {\n basePath,\n pathname,\n entities,\n dashboards = [],\n sidebar,\n permissions,\n searchQuery,\n tApp,\n t,\n pinnedEntityIds = [],\n recentItems = [],\n onTogglePin,\n onReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange,\n sidebarCollapsed = false,\n } = input;\n\n const groups = resolveSidebarGroups(entities, sidebar);\n const entries = Object.entries(groups);\n const pinnedSet = new Set(pinnedEntityIds);\n const pinLabel = t('sidebar.actions.pin');\n const unpinLabel = t('sidebar.actions.unpin');\n const reorderLabel = t('sidebar.actions.reorder');\n const entityGroupLookup = buildEntityGroupLookup(groups, sidebar);\n const normalizedQuery = searchQuery?.trim().toLowerCase() ?? '';\n\n const labelMatchesQuery = (label: string): boolean => {\n return (\n normalizedQuery === '' || label.toLowerCase().includes(normalizedQuery)\n );\n };\n\n const renderPinAction = (entityId: string): ReactNode | null => {\n if (onTogglePin == null) {\n return null;\n }\n const isPinned = pinnedSet.has(entityId);\n let label = pinLabel;\n let Icon = PinSvg;\n if (isPinned) {\n label = unpinLabel;\n Icon = PinFilledSvg;\n }\n\n return (\n <button\n type=\"button\"\n className={styles.actionButton}\n aria-pressed={isPinned}\n aria-label={label}\n title={label}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onTogglePin(entityId);\n }}\n >\n <Icon width={14} height={14} aria-hidden=\"true\" />\n </button>\n );\n };\n\n const buildDashboardItem = (\n inputItem?: {\n id?: string;\n icon?: BackofficeIconComponent;\n label?: string;\n },\n groupId?: string,\n ): SidebarNavigationItem | null => {\n const dashboardId = inputItem?.id ?? 'dashboard';\n const dashboardDescriptor: BackofficeSidebarItemDescriptor = {\n kind: 'dashboard',\n id: dashboardId,\n };\n const isDashboardVisible = sidebar?.isItemVisible?.(\n dashboardDescriptor,\n permissions,\n );\n if (isDashboardVisible === false) {\n return null;\n }\n\n const registration = findBackofficeDashboardRegistration(\n dashboards,\n dashboardId,\n );\n let label = inputItem?.label;\n if (label == null && registration != null) {\n label = resolveLabel(registration.label, tApp);\n }\n label ??= t('sidebar.items.dashboard');\n if (!labelMatchesQuery(label)) {\n return null;\n }\n\n let href = basePath;\n let id = 'dashboard';\n if (dashboardId !== 'dashboard') {\n href = joinBackofficePath(basePath, `dashboard/${dashboardId}`);\n id = `dashboard-${dashboardId}`;\n }\n\n let isActive = isActivePath(pathname, href);\n if (dashboardId === 'dashboard') {\n isActive = pathname === basePath || pathname === `${basePath}/dashboard`;\n }\n\n return {\n id,\n data: {\n kind: 'dashboard',\n id: dashboardId,\n groupId,\n },\n label,\n href,\n icon: renderIcon(\n inputItem?.icon ?? registration?.icon,\n <SidebarHomeSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive,\n ariaLabel: label,\n };\n };\n\n const buildEntityItem = (inputItem: {\n entityId: string;\n groupId?: string;\n groupIcon?: BackofficeIconComponent;\n itemIcon?: BackofficeIconComponent;\n itemLabel?: string;\n enableReorder?: boolean;\n sectionId?: string;\n }): SidebarNavigationItem | null => {\n const {\n entityId,\n groupId,\n groupIcon,\n itemIcon,\n itemLabel,\n enableReorder,\n sectionId,\n } = inputItem;\n const config = entities[entityId];\n if (config == null) {\n return null;\n }\n\n let descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'entity',\n id: entityId,\n };\n if (config.kind === 'tool') {\n descriptor = { kind: 'tool', id: entityId };\n }\n const isEntityVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isEntityVisible === false) {\n return null;\n }\n\n if (config.kind === 'tool') {\n const label = itemLabel ?? resolveLabel(config.label, tApp);\n if (\n normalizedQuery !== '' &&\n !label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n\n let actionsVisibility: SidebarNavigationItem['actionsVisibility'];\n if (sectionId !== 'pinned' && pinnedSet.has(entityId)) {\n actionsVisibility = 'always';\n }\n\n return {\n id: `tool-${entityId}`,\n data: {\n kind: 'tool',\n id: entityId,\n groupId,\n },\n label,\n href: config.routes.list,\n icon: renderIcon(\n itemIcon ?? groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, config.routes.list),\n ariaLabel: label,\n actionSlot: renderPinAction(entityId),\n actionsVisibility,\n };\n }\n\n if (!config.hasList) {\n return null;\n }\n\n const label = itemLabel ?? resolveLabel(config.label, tApp);\n if (\n normalizedQuery !== '' &&\n !label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n\n let dragHandleSlot: ReactNode | undefined;\n if (enableReorder === true && onReorderPin != null) {\n dragHandleSlot = (\n <GripDotsSvg width={14} height={14} aria-hidden=\"true\" />\n );\n }\n\n let dragHandleLabel: string | undefined;\n if (dragHandleSlot != null) {\n dragHandleLabel = reorderLabel;\n }\n\n let actionsVisibility: SidebarNavigationItem['actionsVisibility'];\n if (sectionId !== 'pinned' && pinnedSet.has(entityId)) {\n actionsVisibility = 'always';\n }\n\n return {\n id: entityId,\n data: {\n kind: 'entity',\n id: entityId,\n groupId,\n },\n label,\n href: config.routes.list,\n icon: renderIcon(\n itemIcon ?? groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, config.routes.list),\n ariaLabel: label,\n actionSlot: renderPinAction(entityId),\n actionsVisibility,\n dragHandleSlot,\n dragHandleLabel,\n };\n };\n\n const buildHubItem = (inputItem: {\n hub: ReturnType<typeof resolveSidebarHub>;\n groupId?: string;\n icon?: BackofficeIconComponent;\n }): SidebarNavigationItem | null => {\n const { hub, groupId, icon } = inputItem;\n const descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'hub',\n id: hub.id,\n };\n const isVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isVisible === false) {\n return null;\n }\n const childEntityIds = resolveHubEntityIds(hub);\n const visibleChildConfigs = childEntityIds\n .map((entityId) => {\n return entities[entityId] ?? null;\n })\n .filter((config): config is BackofficeEntityManifestMap[string] => {\n if (config == null) {\n return false;\n }\n let childKind: BackofficeSidebarItemDescriptor['kind'] = 'entity';\n if (config.kind === 'tool') {\n childKind = 'tool';\n }\n const childDescriptor: BackofficeSidebarItemDescriptor = {\n kind: childKind,\n id: config.id,\n };\n const isChildVisible = sidebar?.isItemVisible?.(\n childDescriptor,\n permissions,\n );\n if (isChildVisible === false) {\n return false;\n }\n if (config.kind !== 'tool' && !config.hasList) {\n return false;\n }\n return true;\n });\n if (childEntityIds.length > 0 && visibleChildConfigs.length === 0) {\n return null;\n }\n const label = resolveLabel(hub.title, tApp);\n const matchesHub = labelMatchesQuery(label);\n const matchesChild = visibleChildConfigs.some((config) => {\n return labelMatchesQuery(resolveLabel(config.label, tApp));\n });\n if (!matchesHub && !matchesChild) {\n return null;\n }\n const isActive =\n isActivePath(pathname, hub.href) ||\n visibleChildConfigs.some((config) => {\n return isActivePath(pathname, config.routes.list);\n });\n return {\n id: `hub-${hub.id}`,\n data: {\n kind: 'hub',\n id: hub.id,\n groupId,\n },\n label,\n href: hub.href,\n icon: renderIcon(\n icon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive,\n ariaLabel: label,\n };\n };\n\n const sections: SidebarNavigationSection[] = [];\n\n const primaryItems = sidebar?.primaryItems ?? [];\n if (primaryItems.length > 0) {\n const primarySectionItems = primaryItems\n .map((primaryItem): SidebarNavigationItem | null => {\n if (primaryItem.kind === 'dashboard') {\n let itemLabel: string | undefined;\n if (primaryItem.label != null) {\n itemLabel = resolveLabel(primaryItem.label, tApp);\n }\n return buildDashboardItem({\n id: primaryItem.id,\n icon: primaryItem.icon,\n label: itemLabel,\n });\n }\n if (primaryItem.kind === 'hub') {\n const hub = resolveSidebarHub(primaryItem, sidebar);\n return buildHubItem({\n hub,\n icon: primaryItem.icon,\n });\n }\n let itemLabel: string | undefined;\n if (primaryItem.label != null) {\n itemLabel = resolveLabel(primaryItem.label, tApp);\n }\n return buildEntityItem({\n entityId: primaryItem.id,\n itemIcon: primaryItem.icon,\n itemLabel,\n sectionId: 'primary',\n });\n })\n .filter((item): item is SidebarNavigationItem => {\n return item != null;\n });\n\n if (primarySectionItems.length > 0) {\n sections.push({\n id: 'primary',\n items: primarySectionItems,\n collapsible: false,\n });\n }\n }\n\n if (pinnedEntityIds.length > 0) {\n const pinnedItems = pinnedEntityIds\n .map((entityId) => {\n const groupMeta = entityGroupLookup.get(entityId);\n return buildEntityItem({\n entityId,\n groupId: groupMeta?.groupId,\n groupIcon: groupMeta?.groupIcon,\n itemIcon: groupMeta?.itemIcon,\n enableReorder: true,\n sectionId: 'pinned',\n });\n })\n .filter((item): item is SidebarNavigationItem => {\n return item != null;\n });\n\n if (pinnedItems.length > 0) {\n let reorder: SidebarNavigationSection['reorder'];\n if (onReorderPin != null && pinnedItems.length > 1) {\n reorder = {\n enabled: true,\n onReorder: onReorderPin,\n };\n }\n let sectionItems = pinnedItems;\n if (reorder == null) {\n sectionItems = pinnedItems.map((item) => {\n const { dragHandleSlot, dragHandleLabel, ...rest } = item;\n return rest;\n });\n }\n\n sections.push({\n id: 'pinned',\n title: t('sidebar.sections.pinned'),\n icon: renderIcon(\n undefined,\n <PinSvg width={16} height={16} aria-hidden=\"true\" />,\n ),\n items: sectionItems,\n collapsible: false,\n reorder,\n });\n }\n }\n\n if (recentItems.length > 0) {\n const recentSectionItems = recentItems\n .map((recentItem): SidebarNavigationItem | null => {\n const config = entities[recentItem.id];\n if (config == null) {\n return null;\n }\n const descriptor: BackofficeSidebarItemDescriptor = {\n kind: recentItem.kind,\n id: recentItem.id,\n };\n const isVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isVisible === false) {\n return null;\n }\n if (\n normalizedQuery !== '' &&\n !recentItem.label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n const groupMeta = entityGroupLookup.get(recentItem.id);\n return {\n id: `recent-${recentItem.kind}-${recentItem.id}`,\n data: {\n kind: recentItem.kind,\n id: recentItem.id,\n groupId: groupMeta?.groupId,\n },\n label: recentItem.label,\n href: recentItem.href,\n icon: renderIcon(\n groupMeta?.itemIcon ?? groupMeta?.groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, recentItem.href),\n ariaLabel: recentItem.label,\n } satisfies SidebarNavigationItem;\n })\n .filter((item): item is SidebarNavigationItem => {\n return item != null;\n });\n\n if (recentSectionItems.length > 0) {\n sections.push({\n id: 'recent',\n title: t('sidebar.sections.recent'),\n icon: renderIcon(\n undefined,\n <BackofficeSidebarHistorySvg\n width={16}\n height={16}\n aria-hidden=\"true\"\n />,\n ),\n items: recentSectionItems,\n collapsible: false,\n });\n }\n }\n\n entries.forEach(([groupId, group]) => {\n if (group.isVisible != null && !group.isVisible(permissions)) {\n return;\n }\n\n const items: SidebarNavigationItem[] = [];\n\n const groupItems = resolveGroupItems(group);\n if (groupItems.length > 0) {\n groupItems.forEach((groupItem) => {\n if (groupItem.kind === 'dashboard') {\n let itemLabel: string | undefined;\n if (groupItem.label != null) {\n itemLabel = resolveLabel(groupItem.label, tApp);\n }\n const item = buildDashboardItem(\n {\n id: groupItem.id,\n icon: groupItem.icon ?? group.icon,\n label: itemLabel,\n },\n groupId,\n );\n if (item != null) {\n items.push(item);\n }\n return;\n }\n if (groupItem.kind === 'hub') {\n const hub = resolveSidebarHub(groupItem, sidebar);\n const item = buildHubItem({\n hub,\n groupId,\n icon: groupItem.icon ?? group.icon,\n });\n if (item != null) {\n items.push(item);\n }\n return;\n }\n let itemLabel: string | undefined;\n if (groupItem.label != null) {\n itemLabel = resolveLabel(groupItem.label, tApp);\n }\n const item = buildEntityItem({\n entityId: groupItem.id,\n groupId,\n groupIcon: group.icon,\n itemIcon: groupItem.icon,\n itemLabel,\n sectionId: groupId,\n });\n if (item != null) {\n items.push(item);\n }\n });\n }\n\n let sectionItems: SidebarNavigationItem[] = items;\n if (sidebarCollapsed && group.behavior?.showInCollapsedRail !== true) {\n sectionItems = items.filter((item) => {\n return item.data?.kind === 'dashboard' || item.isActive === true;\n });\n }\n\n if (sectionItems.length === 0) {\n return;\n }\n\n let title: string | undefined;\n if (group.title != null) {\n title = resolveLabel(group.title, tApp);\n }\n\n const isCollapsed = collapsedByGroupId?.[groupId];\n let onCollapsedChange: ((collapsed: boolean) => void) | undefined;\n if (onGroupCollapsedChange != null) {\n onCollapsedChange = (collapsed: boolean) => {\n onGroupCollapsedChange(groupId, collapsed);\n };\n }\n\n sections.push({\n id: groupId,\n title,\n icon: renderIcon(group.icon, undefined, 16),\n items: sectionItems,\n collapsible: group.behavior?.collapsible ?? true,\n defaultCollapsed: group.behavior?.defaultCollapsed ?? true,\n isCollapsed,\n onCollapsedChange,\n });\n });\n\n return sections;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sidebarUtils.js","names":[],"sources":["../../../../../src/components/backoffice/layout/sidebarUtils.ts"],"sourcesContent":["import type { TFunction } from 'i18next';\n\nimport type {\n BackofficeEntityManifestMap,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type {\n BackofficeSidebarConfig,\n BackofficeIconComponent,\n BackofficeSidebarGroupConfig,\n BackofficeSidebarItemDescriptor,\n BackofficeSidebarItemConfig,\n BackofficeSidebarHubConfig,\n BackofficeSidebarHubGroupConfig,\n BackofficeResolvedSidebarHubConfig,\n} from '../../../provider/types.js';\n\nexport const resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nexport const isActivePath = (pathname: string, href: string): boolean => {\n if (pathname === href) {\n return true;\n }\n if (href !== '/' && pathname.startsWith(`${href}/`)) {\n return true;\n }\n return false;\n};\n\nexport const joinBackofficePath = (\n basePath: string,\n pathSegment: string,\n): string => {\n const normalizedBasePath = basePath.replace(/\\/+$/g, '');\n const normalizedPathSegment = pathSegment.replace(/^\\/+/g, '');\n if (normalizedBasePath === '') {\n return `/${normalizedPathSegment}`;\n }\n return `${normalizedBasePath}/${normalizedPathSegment}`;\n};\n\nexport const buildDefaultGroups = (\n entities: BackofficeEntityManifestMap,\n): Record<string, BackofficeSidebarGroupConfig> => {\n const entityIds = Object.keys(entities);\n\n return {\n main: {\n entities: entityIds,\n },\n };\n};\n\nexport const resolveSidebarGroups = (\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n): Record<string, BackofficeSidebarGroupConfig> => {\n return sidebar?.groups ?? buildDefaultGroups(entities);\n};\n\nexport type EntityGroupLookup = Map<\n string,\n {\n groupId: string;\n groupIcon?: BackofficeIconComponent;\n itemIcon?: BackofficeIconComponent;\n }\n>;\n\nexport const resolveItemDescriptor = (\n item: BackofficeSidebarItemConfig,\n): BackofficeSidebarItemDescriptor => {\n if (item.kind === 'dashboard') {\n return { kind: 'dashboard', id: item.id ?? 'dashboard' };\n }\n return { kind: item.kind, id: item.id };\n};\n\nexport const resolveGroupItems = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>(\n group: BackofficeSidebarGroupConfig<TManifest>,\n): readonly BackofficeSidebarItemConfig<TManifest>[] => {\n if (group.items != null) {\n return group.items;\n }\n return (group.entities?.map((entityId) => {\n return { kind: 'entity', id: entityId } as const;\n }) ?? []) as unknown as readonly BackofficeSidebarItemConfig<TManifest>[];\n};\n\nexport type BackofficeResolvedSidebarHubConfigFor<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = BackofficeSidebarHubConfig<TManifest> & {\n groups: readonly BackofficeSidebarHubGroupConfig<TManifest>[];\n};\n\nexport const resolveSidebarHubFor = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>(\n item: BackofficeSidebarHubConfig<TManifest>,\n sidebar: BackofficeSidebarConfig<TManifest> | undefined,\n): BackofficeResolvedSidebarHubConfigFor<TManifest> => {\n const registeredHub = sidebar?.hubs?.[item.id];\n return {\n ...registeredHub,\n ...item,\n groups: item.groups ?? registeredHub?.groups ?? [],\n };\n};\n\nexport const resolveSidebarHub = (\n item: BackofficeSidebarHubConfig,\n sidebar: BackofficeSidebarConfig | undefined,\n): BackofficeResolvedSidebarHubConfig => {\n return resolveSidebarHubFor(item, sidebar);\n};\n\nexport const resolveHubEntityIds = (\n hub: BackofficeResolvedSidebarHubConfig,\n): readonly string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n hub.groups.forEach((group) => {\n group.items.forEach((item) => {\n if (seen.has(item.id)) {\n return;\n }\n seen.add(item.id);\n output.push(item.id);\n });\n });\n return output;\n};\n\nexport type ResolvedSidebarHubEntry = {\n groupId: string | null;\n hub: BackofficeResolvedSidebarHubConfig;\n icon?: BackofficeIconComponent;\n};\n\nexport const resolveSidebarHubEntries = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n sidebar: BackofficeSidebarConfig | undefined,\n): readonly ResolvedSidebarHubEntry[] => {\n const output: ResolvedSidebarHubEntry[] = [];\n const seen = new Set<string>();\n\n Object.entries(groups).forEach(([groupId, group]) => {\n resolveGroupItems(group).forEach((item) => {\n if (item.kind !== 'hub' || seen.has(item.id)) {\n return;\n }\n seen.add(item.id);\n output.push({\n groupId,\n hub: resolveSidebarHub(item, sidebar),\n icon: item.icon ?? group.icon,\n });\n });\n });\n\n Object.values(sidebar?.hubs ?? {}).forEach((hub) => {\n if (seen.has(hub.id)) {\n return;\n }\n seen.add(hub.id);\n output.push({\n groupId: null,\n hub: resolveSidebarHub(hub, sidebar),\n icon: hub.icon,\n });\n });\n\n return output;\n};\n\nexport const resolveGroupEntityIds = (\n group: BackofficeSidebarGroupConfig,\n sidebar?: BackofficeSidebarConfig,\n): readonly string[] => {\n return resolveGroupItems(group).flatMap((item) => {\n if (item.kind === 'entity' || item.kind === 'tool') {\n return [item.id];\n }\n if (item.kind === 'hub') {\n return resolveHubEntityIds(resolveSidebarHub(item, sidebar));\n }\n return [];\n });\n};\n\nexport const buildEntityGroupLookup = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n sidebar?: BackofficeSidebarConfig,\n): EntityGroupLookup => {\n const lookup: EntityGroupLookup = new Map();\n\n Object.entries(groups).forEach(([groupId, group]) => {\n resolveGroupItems(group).forEach((item) => {\n if (item.kind === 'dashboard') {\n return;\n }\n\n if (item.kind === 'hub') {\n const hub = resolveSidebarHub(item, sidebar);\n resolveHubEntityIds(hub).forEach((entityId) => {\n if (!lookup.has(entityId)) {\n lookup.set(entityId, {\n groupId,\n groupIcon: group.icon,\n itemIcon: item.icon ?? hub.icon,\n });\n }\n });\n return;\n }\n\n if (!lookup.has(item.id)) {\n lookup.set(item.id, {\n groupId,\n groupIcon: group.icon,\n itemIcon: item.icon,\n });\n }\n });\n });\n\n return lookup;\n};\n\nconst isEntityVisible = (\n entityId: string,\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n permissions: unknown,\n): boolean => {\n const config = entities[entityId];\n if (config == null) {\n return false;\n }\n\n let descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'entity',\n id: entityId,\n };\n if (config.kind === 'tool') {\n descriptor = { kind: 'tool', id: entityId };\n }\n\n if (sidebar?.isItemVisible != null) {\n return sidebar.isItemVisible(descriptor, permissions);\n }\n\n if (config.kind === 'tool') {\n return true;\n }\n return config.hasList;\n};\n\nexport const resolveVisibleEntityIds = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n permissions: unknown,\n): string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n\n Object.entries(groups).forEach(([, group]) => {\n if (group.isVisible != null && !group.isVisible(permissions)) {\n return;\n }\n resolveGroupEntityIds(group, sidebar).forEach((entityId) => {\n if (seen.has(entityId)) {\n return;\n }\n if (!isEntityVisible(entityId, entities, sidebar, permissions)) {\n return;\n }\n seen.add(entityId);\n output.push(entityId);\n });\n });\n\n return output;\n};\n\nexport const resolveActiveEntityId = (\n pathname: string,\n entities: BackofficeEntityManifestMap,\n): string | null => {\n const entries = Object.entries(entities);\n for (const [entityId, config] of entries) {\n if (config.kind === 'tool') {\n if (isActivePath(pathname, config.routes.list)) {\n return entityId;\n }\n } else if (config.hasList && isActivePath(pathname, config.routes.list)) {\n return entityId;\n }\n }\n return null;\n};\n\nexport const resolveActiveGroupId = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n activeEntityId: string | null,\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n permissions: unknown,\n): string | null => {\n if (activeEntityId == null) {\n return null;\n }\n\n if (!isEntityVisible(activeEntityId, entities, sidebar, permissions)) {\n return null;\n }\n\n for (const [groupId, group] of Object.entries(groups)) {\n const isVisible = group.isVisible == null || group.isVisible(permissions);\n if (\n isVisible &&\n resolveGroupEntityIds(group, sidebar).includes(activeEntityId)\n ) {\n return groupId;\n }\n }\n\n return null;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"sidebarUtils.js","names":[],"sources":["../../../../../src/components/backoffice/layout/sidebarUtils.ts"],"sourcesContent":["import type { TFunction } from 'i18next';\n\nimport type {\n BackofficeEntityManifestMap,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type {\n BackofficeSidebarConfig,\n BackofficeIconComponent,\n BackofficeSidebarGroupConfig,\n BackofficeSidebarItemDescriptor,\n BackofficeSidebarItemConfig,\n BackofficeSidebarHubConfig,\n BackofficeSidebarHubGroupConfig,\n BackofficeResolvedSidebarHubConfig,\n} from '../../../provider/types.js';\n\nexport const resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nexport const isActivePath = (pathname: string, href: string): boolean => {\n if (pathname === href) {\n return true;\n }\n if (href !== '/' && pathname.startsWith(`${href}/`)) {\n return true;\n }\n return false;\n};\n\nexport const joinBackofficePath = (\n basePath: string,\n pathSegment: string,\n): string => {\n const normalizedBasePath = basePath.replace(/\\/+$/g, '');\n const normalizedPathSegment = pathSegment.replace(/^\\/+/g, '');\n if (normalizedBasePath === '') {\n return `/${normalizedPathSegment}`;\n }\n return `${normalizedBasePath}/${normalizedPathSegment}`;\n};\n\nexport const buildDefaultGroups = (\n entities: BackofficeEntityManifestMap,\n): Record<string, BackofficeSidebarGroupConfig> => {\n const entityIds = Object.keys(entities);\n\n return {\n main: {\n entities: entityIds,\n },\n };\n};\n\nexport const resolveSidebarGroups = (\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n): Record<string, BackofficeSidebarGroupConfig> => {\n return sidebar?.groups ?? buildDefaultGroups(entities);\n};\n\nexport type EntityGroupLookup = Map<\n string,\n {\n groupId: string;\n groupIcon?: BackofficeIconComponent;\n itemIcon?: BackofficeIconComponent;\n }\n>;\n\nexport const resolveItemDescriptor = (\n item: BackofficeSidebarItemConfig,\n): BackofficeSidebarItemDescriptor => {\n if (item.kind === 'dashboard') {\n return { kind: 'dashboard', id: item.id ?? 'dashboard' };\n }\n return { kind: item.kind, id: item.id };\n};\n\nexport const resolveGroupItems = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>(\n group: BackofficeSidebarGroupConfig<TManifest>,\n): readonly BackofficeSidebarItemConfig<TManifest>[] => {\n if (group.items != null) {\n return group.items;\n }\n return (group.entities?.map((entityId) => {\n return { kind: 'entity', id: entityId } as const;\n }) ?? []) as unknown as readonly BackofficeSidebarItemConfig<TManifest>[];\n};\n\nexport type BackofficeResolvedSidebarHubConfigFor<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = BackofficeSidebarHubConfig<TManifest> & {\n groups: readonly BackofficeSidebarHubGroupConfig<TManifest>[];\n};\n\nexport const resolveSidebarHubFor = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>(\n item: BackofficeSidebarHubConfig<TManifest>,\n sidebar: BackofficeSidebarConfig<TManifest> | undefined,\n): BackofficeResolvedSidebarHubConfigFor<TManifest> => {\n const registeredHub = sidebar?.hubs?.[item.id];\n return {\n ...registeredHub,\n ...item,\n groups: item.groups ?? registeredHub?.groups ?? [],\n };\n};\n\nexport const resolveSidebarHub = (\n item: BackofficeSidebarHubConfig,\n sidebar: BackofficeSidebarConfig | undefined,\n): BackofficeResolvedSidebarHubConfig => {\n return resolveSidebarHubFor(item, sidebar);\n};\n\nexport const resolveHubEntityIds = (\n hub: BackofficeResolvedSidebarHubConfig,\n): readonly string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n hub.groups.forEach((group) => {\n group.items.forEach((item) => {\n if (seen.has(item.id)) {\n return;\n }\n seen.add(item.id);\n output.push(item.id);\n });\n });\n return output;\n};\n\nexport type ResolvedSidebarHubEntry = {\n groupId: string | null;\n hub: BackofficeResolvedSidebarHubConfig;\n icon?: BackofficeIconComponent;\n};\n\nexport const resolveSidebarHubEntries = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n sidebar: BackofficeSidebarConfig | undefined,\n): readonly ResolvedSidebarHubEntry[] => {\n const output: ResolvedSidebarHubEntry[] = [];\n const seen = new Set<string>();\n\n Object.entries(groups).forEach(([groupId, group]) => {\n resolveGroupItems(group).forEach((item) => {\n if (item.kind !== 'hub' || seen.has(item.id)) {\n return;\n }\n seen.add(item.id);\n output.push({\n groupId,\n hub: resolveSidebarHub(item, sidebar),\n icon: item.icon ?? group.icon,\n });\n });\n });\n\n Object.values(sidebar?.hubs ?? {}).forEach((hub) => {\n if (seen.has(hub.id)) {\n return;\n }\n seen.add(hub.id);\n output.push({\n groupId: null,\n hub: resolveSidebarHub(hub, sidebar),\n icon: hub.icon,\n });\n });\n\n return output;\n};\n\nexport const resolveGroupEntityIds = (\n group: BackofficeSidebarGroupConfig,\n sidebar?: BackofficeSidebarConfig,\n): readonly string[] => {\n return resolveGroupItems(group).flatMap((item) => {\n if (item.kind === 'entity' || item.kind === 'tool') {\n return [item.id];\n }\n if (item.kind === 'hub') {\n return resolveHubEntityIds(resolveSidebarHub(item, sidebar));\n }\n return [];\n });\n};\n\nexport const buildEntityGroupLookup = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n sidebar?: BackofficeSidebarConfig,\n): EntityGroupLookup => {\n const lookup: EntityGroupLookup = new Map();\n\n Object.entries(groups).forEach(([groupId, group]) => {\n resolveGroupItems(group).forEach((item) => {\n if (item.kind === 'dashboard') {\n return;\n }\n\n if (item.kind === 'hub') {\n const hub = resolveSidebarHub(item, sidebar);\n resolveHubEntityIds(hub).forEach((entityId) => {\n if (!lookup.has(entityId)) {\n lookup.set(entityId, {\n groupId,\n groupIcon: group.icon,\n itemIcon: item.icon ?? hub.icon,\n });\n }\n });\n return;\n }\n\n if (!lookup.has(item.id)) {\n lookup.set(item.id, {\n groupId,\n groupIcon: group.icon,\n itemIcon: item.icon,\n });\n }\n });\n });\n\n return lookup;\n};\n\nconst isEntityVisible = (\n entityId: string,\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n permissions: unknown,\n): boolean => {\n const config = entities[entityId];\n if (config == null) {\n return false;\n }\n\n let descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'entity',\n id: entityId,\n };\n if (config.kind === 'tool') {\n descriptor = { kind: 'tool', id: entityId };\n }\n\n if (sidebar?.isItemVisible != null) {\n return sidebar.isItemVisible(descriptor, permissions);\n }\n\n if (config.kind === 'tool') {\n return true;\n }\n return config.hasList;\n};\n\nexport const resolveVisibleEntityIds = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n permissions: unknown,\n): string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n\n Object.entries(groups).forEach(([, group]) => {\n if (group.isVisible != null && !group.isVisible(permissions)) {\n return;\n }\n resolveGroupEntityIds(group, sidebar).forEach((entityId) => {\n if (seen.has(entityId)) {\n return;\n }\n if (!isEntityVisible(entityId, entities, sidebar, permissions)) {\n return;\n }\n seen.add(entityId);\n output.push(entityId);\n });\n });\n\n return output;\n};\n\nexport const resolveActiveEntityId = (\n pathname: string,\n entities: BackofficeEntityManifestMap,\n): string | null => {\n const entries = Object.entries(entities);\n for (const [entityId, config] of entries) {\n if (config.kind === 'tool') {\n if (isActivePath(pathname, config.routes.list)) {\n return entityId;\n }\n } else if (config.hasList && isActivePath(pathname, config.routes.list)) {\n return entityId;\n }\n }\n return null;\n};\n\nexport const resolveActiveGroupId = (\n groups: Record<string, BackofficeSidebarGroupConfig>,\n activeEntityId: string | null,\n entities: BackofficeEntityManifestMap,\n sidebar: BackofficeSidebarConfig | undefined,\n permissions: unknown,\n): string | null => {\n if (activeEntityId == null) {\n return null;\n }\n\n if (!isEntityVisible(activeEntityId, entities, sidebar, permissions)) {\n return null;\n }\n\n for (const [groupId, group] of Object.entries(groups)) {\n const isVisible = group.isVisible == null || group.isVisible(permissions);\n if (\n isVisible &&\n resolveGroupEntityIds(group, sidebar).includes(activeEntityId)\n ) {\n return groupId;\n }\n }\n\n return null;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeInlineLink.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeInlineLink.tsx"],"sourcesContent":["import { type JSX, type MouseEventHandler, type ReactNode } from 'react';\nimport Link, { type LinkHoverPreload } from '@plumile/router/routing/Link.js';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeLinkContent } from './BackofficeLinkContent.js';\nimport type { BackofficeLinkTarget } from './types.js';\nimport { useBackofficeLink } from './useBackofficeLink.js';\n\nexport type BackofficeInlineLinkProps<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = {\n target: BackofficeLinkTarget<TManifest>;\n label?: ReactNode;\n className?: string;\n title?: string;\n ariaLabel?: string;\n icon?: 'auto' | 'none';\n openInNewTab?: boolean;\n preloadOnHover?: LinkHoverPreload;\n endAdornment?: ReactNode;\n onClick?: MouseEventHandler<HTMLAnchorElement>;\n children?: ReactNode;\n};\n\nconst shouldPreloadBackofficeTarget = (\n target: BackofficeLinkTarget,\n preloadOnHover: LinkHoverPreload | undefined,\n openInNewTab: boolean,\n): LinkHoverPreload => {\n if (preloadOnHover != null) {\n return preloadOnHover;\n }\n if (openInNewTab) {\n return 'none';\n }\n if (target.kind === 'href') {\n return 'none';\n }\n return 'code-and-data';\n};\n\nexport const BackofficeInlineLink = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>({\n target,\n label,\n className,\n title,\n ariaLabel,\n icon = 'auto',\n openInNewTab = false,\n preloadOnHover,\n endAdornment,\n onClick,\n children,\n}: BackofficeInlineLinkProps<TManifest>): JSX.Element => {\n const link = useBackofficeLink(target, {\n label: children ?? label,\n });\n\n let linkProps: { target?: '_blank'; rel?: 'noreferrer' } = {};\n if (openInNewTab) {\n linkProps = { target: '_blank', rel: 'noreferrer' };\n }\n\n return (\n <Link\n to={link.href}\n className={className}\n title={title}\n aria-label={ariaLabel}\n onClick={onClick}\n preloadOnHover={shouldPreloadBackofficeTarget(\n target,\n preloadOnHover,\n openInNewTab,\n )}\n {...linkProps}\n >\n <BackofficeLinkContent\n icon={link.icon}\n label={link.label}\n showIcon={icon === 'auto'}\n endAdornment={endAdornment}\n />\n </Link>\n );\n};\n\nexport default BackofficeInlineLink;\n"],"mappings":";;;;;AAyBA,IAAM,KACJ,GACA,GACA,MAEI,MAGA,KAGA,EAAO,SAAS,SACX,SAEF,kBAGI,KAEX,EACA,WACA,UACA,cACA,UACA,cACA,UAAO,QACP,kBAAe,IACf,mBACA,iBACA,YACA,kBACuD;CACvD,IAAM,IAAO,EAAkB,GAAQ,EACrC,OAAO,KAAY,EACrB,CAAC,GAEG,IAAuD,CAAC;CAK5D,OAJI,MACF,IAAY;EAAE,QAAQ;EAAU,KAAK;CAAa,IAIlD,kBAAC,GAAD;EACE,IAAI,EAAK;EACE;EACJ;EACP,cAAY;EACH;EACT,gBAAgB,EACd,GACA,GACA,CACF;EACA,GAAI;YAEJ,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,OAAO,EAAK;GACZ,UAAU,MAAS;GACL;EACf,CAAA;CACG,CAAA;AAEV"}
1
+ {"version":3,"file":"BackofficeInlineLink.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeInlineLink.tsx"],"sourcesContent":["import { type JSX, type MouseEventHandler, type ReactNode } from 'react';\nimport Link, { type LinkHoverPreload } from '@plumile/router/routing/Link.js';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeLinkContent } from './BackofficeLinkContent.js';\nimport type { BackofficeLinkTarget } from './types.js';\nimport { useBackofficeLink } from './useBackofficeLink.js';\n\nexport type BackofficeInlineLinkProps<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = {\n target: BackofficeLinkTarget<TManifest>;\n label?: ReactNode;\n className?: string;\n title?: string;\n ariaLabel?: string;\n icon?: 'auto' | 'none';\n openInNewTab?: boolean;\n preloadOnHover?: LinkHoverPreload;\n endAdornment?: ReactNode;\n onClick?: MouseEventHandler<HTMLAnchorElement>;\n children?: ReactNode;\n};\n\nconst shouldPreloadBackofficeTarget = (\n target: BackofficeLinkTarget,\n preloadOnHover: LinkHoverPreload | undefined,\n openInNewTab: boolean,\n): LinkHoverPreload => {\n if (preloadOnHover != null) {\n return preloadOnHover;\n }\n if (openInNewTab) {\n return 'none';\n }\n if (target.kind === 'href') {\n return 'none';\n }\n return 'code-and-data';\n};\n\nexport const BackofficeInlineLink = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>({\n target,\n label,\n className,\n title,\n ariaLabel,\n icon = 'auto',\n openInNewTab = false,\n preloadOnHover,\n endAdornment,\n onClick,\n children,\n}: BackofficeInlineLinkProps<TManifest>): JSX.Element => {\n const link = useBackofficeLink(target, {\n label: children ?? label,\n });\n\n let linkProps: { target?: '_blank'; rel?: 'noreferrer' } = {};\n if (openInNewTab) {\n linkProps = { target: '_blank', rel: 'noreferrer' };\n }\n\n return (\n <Link\n to={link.href}\n className={className}\n title={title}\n aria-label={ariaLabel}\n onClick={onClick}\n preloadOnHover={shouldPreloadBackofficeTarget(\n target,\n preloadOnHover,\n openInNewTab,\n )}\n {...linkProps}\n >\n <BackofficeLinkContent\n icon={link.icon}\n label={link.label}\n showIcon={icon === 'auto'}\n endAdornment={endAdornment}\n />\n </Link>\n );\n};\n\nexport default BackofficeInlineLink;\n"],"mappings":";;;;;AAyBA,IAAM,KACJ,GACA,GACA,MAEI,MAGA,KAGA,EAAO,SAAS,SACX,SAEF,kBAGI,KAEX,EACA,WACA,UACA,cACA,UACA,cACA,UAAO,QACP,kBAAe,IACf,mBACA,iBACA,YACA,kBACuD;CACvD,IAAM,IAAO,EAAkB,GAAQ,EACrC,OAAO,KAAY,EACrB,CAAC,GAEG,IAAuD,CAAC;CAK5D,OAJI,MACF,IAAY;EAAE,QAAQ;EAAU,KAAK;CAAa,IAIlD,kBAAC,GAAD;EACE,IAAI,EAAK;EACE;EACJ;EACP,cAAY;EACH;EACT,gBAAgB,EACd,GACA,GACA,CACF;EACA,GAAI;EAEJ,UAAA,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,OAAO,EAAK;GACZ,UAAU,MAAS;GACL;EACf,CAAA;CACG,CAAA;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeLink.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeLink.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport Link, { type LinkHoverPreload } from '@plumile/router/routing/Link.js';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeLinkContent } from './BackofficeLinkContent.js';\nimport type { BackofficeLinkTarget } from './types.js';\nimport { useBackofficeLink } from './useBackofficeLink.js';\n\nexport type BackofficeLinkProps<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = {\n target: BackofficeLinkTarget<TManifest>;\n label?: ReactNode;\n className?: string;\n icon?: 'auto' | 'none';\n preloadOnHover?: LinkHoverPreload;\n children?: ReactNode;\n};\n\nconst shouldPreloadBackofficeTarget = (\n target: BackofficeLinkTarget,\n preloadOnHover: LinkHoverPreload | undefined,\n): LinkHoverPreload => {\n if (preloadOnHover != null) {\n return preloadOnHover;\n }\n if (target.kind === 'href') {\n return 'none';\n }\n return 'code-and-data';\n};\n\nexport const BackofficeLink = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>({\n target,\n label,\n className,\n icon = 'auto',\n preloadOnHover,\n children,\n}: BackofficeLinkProps<TManifest>): JSX.Element => {\n const link = useBackofficeLink(target, {\n label: children ?? label,\n });\n\n return (\n <Link\n to={link.href}\n className={className}\n preloadOnHover={shouldPreloadBackofficeTarget(target, preloadOnHover)}\n >\n <BackofficeLinkContent\n icon={link.icon}\n label={link.label}\n showIcon={icon === 'auto'}\n />\n </Link>\n );\n};\n\nexport default BackofficeLink;\n"],"mappings":";;;;;AAoBA,IAAM,KACJ,GACA,MAEI,MAGA,EAAO,SAAS,SACX,SAEF,kBAGI,KAEX,EACA,WACA,UACA,cACA,UAAO,QACP,mBACA,kBACiD;CACjD,IAAM,IAAO,EAAkB,GAAQ,EACrC,OAAO,KAAY,EACrB,CAAC;CAED,OACE,kBAAC,GAAD;EACE,IAAI,EAAK;EACE;EACX,gBAAgB,EAA8B,GAAQ,CAAc;YAEpE,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,OAAO,EAAK;GACZ,UAAU,MAAS;EACpB,CAAA;CACG,CAAA;AAEV"}
1
+ {"version":3,"file":"BackofficeLink.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeLink.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport Link, { type LinkHoverPreload } from '@plumile/router/routing/Link.js';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeLinkContent } from './BackofficeLinkContent.js';\nimport type { BackofficeLinkTarget } from './types.js';\nimport { useBackofficeLink } from './useBackofficeLink.js';\n\nexport type BackofficeLinkProps<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = {\n target: BackofficeLinkTarget<TManifest>;\n label?: ReactNode;\n className?: string;\n icon?: 'auto' | 'none';\n preloadOnHover?: LinkHoverPreload;\n children?: ReactNode;\n};\n\nconst shouldPreloadBackofficeTarget = (\n target: BackofficeLinkTarget,\n preloadOnHover: LinkHoverPreload | undefined,\n): LinkHoverPreload => {\n if (preloadOnHover != null) {\n return preloadOnHover;\n }\n if (target.kind === 'href') {\n return 'none';\n }\n return 'code-and-data';\n};\n\nexport const BackofficeLink = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>({\n target,\n label,\n className,\n icon = 'auto',\n preloadOnHover,\n children,\n}: BackofficeLinkProps<TManifest>): JSX.Element => {\n const link = useBackofficeLink(target, {\n label: children ?? label,\n });\n\n return (\n <Link\n to={link.href}\n className={className}\n preloadOnHover={shouldPreloadBackofficeTarget(target, preloadOnHover)}\n >\n <BackofficeLinkContent\n icon={link.icon}\n label={link.label}\n showIcon={icon === 'auto'}\n />\n </Link>\n );\n};\n\nexport default BackofficeLink;\n"],"mappings":";;;;;AAoBA,IAAM,KACJ,GACA,MAEI,MAGA,EAAO,SAAS,SACX,SAEF,kBAGI,KAEX,EACA,WACA,UACA,cACA,UAAO,QACP,mBACA,kBACiD;CACjD,IAAM,IAAO,EAAkB,GAAQ,EACrC,OAAO,KAAY,EACrB,CAAC;CAED,OACE,kBAAC,GAAD;EACE,IAAI,EAAK;EACE;EACX,gBAAgB,EAA8B,GAAQ,CAAc;EAEpE,UAAA,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,OAAO,EAAK;GACZ,UAAU,MAAS;EACpB,CAAA;CACG,CAAA;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeLinkContent.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeLinkContent.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport type { BackofficeIconComponent } from '../../../provider/types.js';\nimport * as styles from './backofficeLink.css.js';\n\nexport type BackofficeLinkContentProps = {\n icon?: BackofficeIconComponent;\n label: ReactNode;\n showIcon?: boolean;\n endAdornment?: ReactNode;\n};\n\nexport const BackofficeLinkContent = ({\n icon: Icon,\n label,\n showIcon = true,\n endAdornment,\n}: BackofficeLinkContentProps): JSX.Element => {\n return (\n <span className={styles.content}>\n {showIcon && Icon != null && (\n <span className={styles.icon} aria-hidden=\"true\">\n <Icon width={14} height={14} aria-hidden=\"true\" />\n </span>\n )}\n <span className={styles.label}>{label}</span>\n {endAdornment}\n </span>\n );\n};\n"],"mappings":";;;AAYA,IAAa,KAAyB,EACpC,MAAM,GACN,OAAA,GACA,cAAW,IACX,sBAGE,kBAAC,QAAD;CAAM,WAAW;WAAjB;EACG,KAAY,KAAQ,QACnB,kBAAC,QAAD;GAAM,WAAW;GAAa,eAAY;aACxC,kBAAC,GAAD;IAAM,OAAO;IAAI,QAAQ;IAAI,eAAY;GAAQ,CAAA;EAC7C,CAAA;EAER,kBAAC,QAAD;GAAM,WAAW;aAAe;EAAY,CAAA;EAC3C;CACG"}
1
+ {"version":3,"file":"BackofficeLinkContent.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeLinkContent.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport type { BackofficeIconComponent } from '../../../provider/types.js';\nimport * as styles from './backofficeLink.css.js';\n\nexport type BackofficeLinkContentProps = {\n icon?: BackofficeIconComponent;\n label: ReactNode;\n showIcon?: boolean;\n endAdornment?: ReactNode;\n};\n\nexport const BackofficeLinkContent = ({\n icon: Icon,\n label,\n showIcon = true,\n endAdornment,\n}: BackofficeLinkContentProps): JSX.Element => {\n return (\n <span className={styles.content}>\n {showIcon && Icon != null && (\n <span className={styles.icon} aria-hidden=\"true\">\n <Icon width={14} height={14} aria-hidden=\"true\" />\n </span>\n )}\n <span className={styles.label}>{label}</span>\n {endAdornment}\n </span>\n );\n};\n"],"mappings":";;;AAYA,IAAa,KAAyB,EACpC,MAAM,GACN,OAAA,GACA,cAAW,IACX,sBAGE,kBAAC,QAAD;CAAM,WAAW;CAAjB,UAAA;EACG,KAAY,KAAQ,QACnB,kBAAC,QAAD;GAAM,WAAW;GAAa,eAAY;GACxC,UAAA,kBAAC,GAAD;IAAM,OAAO;IAAI,QAAQ;IAAI,eAAY;GAAQ,CAAA;EAC7C,CAAA;EAER,kBAAC,QAAD;GAAM,WAAW;GAAe,UAAA;EAAY,CAAA;EAC3C;CACG"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeLinkLabel.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeLinkLabel.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeLinkContent } from './BackofficeLinkContent.js';\nimport type { BackofficeLinkTarget } from './types.js';\nimport { useBackofficeLink } from './useBackofficeLink.js';\n\nexport type BackofficeLinkLabelProps<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = {\n target: BackofficeLinkTarget<TManifest>;\n label?: ReactNode;\n className?: string;\n icon?: 'auto' | 'none';\n};\n\nexport const BackofficeLinkLabel = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>({\n target,\n label,\n className,\n icon = 'auto',\n}: BackofficeLinkLabelProps<TManifest>): JSX.Element => {\n const link = useBackofficeLink(target, { label });\n\n return (\n <span className={className}>\n <BackofficeLinkContent\n icon={link.icon}\n label={link.label}\n showIcon={icon === 'auto'}\n />\n </span>\n );\n};\n\nexport default BackofficeLinkLabel;\n"],"mappings":";;;;AAiBA,IAAa,KAEX,EACA,WACA,UACA,cACA,UAAO,aAC+C;CACtD,IAAM,IAAO,EAAkB,GAAQ,EAAE,SAAM,CAAC;CAEhD,OACE,kBAAC,QAAD;EAAiB;YACf,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,OAAO,EAAK;GACZ,UAAU,MAAS;EACpB,CAAA;CACG,CAAA;AAEV"}
1
+ {"version":3,"file":"BackofficeLinkLabel.js","names":[],"sources":["../../../../../src/components/backoffice/links/BackofficeLinkLabel.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeLinkContent } from './BackofficeLinkContent.js';\nimport type { BackofficeLinkTarget } from './types.js';\nimport { useBackofficeLink } from './useBackofficeLink.js';\n\nexport type BackofficeLinkLabelProps<\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n> = {\n target: BackofficeLinkTarget<TManifest>;\n label?: ReactNode;\n className?: string;\n icon?: 'auto' | 'none';\n};\n\nexport const BackofficeLinkLabel = <\n TManifest extends BackofficeEntityManifestMap = BackofficeEntityManifestMap,\n>({\n target,\n label,\n className,\n icon = 'auto',\n}: BackofficeLinkLabelProps<TManifest>): JSX.Element => {\n const link = useBackofficeLink(target, { label });\n\n return (\n <span className={className}>\n <BackofficeLinkContent\n icon={link.icon}\n label={link.label}\n showIcon={icon === 'auto'}\n />\n </span>\n );\n};\n\nexport default BackofficeLinkLabel;\n"],"mappings":";;;;AAiBA,IAAa,KAEX,EACA,WACA,UACA,cACA,UAAO,aAC+C;CACtD,IAAM,IAAO,EAAkB,GAAQ,EAAE,SAAM,CAAC;CAEhD,OACE,kBAAC,QAAD;EAAiB;EACf,UAAA,kBAAC,GAAD;GACE,MAAM,EAAK;GACX,OAAO,EAAK;GACZ,UAAU,MAAS;EACpB,CAAA;CACG,CAAA;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"RowFlagsCell.js","names":[],"sources":["../../../../../src/components/backoffice/list/RowFlagsCell.tsx"],"sourcesContent":["import { useMemo, type JSX, type ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\n\nimport type { BackofficeRowFlagSpec } from '@plumile/backoffice-core/types.js';\n\nimport * as styles from './RowFlagsCell.css.js';\n\nexport type RowFlagsCellProps<Row> = {\n row: Row;\n flags: readonly BackofficeRowFlagSpec<Row>[];\n tApp: TFunction;\n};\n\n/**\n * Renders row-level flags (icons) in a dedicated compact column.\n */\nexport const RowFlagsCell = <Row,>({\n row,\n flags,\n tApp,\n}: RowFlagsCellProps<Row>): JSX.Element => {\n const resolved = useMemo(() => {\n const out: { id: string; node: ReactNode; label: string }[] = [];\n for (const flag of flags) {\n const node = flag.render(row) as ReactNode;\n if (node != null && node !== '' && node !== false) {\n out.push({ id: flag.id, node, label: flag.label(row)(tApp) });\n }\n }\n return out;\n }, [flags, row, tApp]);\n\n const ariaLabel = resolved\n .map((entry) => {\n return entry.label.trim();\n })\n .filter((label) => {\n return label !== '';\n })\n .join(', ');\n\n let ariaLabelProp: string | undefined;\n if (ariaLabel !== '') {\n ariaLabelProp = ariaLabel;\n }\n\n return (\n <div className={styles.container} aria-label={ariaLabelProp}>\n {resolved.map((entry) => {\n return (\n <span\n key={entry.id}\n className={styles.flag}\n title={entry.label}\n role=\"img\"\n aria-label={entry.label}\n >\n {entry.node}\n </span>\n );\n })}\n </div>\n );\n};\n"],"mappings":";;;;AAgBA,IAAa,KAAsB,EACjC,QACA,UACA,cACyC;CACzC,IAAM,IAAW,QAAc;EAC7B,IAAM,IAAwD,CAAC;EAC/D,KAAK,IAAM,KAAQ,GAAO;GACxB,IAAM,IAAO,EAAK,OAAO,CAAG;GAC5B,AAAI,KAAQ,QAAQ,MAAS,MAAM,MAAS,MAC1C,EAAI,KAAK;IAAE,IAAI,EAAK;IAAI;IAAM,OAAO,EAAK,MAAM,CAAG,CAAC,CAAC,CAAI;GAAE,CAAC;EAEhE;EACA,OAAO;CACT,GAAG;EAAC;EAAO;EAAK;CAAI,CAAC,GAEf,IAAY,EACf,KAAK,MACG,EAAM,MAAM,KAAK,CACzB,CAAC,CACD,QAAQ,MACA,MAAU,EAClB,CAAC,CACD,KAAK,IAAI,GAER;CAKJ,OAJI,MAAc,OAChB,IAAgB,IAIhB,kBAAC,OAAD;EAAK,WAAW;EAAkB,cAAY;YAC3C,EAAS,KAAK,MAEX,kBAAC,QAAD;GAEE,WAAW;GACX,OAAO,EAAM;GACb,MAAK;GACL,cAAY,EAAM;aAEjB,EAAM;EACH,GAPC,EAAM,EAOP,CAET;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"RowFlagsCell.js","names":[],"sources":["../../../../../src/components/backoffice/list/RowFlagsCell.tsx"],"sourcesContent":["import { useMemo, type JSX, type ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\n\nimport type { BackofficeRowFlagSpec } from '@plumile/backoffice-core/types.js';\n\nimport * as styles from './RowFlagsCell.css.js';\n\nexport type RowFlagsCellProps<Row> = {\n row: Row;\n flags: readonly BackofficeRowFlagSpec<Row>[];\n tApp: TFunction;\n};\n\n/**\n * Renders row-level flags (icons) in a dedicated compact column.\n */\nexport const RowFlagsCell = <Row,>({\n row,\n flags,\n tApp,\n}: RowFlagsCellProps<Row>): JSX.Element => {\n const resolved = useMemo(() => {\n const out: { id: string; node: ReactNode; label: string }[] = [];\n for (const flag of flags) {\n const node = flag.render(row) as ReactNode;\n if (node != null && node !== '' && node !== false) {\n out.push({ id: flag.id, node, label: flag.label(row)(tApp) });\n }\n }\n return out;\n }, [flags, row, tApp]);\n\n const ariaLabel = resolved\n .map((entry) => {\n return entry.label.trim();\n })\n .filter((label) => {\n return label !== '';\n })\n .join(', ');\n\n let ariaLabelProp: string | undefined;\n if (ariaLabel !== '') {\n ariaLabelProp = ariaLabel;\n }\n\n return (\n <div className={styles.container} aria-label={ariaLabelProp}>\n {resolved.map((entry) => {\n return (\n <span\n key={entry.id}\n className={styles.flag}\n title={entry.label}\n role=\"img\"\n aria-label={entry.label}\n >\n {entry.node}\n </span>\n );\n })}\n </div>\n );\n};\n"],"mappings":";;;;AAgBA,IAAa,KAAsB,EACjC,QACA,UACA,cACyC;CACzC,IAAM,IAAW,QAAc;EAC7B,IAAM,IAAwD,CAAC;EAC/D,KAAK,IAAM,KAAQ,GAAO;GACxB,IAAM,IAAO,EAAK,OAAO,CAAG;GAC5B,AAAI,KAAQ,QAAQ,MAAS,MAAM,MAAS,MAC1C,EAAI,KAAK;IAAE,IAAI,EAAK;IAAI;IAAM,OAAO,EAAK,MAAM,CAAG,CAAC,CAAC,CAAI;GAAE,CAAC;EAEhE;EACA,OAAO;CACT,GAAG;EAAC;EAAO;EAAK;CAAI,CAAC,GAEf,IAAY,EACf,KAAK,MACG,EAAM,MAAM,KAAK,CACzB,CAAC,CACD,QAAQ,MACA,MAAU,EAClB,CAAC,CACD,KAAK,IAAI,GAER;CAKJ,OAJI,MAAc,OAChB,IAAgB,IAIhB,kBAAC,OAAD;EAAK,WAAW;EAAkB,cAAY;EAC3C,UAAA,EAAS,KAAK,MAEX,kBAAC,QAAD;GAEE,WAAW;GACX,OAAO,EAAM;GACb,MAAK;GACL,cAAY,EAAM;GAEjB,UAAA,EAAM;EACH,GAPC,EAAM,EAOP,CAET;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeOverviewLayout.js","names":[],"sources":["../../../../../src/components/backoffice/overview/BackofficeOverviewLayout.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport { cx } from '@plumile/ui/theme/tools.js';\n\nimport * as styles from './backofficeOverviewLayout.css.js';\n\nexport type BackofficeOverviewLayoutProps = {\n summary?: ReactNode;\n aside?: ReactNode;\n children?: ReactNode;\n className?: string;\n};\n\nexport const BackofficeOverviewLayout = ({\n summary,\n aside,\n children,\n className,\n}: BackofficeOverviewLayoutProps): JSX.Element => {\n let summaryNode: JSX.Element | null = null;\n if (summary != null) {\n summaryNode = <div className={styles.summary}>{summary}</div>;\n }\n\n let asideNode: JSX.Element | null = null;\n if (aside != null) {\n asideNode = <aside className={styles.aside}>{aside}</aside>;\n }\n\n let primaryNode: JSX.Element | null = null;\n if (children != null || asideNode != null) {\n primaryNode = <div className={styles.primary}>{children}</div>;\n }\n\n return (\n <div className={cx(styles.container, className)}>\n {summaryNode}\n <div className={styles.content}>\n {primaryNode}\n {asideNode}\n </div>\n </div>\n );\n};\n\nexport default BackofficeOverviewLayout;\n"],"mappings":";;;;AAaA,IAAa,KAA4B,EACvC,SAAA,GACA,OAAA,GACA,aACA,mBACgD;CAChD,IAAI,IAAkC;CACtC,AAAI,KAAW,SACb,IAAc,kBAAC,OAAD;EAAK,WAAW;YAAiB;CAAa,CAAA;CAG9D,IAAI,IAAgC;CACpC,AAAI,KAAS,SACX,IAAY,kBAAC,SAAD;EAAO,WAAW;YAAe;CAAa,CAAA;CAG5D,IAAI,IAAkC;CAKtC,QAJI,KAAY,QAAQ,KAAa,UACnC,IAAc,kBAAC,OAAD;EAAK,WAAW;EAAiB;CAAc,CAAA,IAI7D,kBAAC,OAAD;EAAK,WAAW,EAAG,GAAkB,CAAS;YAA9C,CACG,GACD,kBAAC,OAAD;GAAK,WAAW;aAAhB,CACG,GACA,CACE;IACF;;AAET"}
1
+ {"version":3,"file":"BackofficeOverviewLayout.js","names":[],"sources":["../../../../../src/components/backoffice/overview/BackofficeOverviewLayout.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\n\nimport { cx } from '@plumile/ui/theme/tools.js';\n\nimport * as styles from './backofficeOverviewLayout.css.js';\n\nexport type BackofficeOverviewLayoutProps = {\n summary?: ReactNode;\n aside?: ReactNode;\n children?: ReactNode;\n className?: string;\n};\n\nexport const BackofficeOverviewLayout = ({\n summary,\n aside,\n children,\n className,\n}: BackofficeOverviewLayoutProps): JSX.Element => {\n let summaryNode: JSX.Element | null = null;\n if (summary != null) {\n summaryNode = <div className={styles.summary}>{summary}</div>;\n }\n\n let asideNode: JSX.Element | null = null;\n if (aside != null) {\n asideNode = <aside className={styles.aside}>{aside}</aside>;\n }\n\n let primaryNode: JSX.Element | null = null;\n if (children != null || asideNode != null) {\n primaryNode = <div className={styles.primary}>{children}</div>;\n }\n\n return (\n <div className={cx(styles.container, className)}>\n {summaryNode}\n <div className={styles.content}>\n {primaryNode}\n {asideNode}\n </div>\n </div>\n );\n};\n\nexport default BackofficeOverviewLayout;\n"],"mappings":";;;;AAaA,IAAa,KAA4B,EACvC,SAAA,GACA,OAAA,GACA,aACA,mBACgD;CAChD,IAAI,IAAkC;CACtC,AAAI,KAAW,SACb,IAAc,kBAAC,OAAD;EAAK,WAAW;EAAiB,UAAA;CAAa,CAAA;CAG9D,IAAI,IAAgC;CACpC,AAAI,KAAS,SACX,IAAY,kBAAC,SAAD;EAAO,WAAW;EAAe,UAAA;CAAa,CAAA;CAG5D,IAAI,IAAkC;CAKtC,QAJI,KAAY,QAAQ,KAAa,UACnC,IAAc,kBAAC,OAAD;EAAK,WAAW;EAAiB;CAAc,CAAA,IAI7D,kBAAC,OAAD;EAAK,WAAW,EAAG,GAAkB,CAAS;EAA9C,UAAA,CACG,GACD,kBAAC,OAAD;GAAK,WAAW;GAAhB,UAAA,CACG,GACA,CACE;EACF,CAAA,CAAA;;AAET"}
@@ -28,16 +28,16 @@ var { useLazyLoadQuery: C } = _, w = "store-and-network", T = (e, t) => e(t), E
28
28
  ]), s = C(e.query, o, {
29
29
  fetchPolicy: w,
30
30
  fetchKey: i
31
- }), c = r(e.fragment, s), u = e.getConnection(c);
31
+ }), c = r(e.fragment, s), u = e.getConnection(c), d = l(() => u.edges.map((t) => {
32
+ let n = e.toRow(t.node);
33
+ return {
34
+ id: e.getRowId(n),
35
+ title: n.title,
36
+ subtitle: n.subtitle
37
+ };
38
+ }), [e, u.edges]);
32
39
  return /* @__PURE__ */ p(x, {
33
- items: l(() => u.edges.map((t) => {
34
- let n = e.toRow(t.node);
35
- return {
36
- id: e.getRowId(n),
37
- title: n.title,
38
- subtitle: n.subtitle
39
- };
40
- }), [e, u.edges]),
40
+ items: d,
41
41
  onSelectItem: (e) => {
42
42
  a(e.id);
43
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EntityIdPickerDialog.js","names":[],"sources":["../../../../../src/components/backoffice/pickers/EntityIdPickerDialog.tsx"],"sourcesContent":["import {\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type JSX,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport * as ReactRelay from 'react-relay';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { Modal } from '@plumile/ui/atomic/atoms/modal/Modal.js';\nimport { Spinner } from '@plumile/ui/backoffice/atoms/spinner/Spinner.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport {\n BackofficePickerList,\n BackofficePickerShell,\n type BackofficePickerItem,\n} from '@plumile/ui/backoffice/molecules/backoffice_picker/BackofficePicker.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\nimport type {\n BackofficePickerScope,\n BackofficeRuntimeEntityPickerConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficePickerEntityLoader } from '../../../provider/useBackofficeEntityLoader.js';\nimport { useBackofficeFragment } from '../../../relay/typedRelayHooks.js';\n\nimport * as styles from './entityIdPickerDialog.css.js';\n\nconst { useLazyLoadQuery } = ReactRelay;\n\nexport type EntityIdPickerDialogProps = {\n isOpen: boolean;\n entity: string;\n title: string;\n scope?: BackofficePickerScope<Record<string, string>>;\n onClose: () => void;\n onSelectId: (id: string) => void;\n};\n\nconst PICKER_FETCH_POLICY = 'store-and-network' as const;\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\ntype PickerBodyProps = {\n config: BackofficeRuntimeEntityPickerConfig;\n search: string;\n scope?: BackofficePickerScope<Record<string, string>>;\n fetchKey: number;\n onSelectId: (id: string) => void;\n};\n\ntype RuntimePickerRow = {\n title: string;\n subtitle?: string | null | undefined;\n};\n\nconst PickerBody = ({\n config,\n search,\n scope,\n fetchKey,\n onSelectId,\n}: PickerBodyProps): JSX.Element => {\n const variables = useMemo(() => {\n const trimmed = search.trim();\n return config.buildQueryVariables({ search: trimmed, scope });\n }, [config, scope, search]);\n\n const queryData = useLazyLoadQuery(config.query, variables, {\n fetchPolicy: PICKER_FETCH_POLICY,\n fetchKey,\n });\n\n const fragmentData = useBackofficeFragment<unknown, unknown>(\n config.fragment,\n queryData,\n );\n\n const connection = config.getConnection(fragmentData);\n\n const items = useMemo<readonly BackofficePickerItem[]>(() => {\n return connection.edges.map((edge) => {\n const row = config.toRow(edge.node) as RuntimePickerRow;\n const id = config.getRowId(row);\n return {\n id,\n title: row.title,\n subtitle: row.subtitle,\n };\n });\n }, [config, connection.edges]);\n\n return (\n <BackofficePickerList\n items={items}\n onSelectItem={(item) => {\n onSelectId(item.id);\n }}\n />\n );\n};\n\nconst buildFooter = (onClose: () => void, closeLabel: string): JSX.Element => {\n return (\n <>\n <Button type=\"button\" variant=\"secondary\" onClick={onClose}>\n {closeLabel}\n </Button>\n </>\n );\n};\n\nconst PickerUnavailable = ({ message }: { message: string }) => {\n return (\n <InlineBanner tone=\"warning\" title={message}>\n {null}\n </InlineBanner>\n );\n};\n\nconst PickerLoading = ({ label }: { label: string }): JSX.Element => {\n return (\n <div className={styles.loadingState} role=\"status\" aria-live=\"polite\">\n <Spinner size={18} ariaLabel={label} />\n <span className={styles.loadingLabel}>{label}</span>\n </div>\n );\n};\n\nexport const EntityIdPickerDialog = ({\n isOpen,\n entity,\n title,\n scope,\n onClose,\n onSelectId,\n}: EntityIdPickerDialogProps): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const [search, setSearch] = useState('');\n const [fetchKey, setFetchKey] = useState(0);\n const entityState = useBackofficePickerEntityLoader(entity, {\n enabled: isOpen,\n });\n\n let pickerConfig: BackofficeRuntimeEntityPickerConfig | undefined;\n if (entityState.status === 'loaded') {\n pickerConfig = entityState.module.config.picker as\n BackofficeRuntimeEntityPickerConfig | undefined;\n }\n\n useEffect(() => {\n if (isOpen) {\n setSearch('');\n setFetchKey((value) => {\n return value + 1;\n });\n }\n }, [isOpen]);\n\n const footer = useMemo(() => {\n return buildFooter(onClose, t('common.actions.close'));\n }, [onClose, t]);\n\n const handleSearchChange = useCallback((next: string) => {\n setSearch(next);\n setFetchKey((value) => {\n return value + 1;\n });\n }, []);\n\n const handleSelectId = useCallback(\n (id: string) => {\n onSelectId(id);\n onClose();\n },\n [onClose, onSelectId],\n );\n\n if (!isOpen) {\n return null;\n }\n\n let resolvedSearchPlaceholder: string | undefined;\n if (pickerConfig?.searchPlaceholder != null) {\n resolvedSearchPlaceholder = resolveLabel(\n pickerConfig.searchPlaceholder,\n tApp,\n );\n }\n\n const trimmedSearch = search.trim();\n const isSearchRequired = pickerConfig?.searchRequired === true;\n\n let pickerNode: JSX.Element;\n if (entityState.status === 'loading') {\n pickerNode = <PickerLoading label={t('common.loading')} />;\n } else if (pickerConfig != null) {\n if (isSearchRequired && trimmedSearch === '') {\n pickerNode = <BackofficeEmptyState title={t('picker.searchRequired')} />;\n } else {\n pickerNode = (\n <PickerBody\n config={pickerConfig}\n search={search}\n scope={scope}\n fetchKey={fetchKey}\n onSelectId={handleSelectId}\n />\n );\n }\n } else {\n pickerNode = (\n <PickerUnavailable message={t('picker.unavailable', { entity })} />\n );\n }\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n footer={footer}\n initialFocus=\"first-form-control\"\n >\n <BackofficePickerShell\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={resolvedSearchPlaceholder}\n searchAriaLabel={resolvedSearchPlaceholder}\n searchName=\"backoffice-entity-picker-search\"\n searchEnabled={pickerConfig?.searchEnabled ?? true}\n >\n <BackofficeErrorBoundary\n fallback={(args: { error: unknown; reset: () => void }) => {\n const { reset } = args;\n return (\n <InlineBanner\n tone=\"danger\"\n title={t('picker.errors.loadFailed')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n reset();\n setFetchKey((value) => {\n return value + 1;\n });\n }}\n >\n {t('common.actions.retry')}\n </Button>\n }\n >\n {null}\n </InlineBanner>\n );\n }}\n >\n <Suspense fallback={<PickerLoading label={t('common.loading')} />}>\n {pickerNode}\n </Suspense>\n </BackofficeErrorBoundary>\n </BackofficePickerShell>\n </Modal>\n );\n};\n\nexport type { BackofficePickerScope } from '@plumile/backoffice-core/types.js';\n\nexport default EntityIdPickerDialog;\n"],"mappings":"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"}
1
+ {"version":3,"file":"EntityIdPickerDialog.js","names":[],"sources":["../../../../../src/components/backoffice/pickers/EntityIdPickerDialog.tsx"],"sourcesContent":["import {\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type JSX,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport * as ReactRelay from 'react-relay';\n\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { Modal } from '@plumile/ui/atomic/atoms/modal/Modal.js';\nimport { Spinner } from '@plumile/ui/backoffice/atoms/spinner/Spinner.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport {\n BackofficePickerList,\n BackofficePickerShell,\n type BackofficePickerItem,\n} from '@plumile/ui/backoffice/molecules/backoffice_picker/BackofficePicker.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\nimport type {\n BackofficePickerScope,\n BackofficeRuntimeEntityPickerConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficePickerEntityLoader } from '../../../provider/useBackofficeEntityLoader.js';\nimport { useBackofficeFragment } from '../../../relay/typedRelayHooks.js';\n\nimport * as styles from './entityIdPickerDialog.css.js';\n\nconst { useLazyLoadQuery } = ReactRelay;\n\nexport type EntityIdPickerDialogProps = {\n isOpen: boolean;\n entity: string;\n title: string;\n scope?: BackofficePickerScope<Record<string, string>>;\n onClose: () => void;\n onSelectId: (id: string) => void;\n};\n\nconst PICKER_FETCH_POLICY = 'store-and-network' as const;\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\ntype PickerBodyProps = {\n config: BackofficeRuntimeEntityPickerConfig;\n search: string;\n scope?: BackofficePickerScope<Record<string, string>>;\n fetchKey: number;\n onSelectId: (id: string) => void;\n};\n\ntype RuntimePickerRow = {\n title: string;\n subtitle?: string | null | undefined;\n};\n\nconst PickerBody = ({\n config,\n search,\n scope,\n fetchKey,\n onSelectId,\n}: PickerBodyProps): JSX.Element => {\n const variables = useMemo(() => {\n const trimmed = search.trim();\n return config.buildQueryVariables({ search: trimmed, scope });\n }, [config, scope, search]);\n\n const queryData = useLazyLoadQuery(config.query, variables, {\n fetchPolicy: PICKER_FETCH_POLICY,\n fetchKey,\n });\n\n const fragmentData = useBackofficeFragment<unknown, unknown>(\n config.fragment,\n queryData,\n );\n\n const connection = config.getConnection(fragmentData);\n\n const items = useMemo<readonly BackofficePickerItem[]>(() => {\n return connection.edges.map((edge) => {\n const row = config.toRow(edge.node) as RuntimePickerRow;\n const id = config.getRowId(row);\n return {\n id,\n title: row.title,\n subtitle: row.subtitle,\n };\n });\n }, [config, connection.edges]);\n\n return (\n <BackofficePickerList\n items={items}\n onSelectItem={(item) => {\n onSelectId(item.id);\n }}\n />\n );\n};\n\nconst buildFooter = (onClose: () => void, closeLabel: string): JSX.Element => {\n return (\n <>\n <Button type=\"button\" variant=\"secondary\" onClick={onClose}>\n {closeLabel}\n </Button>\n </>\n );\n};\n\nconst PickerUnavailable = ({ message }: { message: string }) => {\n return (\n <InlineBanner tone=\"warning\" title={message}>\n {null}\n </InlineBanner>\n );\n};\n\nconst PickerLoading = ({ label }: { label: string }): JSX.Element => {\n return (\n <div className={styles.loadingState} role=\"status\" aria-live=\"polite\">\n <Spinner size={18} ariaLabel={label} />\n <span className={styles.loadingLabel}>{label}</span>\n </div>\n );\n};\n\nexport const EntityIdPickerDialog = ({\n isOpen,\n entity,\n title,\n scope,\n onClose,\n onSelectId,\n}: EntityIdPickerDialogProps): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const [search, setSearch] = useState('');\n const [fetchKey, setFetchKey] = useState(0);\n const entityState = useBackofficePickerEntityLoader(entity, {\n enabled: isOpen,\n });\n\n let pickerConfig: BackofficeRuntimeEntityPickerConfig | undefined;\n if (entityState.status === 'loaded') {\n pickerConfig = entityState.module.config.picker as\n BackofficeRuntimeEntityPickerConfig | undefined;\n }\n\n useEffect(() => {\n if (isOpen) {\n setSearch('');\n setFetchKey((value) => {\n return value + 1;\n });\n }\n }, [isOpen]);\n\n const footer = useMemo(() => {\n return buildFooter(onClose, t('common.actions.close'));\n }, [onClose, t]);\n\n const handleSearchChange = useCallback((next: string) => {\n setSearch(next);\n setFetchKey((value) => {\n return value + 1;\n });\n }, []);\n\n const handleSelectId = useCallback(\n (id: string) => {\n onSelectId(id);\n onClose();\n },\n [onClose, onSelectId],\n );\n\n if (!isOpen) {\n return null;\n }\n\n let resolvedSearchPlaceholder: string | undefined;\n if (pickerConfig?.searchPlaceholder != null) {\n resolvedSearchPlaceholder = resolveLabel(\n pickerConfig.searchPlaceholder,\n tApp,\n );\n }\n\n const trimmedSearch = search.trim();\n const isSearchRequired = pickerConfig?.searchRequired === true;\n\n let pickerNode: JSX.Element;\n if (entityState.status === 'loading') {\n pickerNode = <PickerLoading label={t('common.loading')} />;\n } else if (pickerConfig != null) {\n if (isSearchRequired && trimmedSearch === '') {\n pickerNode = <BackofficeEmptyState title={t('picker.searchRequired')} />;\n } else {\n pickerNode = (\n <PickerBody\n config={pickerConfig}\n search={search}\n scope={scope}\n fetchKey={fetchKey}\n onSelectId={handleSelectId}\n />\n );\n }\n } else {\n pickerNode = (\n <PickerUnavailable message={t('picker.unavailable', { entity })} />\n );\n }\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n footer={footer}\n initialFocus=\"first-form-control\"\n >\n <BackofficePickerShell\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={resolvedSearchPlaceholder}\n searchAriaLabel={resolvedSearchPlaceholder}\n searchName=\"backoffice-entity-picker-search\"\n searchEnabled={pickerConfig?.searchEnabled ?? true}\n >\n <BackofficeErrorBoundary\n fallback={(args: { error: unknown; reset: () => void }) => {\n const { reset } = args;\n return (\n <InlineBanner\n tone=\"danger\"\n title={t('picker.errors.loadFailed')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n reset();\n setFetchKey((value) => {\n return value + 1;\n });\n }}\n >\n {t('common.actions.retry')}\n </Button>\n }\n >\n {null}\n </InlineBanner>\n );\n }}\n >\n <Suspense fallback={<PickerLoading label={t('common.loading')} />}>\n {pickerNode}\n </Suspense>\n </BackofficeErrorBoundary>\n </BackofficePickerShell>\n </Modal>\n );\n};\n\nexport type { BackofficePickerScope } from '@plumile/backoffice-core/types.js';\n\nexport default EntityIdPickerDialog;\n"],"mappings":";;;;;;;;;;;;;;;;AAmCA,IAAM,EAAE,kBAAA,MAAqB,GAWvB,IAAsB,qBAEtB,KAAgB,GAAkB,MAC/B,EAAM,CAAI,GAgBb,KAAc,EAClB,WACA,WACA,UACA,aACA,oBACkC;CAClC,IAAM,IAAY,QAAc;EAC9B,IAAM,IAAU,EAAO,KAAK;EAC5B,OAAO,EAAO,oBAAoB;GAAE,QAAQ;GAAS;EAAM,CAAC;CAC9D,GAAG;EAAC;EAAQ;EAAO;CAAM,CAAC,GAEpB,IAAY,EAAiB,EAAO,OAAO,GAAW;EAC1D,aAAa;EACb;CACF,CAAC,GAEK,IAAe,EACnB,EAAO,UACP,CACF,GAEM,IAAa,EAAO,cAAc,CAAY,GAE9C,IAAQ,QACL,EAAW,MAAM,KAAK,MAAS;EACpC,IAAM,IAAM,EAAO,MAAM,EAAK,IAAI;EAElC,OAAO;GACL,IAFS,EAAO,SAAS,CAEzB;GACA,OAAO,EAAI;GACX,UAAU,EAAI;EAChB;CACF,CAAC,GACA,CAAC,GAAQ,EAAW,KAAK,CAAC;CAE7B,OACE,kBAAC,GAAD;EACS;EACP,eAAe,MAAS;GACtB,EAAW,EAAK,EAAE;EACpB;CACD,CAAA;AAEL,GAEM,KAAe,GAAqB,MAEtC,kBAAA,GAAA,EAAA,UACE,kBAAC,GAAD;CAAQ,MAAK;CAAS,SAAQ;CAAY,SAAS;CAChD,UAAA;AACK,CAAA,EACR,CAAA,GAIA,KAAqB,EAAE,iBAEzB,kBAAC,GAAD;CAAc,MAAK;CAAU,OAAO;CACjC,UAAA;AACW,CAAA,GAIZ,KAAiB,EAAE,eAErB,kBAAC,OAAD;CAAK,WAAW;CAAqB,MAAK;CAAS,aAAU;CAA7D,UAAA,CACE,kBAAC,GAAD;EAAS,MAAM;EAAI,WAAW;CAAQ,CAAA,GACtC,kBAAC,QAAD;EAAM,WAAW;EAAsB,UAAA;CAAY,CAAA,CAChD;IAII,KAAwB,EACnC,WACA,WACA,UACA,UACA,YACA,oBACmD;CACnD,IAAM,EAAE,GAAG,MAAS,EAAe,GAC7B,EAAE,SAAM,EAA8B,GACtC,CAAC,GAAQ,KAAa,EAAS,EAAE,GACjC,CAAC,GAAU,KAAe,EAAS,CAAC,GACpC,IAAc,EAAgC,GAAQ,EAC1D,SAAS,EACX,CAAC,GAEG;CAMJ,AALI,EAAY,WAAW,aACzB,IAAe,EAAY,OAAO,OAAO,SAI3C,QAAgB;EACd,AAAI,MACF,EAAU,EAAE,GACZ,GAAa,MACJ,IAAQ,CAChB;CAEL,GAAG,CAAC,CAAM,CAAC;CAEX,IAAM,IAAS,QACN,EAAY,GAAS,EAAE,sBAAsB,CAAC,GACpD,CAAC,GAAS,CAAC,CAAC,GAET,IAAqB,GAAa,MAAiB;EAEvD,AADA,EAAU,CAAI,GACd,GAAa,MACJ,IAAQ,CAChB;CACH,GAAG,CAAC,CAAC,GAEC,IAAiB,GACpB,MAAe;EAEd,AADA,EAAW,CAAE,GACb,EAAQ;CACV,GACA,CAAC,GAAS,CAAU,CACtB;CAEA,IAAI,CAAC,GACH,OAAO;CAGT,IAAI;CACJ,AAAI,GAAc,qBAAqB,SACrC,IAA4B,EAC1B,EAAa,mBACb,CACF;CAGF,IAAM,IAAgB,EAAO,KAAK,GAC5B,IAAmB,GAAc,mBAAmB,IAEtD;CAuBJ,OAtBA,AAMI,IANA,EAAY,WAAW,YACZ,kBAAC,GAAD,EAAe,OAAO,EAAE,gBAAgB,EAAI,CAAA,IAChD,KAAgB,OAgBvB,kBAAC,GAAD,EAAmB,SAAS,EAAE,sBAAsB,EAAE,UAAO,CAAC,EAAI,CAAA,IAfhE,KAAoB,MAAkB,KAC3B,kBAAC,GAAD,EAAsB,OAAO,EAAE,uBAAuB,EAAI,CAAA,IAGrE,kBAAC,GAAD;EACE,QAAQ;EACA;EACD;EACG;EACV,YAAY;CACb,CAAA,GAUL,kBAAC,GAAD;EACU;EACC;EACF;EACC;EACR,cAAa;EAEb,UAAA,kBAAC,GAAD;GACE,aAAa;GACb,gBAAgB;GAChB,mBAAmB;GACnB,iBAAiB;GACjB,YAAW;GACX,eAAe,GAAc,iBAAiB;GAE9C,UAAA,kBAAC,GAAD;IACE,WAAW,MAAgD;KACzD,IAAM,EAAE,aAAU;KAClB,OACE,kBAAC,GAAD;MACE,MAAK;MACL,OAAO,EAAE,0BAA0B;MACnC,SACE,kBAAC,GAAD;OACE,MAAK;OACL,SAAQ;OACR,eAAe;QAEb,AADA,EAAM,GACN,GAAa,MACJ,IAAQ,CAChB;OACH;OAEC,UAAA,EAAE,sBAAsB;MACnB,CAAA;MAGT,UAAA;KACW,CAAA;IAElB;IAEA,UAAA,kBAAC,GAAD;KAAU,UAAU,kBAAC,GAAD,EAAe,OAAO,EAAE,gBAAgB,EAAI,CAAA;KAC7D,UAAA;IACO,CAAA;GACa,CAAA;EACJ,CAAA;CAClB,CAAA;AAEX"}
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeEntityIdRef.js","names":[],"sources":["../../../../../src/components/backoffice/refs/BackofficeEntityIdRef.tsx"],"sourcesContent":["import { type JSX } from 'react';\nimport type { BackofficeRuntimeResolvedListFacetConfig } from '@plumile/backoffice-core/types.js';\nimport { BackofficeFilterAction } from '../filters/BackofficeFilterAction.js';\nimport { BackofficeFilterableCell } from '../shared/BackofficeFilterableCell.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport type { BackofficeLinkTarget } from '../links/types.js';\n\nexport type BackofficeEntityIdRefProps = {\n id: string | null | undefined;\n entity?: string;\n filterWhereKey?: string;\n filterPath?: readonly string[];\n filterLabel?: string;\n listConfig?: BackofficeRuntimeResolvedListFacetConfig;\n};\n\nexport const BackofficeEntityIdRef = ({\n id,\n entity,\n filterWhereKey,\n filterPath,\n filterLabel,\n listConfig,\n}: BackofficeEntityIdRefProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n let resolvedId = '';\n if (typeof id === 'string') {\n resolvedId = id.trim();\n }\n if (resolvedId === '') {\n return <span>-</span>;\n }\n\n let target: BackofficeLinkTarget | undefined;\n if (entity != null) {\n target = {\n kind: 'entity-detail',\n entityId: entity,\n id: resolvedId,\n };\n }\n\n const unresolvedLabel = t('filters.placeholders.unresolved');\n let title: string | undefined;\n if (target != null) {\n title = unresolvedLabel;\n }\n let filterAction: JSX.Element | null = null;\n if (filterWhereKey != null) {\n filterAction = (\n <BackofficeFilterAction\n whereKey={filterWhereKey}\n value={resolvedId}\n path={filterPath}\n label={filterLabel}\n listConfig={listConfig}\n />\n );\n }\n\n return (\n <BackofficeFilterableCell\n filterAction={filterAction}\n target={target}\n title={title}\n openInNewTab\n >\n {unresolvedLabel}\n </BackofficeFilterableCell>\n );\n};\n\nexport default BackofficeEntityIdRef;\n"],"mappings":";;;;;AAgBA,IAAa,KAAyB,EACpC,OACA,WACA,mBACA,eACA,gBACA,oBAC6C;CAC7C,IAAM,EAAE,SAAM,EAA8B,GACxC,IAAa;CAIjB,IAHI,OAAO,KAAO,aAChB,IAAa,EAAG,KAAK,IAEnB,MAAe,IACjB,OAAO,kBAAC,QAAD,EAAA,UAAM,IAAO,CAAA;CAGtB,IAAI;CACJ,AAAI,KAAU,SACZ,IAAS;EACP,MAAM;EACN,UAAU;EACV,IAAI;CACN;CAGF,IAAM,IAAkB,EAAE,iCAAiC,GACvD;CACJ,AAAI,KAAU,SACZ,IAAQ;CAEV,IAAI,IAAmC;CAavC,OAZI,KAAkB,SACpB,IACE,kBAAC,GAAD;EACE,UAAU;EACV,OAAO;EACP,MAAM;EACN,OAAO;EACK;CACb,CAAA,IAKH,kBAAC,GAAD;EACgB;EACN;EACD;EACP,cAAA;YAEC;CACuB,CAAA;AAE9B"}
1
+ {"version":3,"file":"BackofficeEntityIdRef.js","names":[],"sources":["../../../../../src/components/backoffice/refs/BackofficeEntityIdRef.tsx"],"sourcesContent":["import { type JSX } from 'react';\nimport type { BackofficeRuntimeResolvedListFacetConfig } from '@plumile/backoffice-core/types.js';\nimport { BackofficeFilterAction } from '../filters/BackofficeFilterAction.js';\nimport { BackofficeFilterableCell } from '../shared/BackofficeFilterableCell.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport type { BackofficeLinkTarget } from '../links/types.js';\n\nexport type BackofficeEntityIdRefProps = {\n id: string | null | undefined;\n entity?: string;\n filterWhereKey?: string;\n filterPath?: readonly string[];\n filterLabel?: string;\n listConfig?: BackofficeRuntimeResolvedListFacetConfig;\n};\n\nexport const BackofficeEntityIdRef = ({\n id,\n entity,\n filterWhereKey,\n filterPath,\n filterLabel,\n listConfig,\n}: BackofficeEntityIdRefProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n let resolvedId = '';\n if (typeof id === 'string') {\n resolvedId = id.trim();\n }\n if (resolvedId === '') {\n return <span>-</span>;\n }\n\n let target: BackofficeLinkTarget | undefined;\n if (entity != null) {\n target = {\n kind: 'entity-detail',\n entityId: entity,\n id: resolvedId,\n };\n }\n\n const unresolvedLabel = t('filters.placeholders.unresolved');\n let title: string | undefined;\n if (target != null) {\n title = unresolvedLabel;\n }\n let filterAction: JSX.Element | null = null;\n if (filterWhereKey != null) {\n filterAction = (\n <BackofficeFilterAction\n whereKey={filterWhereKey}\n value={resolvedId}\n path={filterPath}\n label={filterLabel}\n listConfig={listConfig}\n />\n );\n }\n\n return (\n <BackofficeFilterableCell\n filterAction={filterAction}\n target={target}\n title={title}\n openInNewTab\n >\n {unresolvedLabel}\n </BackofficeFilterableCell>\n );\n};\n\nexport default BackofficeEntityIdRef;\n"],"mappings":";;;;;AAgBA,IAAa,KAAyB,EACpC,OACA,WACA,mBACA,eACA,gBACA,oBAC6C;CAC7C,IAAM,EAAE,SAAM,EAA8B,GACxC,IAAa;CAIjB,IAHI,OAAO,KAAO,aAChB,IAAa,EAAG,KAAK,IAEnB,MAAe,IACjB,OAAO,kBAAC,QAAD,EAAA,UAAM,IAAO,CAAA;CAGtB,IAAI;CACJ,AAAI,KAAU,SACZ,IAAS;EACP,MAAM;EACN,UAAU;EACV,IAAI;CACN;CAGF,IAAM,IAAkB,EAAE,iCAAiC,GACvD;CACJ,AAAI,KAAU,SACZ,IAAQ;CAEV,IAAI,IAAmC;CAavC,OAZI,KAAkB,SACpB,IACE,kBAAC,GAAD;EACE,UAAU;EACV,OAAO;EACP,MAAM;EACN,OAAO;EACK;CACb,CAAA,IAKH,kBAAC,GAAD;EACgB;EACN;EACD;EACP,cAAA;EAEC,UAAA;CACuB,CAAA;AAE9B"}