@plumile/backoffice-react 0.1.179 → 0.1.181

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 (82) hide show
  1. package/lib/esm/auth/authRefreshNotice.css.js +0 -1
  2. package/lib/esm/auth/login/loginPage.css.js +0 -1
  3. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js +1 -1
  4. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js.map +1 -1
  5. package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js +1 -1
  6. package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js.map +1 -1
  7. package/lib/esm/components/backoffice/detail/backofficeDetailRelationLink.css.js +1 -0
  8. package/lib/esm/components/backoffice/filters/BackofficeFilterAction.js +1 -1
  9. package/lib/esm/components/backoffice/filters/BackofficeFilterAction.js.map +1 -1
  10. package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js +1 -1
  11. package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js.map +1 -1
  12. package/lib/esm/components/backoffice/hub/backofficeHubTemplate.css.js +2 -0
  13. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js +1 -1
  14. package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js.map +1 -1
  15. package/lib/esm/components/backoffice/links/BackofficeInlineLink.js +2 -2
  16. package/lib/esm/components/backoffice/links/BackofficeInlineLink.js.map +1 -1
  17. package/lib/esm/components/backoffice/links/BackofficeLink.js +2 -2
  18. package/lib/esm/components/backoffice/links/BackofficeLink.js.map +1 -1
  19. package/lib/esm/components/backoffice/refs/backofficeEntityIdRef.css.js +0 -1
  20. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityDetailNotFound.js +1 -1
  21. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityDetailNotFound.js.map +1 -1
  22. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js +241 -228
  23. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
  24. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js +2 -2
  25. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js.map +1 -1
  26. package/lib/esm/hooks/useBackofficeListRefetch.js +18 -16
  27. package/lib/esm/hooks/useBackofficeListRefetch.js.map +1 -1
  28. package/lib/esm/hooks/useBackofficeListUrlState.js +23 -21
  29. package/lib/esm/hooks/useBackofficeListUrlState.js.map +1 -1
  30. package/lib/esm/i18n/locales/en/backofficeReact.js +1 -0
  31. package/lib/esm/i18n/locales/en/backofficeReact.js.map +1 -1
  32. package/lib/esm/i18n/locales/fr/backofficeReact.js +1 -0
  33. package/lib/esm/i18n/locales/fr/backofficeReact.js.map +1 -1
  34. package/lib/esm/index.js +26 -25
  35. package/lib/esm/pages/BackofficeEntityDetailFramePage.js +4 -4
  36. package/lib/esm/pages/BackofficeEntityDetailFramePage.js.map +1 -1
  37. package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js +1 -1
  38. package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js.map +1 -1
  39. package/lib/esm/pages/BackofficeEntityDetailPage.js +3 -3
  40. package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
  41. package/lib/esm/pages/BackofficeEntityListPage.js +2 -2
  42. package/lib/esm/pages/BackofficeEntityListPage.js.map +1 -1
  43. package/lib/esm/pages/detail/buildTabsItems.js +1 -1
  44. package/lib/esm/pages/detail/buildTabsItems.js.map +1 -1
  45. package/lib/esm/provider/BackofficeProvider.js +63 -63
  46. package/lib/esm/provider/BackofficeProvider.js.map +1 -1
  47. package/lib/esm/relay/RelayProvider.js +2 -13
  48. package/lib/esm/relay/environment.js +2 -463
  49. package/lib/esm/relay/shortAccessTokenEnvironment.js +2 -15
  50. package/lib/esm/relay/useRelayOperationActivity.js +2 -0
  51. package/lib/esm/router/createBackofficeRoutes.js +11 -6
  52. package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
  53. package/lib/types/components/backoffice/links/BackofficeInlineLink.d.ts +3 -2
  54. package/lib/types/components/backoffice/links/BackofficeInlineLink.d.ts.map +1 -1
  55. package/lib/types/components/backoffice/links/BackofficeLink.d.ts +3 -2
  56. package/lib/types/components/backoffice/links/BackofficeLink.d.ts.map +1 -1
  57. package/lib/types/components/backoffice/scaffolds/BackofficeEntityListScaffold.d.ts.map +1 -1
  58. package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts +1 -0
  59. package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts.map +1 -1
  60. package/lib/types/hooks/useBackofficeListRefetch.d.ts +5 -4
  61. package/lib/types/hooks/useBackofficeListRefetch.d.ts.map +1 -1
  62. package/lib/types/hooks/useBackofficeListUrlState.d.ts.map +1 -1
  63. package/lib/types/i18n/resources.d.ts +2 -0
  64. package/lib/types/i18n/resources.d.ts.map +1 -1
  65. package/lib/types/index.d.ts +3 -2
  66. package/lib/types/index.d.ts.map +1 -1
  67. package/lib/types/pages/BackofficeEntityDetailFramePage.d.ts +6 -3
  68. package/lib/types/pages/BackofficeEntityDetailFramePage.d.ts.map +1 -1
  69. package/lib/types/provider/BackofficeProvider.d.ts.map +1 -1
  70. package/lib/types/relay/RelayProvider.d.ts +1 -6
  71. package/lib/types/relay/RelayProvider.d.ts.map +1 -1
  72. package/lib/types/relay/environment.d.ts +1 -119
  73. package/lib/types/relay/environment.d.ts.map +1 -1
  74. package/lib/types/relay/shortAccessTokenEnvironment.d.ts +4 -3
  75. package/lib/types/relay/shortAccessTokenEnvironment.d.ts.map +1 -1
  76. package/lib/types/relay/useRelayOperationActivity.d.ts +2 -0
  77. package/lib/types/relay/useRelayOperationActivity.d.ts.map +1 -0
  78. package/lib/types/router/createBackofficeRoutes.d.ts.map +1 -1
  79. package/package.json +14 -12
  80. package/lib/esm/relay/RelayProvider.js.map +0 -1
  81. package/lib/esm/relay/environment.js.map +0 -1
  82. package/lib/esm/relay/shortAccessTokenEnvironment.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeEntityListScaffold.js","names":[],"sources":["../../../../../src/components/backoffice/scaffolds/BackofficeEntityListScaffold.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n type JSX,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport { BackofficeFilterDrawer } from '@plumile/ui/backoffice/molecules/backoffice_filter_drawer/BackofficeFilterDrawer.js';\nimport { BackofficeFilterField } from '@plumile/ui/backoffice/molecules/backoffice_filter_field/BackofficeFilterField.js';\nimport { BackofficeListFooter } from '@plumile/ui/backoffice/molecules/backoffice_list_footer/BackofficeListFooter.js';\nimport { BackofficePageHeader } from '@plumile/ui/backoffice/molecules/backoffice_page_header/BackofficePageHeader.js';\nimport { BackofficeToolbar } from '@plumile/ui/backoffice/molecules/backoffice_toolbar/BackofficeToolbar.js';\nimport { BackofficeTableSkeleton } from '@plumile/ui/backoffice/molecules/backoffice_table_skeleton/BackofficeTableSkeleton.js';\nimport {\n FilterChipRow,\n type FilterChip,\n} from '@plumile/ui/backoffice/molecules/filter_chip_row/FilterChipRow.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\nimport { ListPageTemplate } from '@plumile/ui/backoffice/templates/list_page_template/ListPageTemplate.js';\nimport {\n type DataTableColumn,\n type GetRowId,\n} from '@plumile/ui/components/data-table/DataTable.js';\nimport { ResponsiveRecordList } from '@plumile/ui/components/data-table/ResponsiveRecordList.js';\nimport { VirtualizedConnectionTable } from '@plumile/ui/components/data-table/VirtualizedConnectionTable.js';\nimport { SimpleSelect } from '@plumile/ui/components/select/SimpleSelect.js';\nimport { denseTableClass } from '@plumile/ui/shared/backofficeTableDensity.css.js';\n\nimport {\n readWhereValue,\n setWhereValue,\n} from '@plumile/backoffice-core/filters/where.js';\nimport { resolveBackofficeListRuntimeConfig } from '@plumile/backoffice-core/config/listRuntime.js';\nimport type {\n BackofficeFilterSpec,\n BackofficeListState,\n BackofficePickerScope,\n BackofficeRuntimeResolvedListFacetConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\nimport {\n EntityFilterValue,\n EntityFilterValueText,\n} from '../filters/EntityFilterValue.js';\nimport { EntityIdPickerDialog } from '../pickers/EntityIdPickerDialog.js';\nimport { EntityIdFilterField } from '../filters/EntityIdFilterField.js';\nimport { DeferredFilterSearchInput } from '../filters/DeferredFilterSearchInput.js';\nimport { BackofficeListFilterProvider } from './BackofficeListFilterContext.js';\nimport { BACKOFFICE_LIST_BODY_SCROLL_MODE } from './backofficeListScrollMode.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeInfiniteScrollSentinel } from '../../../hooks/useBackofficeInfiniteScrollSentinel.js';\nimport { isDevEnv } from '../../../relay/envHelpers.js';\n\nimport * as styles from './backofficeEntityListScaffold.css.js';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst getFilterValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n where: Where | null,\n): unknown => {\n if (filter.fromGraphQL != null && where != null) {\n return filter.fromGraphQL(where);\n }\n\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n return readWhereValue(where, key, filter.path);\n};\n\nconst getFilterDisplayValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n raw: unknown,\n options: {\n enumLabel: (value: string) => string;\n booleanLabel: (value: boolean) => string;\n fallbackBooleanLabels: { yes: string; no: string };\n },\n): ReactNode | null => {\n if (raw == null) {\n return null;\n }\n\n if (Array.isArray(raw)) {\n const normalized = raw\n .map((entry) => {\n if (entry == null) {\n return null;\n }\n if (\n typeof entry !== 'string' &&\n typeof entry !== 'number' &&\n typeof entry !== 'boolean'\n ) {\n return null;\n }\n const value = String(entry).trim();\n if (value === '') {\n return null;\n }\n return value;\n })\n .filter((entry): entry is string => {\n return entry != null;\n });\n\n if (normalized.length === 0) {\n return null;\n }\n return normalized.join(', ');\n }\n\n if (typeof raw === 'boolean') {\n if (filter.kind === 'boolean') {\n return options.booleanLabel(raw);\n }\n if (raw) {\n return options.fallbackBooleanLabels.yes;\n }\n return options.fallbackBooleanLabels.no;\n }\n\n if (typeof raw !== 'string' && typeof raw !== 'number') {\n return null;\n }\n\n const rawString = String(raw).trim();\n if (rawString === '') {\n return null;\n }\n\n if (filter.kind === 'entityId') {\n return <EntityFilterValue entityId={filter.entity} id={rawString} />;\n }\n\n if (filter.kind === 'enum') {\n return options.enumLabel(rawString);\n }\n\n return rawString;\n};\n\nconst toDatetimeInputValue = (value: string): string => {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return value;\n }\n const offsetMs = date.getTimezoneOffset() * 60_000;\n return new Date(date.getTime() - offsetMs).toISOString().slice(0, 16);\n};\n\nconst fromDatetimeInputValue = (value: string): string => {\n const normalized = value.trim();\n if (normalized === '') {\n return '';\n }\n const date = new Date(normalized);\n if (Number.isNaN(date.getTime())) {\n return normalized;\n }\n return date.toISOString();\n};\n\ntype RuntimeWhere = Record<string, unknown>;\ntype RuntimeSort = string;\n\ntype Props<RowView> = {\n config: BackofficeRuntimeResolvedListFacetConfig;\n state: BackofficeListState<RuntimeWhere, RuntimeSort>;\n pushState: (next: BackofficeListState<RuntimeWhere, RuntimeSort>) => void;\n header?: {\n title?: string;\n subtitle?: string;\n };\n headerActions?: ReactNode;\n rows: readonly RowView[];\n getRowId: GetRowId<RowView>;\n columns: readonly DataTableColumn<RowView>[];\n gridTemplateColumns?: string;\n hasNextPage: boolean;\n isLoadingMore: boolean;\n isRefreshing?: boolean;\n onLoadMore: () => void;\n onRefresh?: () => void;\n totalCount?: number | null;\n loadedCountLabel?: ReactNode;\n emptyState?: JSX.Element;\n statusBanner?: ReactNode;\n isLoadingInitial?: boolean;\n virtualize?: boolean;\n variant?: 'page' | 'embedded';\n showFilters?: boolean;\n};\n\nexport const BackofficeEntityListScaffold = <RowView,>(\n props: Props<RowView>,\n): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const {\n config,\n state,\n pushState,\n rows,\n getRowId,\n columns,\n gridTemplateColumns,\n hasNextPage,\n isLoadingMore,\n isRefreshing = false,\n onLoadMore,\n onRefresh,\n totalCount,\n loadedCountLabel,\n emptyState,\n statusBanner,\n header,\n headerActions,\n isLoadingInitial = false,\n variant = 'page',\n showFilters = true,\n } = props;\n const listConfig = config.list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const listDefaults = config.listDefaults ??\n listConfig.defaultState ?? { where: null, sort: null };\n\n const columnsWithPrimary = useMemo(() => {\n const hasPrimary = columns.some((col) => {\n return col.isPrimary === true;\n });\n if (hasPrimary || columns.length === 0) {\n return columns;\n }\n return columns.map((col, index) => {\n const { header } = col;\n if (index === 0) {\n return { ...col, isPrimary: true, header };\n }\n return { ...col, header };\n });\n }, [columns]);\n\n const chips = useMemo<readonly FilterChip[]>(() => {\n const out: FilterChip[] = [];\n for (const filter of listConfig.filters) {\n const raw = getFilterValue(filter, state.where);\n const displayValue = getFilterDisplayValue(filter, raw, {\n enumLabel: (value) => {\n if (filter.kind !== 'enum') {\n return value;\n }\n const match = filter.options.find((option) => {\n return option.value === value;\n });\n if (match != null) {\n return resolveLabel(match.label, tApp);\n }\n return value;\n },\n booleanLabel: (value) => {\n if (filter.kind === 'boolean') {\n if (value && filter.trueLabel != null) {\n return resolveLabel(filter.trueLabel, tApp);\n }\n if (!value && filter.falseLabel != null) {\n return resolveLabel(filter.falseLabel, tApp);\n }\n }\n if (value) {\n return t('filters.boolean.yes');\n }\n return t('filters.boolean.no');\n },\n fallbackBooleanLabels: {\n yes: t('filters.boolean.yes'),\n no: t('filters.boolean.no'),\n },\n });\n\n if (displayValue != null) {\n let idValue = String(raw);\n if (Array.isArray(raw)) {\n idValue = raw.join(',');\n }\n const label = (\n <span>\n {resolveLabel(filter.label, tApp)}: {displayValue}\n </span>\n );\n out.push({\n id: `${filter.id}:${idValue}`,\n label,\n onRemove: () => {\n const key = filter.whereKey ?? filter.id;\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n },\n });\n }\n }\n return out;\n }, [listConfig.filters, pushState, state, t, tApp]);\n\n const handleClearAll = useCallback(() => {\n pushState({\n ...listDefaults,\n });\n }, [listDefaults, pushState]);\n const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false);\n const [filterSearch, setFilterSearch] = useState('');\n\n const [pickerDialog, setPickerDialog] = useState<{\n entity: string;\n whereKey: keyof RuntimeWhere;\n label: string;\n path?: readonly string[];\n scope?: BackofficePickerScope<Record<string, unknown>>;\n } | null>(null);\n\n const renderFilterControl = useCallback(\n (filter: BackofficeFilterSpec<RuntimeWhere>): JSX.Element => {\n const key = filter.whereKey ?? filter.id;\n const candidate = getFilterValue(filter, state.where);\n let value = '';\n if (typeof candidate === 'string') {\n value = candidate;\n }\n if (typeof candidate === 'number' && Number.isFinite(candidate)) {\n value = String(candidate);\n }\n\n const filterLabelText = resolveLabel(filter.label, tApp);\n\n if (filter.kind === 'text') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <DeferredFilterSearchInput\n value={toDatetimeInputValue(value)}\n onApply={(next) => {\n const normalized = fromDatetimeInputValue(next);\n const nextWhere = setWhereValue(\n state.where,\n key,\n normalized,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n ariaLabel={placeholder}\n className={styles.filterInput}\n />\n );\n }\n\n if (filter.kind === 'datetime') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <DeferredFilterSearchInput\n value={value}\n onApply={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n ariaLabel={placeholder}\n className={styles.filterInput}\n type=\"datetime-local\"\n />\n );\n }\n\n if (filter.kind === 'number') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <DeferredFilterSearchInput\n value={value}\n onApply={(next) => {\n const normalized = next.trim();\n const parsed = normalized === '' ? null : Number(normalized);\n const nextWhere = setWhereValue(\n state.where,\n key,\n Number.isFinite(parsed) ? parsed : null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n ariaLabel={placeholder}\n className={styles.filterInput}\n inputMode={filter.inputMode ?? 'numeric'}\n type=\"text\"\n />\n );\n }\n\n if (filter.kind === 'enum') {\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n ...filter.options.map((option) => {\n return {\n id: option.value,\n value: option.value,\n label: resolveLabel(option.label, tApp),\n };\n }),\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={value}\n size=\"small\"\n ariaLabel={filterLabelText}\n onChange={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n if (filter.kind === 'boolean') {\n let current: boolean | null = null;\n if (typeof candidate === 'boolean') {\n current = candidate;\n }\n\n let selectValue = '';\n if (current === true) {\n selectValue = 'true';\n }\n if (current === false) {\n selectValue = 'false';\n }\n\n const trueLabel =\n filter.trueLabel != null\n ? resolveLabel(filter.trueLabel, tApp)\n : t('filters.boolean.yes');\n const falseLabel =\n filter.falseLabel != null\n ? resolveLabel(filter.falseLabel, tApp)\n : t('filters.boolean.no');\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n {\n id: 'true',\n value: 'true',\n label: trueLabel,\n },\n {\n id: 'false',\n value: 'false',\n label: falseLabel,\n },\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={selectValue}\n size=\"small\"\n ariaLabel={filterLabelText}\n onChange={(next) => {\n let parsed: boolean | null = null;\n if (next === 'true') {\n parsed = true;\n }\n if (next === 'false') {\n parsed = false;\n }\n const nextWhere = setWhereValue(\n state.where,\n key,\n parsed,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n const pickerScope = (() => {\n if (filter.pickerScope == null) {\n return undefined;\n }\n if (typeof filter.pickerScope === 'function') {\n return filter.pickerScope(state.where);\n }\n return filter.pickerScope;\n })();\n let currentId: string | null = null;\n if (typeof candidate === 'string') {\n currentId = candidate;\n }\n\n const renderField = (\n displayValue: string | null = null,\n isResolving = false,\n ) => {\n const normalizedDisplayValue = displayValue?.trim() ?? '';\n return (\n <EntityIdFilterField\n label={filterLabelText}\n value={currentId}\n displayValue={normalizedDisplayValue}\n isResolving={isResolving}\n placeholder={t('filters.placeholders.anyEntity', {\n label: filterLabelText,\n })}\n onPick={() => {\n setPickerDialog({\n entity: filter.entity,\n whereKey: key,\n label: filterLabelText,\n path: filter.path,\n scope: pickerScope,\n });\n }}\n onClear={() => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n };\n\n if (currentId == null || currentId.trim() === '') {\n return renderField();\n }\n\n return (\n <EntityFilterValueText entityId={filter.entity} id={currentId}>\n {(label, valueState) => {\n const isResolving = valueState?.status === 'loading';\n return renderField(\n isResolving ? t('common.loading') : label,\n isResolving,\n );\n }}\n </EntityFilterValueText>\n );\n },\n [pushState, state, t, tApp],\n );\n\n const hasPlacementConfig = useMemo(() => {\n return listConfig.filters.some((filter) => {\n return filter.placement != null;\n });\n }, [listConfig.filters]);\n\n const quickFilters = useMemo(() => {\n if (listConfig.filters.length === 0) {\n return [];\n }\n const maxPromotedFilters = listConfig.ui?.toolbar?.maxPromotedFilters ?? 3;\n if (hasPlacementConfig) {\n return listConfig.filters.filter((filter) => {\n return filter.placement === 'quick' || filter.placement === 'both';\n });\n }\n return listConfig.filters.slice(0, maxPromotedFilters);\n }, [listConfig.filters, listConfig.ui?.toolbar, hasPlacementConfig]);\n\n const drawerFilters = useMemo(() => {\n return listConfig.filters.filter((filter) => {\n if (filter.placement == null) {\n return true;\n }\n return filter.placement === 'drawer' || filter.placement === 'both';\n });\n }, [listConfig.filters]);\n\n const searchFilter = useMemo(() => {\n return quickFilters.find((filter) => {\n return filter.kind === 'text';\n });\n }, [quickFilters]);\n\n const quickFiltersNode = useMemo(() => {\n const visibleQuickFilters = quickFilters.filter((filter) => {\n return filter !== searchFilter;\n });\n\n if (visibleQuickFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.controlsRow}>\n {visibleQuickFilters.map((filter) => {\n return <span key={filter.id}>{renderFilterControl(filter)}</span>;\n })}\n </div>\n );\n }, [quickFilters, renderFilterControl, searchFilter]);\n\n const searchNode = useMemo(() => {\n if (searchFilter == null) {\n return null;\n }\n return renderFilterControl(searchFilter);\n }, [renderFilterControl, searchFilter]);\n\n const sortNode = useMemo(() => {\n if (listConfig.sorts.length === 0) {\n return null;\n }\n const firstSort = listConfig.sorts[0];\n if (firstSort == null) {\n return null;\n }\n const options = listConfig.sorts.map((s) => {\n return { id: s.id, value: s.id, label: resolveLabel(s.label, tApp) };\n });\n return (\n <SimpleSelect\n options={options}\n value={state.sort ?? firstSort.id}\n size=\"small\"\n ariaLabel={t('list.sort.label')}\n onChange={(next) => {\n pushState({\n ...state,\n sort: next,\n });\n }}\n />\n );\n }, [listConfig.sorts, pushState, state, t, tApp]);\n\n const chipsNode = useMemo(() => {\n if (chips.length === 0) {\n return null;\n }\n return <FilterChipRow chips={chips} onClearAll={handleClearAll} />;\n }, [chips, handleClearAll]);\n\n const drawerSections = useMemo(() => {\n if (drawerFilters.length === 0) {\n return [];\n }\n\n const normalizedQuery = filterSearch.trim().toLowerCase();\n const items: { id: string; node: JSX.Element }[] = [];\n\n for (const filter of drawerFilters) {\n const resolvedLabel = resolveLabel(filter.label, tApp);\n const matchesQuery =\n normalizedQuery === '' ||\n resolvedLabel.toLowerCase().includes(normalizedQuery);\n\n if (matchesQuery) {\n items.push({\n id: filter.id,\n node: (\n <BackofficeFilterField label={resolvedLabel}>\n {renderFilterControl(filter)}\n </BackofficeFilterField>\n ),\n });\n }\n }\n\n if (items.length === 0) {\n return [];\n }\n\n return [\n {\n id: 'backoffice.filters.sections.default',\n title: t('filters.sections.default'),\n items,\n },\n ];\n }, [drawerFilters, filterSearch, renderFilterControl, t, tApp]);\n\n const allFiltersNode = useMemo(() => {\n if (drawerFilters.length === 0) {\n return null;\n }\n const activeCount = chips.length;\n let label = t('filters.trigger');\n if (activeCount > 0) {\n label = t('filters.triggerWithCount', {\n count: activeCount,\n });\n }\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={() => {\n setIsFilterDrawerOpen(true);\n }}\n >\n {label}\n </Button>\n );\n }, [chips.length, drawerFilters.length, t]);\n\n const filterDrawerEmptyLabel =\n filterSearch.trim() === ''\n ? undefined\n : t('filters.drawer.emptySearchResults');\n\n const filterDrawerNode = (\n <BackofficeFilterDrawer\n isOpen={isFilterDrawerOpen}\n onClose={() => {\n setIsFilterDrawerOpen(false);\n setFilterSearch('');\n }}\n sections={drawerSections}\n searchValue={filterSearch}\n onSearchChange={(next) => {\n setFilterSearch(next);\n }}\n onReset={handleClearAll}\n emptyLabel={filterDrawerEmptyLabel}\n />\n );\n\n const resolvedEmptyState = useMemo((): JSX.Element => {\n if (emptyState != null) {\n return emptyState;\n }\n\n if (isLoadingInitial) {\n return (\n <BackofficeTableSkeleton\n variant=\"embedded\"\n ariaLabel={t('common.loading')}\n />\n );\n }\n\n if (chips.length > 0) {\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmptyFiltered.description')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={handleClearAll}\n >\n {t('emptyState.listEmptyFiltered.actions.reset')}\n </Button>\n }\n />\n );\n }\n\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmpty.description')}\n />\n );\n }, [chips.length, emptyState, handleClearAll, isLoadingInitial, t]);\n\n const tableFooterMeta = useMemo((): ReactNode => {\n if (loadedCountLabel != null) {\n return loadedCountLabel;\n }\n if (typeof totalCount !== 'number') {\n if (rows.length === 0) {\n return null;\n }\n return (\n <span>\n {t('list.loaded', {\n count: rows.length,\n })}\n </span>\n );\n }\n return (\n <span>\n {t('list.showing', {\n shown: rows.length,\n total: totalCount,\n })}\n </span>\n );\n }, [loadedCountLabel, rows.length, t, totalCount]);\n\n const runtimeConfig = useMemo(() => {\n const resolvedDisplayMode =\n listConfig.ui?.displayMode ?? listConfig.responsive?.mode ?? 'auto';\n return resolveBackofficeListRuntimeConfig({\n kind: listConfig.kind,\n displayMode: resolvedDisplayMode,\n ui: listConfig.ui,\n });\n }, [listConfig.kind, listConfig.responsive?.mode, listConfig.ui]);\n\n const hasKnownRemainingRows =\n typeof totalCount === 'number' && rows.length < totalCount;\n const hasInconsistentPageInfo = hasKnownRemainingRows && !hasNextPage;\n\n useEffect(() => {\n if (\n !hasInconsistentPageInfo ||\n !runtimeConfig.infiniteScroll.showInconsistentPageInfo ||\n !isDevEnv()\n ) {\n return;\n }\n // eslint-disable-next-line no-console\n console.warn(\n 'Backoffice list received inconsistent pageInfo: loaded rows are lower than totalCount but hasNextPage is false.',\n {\n entityId: config.id,\n loadedCount: rows.length,\n totalCount,\n },\n );\n }, [\n config.id,\n hasInconsistentPageInfo,\n rows.length,\n runtimeConfig.infiniteScroll.showInconsistentPageInfo,\n totalCount,\n ]);\n\n const shouldVirtualizeTable =\n props.virtualize === true || runtimeConfig.virtualization.enabled;\n\n const { sentinelRef } = useBackofficeInfiniteScrollSentinel({\n enabled: !shouldVirtualizeTable && runtimeConfig.infiniteScroll.enabled,\n hasNextPage,\n isLoading: isLoadingMore,\n onIntersect: onLoadMore,\n rootMargin: runtimeConfig.infiniteScroll.rootMargin,\n threshold: runtimeConfig.infiniteScroll.threshold,\n });\n\n const headerTitle = header?.title ?? resolveLabel(listConfig.title, tApp);\n const headerSubtitle = header?.subtitle;\n\n const actionColumn = columnsWithPrimary.find((column) => {\n return column.mobileRole === 'action' || column.id === 'actions';\n });\n const listMode =\n listConfig.ui?.displayMode ?? listConfig.responsive?.mode ?? 'auto';\n const listDensity =\n listConfig.ui?.density ?? listConfig.responsive?.density ?? 'compact';\n\n const tableInnerNode = shouldVirtualizeTable ? (\n <VirtualizedConnectionTable\n columns={columnsWithPrimary}\n rows={rows}\n getRowId={getRowId}\n emptyState={resolvedEmptyState}\n className={denseTableClass}\n gridTemplateColumns={gridTemplateColumns}\n virtualization={runtimeConfig.virtualization}\n infiniteScroll={{\n enabled: runtimeConfig.infiniteScroll.enabled,\n thresholdPx: runtimeConfig.infiniteScroll.thresholdPx,\n autoLoad: runtimeConfig.infiniteScroll.autoLoad,\n }}\n hasNextPage={hasNextPage}\n isLoadingMore={isLoadingMore}\n onLoadMore={onLoadMore}\n bodyScrollMode={BACKOFFICE_LIST_BODY_SCROLL_MODE}\n />\n ) : (\n <ResponsiveRecordList\n columns={columnsWithPrimary}\n rows={rows}\n getRowId={getRowId}\n emptyState={resolvedEmptyState}\n className={denseTableClass}\n gridTemplateColumns={gridTemplateColumns}\n mode={listMode}\n density={listDensity}\n bodyScrollMode={BACKOFFICE_LIST_BODY_SCROLL_MODE}\n bodyFooterNode={\n runtimeConfig.infiniteScroll.enabled ? (\n <div ref={sentinelRef} aria-hidden=\"true\" />\n ) : null\n }\n renderAction={(row) => {\n return actionColumn?.cell(row) ?? null;\n }}\n />\n );\n\n const tableNodeWithErrorBoundary = (\n <BackofficeErrorBoundary\n fallback={(args: { error: unknown; reset: () => void }) => {\n const { reset } = args;\n\n const retry = (): void => {\n reset();\n if (onRefresh != null) {\n onRefresh();\n }\n };\n\n return (\n <InlineBanner\n tone=\"danger\"\n title={t('list.errors.title')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={retry}\n >\n {t('list.actions.retry')}\n </Button>\n }\n >\n {t('list.errors.tableFailed')}\n </InlineBanner>\n );\n }}\n >\n {tableInnerNode}\n </BackofficeErrorBoundary>\n );\n\n const filtersBarNode = showFilters ? (\n <>\n <BackofficeToolbar\n search={searchNode}\n primaryFilters={quickFiltersNode}\n filterDrawerTrigger={allFiltersNode}\n sort={sortNode}\n utilityActions={\n onRefresh == null ? null : (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n isLoading={isRefreshing}\n loadingLabel={t('list.actions.refreshing')}\n onClick={() => {\n onRefresh();\n }}\n >\n {t('list.actions.refresh')}\n </Button>\n )\n }\n chips={chipsNode}\n density=\"compact\"\n />\n {filterDrawerNode}\n </>\n ) : null;\n\n const tableNode = (\n <div className={styles.tableHost}>\n {tableNodeWithErrorBoundary}\n <EntityIdPickerDialog\n isOpen={pickerDialog != null}\n entity={pickerDialog?.entity ?? config.id}\n title={pickerDialog?.label ?? t('picker.title')}\n scope={pickerDialog?.scope}\n onClose={() => {\n setPickerDialog(null);\n }}\n onSelectId={(id) => {\n if (pickerDialog == null) {\n return;\n }\n const nextWhere = setWhereValue(\n state.where,\n pickerDialog.whereKey,\n id,\n pickerDialog.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n </div>\n );\n\n const shouldRenderTableFooter =\n rows.length > 0 || isLoadingMore || hasNextPage;\n\n const tableFooterNode = shouldRenderTableFooter ? (\n <>\n <BackofficeListFooter\n mode=\"status\"\n loadedCount={rows.length}\n totalCount={totalCount}\n hasNextPage={hasNextPage}\n isLoading={isLoadingMore}\n pageInfoState={\n hasInconsistentPageInfo\n ? 'inconsistent'\n : isLoadingMore\n ? 'loading'\n : hasNextPage\n ? 'ready'\n : 'complete'\n }\n labels={{\n loaded: tableFooterMeta,\n loading: t('list.loadMore.loading'),\n end: t('list.loadMore.end'),\n }}\n />\n </>\n ) : null;\n\n if (variant === 'embedded') {\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <div className={styles.embeddedContainer}>\n <div className={styles.embeddedHeader}>{headerTitle}</div>\n {filtersBarNode}\n {statusBanner}\n {tableNode}\n {tableFooterNode}\n </div>\n </BackofficeListFilterProvider>\n );\n }\n\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <ListPageTemplate\n headerNode={\n <BackofficePageHeader\n title={headerTitle}\n subtitle={headerSubtitle}\n actions={headerActions}\n />\n }\n toolbarNode={filtersBarNode}\n statusNode={statusBanner}\n tableNode={tableNode}\n tableFooterNode={tableFooterNode}\n presentation=\"flat\"\n bodyScrollMode={BACKOFFICE_LIST_BODY_SCROLL_MODE}\n />\n </BackofficeListFilterProvider>\n );\n};\n\nexport default BackofficeEntityListScaffold;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BackofficeEntityListScaffold.js","names":[],"sources":["../../../../../src/components/backoffice/scaffolds/BackofficeEntityListScaffold.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n type JSX,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport type { TFunction } from 'i18next';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '@plumile/ui/atomic/atoms/button/Button.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport { BackofficeFilterDrawer } from '@plumile/ui/backoffice/molecules/backoffice_filter_drawer/BackofficeFilterDrawer.js';\nimport { BackofficeFilterField } from '@plumile/ui/backoffice/molecules/backoffice_filter_field/BackofficeFilterField.js';\nimport { Spinner } from '@plumile/ui/backoffice/atoms/spinner/Spinner.js';\nimport { BackofficeListFooter } from '@plumile/ui/backoffice/molecules/backoffice_list_footer/BackofficeListFooter.js';\nimport { BackofficePageHeader } from '@plumile/ui/backoffice/molecules/backoffice_page_header/BackofficePageHeader.js';\nimport { BackofficeToolbar } from '@plumile/ui/backoffice/molecules/backoffice_toolbar/BackofficeToolbar.js';\nimport { BackofficeTableSkeleton } from '@plumile/ui/backoffice/molecules/backoffice_table_skeleton/BackofficeTableSkeleton.js';\nimport {\n FilterChipRow,\n type FilterChip,\n} from '@plumile/ui/backoffice/molecules/filter_chip_row/FilterChipRow.js';\nimport { InlineBanner } from '@plumile/ui/components/feedback/InlineBanner.js';\nimport { ListPageTemplate } from '@plumile/ui/backoffice/templates/list_page_template/ListPageTemplate.js';\nimport {\n type DataTableColumn,\n type GetRowId,\n} from '@plumile/ui/components/data-table/DataTable.js';\nimport { ResponsiveRecordList } from '@plumile/ui/components/data-table/ResponsiveRecordList.js';\nimport { VirtualizedConnectionTable } from '@plumile/ui/components/data-table/VirtualizedConnectionTable.js';\nimport { SimpleSelect } from '@plumile/ui/components/select/SimpleSelect.js';\nimport { denseTableClass } from '@plumile/ui/shared/backofficeTableDensity.css.js';\n\nimport {\n readWhereValue,\n setWhereValue,\n} from '@plumile/backoffice-core/filters/where.js';\nimport { resolveBackofficeListRuntimeConfig } from '@plumile/backoffice-core/config/listRuntime.js';\nimport type {\n BackofficeFilterSpec,\n BackofficeListState,\n BackofficePickerScope,\n BackofficeRuntimeResolvedListFacetConfig,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\nimport {\n EntityFilterValue,\n EntityFilterValueText,\n} from '../filters/EntityFilterValue.js';\nimport { EntityIdPickerDialog } from '../pickers/EntityIdPickerDialog.js';\nimport { EntityIdFilterField } from '../filters/EntityIdFilterField.js';\nimport { DeferredFilterSearchInput } from '../filters/DeferredFilterSearchInput.js';\nimport { BackofficeListFilterProvider } from './BackofficeListFilterContext.js';\nimport { BACKOFFICE_LIST_BODY_SCROLL_MODE } from './backofficeListScrollMode.js';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeInfiniteScrollSentinel } from '../../../hooks/useBackofficeInfiniteScrollSentinel.js';\nimport { isDevEnv } from '../../../relay/envHelpers.js';\n\nimport * as styles from './backofficeEntityListScaffold.css.js';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst getFilterValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n where: Where | null,\n): unknown => {\n if (filter.fromGraphQL != null && where != null) {\n return filter.fromGraphQL(where);\n }\n\n const key = (filter.whereKey ?? filter.id) as keyof Where;\n return readWhereValue(where, key, filter.path);\n};\n\nconst getFilterDisplayValue = <Where extends Record<string, unknown>>(\n filter: BackofficeFilterSpec<Where>,\n raw: unknown,\n options: {\n enumLabel: (value: string) => string;\n booleanLabel: (value: boolean) => string;\n fallbackBooleanLabels: { yes: string; no: string };\n },\n): ReactNode | null => {\n if (raw == null) {\n return null;\n }\n\n if (Array.isArray(raw)) {\n const normalized = raw\n .map((entry) => {\n if (entry == null) {\n return null;\n }\n if (\n typeof entry !== 'string' &&\n typeof entry !== 'number' &&\n typeof entry !== 'boolean'\n ) {\n return null;\n }\n const value = String(entry).trim();\n if (value === '') {\n return null;\n }\n return value;\n })\n .filter((entry): entry is string => {\n return entry != null;\n });\n\n if (normalized.length === 0) {\n return null;\n }\n return normalized.join(', ');\n }\n\n if (typeof raw === 'boolean') {\n if (filter.kind === 'boolean') {\n return options.booleanLabel(raw);\n }\n if (raw) {\n return options.fallbackBooleanLabels.yes;\n }\n return options.fallbackBooleanLabels.no;\n }\n\n if (typeof raw !== 'string' && typeof raw !== 'number') {\n return null;\n }\n\n const rawString = String(raw).trim();\n if (rawString === '') {\n return null;\n }\n\n if (filter.kind === 'entityId') {\n return <EntityFilterValue entityId={filter.entity} id={rawString} />;\n }\n\n if (filter.kind === 'enum') {\n return options.enumLabel(rawString);\n }\n\n return rawString;\n};\n\nconst toDatetimeInputValue = (value: string): string => {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return value;\n }\n const offsetMs = date.getTimezoneOffset() * 60_000;\n return new Date(date.getTime() - offsetMs).toISOString().slice(0, 16);\n};\n\nconst fromDatetimeInputValue = (value: string): string => {\n const normalized = value.trim();\n if (normalized === '') {\n return '';\n }\n const date = new Date(normalized);\n if (Number.isNaN(date.getTime())) {\n return normalized;\n }\n return date.toISOString();\n};\n\ntype RuntimeWhere = Record<string, unknown>;\ntype RuntimeSort = string;\n\ntype Props<RowView> = {\n config: BackofficeRuntimeResolvedListFacetConfig;\n state: BackofficeListState<RuntimeWhere, RuntimeSort>;\n pushState: (next: BackofficeListState<RuntimeWhere, RuntimeSort>) => void;\n header?: {\n title?: string;\n subtitle?: string;\n };\n headerActions?: ReactNode;\n rows: readonly RowView[];\n getRowId: GetRowId<RowView>;\n columns: readonly DataTableColumn<RowView>[];\n gridTemplateColumns?: string;\n hasNextPage: boolean;\n isLoadingMore: boolean;\n isRefreshing?: boolean;\n onLoadMore: () => void;\n onRefresh?: () => void;\n totalCount?: number | null;\n loadedCountLabel?: ReactNode;\n emptyState?: JSX.Element;\n statusBanner?: ReactNode;\n isLoadingInitial?: boolean;\n virtualize?: boolean;\n variant?: 'page' | 'embedded';\n showFilters?: boolean;\n};\n\nexport const BackofficeEntityListScaffold = <RowView,>(\n props: Props<RowView>,\n): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const {\n config,\n state,\n pushState,\n rows,\n getRowId,\n columns,\n gridTemplateColumns,\n hasNextPage,\n isLoadingMore,\n isRefreshing = false,\n onLoadMore,\n onRefresh,\n totalCount,\n loadedCountLabel,\n emptyState,\n statusBanner,\n header,\n headerActions,\n isLoadingInitial = false,\n variant = 'page',\n showFilters = true,\n } = props;\n const listConfig = config.list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const listDefaults = config.listDefaults ??\n listConfig.defaultState ?? { where: null, sort: null };\n\n const columnsWithPrimary = useMemo(() => {\n const hasPrimary = columns.some((col) => {\n return col.isPrimary === true;\n });\n if (hasPrimary || columns.length === 0) {\n return columns;\n }\n return columns.map((col, index) => {\n const { header } = col;\n if (index === 0) {\n return { ...col, isPrimary: true, header };\n }\n return { ...col, header };\n });\n }, [columns]);\n\n const chips = useMemo<readonly FilterChip[]>(() => {\n const out: FilterChip[] = [];\n for (const filter of listConfig.filters) {\n const raw = getFilterValue(filter, state.where);\n const displayValue = getFilterDisplayValue(filter, raw, {\n enumLabel: (value) => {\n if (filter.kind !== 'enum') {\n return value;\n }\n const match = filter.options.find((option) => {\n return option.value === value;\n });\n if (match != null) {\n return resolveLabel(match.label, tApp);\n }\n return value;\n },\n booleanLabel: (value) => {\n if (filter.kind === 'boolean') {\n if (value && filter.trueLabel != null) {\n return resolveLabel(filter.trueLabel, tApp);\n }\n if (!value && filter.falseLabel != null) {\n return resolveLabel(filter.falseLabel, tApp);\n }\n }\n if (value) {\n return t('filters.boolean.yes');\n }\n return t('filters.boolean.no');\n },\n fallbackBooleanLabels: {\n yes: t('filters.boolean.yes'),\n no: t('filters.boolean.no'),\n },\n });\n\n if (displayValue != null) {\n let idValue = String(raw);\n if (Array.isArray(raw)) {\n idValue = raw.join(',');\n }\n const label = (\n <span>\n {resolveLabel(filter.label, tApp)}: {displayValue}\n </span>\n );\n out.push({\n id: `${filter.id}:${idValue}`,\n label,\n onRemove: () => {\n const key = filter.whereKey ?? filter.id;\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n },\n });\n }\n }\n return out;\n }, [listConfig.filters, pushState, state, t, tApp]);\n\n const handleClearAll = useCallback(() => {\n pushState({\n ...listDefaults,\n });\n }, [listDefaults, pushState]);\n const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false);\n const [filterSearch, setFilterSearch] = useState('');\n\n const [pickerDialog, setPickerDialog] = useState<{\n entity: string;\n whereKey: keyof RuntimeWhere;\n label: string;\n path?: readonly string[];\n scope?: BackofficePickerScope<Record<string, unknown>>;\n } | null>(null);\n\n const renderFilterControl = useCallback(\n (filter: BackofficeFilterSpec<RuntimeWhere>): JSX.Element => {\n const key = filter.whereKey ?? filter.id;\n const candidate = getFilterValue(filter, state.where);\n let value = '';\n if (typeof candidate === 'string') {\n value = candidate;\n }\n if (typeof candidate === 'number' && Number.isFinite(candidate)) {\n value = String(candidate);\n }\n\n const filterLabelText = resolveLabel(filter.label, tApp);\n\n if (filter.kind === 'text') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <DeferredFilterSearchInput\n value={toDatetimeInputValue(value)}\n onApply={(next) => {\n const normalized = fromDatetimeInputValue(next);\n const nextWhere = setWhereValue(\n state.where,\n key,\n normalized,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n ariaLabel={placeholder}\n className={styles.filterInput}\n />\n );\n }\n\n if (filter.kind === 'datetime') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <DeferredFilterSearchInput\n value={value}\n onApply={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n ariaLabel={placeholder}\n className={styles.filterInput}\n type=\"datetime-local\"\n />\n );\n }\n\n if (filter.kind === 'number') {\n const placeholderLabelText =\n filter.placeholderLabel != null\n ? resolveLabel(filter.placeholderLabel, tApp)\n : filterLabelText;\n let placeholder = t('filters.placeholders.search', {\n label: placeholderLabelText,\n });\n if (filter.placeholderText != null) {\n placeholder = resolveLabel(filter.placeholderText, tApp);\n }\n return (\n <DeferredFilterSearchInput\n value={value}\n onApply={(next) => {\n const normalized = next.trim();\n const parsed = normalized === '' ? null : Number(normalized);\n const nextWhere = setWhereValue(\n state.where,\n key,\n Number.isFinite(parsed) ? parsed : null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n placeholder={placeholder}\n ariaLabel={placeholder}\n className={styles.filterInput}\n inputMode={filter.inputMode ?? 'numeric'}\n type=\"text\"\n />\n );\n }\n\n if (filter.kind === 'enum') {\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n ...filter.options.map((option) => {\n return {\n id: option.value,\n value: option.value,\n label: resolveLabel(option.label, tApp),\n };\n }),\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={value}\n size=\"small\"\n ariaLabel={filterLabelText}\n onChange={(next) => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n next,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n if (filter.kind === 'boolean') {\n let current: boolean | null = null;\n if (typeof candidate === 'boolean') {\n current = candidate;\n }\n\n let selectValue = '';\n if (current === true) {\n selectValue = 'true';\n }\n if (current === false) {\n selectValue = 'false';\n }\n\n const trueLabel =\n filter.trueLabel != null\n ? resolveLabel(filter.trueLabel, tApp)\n : t('filters.boolean.yes');\n const falseLabel =\n filter.falseLabel != null\n ? resolveLabel(filter.falseLabel, tApp)\n : t('filters.boolean.no');\n const options = [\n {\n id: 'any',\n value: '',\n label: t('filters.all', {\n label: filterLabelText,\n }),\n },\n {\n id: 'true',\n value: 'true',\n label: trueLabel,\n },\n {\n id: 'false',\n value: 'false',\n label: falseLabel,\n },\n ];\n\n return (\n <SimpleSelect\n options={options}\n value={selectValue}\n size=\"small\"\n ariaLabel={filterLabelText}\n onChange={(next) => {\n let parsed: boolean | null = null;\n if (next === 'true') {\n parsed = true;\n }\n if (next === 'false') {\n parsed = false;\n }\n const nextWhere = setWhereValue(\n state.where,\n key,\n parsed,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n }\n\n const pickerScope = (() => {\n if (filter.pickerScope == null) {\n return undefined;\n }\n if (typeof filter.pickerScope === 'function') {\n return filter.pickerScope(state.where);\n }\n return filter.pickerScope;\n })();\n let currentId: string | null = null;\n if (typeof candidate === 'string') {\n currentId = candidate;\n }\n\n const renderField = (\n displayValue: string | null = null,\n isResolving = false,\n ) => {\n const normalizedDisplayValue = displayValue?.trim() ?? '';\n return (\n <EntityIdFilterField\n label={filterLabelText}\n value={currentId}\n displayValue={normalizedDisplayValue}\n isResolving={isResolving}\n placeholder={t('filters.placeholders.anyEntity', {\n label: filterLabelText,\n })}\n onPick={() => {\n setPickerDialog({\n entity: filter.entity,\n whereKey: key,\n label: filterLabelText,\n path: filter.path,\n scope: pickerScope,\n });\n }}\n onClear={() => {\n const nextWhere = setWhereValue(\n state.where,\n key,\n null,\n filter.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n );\n };\n\n if (currentId == null || currentId.trim() === '') {\n return renderField();\n }\n\n return (\n <EntityFilterValueText entityId={filter.entity} id={currentId}>\n {(label, valueState) => {\n const isResolving = valueState?.status === 'loading';\n return renderField(\n isResolving ? t('common.loading') : label,\n isResolving,\n );\n }}\n </EntityFilterValueText>\n );\n },\n [pushState, state, t, tApp],\n );\n\n const hasPlacementConfig = useMemo(() => {\n return listConfig.filters.some((filter) => {\n return filter.placement != null;\n });\n }, [listConfig.filters]);\n\n const quickFilters = useMemo(() => {\n if (listConfig.filters.length === 0) {\n return [];\n }\n const maxPromotedFilters = listConfig.ui?.toolbar?.maxPromotedFilters ?? 3;\n if (hasPlacementConfig) {\n return listConfig.filters.filter((filter) => {\n return filter.placement === 'quick' || filter.placement === 'both';\n });\n }\n return listConfig.filters.slice(0, maxPromotedFilters);\n }, [listConfig.filters, listConfig.ui?.toolbar, hasPlacementConfig]);\n\n const drawerFilters = useMemo(() => {\n return listConfig.filters.filter((filter) => {\n if (filter.placement == null) {\n return true;\n }\n return filter.placement === 'drawer' || filter.placement === 'both';\n });\n }, [listConfig.filters]);\n\n const searchFilter = useMemo(() => {\n return quickFilters.find((filter) => {\n return filter.kind === 'text';\n });\n }, [quickFilters]);\n\n const quickFiltersNode = useMemo(() => {\n const visibleQuickFilters = quickFilters.filter((filter) => {\n return filter !== searchFilter;\n });\n\n if (visibleQuickFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={styles.controlsRow}>\n {visibleQuickFilters.map((filter) => {\n return <span key={filter.id}>{renderFilterControl(filter)}</span>;\n })}\n </div>\n );\n }, [quickFilters, renderFilterControl, searchFilter]);\n\n const searchNode = useMemo(() => {\n if (searchFilter == null) {\n return null;\n }\n return renderFilterControl(searchFilter);\n }, [renderFilterControl, searchFilter]);\n\n const sortNode = useMemo(() => {\n if (listConfig.sorts.length === 0) {\n return null;\n }\n const firstSort = listConfig.sorts[0];\n if (firstSort == null) {\n return null;\n }\n const options = listConfig.sorts.map((s) => {\n return { id: s.id, value: s.id, label: resolveLabel(s.label, tApp) };\n });\n return (\n <SimpleSelect\n options={options}\n value={state.sort ?? firstSort.id}\n size=\"small\"\n ariaLabel={t('list.sort.label')}\n onChange={(next) => {\n pushState({\n ...state,\n sort: next,\n });\n }}\n />\n );\n }, [listConfig.sorts, pushState, state, t, tApp]);\n\n const chipsNode = useMemo(() => {\n if (chips.length === 0) {\n return null;\n }\n return <FilterChipRow chips={chips} onClearAll={handleClearAll} />;\n }, [chips, handleClearAll]);\n\n const drawerSections = useMemo(() => {\n if (drawerFilters.length === 0) {\n return [];\n }\n\n const normalizedQuery = filterSearch.trim().toLowerCase();\n const items: { id: string; node: JSX.Element }[] = [];\n\n for (const filter of drawerFilters) {\n const resolvedLabel = resolveLabel(filter.label, tApp);\n const matchesQuery =\n normalizedQuery === '' ||\n resolvedLabel.toLowerCase().includes(normalizedQuery);\n\n if (matchesQuery) {\n items.push({\n id: filter.id,\n node: (\n <BackofficeFilterField label={resolvedLabel}>\n {renderFilterControl(filter)}\n </BackofficeFilterField>\n ),\n });\n }\n }\n\n if (items.length === 0) {\n return [];\n }\n\n return [\n {\n id: 'backoffice.filters.sections.default',\n title: t('filters.sections.default'),\n items,\n },\n ];\n }, [drawerFilters, filterSearch, renderFilterControl, t, tApp]);\n\n const allFiltersNode = useMemo(() => {\n if (drawerFilters.length === 0) {\n return null;\n }\n const activeCount = chips.length;\n let label = t('filters.trigger');\n if (activeCount > 0) {\n label = t('filters.triggerWithCount', {\n count: activeCount,\n });\n }\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={() => {\n setIsFilterDrawerOpen(true);\n }}\n >\n {label}\n </Button>\n );\n }, [chips.length, drawerFilters.length, t]);\n\n const filterDrawerEmptyLabel =\n filterSearch.trim() === ''\n ? undefined\n : t('filters.drawer.emptySearchResults');\n\n const filterDrawerNode = (\n <BackofficeFilterDrawer\n isOpen={isFilterDrawerOpen}\n onClose={() => {\n setIsFilterDrawerOpen(false);\n setFilterSearch('');\n }}\n sections={drawerSections}\n searchValue={filterSearch}\n onSearchChange={(next) => {\n setFilterSearch(next);\n }}\n onReset={handleClearAll}\n emptyLabel={filterDrawerEmptyLabel}\n />\n );\n\n const resolvedEmptyState = useMemo((): JSX.Element => {\n if (emptyState != null) {\n return emptyState;\n }\n\n if (isLoadingInitial) {\n return (\n <BackofficeTableSkeleton\n variant=\"embedded\"\n ariaLabel={t('common.loading')}\n />\n );\n }\n\n if (chips.length > 0) {\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmptyFiltered.description')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={handleClearAll}\n >\n {t('emptyState.listEmptyFiltered.actions.reset')}\n </Button>\n }\n />\n );\n }\n\n return (\n <BackofficeEmptyState\n title={t('emptyState.listEmpty.title')}\n description={t('emptyState.listEmpty.description')}\n />\n );\n }, [chips.length, emptyState, handleClearAll, isLoadingInitial, t]);\n\n const tableFooterMeta = useMemo((): ReactNode => {\n if (loadedCountLabel != null) {\n return loadedCountLabel;\n }\n if (typeof totalCount !== 'number') {\n if (rows.length === 0) {\n return null;\n }\n return (\n <span>\n {t('list.loaded', {\n count: rows.length,\n })}\n </span>\n );\n }\n return (\n <span>\n {t('list.showing', {\n shown: rows.length,\n total: totalCount,\n })}\n </span>\n );\n }, [loadedCountLabel, rows.length, t, totalCount]);\n\n const runtimeConfig = useMemo(() => {\n const resolvedDisplayMode =\n listConfig.ui?.displayMode ?? listConfig.responsive?.mode ?? 'auto';\n return resolveBackofficeListRuntimeConfig({\n kind: listConfig.kind,\n displayMode: resolvedDisplayMode,\n ui: listConfig.ui,\n });\n }, [listConfig.kind, listConfig.responsive?.mode, listConfig.ui]);\n\n const hasKnownRemainingRows =\n typeof totalCount === 'number' && rows.length < totalCount;\n const hasInconsistentPageInfo = hasKnownRemainingRows && !hasNextPage;\n\n useEffect(() => {\n if (\n !hasInconsistentPageInfo ||\n !runtimeConfig.infiniteScroll.showInconsistentPageInfo ||\n !isDevEnv()\n ) {\n return;\n }\n // eslint-disable-next-line no-console\n console.warn(\n 'Backoffice list received inconsistent pageInfo: loaded rows are lower than totalCount but hasNextPage is false.',\n {\n entityId: config.id,\n loadedCount: rows.length,\n totalCount,\n },\n );\n }, [\n config.id,\n hasInconsistentPageInfo,\n rows.length,\n runtimeConfig.infiniteScroll.showInconsistentPageInfo,\n totalCount,\n ]);\n\n const shouldVirtualizeTable =\n props.virtualize === true || runtimeConfig.virtualization.enabled;\n\n const { sentinelRef } = useBackofficeInfiniteScrollSentinel({\n enabled: !shouldVirtualizeTable && runtimeConfig.infiniteScroll.enabled,\n hasNextPage,\n isLoading: isLoadingMore,\n onIntersect: onLoadMore,\n rootMargin: runtimeConfig.infiniteScroll.rootMargin,\n threshold: runtimeConfig.infiniteScroll.threshold,\n });\n\n const headerTitle = header?.title ?? resolveLabel(listConfig.title, tApp);\n const headerSubtitle = header?.subtitle;\n\n const actionColumn = columnsWithPrimary.find((column) => {\n return column.mobileRole === 'action' || column.id === 'actions';\n });\n const listMode =\n listConfig.ui?.displayMode ?? listConfig.responsive?.mode ?? 'auto';\n const listDensity =\n listConfig.ui?.density ?? listConfig.responsive?.density ?? 'compact';\n\n const tableInnerNode = shouldVirtualizeTable ? (\n <VirtualizedConnectionTable\n columns={columnsWithPrimary}\n rows={rows}\n getRowId={getRowId}\n emptyState={resolvedEmptyState}\n className={denseTableClass}\n gridTemplateColumns={gridTemplateColumns}\n virtualization={runtimeConfig.virtualization}\n infiniteScroll={{\n enabled: runtimeConfig.infiniteScroll.enabled,\n thresholdPx: runtimeConfig.infiniteScroll.thresholdPx,\n autoLoad: runtimeConfig.infiniteScroll.autoLoad,\n }}\n hasNextPage={hasNextPage}\n isLoadingMore={isLoadingMore}\n onLoadMore={onLoadMore}\n bodyScrollMode={BACKOFFICE_LIST_BODY_SCROLL_MODE}\n />\n ) : (\n <ResponsiveRecordList\n columns={columnsWithPrimary}\n rows={rows}\n getRowId={getRowId}\n emptyState={resolvedEmptyState}\n className={denseTableClass}\n gridTemplateColumns={gridTemplateColumns}\n mode={listMode}\n density={listDensity}\n bodyScrollMode={BACKOFFICE_LIST_BODY_SCROLL_MODE}\n bodyFooterNode={\n runtimeConfig.infiniteScroll.enabled ? (\n <div ref={sentinelRef} aria-hidden=\"true\" />\n ) : null\n }\n renderAction={(row) => {\n return actionColumn?.cell(row) ?? null;\n }}\n />\n );\n\n const tableNodeWithErrorBoundary = (\n <BackofficeErrorBoundary\n fallback={(args: { error: unknown; reset: () => void }) => {\n const { reset } = args;\n\n const retry = (): void => {\n reset();\n if (onRefresh != null) {\n onRefresh();\n }\n };\n\n return (\n <InlineBanner\n tone=\"danger\"\n title={t('list.errors.title')}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={retry}\n >\n {t('list.actions.retry')}\n </Button>\n }\n >\n {t('list.errors.tableFailed')}\n </InlineBanner>\n );\n }}\n >\n {tableInnerNode}\n </BackofficeErrorBoundary>\n );\n\n const filtersBarNode = showFilters ? (\n <>\n <BackofficeToolbar\n search={searchNode}\n primaryFilters={quickFiltersNode}\n filterDrawerTrigger={allFiltersNode}\n sort={sortNode}\n utilityActions={\n onRefresh == null ? null : (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n isLoading={isRefreshing}\n loadingLabel={t('list.actions.refreshing')}\n onClick={() => {\n onRefresh();\n }}\n >\n {t('list.actions.refresh')}\n </Button>\n )\n }\n chips={chipsNode}\n density=\"compact\"\n />\n {filterDrawerNode}\n </>\n ) : null;\n\n const tableNode = (\n <div\n className={styles.tableHost}\n aria-busy={isRefreshing ? 'true' : undefined}\n >\n {isRefreshing && !isLoadingInitial ? (\n <div className={styles.refreshingIndicator} role=\"status\">\n <Spinner size={14} ariaLabel={t('list.refreshingRows')} />\n <span>{t('list.refreshingRows')}</span>\n </div>\n ) : null}\n {tableNodeWithErrorBoundary}\n <EntityIdPickerDialog\n isOpen={pickerDialog != null}\n entity={pickerDialog?.entity ?? config.id}\n title={pickerDialog?.label ?? t('picker.title')}\n scope={pickerDialog?.scope}\n onClose={() => {\n setPickerDialog(null);\n }}\n onSelectId={(id) => {\n if (pickerDialog == null) {\n return;\n }\n const nextWhere = setWhereValue(\n state.where,\n pickerDialog.whereKey,\n id,\n pickerDialog.path,\n );\n pushState({ ...state, where: nextWhere });\n }}\n />\n </div>\n );\n\n const shouldRenderTableFooter =\n rows.length > 0 || isLoadingMore || hasNextPage;\n\n const tableFooterNode = shouldRenderTableFooter ? (\n <>\n <BackofficeListFooter\n mode=\"status\"\n loadedCount={rows.length}\n totalCount={totalCount}\n hasNextPage={hasNextPage}\n isLoading={isLoadingMore}\n pageInfoState={\n hasInconsistentPageInfo\n ? 'inconsistent'\n : isLoadingMore\n ? 'loading'\n : hasNextPage\n ? 'ready'\n : 'complete'\n }\n labels={{\n loaded: tableFooterMeta,\n loading: t('list.loadMore.loading'),\n end: t('list.loadMore.end'),\n }}\n />\n </>\n ) : null;\n\n if (variant === 'embedded') {\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <div className={styles.embeddedContainer}>\n <div className={styles.embeddedHeader}>{headerTitle}</div>\n {filtersBarNode}\n {statusBanner}\n {tableNode}\n {tableFooterNode}\n </div>\n </BackofficeListFilterProvider>\n );\n }\n\n return (\n <BackofficeListFilterProvider\n config={config}\n state={state}\n pushState={pushState}\n >\n <ListPageTemplate\n headerNode={\n <BackofficePageHeader\n title={headerTitle}\n subtitle={headerSubtitle}\n actions={headerActions}\n />\n }\n toolbarNode={filtersBarNode}\n statusNode={statusBanner}\n tableNode={tableNode}\n tableFooterNode={tableFooterNode}\n presentation=\"flat\"\n bodyScrollMode={BACKOFFICE_LIST_BODY_SCROLL_MODE}\n />\n </BackofficeListFilterProvider>\n );\n};\n\nexport default BackofficeEntityListScaffold;\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /* empty css */
2
2
  //#region src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts
3
- var e = "txvbqbfpn txvbqbh7g txvbqbey txvbqbhdl", t = "txvbqb19q3 txvbqb19ul txvbqbu4k", n = "txvbqbfpn txvbqbh4x txvbqbhdy", r = "txvbqbfpn txvbqbh4x txvbqbjzu txvbqbu86", i = "txvbqb9w txvbqbhbf txvbqb1bg1";
3
+ var e = "txvbqbfpn txvbqbh7g txvbqbey txvbqbhdl", t = "txvbqb19q3 txvbqb19ul txvbqbu4k", n = "txvbqbfpn txvbqbh4x txvbqbhdy", r = "txvbqbfpn txvbqbh4x txvbqbjzu txvbqbu86", i = "txvbqb10mk txvbqb11k5 txvbqb12hd txvbqbxtg txvbqbfpn txvbqbey txvbqbhdl txvbqbge txvbqbp66 txvbqb29r txvbqb2sj txvbqb1d9 txvbqb2tz txvbqb1b7z txvbqb1bg3 txvbqb9j txvbqbo4z", a = "txvbqb9w txvbqbhbf txvbqb1bg1";
4
4
  //#endregion
5
- export { e as controlsRow, n as embeddedContainer, i as embeddedHeader, t as filterInput, r as tableHost };
5
+ export { e as controlsRow, n as embeddedContainer, a as embeddedHeader, t as filterInput, i as refreshingIndicator, r as tableHost };
6
6
 
7
7
  //# sourceMappingURL=backofficeEntityListScaffold.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backofficeEntityListScaffold.css.js","names":[],"sources":["../../../../../src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts"],"sourcesContent":["import { sprinkles } from '@plumile/ui/theme/sprinkles.css.js';\n\nexport const controlsRow = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 2,\n});\n\nexport const filterInput = sprinkles({\n width: {\n base: 72,\n max767: 'full',\n },\n maxWidth: 'full',\n});\n\nexport const embeddedContainer = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n});\n\nexport const tableHost = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n height: 'full',\n minHeight: 0,\n});\n\nexport const embeddedHeader = sprinkles({\n fontSize: 'base',\n fontWeight: 'semibold',\n color: 'text',\n});\n"],"mappings":""}
1
+ {"version":3,"file":"backofficeEntityListScaffold.css.js","names":[],"sources":["../../../../../src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts"],"sourcesContent":["import { sprinkles } from '@plumile/ui/theme/sprinkles.css.js';\n\nexport const controlsRow = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 2,\n});\n\nexport const filterInput = sprinkles({\n width: {\n base: 72,\n max767: 'full',\n },\n maxWidth: 'full',\n});\n\nexport const embeddedContainer = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n});\n\nexport const tableHost = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n height: 'full',\n minHeight: 0,\n});\n\nexport const refreshingIndicator = sprinkles({\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n alignSelf: 'flex-start',\n paddingX: 2,\n paddingY: 1,\n marginBottom: 2,\n borderWidth: 'px',\n borderStyle: 'solid',\n borderColor: 'borderSubtle',\n borderRadius: 'md',\n backgroundColor: 'surface',\n color: 'textSecondary',\n fontSize: 'sm',\n lineHeight: 'tight',\n});\n\nexport const embeddedHeader = sprinkles({\n fontSize: 'base',\n fontWeight: 'semibold',\n color: 'text',\n});\n"],"mappings":""}
@@ -1,36 +1,38 @@
1
1
  import { startTransition as e, useCallback as t, useEffect as n, useRef as r, useState as i } from "react";
2
2
  import { stableListVariablesKey as a } from "@plumile/backoffice-core/state/stableKey.js";
3
3
  //#region src/hooks/useBackofficeListRefetch.ts
4
- function o({ refetch: o, variables: s, defaults: c, fetchPolicy: l, buildQueryVariables: u }) {
5
- let [d, f] = i(!1), p = r(0), m = r(a({
6
- where: c.where,
7
- sort: c.sort,
8
- count: c.count
9
- })), h = t((e) => u(e), [u]), g = t((t) => {
10
- let n = p.current + 1;
11
- p.current = n, f(!0);
4
+ function o({ refetch: o, variables: s, fetchPolicy: c, buildQueryVariables: l }) {
5
+ let [u, d] = i(!1), f = r(0), p = r(null), m = r(a({
6
+ where: s.where,
7
+ sort: s.sort,
8
+ count: s.count
9
+ })), h = t((e) => l(e), [l]), g = t((t) => {
10
+ let n = f.current + 1;
11
+ f.current = n, d(!0);
12
12
  let r = h({
13
13
  ...t,
14
14
  cursor: null
15
15
  });
16
16
  try {
17
17
  e(() => {
18
- o(r, {
19
- fetchPolicy: l,
18
+ p.current?.dispose(), p.current = o(r, {
19
+ fetchPolicy: c,
20
20
  onComplete: () => {
21
- p.current === n && f(!1);
21
+ f.current === n && (p.current = null, d(!1));
22
22
  }
23
- });
23
+ }) ?? null;
24
24
  });
25
25
  } catch (e) {
26
- throw p.current === n && f(!1), e;
26
+ throw f.current === n && (p.current = null, d(!1)), e;
27
27
  }
28
28
  }, [
29
- l,
29
+ c,
30
30
  o,
31
31
  h
32
32
  ]);
33
- return n(() => {
33
+ return n(() => () => {
34
+ p.current?.dispose(), p.current = null;
35
+ }, []), n(() => {
34
36
  let e = a({
35
37
  where: s.where,
36
38
  sort: s.sort,
@@ -38,7 +40,7 @@ function o({ refetch: o, variables: s, defaults: c, fetchPolicy: l, buildQueryVa
38
40
  });
39
41
  m.current !== e && (m.current = e, g(s));
40
42
  }, [g, s]), {
41
- isRefreshing: d,
43
+ isRefreshing: u,
42
44
  onRefresh: t(() => {
43
45
  g(s);
44
46
  }, [g, s])
@@ -1 +1 @@
1
- {"version":3,"file":"useBackofficeListRefetch.js","names":[],"sources":["../../../src/hooks/useBackofficeListRefetch.ts"],"sourcesContent":["import {\n startTransition,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport type { FetchPolicy } from 'relay-runtime';\n\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficeListVariables } from '@plumile/backoffice-core/types.js';\n\ntype RefetchFn<TVariables> = (\n vars: TVariables,\n opts: {\n fetchPolicy: FetchPolicy;\n onComplete?: (error: Error | null) => void;\n },\n) => { dispose: () => void } | undefined;\n\ntype Params<Where, Sort extends string, Variables> = {\n refetch: RefetchFn<Variables>;\n variables: BackofficeListVariables<Where, Sort>;\n defaults: BackofficeListVariables<Where, Sort>;\n fetchPolicy: FetchPolicy;\n buildQueryVariables: (\n input: BackofficeListVariables<Where, Sort>,\n ) => Variables;\n};\n\n/**\n * Standardizes refetch behavior for backoffice list components:\n * - Refetches when list URL state changes (where/sort/count), gated by a stable key.\n * - Exposes a manual refresh callback using the same variables.\n *\n * This hook must not call Relay hooks (`useFragment`, `usePaginationFragment`, ...).\n */\nexport function useBackofficeListRefetch<\n Where,\n Sort extends string,\n Variables extends Record<string, unknown>,\n>({\n refetch,\n variables,\n defaults,\n fetchPolicy,\n buildQueryVariables,\n}: Params<Where, Sort, Variables>): {\n isRefreshing: boolean;\n onRefresh: () => void;\n} {\n const [isRefreshing, setIsRefreshing] = useState(false);\n const requestIdRef = useRef(0);\n const lastRefetchKeyRef = useRef<string | null>(\n stableListVariablesKey({\n where: defaults.where,\n sort: defaults.sort,\n count: defaults.count,\n }),\n );\n\n const resolveVariables = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n return buildQueryVariables(input);\n },\n [buildQueryVariables],\n );\n\n const runRefetch = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n const requestId = requestIdRef.current + 1;\n requestIdRef.current = requestId;\n setIsRefreshing(true);\n\n const nextVariables = resolveVariables({ ...input, cursor: null });\n try {\n startTransition(() => {\n refetch(nextVariables, {\n fetchPolicy,\n onComplete: () => {\n if (requestIdRef.current === requestId) {\n setIsRefreshing(false);\n }\n },\n });\n });\n } catch (error) {\n if (requestIdRef.current === requestId) {\n setIsRefreshing(false);\n }\n throw error;\n }\n },\n [fetchPolicy, refetch, resolveVariables],\n );\n\n useEffect(() => {\n const key = stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n });\n if (lastRefetchKeyRef.current === key) {\n return;\n }\n lastRefetchKeyRef.current = key;\n\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n const onRefresh = useCallback(() => {\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n return { isRefreshing, onRefresh };\n}\n"],"mappings":";;;AAqCA,SAAgB,EAId,EACA,YACA,cACA,aACA,gBACA,0BAIA;CACA,IAAM,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,IAAe,EAAO,CAAC,GACvB,IAAoB,EACxB,EAAuB;EACrB,OAAO,EAAS;EAChB,MAAM,EAAS;EACf,OAAO,EAAS;CAClB,CAAC,CACH,GAEM,IAAmB,GACtB,MACQ,EAAoB,CAAK,GAElC,CAAC,CAAmB,CACtB,GAEM,IAAa,GAChB,MAAgD;EAC/C,IAAM,IAAY,EAAa,UAAU;EAEzC,AADA,EAAa,UAAU,GACvB,EAAgB,EAAI;EAEpB,IAAM,IAAgB,EAAiB;GAAE,GAAG;GAAO,QAAQ;EAAK,CAAC;EACjE,IAAI;GACF,QAAsB;IACpB,EAAQ,GAAe;KACrB;KACA,kBAAkB;MAChB,AAAI,EAAa,YAAY,KAC3B,EAAgB,EAAK;KAEzB;IACF,CAAC;GACH,CAAC;EACH,SAAS,GAAO;GAId,MAHI,EAAa,YAAY,KAC3B,EAAgB,EAAK,GAEjB;EACR;CACF,GACA;EAAC;EAAa;EAAS;CAAgB,CACzC;CAoBA,OAlBA,QAAgB;EACd,IAAM,IAAM,EAAuB;GACjC,OAAO,EAAU;GACjB,MAAM,EAAU;GAChB,OAAO,EAAU;EACnB,CAAC;EACG,EAAkB,YAAY,MAGlC,EAAkB,UAAU,GAE5B,EAAW,CAAS;CACtB,GAAG,CAAC,GAAY,CAAS,CAAC,GAMnB;EAAE;EAAc,WAJL,QAAkB;GAClC,EAAW,CAAS;EACtB,GAAG,CAAC,GAAY,CAAS,CAEF;CAAU;AACnC"}
1
+ {"version":3,"file":"useBackofficeListRefetch.js","names":[],"sources":["../../../src/hooks/useBackofficeListRefetch.ts"],"sourcesContent":["import {\n startTransition,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport type { FetchPolicy } from 'relay-runtime';\n\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficeListVariables } from '@plumile/backoffice-core/types.js';\n\ntype RefetchDisposable = {\n dispose: () => void;\n};\n\ntype RefetchFn<TVariables> = (\n vars: TVariables,\n opts: {\n fetchPolicy: FetchPolicy;\n onComplete?: (error: Error | null) => void;\n },\n) => RefetchDisposable | undefined;\n\ntype Params<Where, Sort extends string, Variables> = {\n refetch: RefetchFn<Variables>;\n variables: BackofficeListVariables<Where, Sort>;\n defaults: BackofficeListVariables<Where, Sort>;\n fetchPolicy: FetchPolicy;\n buildQueryVariables: (\n input: BackofficeListVariables<Where, Sort>,\n ) => Variables;\n};\n\n/**\n * Standardizes refetch behavior for backoffice list components:\n * - Refetches when list URL state changes (where/sort/count), gated by a stable key.\n * - Exposes a manual refresh callback using the same variables.\n *\n * This hook must not call Relay hooks (`useFragment`, `usePaginationFragment`, ...).\n */\nexport function useBackofficeListRefetch<\n Where,\n Sort extends string,\n Variables extends Record<string, unknown>,\n>({\n refetch,\n variables,\n fetchPolicy,\n buildQueryVariables,\n}: Params<Where, Sort, Variables>): {\n isRefreshing: boolean;\n onRefresh: () => void;\n} {\n const [isRefreshing, setIsRefreshing] = useState(false);\n const requestIdRef = useRef(0);\n const disposableRef = useRef<RefetchDisposable | null>(null);\n const lastRefetchKeyRef = useRef<string | null>(\n stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n }),\n );\n\n const resolveVariables = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n return buildQueryVariables(input);\n },\n [buildQueryVariables],\n );\n\n const runRefetch = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n const requestId = requestIdRef.current + 1;\n requestIdRef.current = requestId;\n setIsRefreshing(true);\n\n const nextVariables = resolveVariables({ ...input, cursor: null });\n try {\n startTransition(() => {\n disposableRef.current?.dispose();\n disposableRef.current =\n refetch(nextVariables, {\n fetchPolicy,\n onComplete: () => {\n if (requestIdRef.current === requestId) {\n disposableRef.current = null;\n setIsRefreshing(false);\n }\n },\n }) ?? null;\n });\n } catch (error) {\n if (requestIdRef.current === requestId) {\n disposableRef.current = null;\n setIsRefreshing(false);\n }\n throw error;\n }\n },\n [fetchPolicy, refetch, resolveVariables],\n );\n\n useEffect(() => {\n return () => {\n disposableRef.current?.dispose();\n disposableRef.current = null;\n };\n }, []);\n\n useEffect(() => {\n const key = stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n });\n if (lastRefetchKeyRef.current === key) {\n return;\n }\n lastRefetchKeyRef.current = key;\n\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n const onRefresh = useCallback(() => {\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n return { isRefreshing, onRefresh };\n}\n"],"mappings":";;;AAyCA,SAAgB,EAId,EACA,YACA,cACA,gBACA,0BAIA;CACA,IAAM,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,IAAe,EAAO,CAAC,GACvB,IAAgB,EAAiC,IAAI,GACrD,IAAoB,EACxB,EAAuB;EACrB,OAAO,EAAU;EACjB,MAAM,EAAU;EAChB,OAAO,EAAU;CACnB,CAAC,CACH,GAEM,IAAmB,GACtB,MACQ,EAAoB,CAAK,GAElC,CAAC,CAAmB,CACtB,GAEM,IAAa,GAChB,MAAgD;EAC/C,IAAM,IAAY,EAAa,UAAU;EAEzC,AADA,EAAa,UAAU,GACvB,EAAgB,EAAI;EAEpB,IAAM,IAAgB,EAAiB;GAAE,GAAG;GAAO,QAAQ;EAAK,CAAC;EACjE,IAAI;GACF,QAAsB;IAEpB,AADA,EAAc,SAAS,QAAQ,GAC/B,EAAc,UACZ,EAAQ,GAAe;KACrB;KACA,kBAAkB;MAChB,AAAI,EAAa,YAAY,MAC3B,EAAc,UAAU,MACxB,EAAgB,EAAK;KAEzB;IACF,CAAC,KAAK;GACV,CAAC;EACH,SAAS,GAAO;GAKd,MAJI,EAAa,YAAY,MAC3B,EAAc,UAAU,MACxB,EAAgB,EAAK,IAEjB;EACR;CACF,GACA;EAAC;EAAa;EAAS;CAAgB,CACzC;CA2BA,OAzBA,cACe;EAEX,AADA,EAAc,SAAS,QAAQ,GAC/B,EAAc,UAAU;CAC1B,GACC,CAAC,CAAC,GAEL,QAAgB;EACd,IAAM,IAAM,EAAuB;GACjC,OAAO,EAAU;GACjB,MAAM,EAAU;GAChB,OAAO,EAAU;EACnB,CAAC;EACG,EAAkB,YAAY,MAGlC,EAAkB,UAAU,GAE5B,EAAW,CAAS;CACtB,GAAG,CAAC,GAAY,CAAS,CAAC,GAMnB;EAAE;EAAc,WAJL,QAAkB;GAClC,EAAW,CAAS;EACtB,GAAG,CAAC,GAAY,CAAS,CAEF;CAAU;AACnC"}
@@ -1,38 +1,40 @@
1
- import { useCallback as e, useContext as t, useMemo as n } from "react";
2
- import r from "@plumile/router/routing/RoutingContext.js";
3
- import i from "@plumile/router/routing/useLocation.js";
1
+ import { startTransition as e, useCallback as t, useContext as n, useMemo as r } from "react";
2
+ import i from "@plumile/router/routing/RoutingContext.js";
3
+ import a from "@plumile/router/routing/useLocation.js";
4
4
  //#region src/hooks/useBackofficeListUrlState.ts
5
- function a(e) {
5
+ function o(e) {
6
6
  return e.trim() === "" ? new URLSearchParams() : new URLSearchParams(e);
7
7
  }
8
- function o(o) {
9
- let s = t(r), { hash: c, pathname: l, search: u } = i(), d = n(() => ({
8
+ function s(s) {
9
+ let c = n(i), { hash: l, pathname: u, search: d } = a(), f = r(() => ({
10
10
  where: null,
11
11
  sort: null
12
12
  }), []);
13
13
  return {
14
- state: n(() => o.listUrlCodec == null ? d : o.listUrlCodec.parse(a(u)), [
15
- o.listUrlCodec,
16
- d,
17
- u
14
+ state: r(() => s.listUrlCodec == null ? f : s.listUrlCodec.parse(o(d)), [
15
+ s.listUrlCodec,
16
+ f,
17
+ d
18
18
  ]),
19
- pushState: e((e) => {
20
- if (s == null || o.listUrlCodec == null) return;
21
- let t = o.listUrlCodec.serialize(e).toString(), n = "";
22
- t !== "" && (n = `?${t}`), s.history.push({
23
- pathname: l,
24
- search: n,
25
- hash: c
19
+ pushState: t((t) => {
20
+ if (c == null || s.listUrlCodec == null) return;
21
+ let n = s.listUrlCodec.serialize(t).toString(), r = "";
22
+ n !== "" && (r = `?${n}`), e(() => {
23
+ c.history.push({
24
+ pathname: u,
25
+ search: r,
26
+ hash: l
27
+ });
26
28
  });
27
29
  }, [
28
- o.listUrlCodec,
29
- c,
30
+ s.listUrlCodec,
30
31
  l,
31
- s
32
+ u,
33
+ c
32
34
  ])
33
35
  };
34
36
  }
35
37
  //#endregion
36
- export { o as useBackofficeListUrlState };
38
+ export { s as useBackofficeListUrlState };
37
39
 
38
40
  //# sourceMappingURL=useBackofficeListUrlState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useBackofficeListUrlState.js","names":[],"sources":["../../../src/hooks/useBackofficeListUrlState.ts"],"sourcesContent":["import { useCallback, useContext, useMemo } from 'react';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport type {\n BackofficeListState,\n BackofficeRuntimeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\n\n/** Normalizes a router `location.search` string into URLSearchParams. */\nfunction normalizeSearch(value: string): URLSearchParams {\n if (value.trim() === '') {\n return new URLSearchParams();\n }\n return new URLSearchParams(value);\n}\n\ntype ReturnValue<Where extends Record<string, unknown>, Sort extends string> = {\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n};\n\n/** Keeps list state in sync with the URL search params for backoffice pages. */\nexport function useBackofficeListUrlState<\n Where extends Record<string, unknown>,\n Sort extends string,\n>(config: BackofficeRuntimeResolvedListFacetConfig): ReturnValue<Where, Sort> {\n const routing = useContext(RoutingContext);\n const { hash, pathname, search } = useLocation();\n const fallbackState = useMemo(() => {\n return {\n where: null,\n sort: null,\n };\n }, []);\n\n const state = useMemo(() => {\n if (config.listUrlCodec == null) {\n return fallbackState;\n }\n return config.listUrlCodec.parse(\n normalizeSearch(search),\n ) as BackofficeListState<Where, Sort>;\n }, [config.listUrlCodec, fallbackState, search]);\n\n const pushState = useCallback(\n (next: BackofficeListState<Where, Sort>) => {\n if (routing == null) {\n return;\n }\n if (config.listUrlCodec == null) {\n return;\n }\n\n const codec = config.listUrlCodec as unknown as {\n serialize: (state: BackofficeListState<Where, Sort>) => URLSearchParams;\n };\n const params = codec.serialize(next);\n const qs = params.toString();\n\n let nextSearch = '';\n if (qs !== '') {\n nextSearch = `?${qs}`;\n }\n\n routing.history.push({\n pathname,\n search: nextSearch,\n hash,\n });\n },\n [config.listUrlCodec, hash, pathname, routing],\n );\n\n return { state, pushState };\n}\n"],"mappings":";;;;AAUA,SAAS,EAAgB,GAAgC;CAIvD,OAHI,EAAM,KAAK,MAAM,KACZ,IAAI,gBAAgB,IAEtB,IAAI,gBAAgB,CAAK;AAClC;AAQA,SAAgB,EAGd,GAA4E;CAC5E,IAAM,IAAU,EAAW,CAAc,GACnC,EAAE,SAAM,aAAU,cAAW,EAAY,GACzC,IAAgB,SACb;EACL,OAAO;EACP,MAAM;CACR,IACC,CAAC,CAAC;CAwCL,OAAO;EAAE,OAtCK,QACR,EAAO,gBAAgB,OAClB,IAEF,EAAO,aAAa,MACzB,EAAgB,CAAM,CACxB,GACC;GAAC,EAAO;GAAc;GAAe;EAAM,CA+BrC;EAAO,WA7BE,GACf,MAA2C;GAI1C,IAHI,KAAW,QAGX,EAAO,gBAAgB,MACzB;GAOF,IAAM,IAJQ,EAAO,aAGA,UAAU,CACpB,EAAO,SAAS,GAEvB,IAAa;GAKjB,AAJI,MAAO,OACT,IAAa,IAAI,MAGnB,EAAQ,QAAQ,KAAK;IACnB;IACA,QAAQ;IACR;GACF,CAAC;EACH,GACA;GAAC,EAAO;GAAc;GAAM;GAAU;EAAO,CAG/B;CAAU;AAC5B"}
1
+ {"version":3,"file":"useBackofficeListUrlState.js","names":[],"sources":["../../../src/hooks/useBackofficeListUrlState.ts"],"sourcesContent":["import { startTransition, useCallback, useContext, useMemo } from 'react';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport type {\n BackofficeListState,\n BackofficeRuntimeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\n\n/** Normalizes a router `location.search` string into URLSearchParams. */\nfunction normalizeSearch(value: string): URLSearchParams {\n if (value.trim() === '') {\n return new URLSearchParams();\n }\n return new URLSearchParams(value);\n}\n\ntype ReturnValue<Where extends Record<string, unknown>, Sort extends string> = {\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n};\n\n/** Keeps list state in sync with the URL search params for backoffice pages. */\nexport function useBackofficeListUrlState<\n Where extends Record<string, unknown>,\n Sort extends string,\n>(config: BackofficeRuntimeResolvedListFacetConfig): ReturnValue<Where, Sort> {\n const routing = useContext(RoutingContext);\n const { hash, pathname, search } = useLocation();\n const fallbackState = useMemo(() => {\n return {\n where: null,\n sort: null,\n };\n }, []);\n\n const state = useMemo(() => {\n if (config.listUrlCodec == null) {\n return fallbackState;\n }\n return config.listUrlCodec.parse(\n normalizeSearch(search),\n ) as BackofficeListState<Where, Sort>;\n }, [config.listUrlCodec, fallbackState, search]);\n\n const pushState = useCallback(\n (next: BackofficeListState<Where, Sort>) => {\n if (routing == null) {\n return;\n }\n if (config.listUrlCodec == null) {\n return;\n }\n\n const codec = config.listUrlCodec as unknown as {\n serialize: (state: BackofficeListState<Where, Sort>) => URLSearchParams;\n };\n const params = codec.serialize(next);\n const qs = params.toString();\n\n let nextSearch = '';\n if (qs !== '') {\n nextSearch = `?${qs}`;\n }\n\n startTransition(() => {\n routing.history.push({\n pathname,\n search: nextSearch,\n hash,\n });\n });\n },\n [config.listUrlCodec, hash, pathname, routing],\n );\n\n return { state, pushState };\n}\n"],"mappings":";;;;AAUA,SAAS,EAAgB,GAAgC;CAIvD,OAHI,EAAM,KAAK,MAAM,KACZ,IAAI,gBAAgB,IAEtB,IAAI,gBAAgB,CAAK;AAClC;AAQA,SAAgB,EAGd,GAA4E;CAC5E,IAAM,IAAU,EAAW,CAAc,GACnC,EAAE,SAAM,aAAU,cAAW,EAAY,GACzC,IAAgB,SACb;EACL,OAAO;EACP,MAAM;CACR,IACC,CAAC,CAAC;CA0CL,OAAO;EAAE,OAxCK,QACR,EAAO,gBAAgB,OAClB,IAEF,EAAO,aAAa,MACzB,EAAgB,CAAM,CACxB,GACC;GAAC,EAAO;GAAc;GAAe;EAAM,CAiCrC;EAAO,WA/BE,GACf,MAA2C;GAI1C,IAHI,KAAW,QAGX,EAAO,gBAAgB,MACzB;GAOF,IAAM,IAJQ,EAAO,aAGA,UAAU,CACpB,EAAO,SAAS,GAEvB,IAAa;GAKjB,AAJI,MAAO,OACT,IAAa,IAAI,MAGnB,QAAsB;IACpB,EAAQ,QAAQ,KAAK;KACnB;KACA,QAAQ;KACR;IACF,CAAC;GACH,CAAC;EACH,GACA;GAAC,EAAO;GAAc;GAAM;GAAU;EAAO,CAG/B;CAAU;AAC5B"}
@@ -369,6 +369,7 @@ var e = {
369
369
  end: "End of results",
370
370
  loading: "Loading more…"
371
371
  },
372
+ refreshingRows: "Filtering…",
372
373
  showing: "Showing {{shown, number}} of {{total, number}}",
373
374
  sort: { label: "Sort order" },
374
375
  title: ""
@@ -1 +1 @@
1
- {"version":3,"file":"backofficeReact.js","names":[],"sources":["../../../../../src/i18n/locales/en/backofficeReact.json"],"sourcesContent":["{\n \"actions\": {\n \"form\": {\n \"cancel\": \"Cancel\",\n \"errors\": {\n \"invalidJson\": \"{{label}} must be valid JSON.\",\n \"invalidJsonArray\": \"{{label}} must be a valid JSON array.\",\n \"invalidJsonObject\": \"{{label}} must be a valid JSON object.\",\n \"invalidNumber\": \"{{label}} must be a valid number.\",\n \"invalidPayload\": \"The submitted payload is invalid.\",\n \"required\": \"{{label}} is required.\",\n \"submitFailed\": \"Unable to complete this action. Please try again.\"\n },\n \"submitting\": \"Submitting...\"\n },\n \"view\": \"View\"\n },\n \"auth\": {\n \"acceptInvitation\": {\n \"actions\": {\n \"backToLogin\": \"Back to login\"\n },\n \"errors\": {\n \"alreadyAccepted\": \"This invitation has already been accepted.\",\n \"default\": \"Unable to accept invitation.\",\n \"emailMismatch\": \"This invitation was sent to a different email address.\",\n \"expired\": \"Invitation link has expired.\",\n \"invalidToken\": \"Invitation link is invalid.\",\n \"missingToken\": \"Invitation link is missing or invalid.\",\n \"passwordMismatch\": \"Password and confirmation do not match.\",\n \"passwordPolicyViolation\": \"Your password does not meet policy requirements.\",\n \"rateLimited\": \"Too many attempts. Please try again later.\",\n \"unavailable\": \"Invitation acceptance is not available.\"\n },\n \"form\": {\n \"confirmLabel\": \"Confirm password\",\n \"confirmPlaceholder\": \"Confirm your password\",\n \"passwordLabel\": \"Password\",\n \"passwordPlaceholder\": \"Create a password\",\n \"submit\": \"Accept invitation\"\n },\n \"mfaSubtitle\": \"Enter the verification code to continue.\",\n \"mfaTitle\": \"Verify your identity\",\n \"status\": {\n \"success\": \"Invitation accepted.\",\n \"workingButton\": \"Working...\"\n },\n \"subtitle\": \"Create your account to join.\",\n \"title\": \"Accept invitation\"\n },\n \"emailCapture\": {\n \"continue\": \"Continue\",\n \"description\": \"Enter your work email to continue.\",\n \"emailLabel\": \"Work email\",\n \"emailPlaceholder\": \"you@company.com\",\n \"forgotPassword\": \"Forgot your password?\"\n },\n \"loginFlow\": {\n \"errors\": {\n \"accountLocked\": \"Too many attempts. Try again later.\",\n \"emailRequired\": \"Enter an email address to continue.\",\n \"invalidCredentials\": \"Email or password is incorrect.\",\n \"invalidEmail\": \"Enter a valid email address.\",\n \"passkeyUnavailable\": \"Passkeys are not available.\",\n \"rateLimited\": \"Too many attempts. Please try again later.\",\n \"tryAgain\": \"Something went wrong. Please try again.\"\n },\n \"methods\": {\n \"title\": \"Choose a sign-in method\"\n },\n \"passkey\": {\n \"description\": \"Use the passkey associated with {{email}}.\",\n \"title\": \"Use a passkey\"\n },\n \"subtitle\": {\n \"default\": \"Choose a sign-in method to continue.\",\n \"mfa\": \"Enter the verification code to continue.\"\n },\n \"title\": {\n \"default\": \"Sign in\",\n \"mfa\": \"Two-factor authentication\"\n }\n },\n \"logout\": {\n \"errors\": {\n \"default\": \"Logout failed.\"\n }\n },\n \"methodChooser\": {\n \"actions\": {\n \"back\": \"Back\"\n },\n \"locked\": \"Too many attempts. Try again later.\",\n \"lockedWithTime\": \"Too many attempts. Try again at {{time}}.\",\n \"methods\": {\n \"other\": \"{{method}}\",\n \"passkey\": \"Passkey\",\n \"password\": \"Password\"\n },\n \"prompt\": \"Choose how to sign in for <strong>{{email}}</strong>.\"\n },\n \"mfa\": {\n \"actions\": {\n \"back\": \"Back\",\n \"submit\": \"Verify\"\n },\n \"errors\": {\n \"expired\": \"Verification session expired. Please try again.\",\n \"invalidChallenge\": \"Verification session is invalid. Restart the login.\",\n \"invalidCode\": \"Invalid code. Try again.\",\n \"shortCode\": \"Enter the 6-digit code.\",\n \"tooManyAttempts\": \"Too many attempts. Try again later.\",\n \"verificationFailed\": \"Verification failed. Try again.\"\n },\n \"form\": {\n \"label\": \"Verification code\",\n \"placeholder\": \"123456\"\n },\n \"helper\": {\n \"default\": \"Enter the 6-digit code from your authenticator.\",\n \"withEmail\": \"Enter the 6-digit code sent to {{email}}.\"\n }\n },\n \"oidc\": {\n \"buttons\": {\n \"apple\": \"Continue with Apple\",\n \"generic\": \"Continue with single sign-on\",\n \"google\": \"Continue with Google\"\n }\n },\n \"passkey\": {\n \"actions\": {\n \"showMethods\": \"Use another method\",\n \"submit\": \"Continue with passkey\",\n \"submitting\": \"Waiting for passkey...\"\n },\n \"errors\": {\n \"cancelled\": \"Passkey sign-in was cancelled.\",\n \"challengeExpired\": \"Passkey request expired. Try again.\",\n \"emailRequired\": \"Enter your email to continue.\",\n \"failed\": \"Passkey sign-in failed.\",\n \"invalidAssertion\": \"Passkey response is invalid. Try again.\",\n \"invalidChallenge\": \"Passkey request is invalid. Try again.\",\n \"invalidEmail\": \"Enter a valid email address.\",\n \"locked\": \"Too many attempts. Try again later.\",\n \"lockedWithTime\": \"Too many attempts. Try again at {{time}}.\",\n \"noCredential\": \"No credential was returned by the authenticator.\",\n \"notAvailable\": \"Passkeys are not available on this device.\",\n \"notFound\": \"No passkey found for this account.\"\n },\n \"form\": {\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"you@company.com\"\n },\n \"helper\": \"Use a passkey instead of your password.\"\n },\n \"passwordLogin\": {\n \"forgotPassword\": \"Forgot your password?\",\n \"title\": \"Sign in\"\n },\n \"passwordResetComplete\": {\n \"errors\": {\n \"expired\": \"This reset link has expired.\",\n \"invalid\": \"Reset link is invalid or expired.\",\n \"minLength\": \"Password must be at least {{minLength}} characters.\",\n \"mismatch\": \"Passwords do not match.\",\n \"missingToken\": \"Reset link is missing or invalid.\",\n \"policyViolation\": \"Your new password does not meet policy requirements.\"\n },\n \"form\": {\n \"confirmLabel\": \"Confirm password\",\n \"confirmPlaceholder\": \"Re-enter your password\",\n \"description\": \"Enter a new password for your account.\",\n \"passwordLabel\": \"Password\",\n \"passwordPlaceholder\": \"Enter a new password\",\n \"submit\": \"Update password\",\n \"title\": \"New password\"\n },\n \"subtitle\": \"Choose a strong password to secure your account.\",\n \"success\": {\n \"action\": \"Back to login\",\n \"description\": \"Your password has been changed.\",\n \"helper\": \"You can now sign in with your new password.\",\n \"title\": \"Password updated\"\n },\n \"title\": \"Set a new password\"\n },\n \"passwordResetRequest\": {\n \"errors\": {\n \"emailRequired\": \"Enter an email address.\",\n \"invalidEmail\": \"Please enter a valid email address.\",\n \"rateLimited\": \"Too many requests. Please wait and try again.\",\n \"startFailed\": \"Unable to start password reset.\"\n },\n \"form\": {\n \"description\": \"Enter the email for your account.\",\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"you@company.com\",\n \"submit\": \"Send reset link\"\n },\n \"sent\": {\n \"action\": \"Send another email\",\n \"description\": \"We sent a reset link to {{email}}.\",\n \"helper\": \"If you don't see it, check spam or try again.\",\n \"title\": \"Check your email\"\n },\n \"title\": \"Reset your password\"\n },\n \"verifyEmail\": {\n \"actions\": {\n \"continue\": \"Continue\",\n \"return\": \"Back to login\"\n },\n \"errors\": {\n \"alreadyVerified\": \"This email address is already verified.\",\n \"expired\": \"This verification link has expired.\",\n \"invalid\": \"Verification link is invalid or expired.\",\n \"missingToken\": \"Verification link is missing or invalid.\"\n },\n \"status\": {\n \"success\": \"Email verified. You can continue.\",\n \"verifying\": \"Verifying...\",\n \"verifyingButton\": \"Verifying\"\n },\n \"subtitle\": \"Confirm your email address to continue.\",\n \"title\": \"Verify your email\"\n }\n },\n \"common\": {\n \"actions\": {\n \"close\": \"Close\",\n \"copied\": \"Copied\",\n \"copy\": \"Copy\",\n \"pick\": \"Pick\",\n \"retry\": \"Retry\"\n },\n \"boolean\": {\n \"no\": \"No\",\n \"yes\": \"Yes\"\n },\n \"breadcrumb\": \"Breadcrumb\",\n \"errors\": {\n \"unexpected\": \"An unexpected error occurred.\"\n },\n \"loading\": \"Loading...\",\n \"notAvailable\": \"N/A\",\n \"time\": {\n \"lastDay\": \"24 h\",\n \"lastHour\": \"1 h\",\n \"lastSevenDays\": \"7 j\",\n \"lastThirtyDays\": \"30 j\"\n }\n },\n \"dashboard\": {\n \"actions\": {\n \"openList\": \"Open list\",\n \"openTool\": \"Open tool\"\n },\n \"subtitle\": \"Overview of the Work context.\",\n \"title\": \"Dashboard\"\n },\n \"detail\": {\n \"actionResult\": {\n \"message\": \"Message\",\n \"status\": \"Status\"\n },\n \"actions\": {\n \"backToList\": \"Back to list\",\n \"viewDetails\": \"View details\"\n },\n \"columns\": {\n \"charged\": \"Charged\",\n \"events\": \"Events\",\n \"markup\": \"Markup\",\n \"name\": \"Name\",\n \"rawCost\": \"Raw cost\"\n },\n \"notFound\": \"Not found\",\n \"notFoundDescription\": \"This item does not exist or is no longer available.\"\n },\n \"emptyState\": {\n \"listEmpty\": {\n \"description\": \"There are no records to display.\",\n \"title\": \"No results\"\n },\n \"listEmptyFiltered\": {\n \"actions\": {\n \"reset\": \"Reset filters\"\n },\n \"description\": \"No results match the current filters.\"\n }\n },\n \"filters\": {\n \"actions\": {\n \"applyFilter\": \"Apply {{label}} filter\",\n \"changeFilterValue\": \"Change {{label}}\",\n \"clearFilter\": \"Clear {{label}} filter\",\n \"filterBy\": \"Filter by {{label}}\"\n },\n \"all\": \"All {{label}}\",\n \"boolean\": {\n \"no\": \"No\",\n \"yes\": \"Yes\"\n },\n \"drawer\": {\n \"emptySearchResults\": \"No filters match this search.\"\n },\n \"placeholders\": {\n \"anyEntity\": \"All\",\n \"search\": \"Search {{label}}\",\n \"unresolved\": \"Unresolved ID\"\n },\n \"sections\": {\n \"default\": \"Filters\"\n },\n \"trigger\": \"Filters\",\n \"triggerWithCount_one\": \"Filters ({{count}})\",\n \"triggerWithCount_other\": \"Filters ({{count}})\"\n },\n \"flags\": {\n \"agentManaged\": {\n \"agentManaged\": \"Agent managed\",\n \"userManaged\": \"User managed\"\n },\n \"capability\": {\n \"allowed\": \"Allowed\",\n \"denied\": \"Denied\"\n },\n \"default\": {\n \"default\": \"Default\",\n \"notDefault\": \"Not default\"\n },\n \"deployedProduction\": {\n \"deployed\": \"Deployed\",\n \"notDeployed\": \"Not deployed\"\n },\n \"enabled\": {\n \"disabled\": \"Disabled\",\n \"enabled\": \"Enabled\"\n },\n \"encrypted\": {\n \"encrypted\": \"Encrypted\",\n \"notEncrypted\": \"Not encrypted\"\n },\n \"failure\": {\n \"failed\": \"Failed\",\n \"ok\": \"OK\"\n },\n \"forced\": {\n \"forced\": \"Forced\",\n \"normal\": \"Normal\"\n },\n \"locked\": {\n \"locked\": \"Locked\",\n \"unlocked\": \"Unlocked\"\n }\n },\n \"format\": {\n \"currency\": \"{{value, currency}}\",\n \"number\": \"{{value, number}}\",\n \"percent\": \"{{value, percent}}\"\n },\n \"history\": \"\",\n \"hub\": {\n \"empty\": {\n \"description\": \"No available item matches the current filters.\",\n \"title\": \"No items\"\n },\n \"itemKinds\": {\n \"entity\": \"List\",\n \"tool\": \"Tool\"\n },\n \"search\": {\n \"placeholder\": \"Search\"\n },\n \"subtitle\": \"Choose an item to continue.\"\n },\n \"list\": {\n \"actions\": {\n \"refresh\": \"Refresh\",\n \"refreshing\": \"Refreshing…\",\n \"retry\": \"Retry\"\n },\n \"errors\": {\n \"tableFailed\": \"The table failed to load.\",\n \"title\": \"Table error\"\n },\n \"loaded_one\": \"{{count, number}} item loaded\",\n \"loaded_other\": \"{{count, number}} items loaded\",\n \"loadMore\": {\n \"end\": \"End of results\",\n \"loading\": \"Loading more…\"\n },\n \"showing\": \"Showing {{shown, number}} of {{total, number}}\",\n \"sort\": {\n \"label\": \"Sort order\"\n },\n \"title\": \"\"\n },\n \"overview\": \"\",\n \"picker\": {\n \"errors\": {\n \"loadFailed\": \"Failed to load.\"\n },\n \"searchRequired\": \"Enter an ID to search.\",\n \"title\": \"Select an ID\",\n \"unavailable\": \"Picker not available for {{entity}}.\"\n },\n \"relations\": {\n \"menu\": {\n \"label\": \"Relations\"\n },\n \"openFilteredList\": \"Open filtered list: {{label}}\"\n },\n \"review\": {\n \"status\": {\n \"approved\": \"Approved\",\n \"changesRequested\": \"Changes requested\",\n \"pending\": \"Pending\",\n \"unknown\": \"Unknown\"\n }\n },\n \"sidebar\": {\n \"actions\": {\n \"collapseSidebar\": \"Close\",\n \"expandSidebar\": \"Open\",\n \"pin\": \"Pin\",\n \"reorder\": \"Reorder\",\n \"unpin\": \"Unpin\"\n },\n \"items\": {\n \"dashboard\": \"Dashboard\"\n },\n \"navigationAriaLabel\": \"Backoffice navigation\",\n \"profile\": {\n \"actions\": {\n \"signOut\": \"Sign out\"\n },\n \"menuAriaLabel\": \"Open profile menu\",\n \"title\": \"Profile\",\n \"unknownUser\": \"Unknown user\"\n },\n \"search\": {\n \"placeholder\": \"Search…\"\n },\n \"sections\": {\n \"pinned\": \"Pinned\",\n \"recent\": \"Recent\"\n }\n },\n \"tools\": {\n \"errors\": {\n \"description\": \"We couldn't run this tool.\",\n \"details\": \"Error details\",\n \"label\": \"Error\",\n \"title\": \"Tool error\",\n \"unknown\": \"Unknown error\"\n },\n \"forms\": {\n \"actions\": {\n \"insertExample\": \"Insert example\",\n \"run\": \"Run\"\n },\n \"inputJsonLabel\": \"Input JSON\"\n },\n \"loading\": {\n \"description\": \"Running tool...\"\n },\n \"output\": \"Output\"\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"backofficeReact.js","names":[],"sources":["../../../../../src/i18n/locales/en/backofficeReact.json"],"sourcesContent":["{\n \"actions\": {\n \"form\": {\n \"cancel\": \"Cancel\",\n \"errors\": {\n \"invalidJson\": \"{{label}} must be valid JSON.\",\n \"invalidJsonArray\": \"{{label}} must be a valid JSON array.\",\n \"invalidJsonObject\": \"{{label}} must be a valid JSON object.\",\n \"invalidNumber\": \"{{label}} must be a valid number.\",\n \"invalidPayload\": \"The submitted payload is invalid.\",\n \"required\": \"{{label}} is required.\",\n \"submitFailed\": \"Unable to complete this action. Please try again.\"\n },\n \"submitting\": \"Submitting...\"\n },\n \"view\": \"View\"\n },\n \"auth\": {\n \"acceptInvitation\": {\n \"actions\": {\n \"backToLogin\": \"Back to login\"\n },\n \"errors\": {\n \"alreadyAccepted\": \"This invitation has already been accepted.\",\n \"default\": \"Unable to accept invitation.\",\n \"emailMismatch\": \"This invitation was sent to a different email address.\",\n \"expired\": \"Invitation link has expired.\",\n \"invalidToken\": \"Invitation link is invalid.\",\n \"missingToken\": \"Invitation link is missing or invalid.\",\n \"passwordMismatch\": \"Password and confirmation do not match.\",\n \"passwordPolicyViolation\": \"Your password does not meet policy requirements.\",\n \"rateLimited\": \"Too many attempts. Please try again later.\",\n \"unavailable\": \"Invitation acceptance is not available.\"\n },\n \"form\": {\n \"confirmLabel\": \"Confirm password\",\n \"confirmPlaceholder\": \"Confirm your password\",\n \"passwordLabel\": \"Password\",\n \"passwordPlaceholder\": \"Create a password\",\n \"submit\": \"Accept invitation\"\n },\n \"mfaSubtitle\": \"Enter the verification code to continue.\",\n \"mfaTitle\": \"Verify your identity\",\n \"status\": {\n \"success\": \"Invitation accepted.\",\n \"workingButton\": \"Working...\"\n },\n \"subtitle\": \"Create your account to join.\",\n \"title\": \"Accept invitation\"\n },\n \"emailCapture\": {\n \"continue\": \"Continue\",\n \"description\": \"Enter your work email to continue.\",\n \"emailLabel\": \"Work email\",\n \"emailPlaceholder\": \"you@company.com\",\n \"forgotPassword\": \"Forgot your password?\"\n },\n \"loginFlow\": {\n \"errors\": {\n \"accountLocked\": \"Too many attempts. Try again later.\",\n \"emailRequired\": \"Enter an email address to continue.\",\n \"invalidCredentials\": \"Email or password is incorrect.\",\n \"invalidEmail\": \"Enter a valid email address.\",\n \"passkeyUnavailable\": \"Passkeys are not available.\",\n \"rateLimited\": \"Too many attempts. Please try again later.\",\n \"tryAgain\": \"Something went wrong. Please try again.\"\n },\n \"methods\": {\n \"title\": \"Choose a sign-in method\"\n },\n \"passkey\": {\n \"description\": \"Use the passkey associated with {{email}}.\",\n \"title\": \"Use a passkey\"\n },\n \"subtitle\": {\n \"default\": \"Choose a sign-in method to continue.\",\n \"mfa\": \"Enter the verification code to continue.\"\n },\n \"title\": {\n \"default\": \"Sign in\",\n \"mfa\": \"Two-factor authentication\"\n }\n },\n \"logout\": {\n \"errors\": {\n \"default\": \"Logout failed.\"\n }\n },\n \"methodChooser\": {\n \"actions\": {\n \"back\": \"Back\"\n },\n \"locked\": \"Too many attempts. Try again later.\",\n \"lockedWithTime\": \"Too many attempts. Try again at {{time}}.\",\n \"methods\": {\n \"other\": \"{{method}}\",\n \"passkey\": \"Passkey\",\n \"password\": \"Password\"\n },\n \"prompt\": \"Choose how to sign in for <strong>{{email}}</strong>.\"\n },\n \"mfa\": {\n \"actions\": {\n \"back\": \"Back\",\n \"submit\": \"Verify\"\n },\n \"errors\": {\n \"expired\": \"Verification session expired. Please try again.\",\n \"invalidChallenge\": \"Verification session is invalid. Restart the login.\",\n \"invalidCode\": \"Invalid code. Try again.\",\n \"shortCode\": \"Enter the 6-digit code.\",\n \"tooManyAttempts\": \"Too many attempts. Try again later.\",\n \"verificationFailed\": \"Verification failed. Try again.\"\n },\n \"form\": {\n \"label\": \"Verification code\",\n \"placeholder\": \"123456\"\n },\n \"helper\": {\n \"default\": \"Enter the 6-digit code from your authenticator.\",\n \"withEmail\": \"Enter the 6-digit code sent to {{email}}.\"\n }\n },\n \"oidc\": {\n \"buttons\": {\n \"apple\": \"Continue with Apple\",\n \"generic\": \"Continue with single sign-on\",\n \"google\": \"Continue with Google\"\n }\n },\n \"passkey\": {\n \"actions\": {\n \"showMethods\": \"Use another method\",\n \"submit\": \"Continue with passkey\",\n \"submitting\": \"Waiting for passkey...\"\n },\n \"errors\": {\n \"cancelled\": \"Passkey sign-in was cancelled.\",\n \"challengeExpired\": \"Passkey request expired. Try again.\",\n \"emailRequired\": \"Enter your email to continue.\",\n \"failed\": \"Passkey sign-in failed.\",\n \"invalidAssertion\": \"Passkey response is invalid. Try again.\",\n \"invalidChallenge\": \"Passkey request is invalid. Try again.\",\n \"invalidEmail\": \"Enter a valid email address.\",\n \"locked\": \"Too many attempts. Try again later.\",\n \"lockedWithTime\": \"Too many attempts. Try again at {{time}}.\",\n \"noCredential\": \"No credential was returned by the authenticator.\",\n \"notAvailable\": \"Passkeys are not available on this device.\",\n \"notFound\": \"No passkey found for this account.\"\n },\n \"form\": {\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"you@company.com\"\n },\n \"helper\": \"Use a passkey instead of your password.\"\n },\n \"passwordLogin\": {\n \"forgotPassword\": \"Forgot your password?\",\n \"title\": \"Sign in\"\n },\n \"passwordResetComplete\": {\n \"errors\": {\n \"expired\": \"This reset link has expired.\",\n \"invalid\": \"Reset link is invalid or expired.\",\n \"minLength\": \"Password must be at least {{minLength}} characters.\",\n \"mismatch\": \"Passwords do not match.\",\n \"missingToken\": \"Reset link is missing or invalid.\",\n \"policyViolation\": \"Your new password does not meet policy requirements.\"\n },\n \"form\": {\n \"confirmLabel\": \"Confirm password\",\n \"confirmPlaceholder\": \"Re-enter your password\",\n \"description\": \"Enter a new password for your account.\",\n \"passwordLabel\": \"Password\",\n \"passwordPlaceholder\": \"Enter a new password\",\n \"submit\": \"Update password\",\n \"title\": \"New password\"\n },\n \"subtitle\": \"Choose a strong password to secure your account.\",\n \"success\": {\n \"action\": \"Back to login\",\n \"description\": \"Your password has been changed.\",\n \"helper\": \"You can now sign in with your new password.\",\n \"title\": \"Password updated\"\n },\n \"title\": \"Set a new password\"\n },\n \"passwordResetRequest\": {\n \"errors\": {\n \"emailRequired\": \"Enter an email address.\",\n \"invalidEmail\": \"Please enter a valid email address.\",\n \"rateLimited\": \"Too many requests. Please wait and try again.\",\n \"startFailed\": \"Unable to start password reset.\"\n },\n \"form\": {\n \"description\": \"Enter the email for your account.\",\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"you@company.com\",\n \"submit\": \"Send reset link\"\n },\n \"sent\": {\n \"action\": \"Send another email\",\n \"description\": \"We sent a reset link to {{email}}.\",\n \"helper\": \"If you don't see it, check spam or try again.\",\n \"title\": \"Check your email\"\n },\n \"title\": \"Reset your password\"\n },\n \"verifyEmail\": {\n \"actions\": {\n \"continue\": \"Continue\",\n \"return\": \"Back to login\"\n },\n \"errors\": {\n \"alreadyVerified\": \"This email address is already verified.\",\n \"expired\": \"This verification link has expired.\",\n \"invalid\": \"Verification link is invalid or expired.\",\n \"missingToken\": \"Verification link is missing or invalid.\"\n },\n \"status\": {\n \"success\": \"Email verified. You can continue.\",\n \"verifying\": \"Verifying...\",\n \"verifyingButton\": \"Verifying\"\n },\n \"subtitle\": \"Confirm your email address to continue.\",\n \"title\": \"Verify your email\"\n }\n },\n \"common\": {\n \"actions\": {\n \"close\": \"Close\",\n \"copied\": \"Copied\",\n \"copy\": \"Copy\",\n \"pick\": \"Pick\",\n \"retry\": \"Retry\"\n },\n \"boolean\": {\n \"no\": \"No\",\n \"yes\": \"Yes\"\n },\n \"breadcrumb\": \"Breadcrumb\",\n \"errors\": {\n \"unexpected\": \"An unexpected error occurred.\"\n },\n \"loading\": \"Loading...\",\n \"notAvailable\": \"N/A\",\n \"time\": {\n \"lastDay\": \"24 h\",\n \"lastHour\": \"1 h\",\n \"lastSevenDays\": \"7 j\",\n \"lastThirtyDays\": \"30 j\"\n }\n },\n \"dashboard\": {\n \"actions\": {\n \"openList\": \"Open list\",\n \"openTool\": \"Open tool\"\n },\n \"subtitle\": \"Overview of the Work context.\",\n \"title\": \"Dashboard\"\n },\n \"detail\": {\n \"actionResult\": {\n \"message\": \"Message\",\n \"status\": \"Status\"\n },\n \"actions\": {\n \"backToList\": \"Back to list\",\n \"viewDetails\": \"View details\"\n },\n \"columns\": {\n \"charged\": \"Charged\",\n \"events\": \"Events\",\n \"markup\": \"Markup\",\n \"name\": \"Name\",\n \"rawCost\": \"Raw cost\"\n },\n \"notFound\": \"Not found\",\n \"notFoundDescription\": \"This item does not exist or is no longer available.\"\n },\n \"emptyState\": {\n \"listEmpty\": {\n \"description\": \"There are no records to display.\",\n \"title\": \"No results\"\n },\n \"listEmptyFiltered\": {\n \"actions\": {\n \"reset\": \"Reset filters\"\n },\n \"description\": \"No results match the current filters.\"\n }\n },\n \"filters\": {\n \"actions\": {\n \"applyFilter\": \"Apply {{label}} filter\",\n \"changeFilterValue\": \"Change {{label}}\",\n \"clearFilter\": \"Clear {{label}} filter\",\n \"filterBy\": \"Filter by {{label}}\"\n },\n \"all\": \"All {{label}}\",\n \"boolean\": {\n \"no\": \"No\",\n \"yes\": \"Yes\"\n },\n \"drawer\": {\n \"emptySearchResults\": \"No filters match this search.\"\n },\n \"placeholders\": {\n \"anyEntity\": \"All\",\n \"search\": \"Search {{label}}\",\n \"unresolved\": \"Unresolved ID\"\n },\n \"sections\": {\n \"default\": \"Filters\"\n },\n \"trigger\": \"Filters\",\n \"triggerWithCount_one\": \"Filters ({{count}})\",\n \"triggerWithCount_other\": \"Filters ({{count}})\"\n },\n \"flags\": {\n \"agentManaged\": {\n \"agentManaged\": \"Agent managed\",\n \"userManaged\": \"User managed\"\n },\n \"capability\": {\n \"allowed\": \"Allowed\",\n \"denied\": \"Denied\"\n },\n \"default\": {\n \"default\": \"Default\",\n \"notDefault\": \"Not default\"\n },\n \"deployedProduction\": {\n \"deployed\": \"Deployed\",\n \"notDeployed\": \"Not deployed\"\n },\n \"enabled\": {\n \"disabled\": \"Disabled\",\n \"enabled\": \"Enabled\"\n },\n \"encrypted\": {\n \"encrypted\": \"Encrypted\",\n \"notEncrypted\": \"Not encrypted\"\n },\n \"failure\": {\n \"failed\": \"Failed\",\n \"ok\": \"OK\"\n },\n \"forced\": {\n \"forced\": \"Forced\",\n \"normal\": \"Normal\"\n },\n \"locked\": {\n \"locked\": \"Locked\",\n \"unlocked\": \"Unlocked\"\n }\n },\n \"format\": {\n \"currency\": \"{{value, currency}}\",\n \"number\": \"{{value, number}}\",\n \"percent\": \"{{value, percent}}\"\n },\n \"history\": \"\",\n \"hub\": {\n \"empty\": {\n \"description\": \"No available item matches the current filters.\",\n \"title\": \"No items\"\n },\n \"itemKinds\": {\n \"entity\": \"List\",\n \"tool\": \"Tool\"\n },\n \"search\": {\n \"placeholder\": \"Search\"\n },\n \"subtitle\": \"Choose an item to continue.\"\n },\n \"list\": {\n \"actions\": {\n \"refresh\": \"Refresh\",\n \"refreshing\": \"Refreshing…\",\n \"retry\": \"Retry\"\n },\n \"errors\": {\n \"tableFailed\": \"The table failed to load.\",\n \"title\": \"Table error\"\n },\n \"loaded_one\": \"{{count, number}} item loaded\",\n \"loaded_other\": \"{{count, number}} items loaded\",\n \"loadMore\": {\n \"end\": \"End of results\",\n \"loading\": \"Loading more…\"\n },\n \"refreshingRows\": \"Filtering…\",\n \"showing\": \"Showing {{shown, number}} of {{total, number}}\",\n \"sort\": {\n \"label\": \"Sort order\"\n },\n \"title\": \"\"\n },\n \"overview\": \"\",\n \"picker\": {\n \"errors\": {\n \"loadFailed\": \"Failed to load.\"\n },\n \"searchRequired\": \"Enter an ID to search.\",\n \"title\": \"Select an ID\",\n \"unavailable\": \"Picker not available for {{entity}}.\"\n },\n \"relations\": {\n \"menu\": {\n \"label\": \"Relations\"\n },\n \"openFilteredList\": \"Open filtered list: {{label}}\"\n },\n \"review\": {\n \"status\": {\n \"approved\": \"Approved\",\n \"changesRequested\": \"Changes requested\",\n \"pending\": \"Pending\",\n \"unknown\": \"Unknown\"\n }\n },\n \"sidebar\": {\n \"actions\": {\n \"collapseSidebar\": \"Close\",\n \"expandSidebar\": \"Open\",\n \"pin\": \"Pin\",\n \"reorder\": \"Reorder\",\n \"unpin\": \"Unpin\"\n },\n \"items\": {\n \"dashboard\": \"Dashboard\"\n },\n \"navigationAriaLabel\": \"Backoffice navigation\",\n \"profile\": {\n \"actions\": {\n \"signOut\": \"Sign out\"\n },\n \"menuAriaLabel\": \"Open profile menu\",\n \"title\": \"Profile\",\n \"unknownUser\": \"Unknown user\"\n },\n \"search\": {\n \"placeholder\": \"Search…\"\n },\n \"sections\": {\n \"pinned\": \"Pinned\",\n \"recent\": \"Recent\"\n }\n },\n \"tools\": {\n \"errors\": {\n \"description\": \"We couldn't run this tool.\",\n \"details\": \"Error details\",\n \"label\": \"Error\",\n \"title\": \"Tool error\",\n \"unknown\": \"Unknown error\"\n },\n \"forms\": {\n \"actions\": {\n \"insertExample\": \"Insert example\",\n \"run\": \"Run\"\n },\n \"inputJsonLabel\": \"Input JSON\"\n },\n \"loading\": {\n \"description\": \"Running tool...\"\n },\n \"output\": \"Output\"\n }\n}\n"],"mappings":""}
@@ -371,6 +371,7 @@ var e = {
371
371
  end: "Fin des résultats",
372
372
  loading: "Chargement…"
373
373
  },
374
+ refreshingRows: "Filtrage en cours…",
374
375
  showing: "Affichage de {{shown, number}} sur {{total, number}}",
375
376
  sort: { label: "Ordre de tri" },
376
377
  title: ""