@plumile/backoffice-react 0.1.115 → 0.1.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/auth/authRefreshNotice.css.js +1 -0
- package/lib/esm/components/backoffice/detail/BackofficeDetailFlagTag.css.js +0 -1
- package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js +271 -263
- package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js +2 -2
- package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/backofficeListScrollMode.js +6 -0
- package/lib/esm/components/backoffice/scaffolds/backofficeListScrollMode.js.map +1 -0
- package/lib/esm/pages/BackofficeLayoutPage.js +1 -0
- package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
- package/lib/types/components/backoffice/scaffolds/BackofficeEntityListScaffold.d.ts.map +1 -1
- package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts +1 -0
- package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts.map +1 -1
- package/lib/types/components/backoffice/scaffolds/backofficeListScrollMode.d.ts +2 -0
- package/lib/types/components/backoffice/scaffolds/backofficeListScrollMode.d.ts.map +1 -0
- package/lib/types/pages/BackofficeLayoutPage.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -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 { BackofficeInfiniteListStatus } from '@plumile/ui/backoffice/molecules/backoffice_infinite_list_status/BackofficeInfiniteListStatus.js';\nimport { BackofficePageHeader } from '@plumile/ui/backoffice/molecules/backoffice_page_header/BackofficePageHeader.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/backoffice/molecules/inline_banner/InlineBanner.js';\nimport { BackofficeVirtualizedConnectionTable } from '@plumile/ui/backoffice/organisms/backoffice_virtualized_connection_table/BackofficeVirtualizedConnectionTable.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 { 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 { BackofficeListToolbar } from '../lists/BackofficeListToolbar.js';\nimport { BackofficeListFilterProvider } from './BackofficeListFilterContext.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 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 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=\"number\"\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(() => {\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 }, [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 <BackofficeVirtualizedConnectionTable\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 />\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 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 <BackofficeListToolbar\n primaryFilters={\n searchNode != null || quickFiltersNode != null ? (\n <>\n {searchNode}\n {quickFiltersNode}\n </>\n ) : null\n }\n filterDrawerTrigger={allFiltersNode}\n sortControl={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 activeFilters={chipsNode}\n density=\"compact\"\n />\n {filterDrawerNode}\n </>\n ) : null;\n\n const tableNode = (\n <div>\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 {!shouldVirtualizeTable && <div ref={sentinelRef} aria-hidden=\"true\" />}\n <BackofficeInfiniteListStatus\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 loadedLabel={tableFooterMeta}\n loadingLabel={t('list.loadMore.loading')}\n endLabel={t('list.loadMore.end')}\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 />\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 { BackofficeInfiniteListStatus } from '@plumile/ui/backoffice/molecules/backoffice_infinite_list_status/BackofficeInfiniteListStatus.js';\nimport { BackofficePageHeader } from '@plumile/ui/backoffice/molecules/backoffice_page_header/BackofficePageHeader.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/backoffice/molecules/inline_banner/InlineBanner.js';\nimport { BackofficeVirtualizedConnectionTable } from '@plumile/ui/backoffice/organisms/backoffice_virtualized_connection_table/BackofficeVirtualizedConnectionTable.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 { 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 { BackofficeListToolbar } from '../lists/BackofficeListToolbar.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 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 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=\"number\"\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(() => {\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 }, [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 <BackofficeVirtualizedConnectionTable\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 <BackofficeListToolbar\n primaryFilters={\n searchNode != null || quickFiltersNode != null ? (\n <>\n {searchNode}\n {quickFiltersNode}\n </>\n ) : null\n }\n filterDrawerTrigger={allFiltersNode}\n sortControl={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 activeFilters={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 <BackofficeInfiniteListStatus\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 loadedLabel={tableFooterMeta}\n loadingLabel={t('list.loadMore.loading')}\n endLabel={t('list.loadMore.end')}\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 = "txvbqb9ip txvbqbajy txvbqbcp txvbqbao7", t = "_8gc5760 txvbqbu4g txvbqbjep", n = "txvbqb9ip txvbqbai7 txvbqbaog", r = "txvbqb97 txvbqbamp txvbqbv9z";
|
|
3
|
+
var e = "txvbqb9ip txvbqbajy txvbqbcp txvbqbao7", t = "_8gc5760 txvbqbu4g txvbqbjep", n = "txvbqb9ip txvbqbai7 txvbqbaog", r = "txvbqb9ip txvbqbai7 txvbqbcgg txvbqbjh7", i = "txvbqb97 txvbqbamp txvbqbv9z";
|
|
4
4
|
//#endregion
|
|
5
|
-
export { e as controlsRow, n as embeddedContainer,
|
|
5
|
+
export { e as controlsRow, n as embeddedContainer, i as embeddedHeader, t as filterInput, 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 { style } from '@vanilla-extract/css';\nimport { sprinkles } from '@plumile/ui/theme/sprinkles.css.js';\n\nconst MOBILE_MEDIA_QUERY = 'screen and (max-width: 767px)';\n\nexport const controlsRow = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 2,\n});\n\nexport const filterInput = style([\n sprinkles({\n width: 72,\n maxWidth: 'full',\n }),\n {\n '@media': {\n [MOBILE_MEDIA_QUERY]: {\n width: '100%',\n },\n },\n },\n]);\n\nexport const embeddedContainer = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\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 { style } from '@vanilla-extract/css';\nimport { sprinkles } from '@plumile/ui/theme/sprinkles.css.js';\n\nconst MOBILE_MEDIA_QUERY = 'screen and (max-width: 767px)';\n\nexport const controlsRow = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 2,\n});\n\nexport const filterInput = style([\n sprinkles({\n width: 72,\n maxWidth: 'full',\n }),\n {\n '@media': {\n [MOBILE_MEDIA_QUERY]: {\n width: '100%',\n },\n },\n },\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":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backofficeListScrollMode.js","names":[],"sources":["../../../../../src/components/backoffice/scaffolds/backofficeListScrollMode.ts"],"sourcesContent":["export const BACKOFFICE_LIST_BODY_SCROLL_MODE = 'contained' as const;\n"],"mappings":";AAAA,IAAa,IAAmC"}
|
|
@@ -243,6 +243,7 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
243
243
|
navigationAriaLabel: b("sidebar.navigationAriaLabel")
|
|
244
244
|
},
|
|
245
245
|
topbar: { breadcrumb: /* @__PURE__ */ u("div", { ref: xe }) },
|
|
246
|
+
contentScrollMode: "contained",
|
|
246
247
|
children: /* @__PURE__ */ u(te, {
|
|
247
248
|
permissions: g,
|
|
248
249
|
children: /* @__PURE__ */ u(n, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeLayoutPage.js","names":[],"sources":["../../../src/pages/BackofficeLayoutPage.tsx"],"sourcesContent":["import {\n useEffect,\n useMemo,\n type JSX,\n type ReactNode,\n useCallback,\n useContext,\n useState,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n commitMutation,\n usePreloadedQuery,\n type PreloadedQuery,\n} from 'react-relay';\nimport type {\n GraphQLTaggedNode,\n MutationParameters,\n OperationType,\n} from 'relay-runtime';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport { AdminShellLayout } from '@plumile/ui/admin/templates/admin_shell_layout/AdminShellLayout.js';\nimport { ToastProvider } from '@plumile/ui/atomic/molecules/toast/ToastProvider.js';\nimport { EnvironmentBadge } from '@plumile/ui/backoffice/atoms/environment_badge/EnvironmentBadge.js';\nimport { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { BackofficeSidebarProfileMenu } from '@plumile/ui/backoffice/molecules/sidebar_profile_menu/BackofficeSidebarProfileMenu.js';\n\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { LogoutResponse, LogoutVariables } from '../hooks/useAuth.js';\nimport { useBackofficeSidebarPins } from '../hooks/useBackofficeSidebarPins.js';\nimport { useSidebarGroupCollapse } from '../hooks/useSidebarGroupCollapse.js';\nimport { buildSidebarSections } from '../components/backoffice/layout/buildSidebarSections.js';\nimport { BackofficeContentBoundary } from '../components/backoffice/routing/BackofficeContentBoundary.js';\nimport {\n resolveActiveEntityId,\n resolveSidebarGroups,\n resolveVisibleEntityIds,\n} from '../components/backoffice/layout/sidebarUtils.js';\nimport { BackofficeTopbarPortalContextProvider } from '../components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js';\nimport { BackofficePermissionsProvider } from '../components/backoffice/layout/BackofficePermissionsContext.js';\nimport {\n mapViewerToSidebarProfileView,\n type BackofficeViewerIdentity,\n} from '../components/backoffice/layout/mapViewerToSidebarProfileView.js';\nimport { resetRelayStore } from '../relay/environment.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\nimport type { BackofficeSidebarRecentItem } from '../provider/types.js';\n\nexport type BackofficeLayoutPageProps = {\n children: ReactNode;\n permissionsQuery?: GraphQLTaggedNode;\n prepared?: PreloadedQuery<OperationType> | null;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\ntype LayoutShellProps = {\n children: ReactNode;\n permissions: unknown;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\nconst DEFAULT_RECENT_ITEMS_STORAGE_KEY = 'plumile:backoffice:recent-items';\nconst DEFAULT_SIDEBAR_PREFS_STORAGE_KEY = 'plumile:backoffice:sidebar';\n\nconst readRecentItems = (\n storageKey: string,\n): readonly BackofficeSidebarRecentItem[] => {\n if (typeof window === 'undefined') {\n return [];\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return [];\n }\n const parsed = JSON.parse(raw) as unknown;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((item): item is BackofficeSidebarRecentItem => {\n if (item == null || typeof item !== 'object') {\n return false;\n }\n const candidate = item as Partial<BackofficeSidebarRecentItem>;\n return (\n (candidate.kind === 'entity' || candidate.kind === 'tool') &&\n typeof candidate.id === 'string' &&\n typeof candidate.label === 'string' &&\n typeof candidate.href === 'string' &&\n typeof candidate.visitedAt === 'number'\n );\n });\n } catch {\n return [];\n }\n};\n\nconst writeRecentItems = (\n storageKey: string,\n items: readonly BackofficeSidebarRecentItem[],\n): void => {\n if (typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(items));\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n};\n\nconst BackofficeLayoutShell = ({\n children,\n permissions,\n authStatus,\n activeGroupId,\n}: LayoutShellProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { pathname } = useLocation();\n const routing = useContext(RoutingContext);\n const relayEnvironment = useRelayEnvironment();\n const {\n auth: authConfig,\n basePath,\n entities,\n sidebar,\n } = useBackofficeConfig();\n const [sidebarQuery, setSidebarQuery] = useState('');\n const sidebarPreferencesStorageKey =\n sidebar?.preferences?.storageKey ?? DEFAULT_SIDEBAR_PREFS_STORAGE_KEY;\n const persistSidebarCollapsed =\n sidebar?.preferences?.persistCollapsed === true;\n const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return false;\n }\n try {\n return (\n window.localStorage.getItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n ) === 'true'\n );\n } catch {\n return false;\n }\n });\n const [isSigningOut, setIsSigningOut] = useState(false);\n const [topbarTarget, setTopbarTarget] = useState<HTMLDivElement | null>(null);\n const recentItemsConfig = sidebar?.recentItems;\n const recentItemsEnabled = recentItemsConfig?.enabled === true;\n const recentItemsStorageKey =\n recentItemsConfig?.storageKey ?? DEFAULT_RECENT_ITEMS_STORAGE_KEY;\n const recentItemsMaxItems = recentItemsConfig?.maxItems ?? 8;\n const [recentItems, setRecentItems] = useState<\n readonly BackofficeSidebarRecentItem[]\n >(() => {\n if (!recentItemsEnabled) {\n return [];\n }\n return readRecentItems(recentItemsStorageKey);\n });\n\n useEffect(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n String(isSidebarCollapsed),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [\n isSidebarCollapsed,\n persistSidebarCollapsed,\n sidebarPreferencesStorageKey,\n ]);\n\n const groups = useMemo(() => {\n return resolveSidebarGroups(entities, sidebar);\n }, [entities, sidebar]);\n\n const groupIds = useMemo(() => {\n return Object.keys(groups);\n }, [groups]);\n\n const defaultCollapsedByGroupId = useMemo(() => {\n return Object.fromEntries(\n Object.entries(groups).map(([groupId, group]) => {\n return [groupId, group.behavior?.defaultCollapsed ?? true];\n }),\n );\n }, [groups]);\n\n const visibleEntityIds = useMemo(() => {\n return resolveVisibleEntityIds(groups, entities, sidebar, permissions);\n }, [entities, groups, permissions, sidebar]);\n\n const activeEntityId = useMemo(() => {\n return resolveActiveEntityId(pathname, entities);\n }, [entities, pathname]);\n\n useEffect(() => {\n if (!recentItemsEnabled || activeEntityId == null) {\n return;\n }\n const config = entities[activeEntityId];\n if (config == null) {\n return;\n }\n if (config.kind !== 'tool' && !config.hasList) {\n return;\n }\n const href = config.routes.list;\n let kind: BackofficeSidebarRecentItem['kind'] = 'entity';\n if (config.kind === 'tool') {\n kind = 'tool';\n }\n const item: BackofficeSidebarRecentItem = {\n kind,\n id: activeEntityId,\n label: config.label(tApp),\n href,\n visitedAt: Date.now(),\n };\n setRecentItems((prev) => {\n const next = [\n item,\n ...prev.filter((entry) => {\n return entry.id !== item.id || entry.kind !== item.kind;\n }),\n ].slice(0, recentItemsMaxItems);\n writeRecentItems(recentItemsStorageKey, next);\n return next;\n });\n }, [\n activeEntityId,\n entities,\n recentItemsEnabled,\n recentItemsMaxItems,\n recentItemsStorageKey,\n tApp,\n ]);\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({\n enabled: sidebar?.pinnedItems?.enabled === true,\n storageKey: sidebar?.pinnedItems?.storageKey,\n visibleEntityIds,\n });\n\n let groupCollapseStorageKey: string | undefined;\n if (sidebar?.preferences?.storageKey != null) {\n groupCollapseStorageKey = `${sidebar.preferences.storageKey}:groups`;\n }\n\n const { collapsedByGroupId, setCollapsed } = useSidebarGroupCollapse({\n groupIds,\n activeGroupId,\n defaultCollapsedByGroupId,\n persist: sidebar?.preferences?.persistGroups === true,\n storageKey: groupCollapseStorageKey,\n });\n\n const sections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n recentItems,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const mobileSections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n recentItems,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const environment = useMemo(() => {\n const meta = import.meta as unknown as { env?: Record<string, unknown> };\n if (meta.env?.DEV === true) {\n return 'dev' as const;\n }\n return 'prod' as const;\n }, []);\n\n const handleSignOut = useCallback(() => {\n if (isSigningOut) {\n return;\n }\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n setIsSigningOut(true);\n\n const runSignOut = async (): Promise<void> => {\n try {\n const config = await authConfig.logout.load();\n await new Promise<void>((resolve, reject) => {\n commitMutation<LogoutMutation>(relayEnvironment, {\n mutation: config.logoutMutation,\n variables: {},\n onCompleted: () => {\n resolve();\n },\n onError: (error) => {\n reject(error);\n },\n });\n });\n localStorage.removeItem('auth_token');\n localStorage.removeItem('remember_me');\n resetRelayStore();\n routing?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n } finally {\n setIsSigningOut(false);\n }\n };\n\n runSignOut().catch(() => {\n /* noop */\n });\n }, [authConfig.logout, basePath, isSigningOut, relayEnvironment, routing]);\n\n const viewer = authStatus?.me ?? null;\n const sidebarProfile = useMemo(() => {\n return mapViewerToSidebarProfileView({\n viewer,\n unknownUserLabel: t('sidebar.profile.unknownUser'),\n });\n }, [t, viewer]);\n\n const sidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={false}\n viewer={sidebarProfile}\n labels={{\n sectionTitle: t('sidebar.profile.title'),\n menuAriaLabel: t('sidebar.profile.menuAriaLabel'),\n signOut: t('sidebar.profile.actions.signOut'),\n }}\n onSignOut={handleSignOut}\n isSigningOut={isSigningOut}\n />\n );\n\n const mobileSidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={false}\n viewer={sidebarProfile}\n labels={{\n sectionTitle: t('sidebar.profile.title'),\n menuAriaLabel: t('sidebar.profile.menuAriaLabel'),\n signOut: t('sidebar.profile.actions.signOut'),\n }}\n onSignOut={handleSignOut}\n isSigningOut={isSigningOut}\n />\n );\n\n let contentNode: JSX.Element | null = null;\n if (topbarTarget != null) {\n contentNode = (\n <BackofficeContentBoundary>{children}</BackofficeContentBoundary>\n );\n }\n\n const sidebarSearchNode = (\n <GlobalSearchInput\n value={sidebarQuery}\n onChange={setSidebarQuery}\n placeholder={t('sidebar.search.placeholder')}\n ariaLabel={t('sidebar.search.placeholder')}\n />\n );\n\n return (\n <ToastProvider>\n <AdminShellLayout\n sidebar={{\n sections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: sidebarFooter,\n isCollapsed: isSidebarCollapsed,\n onCollapsedChange: setIsSidebarCollapsed,\n collapseToggleLabel: t('sidebar.actions.collapseSidebar'),\n expandToggleLabel: t('sidebar.actions.expandSidebar'),\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n mobileSidebar={{\n sections: mobileSections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: mobileSidebarFooter,\n isCollapsed: false,\n hideCollapseToggle: true,\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n topbar={{\n breadcrumb: <div ref={setTopbarTarget} />,\n }}\n >\n <BackofficePermissionsProvider permissions={permissions}>\n <BackofficeTopbarPortalContextProvider\n value={{\n target: topbarTarget,\n dashboardHref: basePath,\n dashboardLabel: t('sidebar.items.dashboard'),\n }}\n >\n {contentNode}\n </BackofficeTopbarPortalContextProvider>\n </BackofficePermissionsProvider>\n </AdminShellLayout>\n </ToastProvider>\n );\n};\n\ntype LayoutWithPermissionsProps = {\n children: ReactNode;\n permissionsQuery: GraphQLTaggedNode;\n prepared: PreloadedQuery<OperationType>;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\nconst LayoutWithPermissions = ({\n children,\n permissionsQuery,\n prepared,\n authStatus,\n activeGroupId,\n}: LayoutWithPermissionsProps): JSX.Element => {\n const permissions = usePreloadedQuery(permissionsQuery, prepared);\n\n return (\n <BackofficeLayoutShell\n permissions={permissions}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </BackofficeLayoutShell>\n );\n};\n\nexport const BackofficeLayoutPage = ({\n children,\n permissionsQuery,\n prepared,\n authStatus,\n activeGroupId,\n}: BackofficeLayoutPageProps): JSX.Element => {\n if (permissionsQuery != null && prepared != null) {\n return (\n <LayoutWithPermissions\n permissionsQuery={permissionsQuery}\n prepared={prepared}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </LayoutWithPermissions>\n );\n }\n\n return (\n <BackofficeLayoutShell\n permissions={null}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </BackofficeLayoutShell>\n );\n};\n\nexport default BackofficeLayoutPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BackofficeLayoutPage.js","names":[],"sources":["../../../src/pages/BackofficeLayoutPage.tsx"],"sourcesContent":["import {\n useEffect,\n useMemo,\n type JSX,\n type ReactNode,\n useCallback,\n useContext,\n useState,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n commitMutation,\n usePreloadedQuery,\n type PreloadedQuery,\n} from 'react-relay';\nimport type {\n GraphQLTaggedNode,\n MutationParameters,\n OperationType,\n} from 'relay-runtime';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport { AdminShellLayout } from '@plumile/ui/admin/templates/admin_shell_layout/AdminShellLayout.js';\nimport { ToastProvider } from '@plumile/ui/atomic/molecules/toast/ToastProvider.js';\nimport { EnvironmentBadge } from '@plumile/ui/backoffice/atoms/environment_badge/EnvironmentBadge.js';\nimport { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { BackofficeSidebarProfileMenu } from '@plumile/ui/backoffice/molecules/sidebar_profile_menu/BackofficeSidebarProfileMenu.js';\n\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { LogoutResponse, LogoutVariables } from '../hooks/useAuth.js';\nimport { useBackofficeSidebarPins } from '../hooks/useBackofficeSidebarPins.js';\nimport { useSidebarGroupCollapse } from '../hooks/useSidebarGroupCollapse.js';\nimport { buildSidebarSections } from '../components/backoffice/layout/buildSidebarSections.js';\nimport { BackofficeContentBoundary } from '../components/backoffice/routing/BackofficeContentBoundary.js';\nimport {\n resolveActiveEntityId,\n resolveSidebarGroups,\n resolveVisibleEntityIds,\n} from '../components/backoffice/layout/sidebarUtils.js';\nimport { BackofficeTopbarPortalContextProvider } from '../components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js';\nimport { BackofficePermissionsProvider } from '../components/backoffice/layout/BackofficePermissionsContext.js';\nimport {\n mapViewerToSidebarProfileView,\n type BackofficeViewerIdentity,\n} from '../components/backoffice/layout/mapViewerToSidebarProfileView.js';\nimport { resetRelayStore } from '../relay/environment.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\nimport type { BackofficeSidebarRecentItem } from '../provider/types.js';\n\nexport type BackofficeLayoutPageProps = {\n children: ReactNode;\n permissionsQuery?: GraphQLTaggedNode;\n prepared?: PreloadedQuery<OperationType> | null;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\ntype LayoutShellProps = {\n children: ReactNode;\n permissions: unknown;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\nconst DEFAULT_RECENT_ITEMS_STORAGE_KEY = 'plumile:backoffice:recent-items';\nconst DEFAULT_SIDEBAR_PREFS_STORAGE_KEY = 'plumile:backoffice:sidebar';\n\nconst readRecentItems = (\n storageKey: string,\n): readonly BackofficeSidebarRecentItem[] => {\n if (typeof window === 'undefined') {\n return [];\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return [];\n }\n const parsed = JSON.parse(raw) as unknown;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((item): item is BackofficeSidebarRecentItem => {\n if (item == null || typeof item !== 'object') {\n return false;\n }\n const candidate = item as Partial<BackofficeSidebarRecentItem>;\n return (\n (candidate.kind === 'entity' || candidate.kind === 'tool') &&\n typeof candidate.id === 'string' &&\n typeof candidate.label === 'string' &&\n typeof candidate.href === 'string' &&\n typeof candidate.visitedAt === 'number'\n );\n });\n } catch {\n return [];\n }\n};\n\nconst writeRecentItems = (\n storageKey: string,\n items: readonly BackofficeSidebarRecentItem[],\n): void => {\n if (typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(items));\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n};\n\nconst BackofficeLayoutShell = ({\n children,\n permissions,\n authStatus,\n activeGroupId,\n}: LayoutShellProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { pathname } = useLocation();\n const routing = useContext(RoutingContext);\n const relayEnvironment = useRelayEnvironment();\n const {\n auth: authConfig,\n basePath,\n entities,\n sidebar,\n } = useBackofficeConfig();\n const [sidebarQuery, setSidebarQuery] = useState('');\n const sidebarPreferencesStorageKey =\n sidebar?.preferences?.storageKey ?? DEFAULT_SIDEBAR_PREFS_STORAGE_KEY;\n const persistSidebarCollapsed =\n sidebar?.preferences?.persistCollapsed === true;\n const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return false;\n }\n try {\n return (\n window.localStorage.getItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n ) === 'true'\n );\n } catch {\n return false;\n }\n });\n const [isSigningOut, setIsSigningOut] = useState(false);\n const [topbarTarget, setTopbarTarget] = useState<HTMLDivElement | null>(null);\n const recentItemsConfig = sidebar?.recentItems;\n const recentItemsEnabled = recentItemsConfig?.enabled === true;\n const recentItemsStorageKey =\n recentItemsConfig?.storageKey ?? DEFAULT_RECENT_ITEMS_STORAGE_KEY;\n const recentItemsMaxItems = recentItemsConfig?.maxItems ?? 8;\n const [recentItems, setRecentItems] = useState<\n readonly BackofficeSidebarRecentItem[]\n >(() => {\n if (!recentItemsEnabled) {\n return [];\n }\n return readRecentItems(recentItemsStorageKey);\n });\n\n useEffect(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n String(isSidebarCollapsed),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [\n isSidebarCollapsed,\n persistSidebarCollapsed,\n sidebarPreferencesStorageKey,\n ]);\n\n const groups = useMemo(() => {\n return resolveSidebarGroups(entities, sidebar);\n }, [entities, sidebar]);\n\n const groupIds = useMemo(() => {\n return Object.keys(groups);\n }, [groups]);\n\n const defaultCollapsedByGroupId = useMemo(() => {\n return Object.fromEntries(\n Object.entries(groups).map(([groupId, group]) => {\n return [groupId, group.behavior?.defaultCollapsed ?? true];\n }),\n );\n }, [groups]);\n\n const visibleEntityIds = useMemo(() => {\n return resolveVisibleEntityIds(groups, entities, sidebar, permissions);\n }, [entities, groups, permissions, sidebar]);\n\n const activeEntityId = useMemo(() => {\n return resolveActiveEntityId(pathname, entities);\n }, [entities, pathname]);\n\n useEffect(() => {\n if (!recentItemsEnabled || activeEntityId == null) {\n return;\n }\n const config = entities[activeEntityId];\n if (config == null) {\n return;\n }\n if (config.kind !== 'tool' && !config.hasList) {\n return;\n }\n const href = config.routes.list;\n let kind: BackofficeSidebarRecentItem['kind'] = 'entity';\n if (config.kind === 'tool') {\n kind = 'tool';\n }\n const item: BackofficeSidebarRecentItem = {\n kind,\n id: activeEntityId,\n label: config.label(tApp),\n href,\n visitedAt: Date.now(),\n };\n setRecentItems((prev) => {\n const next = [\n item,\n ...prev.filter((entry) => {\n return entry.id !== item.id || entry.kind !== item.kind;\n }),\n ].slice(0, recentItemsMaxItems);\n writeRecentItems(recentItemsStorageKey, next);\n return next;\n });\n }, [\n activeEntityId,\n entities,\n recentItemsEnabled,\n recentItemsMaxItems,\n recentItemsStorageKey,\n tApp,\n ]);\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({\n enabled: sidebar?.pinnedItems?.enabled === true,\n storageKey: sidebar?.pinnedItems?.storageKey,\n visibleEntityIds,\n });\n\n let groupCollapseStorageKey: string | undefined;\n if (sidebar?.preferences?.storageKey != null) {\n groupCollapseStorageKey = `${sidebar.preferences.storageKey}:groups`;\n }\n\n const { collapsedByGroupId, setCollapsed } = useSidebarGroupCollapse({\n groupIds,\n activeGroupId,\n defaultCollapsedByGroupId,\n persist: sidebar?.preferences?.persistGroups === true,\n storageKey: groupCollapseStorageKey,\n });\n\n const sections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n recentItems,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const mobileSections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n recentItems,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const environment = useMemo(() => {\n const meta = import.meta as unknown as { env?: Record<string, unknown> };\n if (meta.env?.DEV === true) {\n return 'dev' as const;\n }\n return 'prod' as const;\n }, []);\n\n const handleSignOut = useCallback(() => {\n if (isSigningOut) {\n return;\n }\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n setIsSigningOut(true);\n\n const runSignOut = async (): Promise<void> => {\n try {\n const config = await authConfig.logout.load();\n await new Promise<void>((resolve, reject) => {\n commitMutation<LogoutMutation>(relayEnvironment, {\n mutation: config.logoutMutation,\n variables: {},\n onCompleted: () => {\n resolve();\n },\n onError: (error) => {\n reject(error);\n },\n });\n });\n localStorage.removeItem('auth_token');\n localStorage.removeItem('remember_me');\n resetRelayStore();\n routing?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n } finally {\n setIsSigningOut(false);\n }\n };\n\n runSignOut().catch(() => {\n /* noop */\n });\n }, [authConfig.logout, basePath, isSigningOut, relayEnvironment, routing]);\n\n const viewer = authStatus?.me ?? null;\n const sidebarProfile = useMemo(() => {\n return mapViewerToSidebarProfileView({\n viewer,\n unknownUserLabel: t('sidebar.profile.unknownUser'),\n });\n }, [t, viewer]);\n\n const sidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={false}\n viewer={sidebarProfile}\n labels={{\n sectionTitle: t('sidebar.profile.title'),\n menuAriaLabel: t('sidebar.profile.menuAriaLabel'),\n signOut: t('sidebar.profile.actions.signOut'),\n }}\n onSignOut={handleSignOut}\n isSigningOut={isSigningOut}\n />\n );\n\n const mobileSidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={false}\n viewer={sidebarProfile}\n labels={{\n sectionTitle: t('sidebar.profile.title'),\n menuAriaLabel: t('sidebar.profile.menuAriaLabel'),\n signOut: t('sidebar.profile.actions.signOut'),\n }}\n onSignOut={handleSignOut}\n isSigningOut={isSigningOut}\n />\n );\n\n let contentNode: JSX.Element | null = null;\n if (topbarTarget != null) {\n contentNode = (\n <BackofficeContentBoundary>{children}</BackofficeContentBoundary>\n );\n }\n\n const sidebarSearchNode = (\n <GlobalSearchInput\n value={sidebarQuery}\n onChange={setSidebarQuery}\n placeholder={t('sidebar.search.placeholder')}\n ariaLabel={t('sidebar.search.placeholder')}\n />\n );\n\n return (\n <ToastProvider>\n <AdminShellLayout\n sidebar={{\n sections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: sidebarFooter,\n isCollapsed: isSidebarCollapsed,\n onCollapsedChange: setIsSidebarCollapsed,\n collapseToggleLabel: t('sidebar.actions.collapseSidebar'),\n expandToggleLabel: t('sidebar.actions.expandSidebar'),\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n mobileSidebar={{\n sections: mobileSections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: mobileSidebarFooter,\n isCollapsed: false,\n hideCollapseToggle: true,\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n topbar={{\n breadcrumb: <div ref={setTopbarTarget} />,\n }}\n contentScrollMode=\"contained\"\n >\n <BackofficePermissionsProvider permissions={permissions}>\n <BackofficeTopbarPortalContextProvider\n value={{\n target: topbarTarget,\n dashboardHref: basePath,\n dashboardLabel: t('sidebar.items.dashboard'),\n }}\n >\n {contentNode}\n </BackofficeTopbarPortalContextProvider>\n </BackofficePermissionsProvider>\n </AdminShellLayout>\n </ToastProvider>\n );\n};\n\ntype LayoutWithPermissionsProps = {\n children: ReactNode;\n permissionsQuery: GraphQLTaggedNode;\n prepared: PreloadedQuery<OperationType>;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\nconst LayoutWithPermissions = ({\n children,\n permissionsQuery,\n prepared,\n authStatus,\n activeGroupId,\n}: LayoutWithPermissionsProps): JSX.Element => {\n const permissions = usePreloadedQuery(permissionsQuery, prepared);\n\n return (\n <BackofficeLayoutShell\n permissions={permissions}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </BackofficeLayoutShell>\n );\n};\n\nexport const BackofficeLayoutPage = ({\n children,\n permissionsQuery,\n prepared,\n authStatus,\n activeGroupId,\n}: BackofficeLayoutPageProps): JSX.Element => {\n if (permissionsQuery != null && prepared != null) {\n return (\n <LayoutWithPermissions\n permissionsQuery={permissionsQuery}\n prepared={prepared}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </LayoutWithPermissions>\n );\n }\n\n return (\n <BackofficeLayoutShell\n permissions={null}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </BackofficeLayoutShell>\n );\n};\n\nexport default BackofficeLayoutPage;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeEntityListScaffold.d.ts","sourceRoot":"","sources":["../../../../../src/components/backoffice/scaffolds/BackofficeEntityListScaffold.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,GAAG,EACR,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAiBf,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,gDAAgD,CAAC;AAUxD,OAAO,KAAK,EAEV,mBAAmB,EAEnB,wCAAwC,EAEzC,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"BackofficeEntityListScaffold.d.ts","sourceRoot":"","sources":["../../../../../src/components/backoffice/scaffolds/BackofficeEntityListScaffold.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,GAAG,EACR,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAiBf,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,gDAAgD,CAAC;AAUxD,OAAO,KAAK,EAEV,mBAAmB,EAEnB,wCAAwC,EAEzC,MAAM,mCAAmC,CAAC;AAgI3C,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC5C,KAAK,WAAW,GAAG,MAAM,CAAC;AAE1B,KAAK,KAAK,CAAC,OAAO,IAAI;IACpB,MAAM,EAAE,wCAAwC,CAAC;IACjD,KAAK,EAAE,mBAAmB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,SAAS,EAAE,CAAC,IAAI,EAAE,mBAAmB,CAAC,YAAY,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;IAC1E,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,EAAE,SAAS,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,OAAO,EAClD,OAAO,KAAK,CAAC,OAAO,CAAC,KACpB,GAAG,CAAC,OAAO,GAAG,IA45BhB,CAAC;AAEF,eAAe,4BAA4B,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const controlsRow: string;
|
|
2
2
|
export declare const filterInput: string;
|
|
3
3
|
export declare const embeddedContainer: string;
|
|
4
|
+
export declare const tableHost: string;
|
|
4
5
|
export declare const embeddedHeader: string;
|
|
5
6
|
//# sourceMappingURL=backofficeEntityListScaffold.css.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backofficeEntityListScaffold.css.d.ts","sourceRoot":"","sources":["../../../../../src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,QAKtB,CAAC;AAEH,eAAO,MAAM,WAAW,QAYtB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAI5B,CAAC;AAEH,eAAO,MAAM,cAAc,QAIzB,CAAC"}
|
|
1
|
+
{"version":3,"file":"backofficeEntityListScaffold.css.d.ts","sourceRoot":"","sources":["../../../../../src/components/backoffice/scaffolds/backofficeEntityListScaffold.css.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,QAKtB,CAAC;AAEH,eAAO,MAAM,WAAW,QAYtB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAI5B,CAAC;AAEH,eAAO,MAAM,SAAS,QAKpB,CAAC;AAEH,eAAO,MAAM,cAAc,QAIzB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backofficeListScrollMode.d.ts","sourceRoot":"","sources":["../../../../../src/components/backoffice/scaffolds/backofficeListScrollMode.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gCAAgC,EAAG,WAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeLayoutPage.d.ts","sourceRoot":"","sources":["../../../src/pages/BackofficeLayoutPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,GAAG,EACR,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AAEf,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,iBAAiB,EAEjB,aAAa,EACd,MAAM,eAAe,CAAC;AAwBvB,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,kEAAkE,CAAC;AAM1E,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAChD,UAAU,CAAC,EAAE;QACX,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC5B,EAAE,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;KACtC,GAAG,IAAI,CAAC;IACT,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;
|
|
1
|
+
{"version":3,"file":"BackofficeLayoutPage.d.ts","sourceRoot":"","sources":["../../../src/pages/BackofficeLayoutPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,GAAG,EACR,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AAEf,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,iBAAiB,EAEjB,aAAa,EACd,MAAM,eAAe,CAAC;AAwBvB,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,kEAAkE,CAAC;AAM1E,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,EAAE,cAAc,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAChD,UAAU,CAAC,EAAE;QACX,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC5B,EAAE,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;KACtC,GAAG,IAAI,CAAC;IACT,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAmdF,eAAO,MAAM,oBAAoB,GAAI,sEAMlC,yBAAyB,KAAG,GAAG,CAAC,OAuBlC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumile/backoffice-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.116",
|
|
4
4
|
"description": "React provider and pages for Kronex backoffice",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -179,11 +179,11 @@
|
|
|
179
179
|
"tslib": "^2.8.1"
|
|
180
180
|
},
|
|
181
181
|
"devDependencies": {
|
|
182
|
-
"@plumile/auth": "^0.1.
|
|
183
|
-
"@plumile/backoffice-core": "^0.1.
|
|
184
|
-
"@plumile/filter-query": "^0.1.
|
|
185
|
-
"@plumile/router": "^0.1.
|
|
186
|
-
"@plumile/ui": "^0.1.
|
|
182
|
+
"@plumile/auth": "^0.1.116",
|
|
183
|
+
"@plumile/backoffice-core": "^0.1.116",
|
|
184
|
+
"@plumile/filter-query": "^0.1.116",
|
|
185
|
+
"@plumile/router": "^0.1.116",
|
|
186
|
+
"@plumile/ui": "^0.1.116",
|
|
187
187
|
"@types/react": "19.2.14",
|
|
188
188
|
"@types/react-dom": "19.2.3",
|
|
189
189
|
"@types/relay-runtime": "20.1.1",
|