@plumile/backoffice-react 0.2.10 → 0.2.11

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/README.md CHANGED
@@ -140,6 +140,10 @@ only helpers tied to backoffice mutations, connections, and typed data.
140
140
  The reusable picker visuals live in `@plumile/ui` as
141
141
  `BackofficePickerShell`, `BackofficePickerList`, and `BackofficePickerRow`.
142
142
 
143
+ `BackofficeUsageCostBreakdown` totals accept rich `value` content when copying
144
+ is disabled. A total with `copyValue` requires a `UiText` value (`string | number`),
145
+ matching the shared `MetricCard` copy contract at compile time.
146
+
143
147
  Backoffice React no longer exports generic toolbar or detail-header wrappers.
144
148
  Use `BackofficeToolbar`, `BackofficeListFilterToolbar`,
145
149
  `BackofficeListFooter`, and `PageHeader` from `@plumile/ui` for
@@ -14,76 +14,79 @@ var c = (e, t) => e(t), l = (e, t) => e == null || typeof e == "string" && e.tri
14
14
  };
15
15
  function f(f, p) {
16
16
  let { tApp: m, t: h } = p, g = h("common.notAvailable");
17
- return f.filter((e) => e.key !== "id").map((f) => ({
18
- id: f.key,
19
- header: c(f.header, m),
20
- size: f.size,
21
- isPrimary: f.visibility?.priority === "primary",
22
- priority: f.visibility?.priority,
23
- align: f.visibility?.align,
24
- mobileRole: u(f),
25
- minVisibleAt: d(f.visibility?.minVisibleAt),
26
- cell: (c) => {
27
- let { cell: u } = f;
28
- switch (u.type) {
29
- case "text": return l(u.value(c), g);
30
- case "link": {
31
- let e = u.value(c);
32
- return e == null || typeof e == "string" && e.trim() === "" ? g : /* @__PURE__ */ i(o, {
33
- to: u.to(c),
34
- preloadOnHover: "code",
35
- children: e
36
- });
17
+ return f.filter((e) => e.key !== "id").map((f) => {
18
+ let p = u(f);
19
+ return {
20
+ id: f.key,
21
+ header: c(f.header, m),
22
+ size: f.size,
23
+ isPrimary: f.visibility.priority === "primary",
24
+ priority: f.visibility.priority,
25
+ align: f.visibility.align,
26
+ mobileRole: p,
27
+ minVisibleAt: d(f.visibility.minVisibleAt),
28
+ cell: (c) => {
29
+ let { cell: u } = f;
30
+ switch (u.type) {
31
+ case "text": return l(u.value(c), g);
32
+ case "link": {
33
+ let e = u.value(c);
34
+ return e == null || typeof e == "string" && e.trim() === "" ? g : /* @__PURE__ */ i(o, {
35
+ to: u.to(c),
36
+ preloadOnHover: "code",
37
+ children: e
38
+ });
39
+ }
40
+ case "badge": {
41
+ let e = u.value(c);
42
+ if (e == null || e.trim() === "") return g;
43
+ let { tone: t } = u;
44
+ return typeof t == "function" && (t = t(c)), /* @__PURE__ */ i(s, {
45
+ tone: t,
46
+ children: e
47
+ });
48
+ }
49
+ case "dateTime": {
50
+ let e = u.value(c);
51
+ return /* @__PURE__ */ i(t, {
52
+ value: e,
53
+ fallback: g,
54
+ options: a
55
+ });
56
+ }
57
+ case "entityRef": {
58
+ let t = u.value(c);
59
+ if (t.trim() === "") return g;
60
+ let n = u.label?.(c);
61
+ if (n == null || n.trim() === "") return h("filters.placeholders.unresolved");
62
+ let r = {
63
+ kind: "entity-detail",
64
+ entityId: u.entity,
65
+ id: t
66
+ };
67
+ return /* @__PURE__ */ i(e, {
68
+ target: r,
69
+ children: n
70
+ });
71
+ }
72
+ case "technicalIdentifier": {
73
+ let e = u.value(c);
74
+ return e == null || String(e).trim() === "" ? g : /* @__PURE__ */ i(n, {
75
+ value: e,
76
+ copyValue: u.copyValue?.(c) ?? void 0,
77
+ abbreviation: u.abbreviation,
78
+ copyLabel: h("common.actions.copy")
79
+ });
80
+ }
81
+ case "custom": {
82
+ let e = u.render(c);
83
+ return e == null || e === "" ? g : /* @__PURE__ */ i(r, { children: e });
84
+ }
85
+ default: return g;
37
86
  }
38
- case "badge": {
39
- let e = u.value(c);
40
- if (e == null || e.trim() === "") return g;
41
- let { tone: t } = u;
42
- return typeof t == "function" && (t = t(c)), /* @__PURE__ */ i(s, {
43
- tone: t,
44
- children: e
45
- });
46
- }
47
- case "dateTime": {
48
- let e = u.value(c);
49
- return /* @__PURE__ */ i(t, {
50
- value: e,
51
- fallback: g,
52
- options: a
53
- });
54
- }
55
- case "entityRef": {
56
- let t = u.value(c);
57
- if (t.trim() === "") return g;
58
- let n = u.label?.(c);
59
- if (n == null || n.trim() === "") return h("filters.placeholders.unresolved");
60
- let r = {
61
- kind: "entity-detail",
62
- entityId: u.entity,
63
- id: t
64
- };
65
- return /* @__PURE__ */ i(e, {
66
- target: r,
67
- children: n
68
- });
69
- }
70
- case "technicalIdentifier": {
71
- let e = u.value(c);
72
- return e == null || String(e).trim() === "" ? g : /* @__PURE__ */ i(n, {
73
- value: e,
74
- copyValue: u.copyValue?.(c) ?? void 0,
75
- abbreviation: u.abbreviation,
76
- copyLabel: h("common.actions.copy")
77
- });
78
- }
79
- case "custom": {
80
- let e = u.render(c);
81
- return e == null || e === "" ? g : /* @__PURE__ */ i(r, { children: e });
82
- }
83
- default: return g;
84
87
  }
85
- }
86
- }));
88
+ };
89
+ });
87
90
  }
88
91
  //#endregion
89
92
  export { f as buildDataTableColumns };
@@ -1 +1 @@
1
- {"version":3,"file":"buildDataTableColumns.js","names":[],"sources":["../../../../../src/components/backoffice/columns/buildDataTableColumns.tsx"],"sourcesContent":["import { BACKOFFICE_DATE_TIME_OPTIONS } from '@plumile/backoffice-core/constants.js';\nimport type {\n BackofficeColumnSpec,\n BackofficeFieldSize,\n BackofficeListColumnVisibility,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type { TFunction } from 'i18next';\nimport Link from '@plumile/router/routing/Link.js';\nimport {\n FormattedDate,\n TechnicalIdentifierValue,\n type DataTableBreakpoint,\n type ResponsiveRecordListColumn,\n} from '@plumile/ui';\nimport { Tag } from '@plumile/ui/backoffice/atoms/tag/Tag.js';\n\nimport { BackofficeInlineLink } from '../links/BackofficeInlineLink.js';\nimport type { BackofficeLinkTarget } from '../links/types.js';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst resolveTextValue = (\n value: string | number | null,\n fallback: string,\n): string => {\n if (value == null) {\n return fallback;\n }\n if (typeof value === 'string' && value.trim() === '') {\n return fallback;\n }\n return String(value);\n};\n\nexport type BuildDataTableColumnsOptions = {\n tApp: TFunction;\n t: TFunction;\n};\n\nexport type BackofficeSizedDataTableColumn<Row> =\n ResponsiveRecordListColumn<Row> & {\n size: BackofficeFieldSize;\n };\n\nconst resolveMobileRole = <Row,>(\n column: BackofficeColumnSpec<Row>,\n): ResponsiveRecordListColumn<Row>['mobileRole'] => {\n const role = column.visibility?.mobile;\n if (role == null) {\n throw new Error(\n `[buildDataTableColumns] column \"${column.key}\" must declare visibility.mobile.`,\n );\n }\n return role;\n};\n\nconst resolveBreakpoint = (\n value: BackofficeListColumnVisibility['minVisibleAt'] | undefined,\n): DataTableBreakpoint | undefined => {\n if (\n value === 'sm' ||\n value === 'md' ||\n value === 'lg' ||\n value === 'xl' ||\n value === '2xl'\n ) {\n return value;\n }\n return undefined;\n};\n\n/**\n *\n */\nexport function buildDataTableColumns<Row>(\n columns: readonly BackofficeColumnSpec<Row>[],\n options: BuildDataTableColumnsOptions,\n): readonly BackofficeSizedDataTableColumn<Row>[] {\n const { tApp, t } = options;\n const fallback = t('common.notAvailable');\n const filteredColumns = columns.filter((column) => {\n return column.key !== 'id';\n });\n\n return filteredColumns.map((column) => {\n return {\n id: column.key,\n header: resolveLabel(column.header, tApp),\n size: column.size,\n isPrimary: column.visibility?.priority === 'primary',\n priority: column.visibility?.priority,\n align: column.visibility?.align,\n mobileRole: resolveMobileRole(column),\n minVisibleAt: resolveBreakpoint(column.visibility?.minVisibleAt),\n cell: (row) => {\n const { cell } = column;\n switch (cell.type) {\n case 'text': {\n return resolveTextValue(cell.value(row), fallback);\n }\n case 'link': {\n const value = cell.value(row);\n if (\n value == null ||\n (typeof value === 'string' && value.trim() === '')\n ) {\n return fallback;\n }\n return (\n <Link to={cell.to(row)} preloadOnHover=\"code\">\n {value}\n </Link>\n );\n }\n case 'badge': {\n const value = cell.value(row);\n if (value == null || value.trim() === '') {\n return fallback;\n }\n let { tone } = cell;\n if (typeof tone === 'function') {\n tone = tone(row);\n }\n return <Tag tone={tone}>{value}</Tag>;\n }\n case 'dateTime': {\n const value = cell.value(row);\n return (\n <FormattedDate\n value={value}\n fallback={fallback}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n />\n );\n }\n case 'entityRef': {\n const id = cell.value(row);\n if (id.trim() === '') {\n return fallback;\n }\n const label = cell.label?.(row);\n if (label == null || label.trim() === '') {\n return t('filters.placeholders.unresolved');\n }\n const target = {\n kind: 'entity-detail',\n entityId: cell.entity,\n id,\n } as BackofficeLinkTarget;\n return (\n <BackofficeInlineLink target={target}>\n {label}\n </BackofficeInlineLink>\n );\n }\n case 'technicalIdentifier': {\n const value = cell.value(row);\n if (value == null || String(value).trim() === '') {\n return fallback;\n }\n return (\n <TechnicalIdentifierValue\n value={value}\n copyValue={cell.copyValue?.(row) ?? undefined}\n abbreviation={cell.abbreviation}\n copyLabel={t('common.actions.copy')}\n />\n );\n }\n case 'custom': {\n const rendered = cell.render(row);\n if (rendered == null || rendered === '') {\n return fallback;\n }\n return <>{rendered}</>;\n }\n default: {\n return fallback;\n }\n }\n },\n };\n });\n}\n"],"mappings":";;;;;;;AAoBA,IAAM,KAAgB,GAAkB,MAC/B,EAAM,CAAI,GAGb,KACJ,GACA,MAEI,KAAS,QAGT,OAAO,KAAU,YAAY,EAAM,KAAK,MAAM,KACzC,IAEF,OAAO,CAAK,GAaf,KACJ,MACkD;CAClD,IAAM,IAAO,EAAO,YAAY;CAChC,IAAI,KAAQ,MACV,MAAU,MACR,mCAAmC,EAAO,IAAI,kCAChD;CAEF,OAAO;AACT,GAEM,KACJ,MACoC;CACpC,IACE,MAAU,QACV,MAAU,QACV,MAAU,QACV,MAAU,QACV,MAAU,OAEV,OAAO;AAGX;AAKA,SAAgB,EACd,GACA,GACgD;CAChD,IAAM,EAAE,SAAM,SAAM,GACd,IAAW,EAAE,qBAAqB;CAKxC,OAJwB,EAAQ,QAAQ,MAC/B,EAAO,QAAQ,IAGjB,CAAA,CAAgB,KAAK,OACnB;EACL,IAAI,EAAO;EACX,QAAQ,EAAa,EAAO,QAAQ,CAAI;EACxC,MAAM,EAAO;EACb,WAAW,EAAO,YAAY,aAAa;EAC3C,UAAU,EAAO,YAAY;EAC7B,OAAO,EAAO,YAAY;EAC1B,YAAY,EAAkB,CAAM;EACpC,cAAc,EAAkB,EAAO,YAAY,YAAY;EAC/D,OAAO,MAAQ;GACb,IAAM,EAAE,YAAS;GACjB,QAAQ,EAAK,MAAb;IACE,KAAK,QACH,OAAO,EAAiB,EAAK,MAAM,CAAG,GAAG,CAAQ;IAEnD,KAAK,QAAQ;KACX,IAAM,IAAQ,EAAK,MAAM,CAAG;KAO5B,OALE,KAAS,QACR,OAAO,KAAU,YAAY,EAAM,KAAK,MAAM,KAExC,IAGP,kBAAC,GAAD;MAAM,IAAI,EAAK,GAAG,CAAG;MAAG,gBAAe;MACpC,UAAA;KACG,CAAA;IAEV;IACA,KAAK,SAAS;KACZ,IAAM,IAAQ,EAAK,MAAM,CAAG;KAC5B,IAAI,KAAS,QAAQ,EAAM,KAAK,MAAM,IACpC,OAAO;KAET,IAAI,EAAE,YAAS;KAIf,OAHI,OAAO,KAAS,eAClB,IAAO,EAAK,CAAG,IAEV,kBAAC,GAAD;MAAW;MAAO,UAAA;KAAW,CAAA;IACtC;IACA,KAAK,YAAY;KACf,IAAM,IAAQ,EAAK,MAAM,CAAG;KAC5B,OACE,kBAAC,GAAD;MACS;MACG;MACV,SAAS;KACV,CAAA;IAEL;IACA,KAAK,aAAa;KAChB,IAAM,IAAK,EAAK,MAAM,CAAG;KACzB,IAAI,EAAG,KAAK,MAAM,IAChB,OAAO;KAET,IAAM,IAAQ,EAAK,QAAQ,CAAG;KAC9B,IAAI,KAAS,QAAQ,EAAM,KAAK,MAAM,IACpC,OAAO,EAAE,iCAAiC;KAE5C,IAAM,IAAS;MACb,MAAM;MACN,UAAU,EAAK;MACf;KACF;KACA,OACE,kBAAC,GAAD;MAA8B;MAC3B,UAAA;KACmB,CAAA;IAE1B;IACA,KAAK,uBAAuB;KAC1B,IAAM,IAAQ,EAAK,MAAM,CAAG;KAI5B,OAHI,KAAS,QAAQ,OAAO,CAAK,CAAC,CAAC,KAAK,MAAM,KACrC,IAGP,kBAAC,GAAD;MACS;MACP,WAAW,EAAK,YAAY,CAAG,KAAK,KAAA;MACpC,cAAc,EAAK;MACnB,WAAW,EAAE,qBAAqB;KACnC,CAAA;IAEL;IACA,KAAK,UAAU;KACb,IAAM,IAAW,EAAK,OAAO,CAAG;KAIhC,OAHI,KAAY,QAAQ,MAAa,KAC5B,IAEF,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA;IACvB;IACA,SACE,OAAO;GAEX;EACF;CACF,EACD;AACH"}
1
+ {"version":3,"file":"buildDataTableColumns.js","names":[],"sources":["../../../../../src/components/backoffice/columns/buildDataTableColumns.tsx"],"sourcesContent":["import { BACKOFFICE_DATE_TIME_OPTIONS } from '@plumile/backoffice-core/constants.js';\nimport type {\n BackofficeColumnSpec,\n BackofficeFieldSize,\n BackofficeListColumnVisibility,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type { TFunction } from 'i18next';\nimport Link from '@plumile/router/routing/Link.js';\nimport {\n FormattedDate,\n TechnicalIdentifierValue,\n type DataTableBreakpoint,\n type ResponsiveRecordListColumn,\n} from '@plumile/ui';\nimport { Tag } from '@plumile/ui/backoffice/atoms/tag/Tag.js';\n\nimport { BackofficeInlineLink } from '../links/BackofficeInlineLink.js';\nimport type { BackofficeLinkTarget } from '../links/types.js';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst resolveTextValue = (\n value: string | number | null,\n fallback: string,\n): string => {\n if (value == null) {\n return fallback;\n }\n if (typeof value === 'string' && value.trim() === '') {\n return fallback;\n }\n return String(value);\n};\n\nexport type BuildDataTableColumnsOptions = {\n tApp: TFunction;\n t: TFunction;\n};\n\nexport type BackofficeSizedDataTableColumn<Row> =\n ResponsiveRecordListColumn<Row> & {\n size: BackofficeFieldSize;\n };\n\nconst resolveMobileRole = <Row,>(\n column: BackofficeColumnSpec<Row>,\n): ResponsiveRecordListColumn<Row>['mobileRole'] => {\n // JavaScript callers can bypass the required TypeScript contract.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const role = column.visibility?.mobile;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Untyped callers.\n if (role == null) {\n throw new Error(\n `[buildDataTableColumns] column \"${column.key}\" must declare visibility.mobile.`,\n );\n }\n return role;\n};\n\nconst resolveBreakpoint = (\n value: BackofficeListColumnVisibility['minVisibleAt'] | undefined,\n): DataTableBreakpoint | undefined => {\n if (\n value === 'sm' ||\n value === 'md' ||\n value === 'lg' ||\n value === 'xl' ||\n value === '2xl'\n ) {\n return value;\n }\n return undefined;\n};\n\n/**\n *\n */\nexport function buildDataTableColumns<Row>(\n columns: readonly BackofficeColumnSpec<Row>[],\n options: BuildDataTableColumnsOptions,\n): readonly BackofficeSizedDataTableColumn<Row>[] {\n const { tApp, t } = options;\n const fallback = t('common.notAvailable');\n const filteredColumns = columns.filter((column) => {\n return column.key !== 'id';\n });\n\n return filteredColumns.map((column) => {\n const mobileRole = resolveMobileRole(column);\n return {\n id: column.key,\n header: resolveLabel(column.header, tApp),\n size: column.size,\n isPrimary: column.visibility.priority === 'primary',\n priority: column.visibility.priority,\n align: column.visibility.align,\n mobileRole,\n minVisibleAt: resolveBreakpoint(column.visibility.minVisibleAt),\n cell: (row) => {\n const { cell } = column;\n switch (cell.type) {\n case 'text': {\n return resolveTextValue(cell.value(row), fallback);\n }\n case 'link': {\n const value = cell.value(row);\n if (\n value == null ||\n (typeof value === 'string' && value.trim() === '')\n ) {\n return fallback;\n }\n return (\n <Link to={cell.to(row)} preloadOnHover=\"code\">\n {value}\n </Link>\n );\n }\n case 'badge': {\n const value = cell.value(row);\n if (value == null || value.trim() === '') {\n return fallback;\n }\n let { tone } = cell;\n if (typeof tone === 'function') {\n tone = tone(row);\n }\n return <Tag tone={tone}>{value}</Tag>;\n }\n case 'dateTime': {\n const value = cell.value(row);\n return (\n <FormattedDate\n value={value}\n fallback={fallback}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n />\n );\n }\n case 'entityRef': {\n const id = cell.value(row);\n if (id.trim() === '') {\n return fallback;\n }\n const label = cell.label?.(row);\n if (label == null || label.trim() === '') {\n return t('filters.placeholders.unresolved');\n }\n const target = {\n kind: 'entity-detail',\n entityId: cell.entity,\n id,\n } as BackofficeLinkTarget;\n return (\n <BackofficeInlineLink target={target}>\n {label}\n </BackofficeInlineLink>\n );\n }\n case 'technicalIdentifier': {\n const value = cell.value(row);\n if (value == null || String(value).trim() === '') {\n return fallback;\n }\n return (\n <TechnicalIdentifierValue\n value={value}\n copyValue={cell.copyValue?.(row) ?? undefined}\n abbreviation={cell.abbreviation}\n copyLabel={t('common.actions.copy')}\n />\n );\n }\n case 'custom': {\n const rendered = cell.render(row);\n if (rendered == null || rendered === '') {\n return fallback;\n }\n return <>{rendered}</>;\n }\n default: {\n return fallback;\n }\n }\n },\n };\n });\n}\n"],"mappings":";;;;;;;AAoBA,IAAM,KAAgB,GAAkB,MAC/B,EAAM,CAAI,GAGb,KACJ,GACA,MAEI,KAAS,QAGT,OAAO,KAAU,YAAY,EAAM,KAAK,MAAM,KACzC,IAEF,OAAO,CAAK,GAaf,KACJ,MACkD;CAGlD,IAAM,IAAO,EAAO,YAAY;CAEhC,IAAI,KAAQ,MACV,MAAU,MACR,mCAAmC,EAAO,IAAI,kCAChD;CAEF,OAAO;AACT,GAEM,KACJ,MACoC;CACpC,IACE,MAAU,QACV,MAAU,QACV,MAAU,QACV,MAAU,QACV,MAAU,OAEV,OAAO;AAGX;AAKA,SAAgB,EACd,GACA,GACgD;CAChD,IAAM,EAAE,SAAM,SAAM,GACd,IAAW,EAAE,qBAAqB;CAKxC,OAJwB,EAAQ,QAAQ,MAC/B,EAAO,QAAQ,IAGjB,CAAA,CAAgB,KAAK,MAAW;EACrC,IAAM,IAAa,EAAkB,CAAM;EAC3C,OAAO;GACL,IAAI,EAAO;GACX,QAAQ,EAAa,EAAO,QAAQ,CAAI;GACxC,MAAM,EAAO;GACb,WAAW,EAAO,WAAW,aAAa;GAC1C,UAAU,EAAO,WAAW;GAC5B,OAAO,EAAO,WAAW;GACzB;GACA,cAAc,EAAkB,EAAO,WAAW,YAAY;GAC9D,OAAO,MAAQ;IACb,IAAM,EAAE,YAAS;IACjB,QAAQ,EAAK,MAAb;KACE,KAAK,QACH,OAAO,EAAiB,EAAK,MAAM,CAAG,GAAG,CAAQ;KAEnD,KAAK,QAAQ;MACX,IAAM,IAAQ,EAAK,MAAM,CAAG;MAO5B,OALE,KAAS,QACR,OAAO,KAAU,YAAY,EAAM,KAAK,MAAM,KAExC,IAGP,kBAAC,GAAD;OAAM,IAAI,EAAK,GAAG,CAAG;OAAG,gBAAe;OACpC,UAAA;MACG,CAAA;KAEV;KACA,KAAK,SAAS;MACZ,IAAM,IAAQ,EAAK,MAAM,CAAG;MAC5B,IAAI,KAAS,QAAQ,EAAM,KAAK,MAAM,IACpC,OAAO;MAET,IAAI,EAAE,YAAS;MAIf,OAHI,OAAO,KAAS,eAClB,IAAO,EAAK,CAAG,IAEV,kBAAC,GAAD;OAAW;OAAO,UAAA;MAAW,CAAA;KACtC;KACA,KAAK,YAAY;MACf,IAAM,IAAQ,EAAK,MAAM,CAAG;MAC5B,OACE,kBAAC,GAAD;OACS;OACG;OACV,SAAS;MACV,CAAA;KAEL;KACA,KAAK,aAAa;MAChB,IAAM,IAAK,EAAK,MAAM,CAAG;MACzB,IAAI,EAAG,KAAK,MAAM,IAChB,OAAO;MAET,IAAM,IAAQ,EAAK,QAAQ,CAAG;MAC9B,IAAI,KAAS,QAAQ,EAAM,KAAK,MAAM,IACpC,OAAO,EAAE,iCAAiC;MAE5C,IAAM,IAAS;OACb,MAAM;OACN,UAAU,EAAK;OACf;MACF;MACA,OACE,kBAAC,GAAD;OAA8B;OAC3B,UAAA;MACmB,CAAA;KAE1B;KACA,KAAK,uBAAuB;MAC1B,IAAM,IAAQ,EAAK,MAAM,CAAG;MAI5B,OAHI,KAAS,QAAQ,OAAO,CAAK,CAAC,CAAC,KAAK,MAAM,KACrC,IAGP,kBAAC,GAAD;OACS;OACP,WAAW,EAAK,YAAY,CAAG,KAAK,KAAA;OACpC,cAAc,EAAK;OACnB,WAAW,EAAE,qBAAqB;MACnC,CAAA;KAEL;KACA,KAAK,UAAU;MACb,IAAM,IAAW,EAAK,OAAO,CAAG;MAIhC,OAHI,KAAY,QAAQ,MAAa,KAC5B,IAEF,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA;KACvB;KACA,SACE,OAAO;IAEX;GACF;EACF;CACF,CAAC;AACH"}
@@ -24,19 +24,22 @@ var c = ({ title: c, rows: l, totals: u, emptyLabel: d, columnLabels: f }) => {
24
24
  density: "compact",
25
25
  minColumn: "180",
26
26
  children: u.map((e) => {
27
- let t = e.copyValue?.trim(), r = {
28
- ...t == null || t === "" ? { copyValue: void 0 } : {
29
- copyValue: t,
27
+ let t = {
28
+ ...e.copyValue == null || e.copyValue.trim() === "" ? {
29
+ value: e.value,
30
+ copyValue: void 0
31
+ } : {
32
+ value: e.value,
33
+ copyValue: e.copyValue.trim(),
30
34
  copyLabel: p("common.actions.copy"),
31
35
  copiedLabel: p("common.actions.copied")
32
36
  },
33
37
  label: e.label,
34
- value: e.value,
35
38
  hint: e.hint,
36
39
  tone: e.tone ?? "neutral",
37
40
  density: "compact"
38
41
  };
39
- return /* @__PURE__ */ a(n, { ...r }, e.id);
42
+ return /* @__PURE__ */ a(n, { ...t }, e.id);
40
43
  })
41
44
  }), l.length > 0 && /* @__PURE__ */ o("div", {
42
45
  className: "txvbqb5m1 txvbqb6rp",
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeUsageCostBreakdown.js","names":[],"sources":["../../../../../src/components/backoffice/detail/BackofficeUsageCostBreakdown.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport { BackofficeDetailSection } from '@plumile/ui/backoffice/molecules/backoffice_detail_section/BackofficeDetailSection.js';\nimport {\n MetricCard,\n type MetricCardProps,\n type MetricTone,\n MetricTileGroup,\n} from '@plumile/ui';\nimport { cx } from '@plumile/ui/theme';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport * as styles from './backofficeUsageCostBreakdown.css.js';\n\nexport type BackofficeMoneyValue = {\n readonly amount: string | number;\n readonly currency: string;\n};\n\nexport type BackofficeUsageCostBreakdownRow = {\n readonly id: string;\n readonly label: string;\n readonly rawCost?: ReactNode;\n readonly markup?: ReactNode;\n readonly charged?: ReactNode;\n readonly eventsCount?: ReactNode;\n readonly quantity?: ReactNode;\n};\n\nexport type BackofficeUsageCostBreakdownTotal = {\n readonly id: string;\n readonly label: string;\n readonly value: ReactNode;\n readonly hint?: ReactNode;\n readonly tone?: MetricTone;\n readonly copyValue?: string;\n};\n\nexport type BackofficeUsageCostBreakdownProps = {\n readonly title: string;\n readonly rows: readonly BackofficeUsageCostBreakdownRow[];\n readonly totals?: readonly BackofficeUsageCostBreakdownTotal[];\n readonly emptyLabel?: string;\n readonly columnLabels?: {\n readonly name: string;\n readonly rawCost: string;\n readonly markup: string;\n readonly charged: string;\n readonly events: string;\n };\n};\n\nexport const BackofficeUsageCostBreakdown = ({\n title,\n rows,\n totals,\n emptyLabel,\n columnLabels,\n}: BackofficeUsageCostBreakdownProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const missing = t('common.notAvailable');\n const labels = columnLabels ?? {\n name: t('detail.columns.name'),\n rawCost: t('detail.columns.rawCost'),\n markup: t('detail.columns.markup'),\n charged: t('detail.columns.charged'),\n events: t('detail.columns.events'),\n };\n\n if (rows.length === 0 && (totals == null || totals.length === 0)) {\n return (\n <BackofficeDetailSection title={title}>\n {emptyLabel ?? missing}\n </BackofficeDetailSection>\n );\n }\n\n return (\n <BackofficeDetailSection title={title}>\n <div className={styles.content}>\n {totals != null && totals.length > 0 && (\n <MetricTileGroup density=\"compact\" minColumn=\"180\">\n {totals.map((total) => {\n const normalizedCopyValue = total.copyValue?.trim();\n const copyProps =\n normalizedCopyValue == null || normalizedCopyValue === ''\n ? { copyValue: undefined }\n : {\n copyValue: normalizedCopyValue,\n copyLabel: t('common.actions.copy'),\n copiedLabel: t('common.actions.copied'),\n };\n const metricProps = {\n ...copyProps,\n label: total.label,\n value: total.value,\n hint: total.hint,\n tone: total.tone ?? 'neutral',\n density: 'compact',\n } satisfies MetricCardProps;\n return <MetricCard key={total.id} {...metricProps} />;\n })}\n </MetricTileGroup>\n )}\n {rows.length > 0 && (\n <div className={styles.table}>\n <div className={styles.row}>\n <span className={styles.header}>{labels.name}</span>\n <span className={styles.header}>{labels.rawCost}</span>\n <span className={styles.header}>{labels.markup}</span>\n <span className={styles.header}>{labels.charged}</span>\n <span className={styles.header}>{labels.events}</span>\n </div>\n {rows.map((row) => {\n return (\n <div className={styles.row} key={row.id}>\n <span className={cx(styles.cell, styles.label)}>\n {row.label}\n </span>\n <span className={styles.cell}>{row.rawCost ?? missing}</span>\n <span className={styles.cell}>{row.markup ?? missing}</span>\n <span className={styles.cell}>{row.charged ?? missing}</span>\n <span className={styles.cell}>\n {row.eventsCount ?? row.quantity ?? missing}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </BackofficeDetailSection>\n );\n};\n\nexport default BackofficeUsageCostBreakdown;\n"],"mappings":";;;;;;;AAmDA,IAAa,KAAgC,EAC3C,UACA,SACA,WACA,eACA,sBACoD;CACpD,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAU,EAAE,qBAAqB,GACjC,IAAS,KAAgB;EAC7B,MAAM,EAAE,qBAAqB;EAC7B,SAAS,EAAE,wBAAwB;EACnC,QAAQ,EAAE,uBAAuB;EACjC,SAAS,EAAE,wBAAwB;EACnC,QAAQ,EAAE,uBAAuB;CACnC;CAUA,OARI,EAAK,WAAW,MAAM,KAAU,QAAQ,EAAO,WAAW,KAE1D,kBAAC,GAAD;EAAgC;EAC7B,UAAA,KAAc;CACQ,CAAA,IAK3B,kBAAC,GAAD;EAAgC;EAC9B,UAAA,kBAAC,OAAD;GAAK,WAAW;GAAhB,UAAA,CACG,KAAU,QAAQ,EAAO,SAAS,KACjC,kBAAC,GAAD;IAAiB,SAAQ;IAAU,WAAU;IAC1C,UAAA,EAAO,KAAK,MAAU;KACrB,IAAM,IAAsB,EAAM,WAAW,KAAK,GAS5C,IAAc;MAClB,GARA,KAAuB,QAAQ,MAAwB,KACnD,EAAE,WAAW,KAAA,EAAU,IACvB;OACE,WAAW;OACX,WAAW,EAAE,qBAAqB;OAClC,aAAa,EAAE,uBAAuB;MACxC;MAGJ,OAAO,EAAM;MACb,OAAO,EAAM;MACb,MAAM,EAAM;MACZ,MAAM,EAAM,QAAQ;MACpB,SAAS;KACX;KACA,OAAO,kBAAC,GAAD,EAA2B,GAAI,EAAc,GAA5B,EAAM,EAAsB;IACtD,CAAC;GACc,CAAA,GAElB,EAAK,SAAS,KACb,kBAAC,OAAD;IAAK,WAAW;IAAhB,UAAA,CACE,kBAAC,OAAD;KAAK,WAAW;KAAhB,UAAA;MACE,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAW,CAAA;MACnD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAc,CAAA;MACtD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAa,CAAA;MACrD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAc,CAAA;MACtD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAa,CAAA;KAClD;IACJ,CAAA,GAAA,EAAK,KAAK,MAEP,kBAAC,OAAD;KAAK,WAAW;KAAhB,UAAA;MACE,kBAAC,QAAD;OAAM,WAAW,EAAG,gCAAa,WAAY;OAC1C,UAAA,EAAI;MACD,CAAA;MACN,kBAAC,QAAD;OAAM,WAAW;OAAc,UAAA,EAAI,WAAW;MAAc,CAAA;MAC5D,kBAAC,QAAD;OAAM,WAAW;OAAc,UAAA,EAAI,UAAU;MAAc,CAAA;MAC3D,kBAAC,QAAD;OAAM,WAAW;OAAc,UAAA,EAAI,WAAW;MAAc,CAAA;MAC5D,kBAAC,QAAD;OAAM,WAAW;OACd,UAAA,EAAI,eAAe,EAAI,YAAY;MAChC,CAAA;KACH;IAV4B,GAAA,EAAI,EAUhC,CAER,CACE;GAEJ,CAAA,CAAA;;CACkB,CAAA;AAE7B"}
1
+ {"version":3,"file":"BackofficeUsageCostBreakdown.js","names":[],"sources":["../../../../../src/components/backoffice/detail/BackofficeUsageCostBreakdown.tsx"],"sourcesContent":["import { type JSX, type ReactNode } from 'react';\nimport { BackofficeDetailSection } from '@plumile/ui/backoffice/molecules/backoffice_detail_section/BackofficeDetailSection.js';\nimport {\n MetricCard,\n type MetricCardProps,\n type MetricTone,\n type UiText,\n MetricTileGroup,\n} from '@plumile/ui';\nimport { cx } from '@plumile/ui/theme';\n\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\nimport * as styles from './backofficeUsageCostBreakdown.css.js';\n\nexport type BackofficeMoneyValue = {\n readonly amount: string | number;\n readonly currency: string;\n};\n\nexport type BackofficeUsageCostBreakdownRow = {\n readonly id: string;\n readonly label: string;\n readonly rawCost?: ReactNode;\n readonly markup?: ReactNode;\n readonly charged?: ReactNode;\n readonly eventsCount?: ReactNode;\n readonly quantity?: ReactNode;\n};\n\nexport type BackofficeUsageCostBreakdownTotal = {\n readonly id: string;\n readonly label: string;\n readonly hint?: ReactNode;\n readonly tone?: MetricTone;\n} & (\n | { readonly copyValue?: undefined; readonly value: ReactNode }\n | { readonly copyValue: string; readonly value: UiText }\n);\n\nexport type BackofficeUsageCostBreakdownProps = {\n readonly title: string;\n readonly rows: readonly BackofficeUsageCostBreakdownRow[];\n readonly totals?: readonly BackofficeUsageCostBreakdownTotal[];\n readonly emptyLabel?: string;\n readonly columnLabels?: {\n readonly name: string;\n readonly rawCost: string;\n readonly markup: string;\n readonly charged: string;\n readonly events: string;\n };\n};\n\nexport const BackofficeUsageCostBreakdown = ({\n title,\n rows,\n totals,\n emptyLabel,\n columnLabels,\n}: BackofficeUsageCostBreakdownProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const missing = t('common.notAvailable');\n const labels = columnLabels ?? {\n name: t('detail.columns.name'),\n rawCost: t('detail.columns.rawCost'),\n markup: t('detail.columns.markup'),\n charged: t('detail.columns.charged'),\n events: t('detail.columns.events'),\n };\n\n if (rows.length === 0 && (totals == null || totals.length === 0)) {\n return (\n <BackofficeDetailSection title={title}>\n {emptyLabel ?? missing}\n </BackofficeDetailSection>\n );\n }\n\n return (\n <BackofficeDetailSection title={title}>\n <div className={styles.content}>\n {totals != null && totals.length > 0 && (\n <MetricTileGroup density=\"compact\" minColumn=\"180\">\n {totals.map((total) => {\n const copyProps =\n total.copyValue == null || total.copyValue.trim() === ''\n ? { value: total.value, copyValue: undefined }\n : {\n value: total.value,\n copyValue: total.copyValue.trim(),\n copyLabel: t('common.actions.copy'),\n copiedLabel: t('common.actions.copied'),\n };\n const metricProps = {\n ...copyProps,\n label: total.label,\n hint: total.hint,\n tone: total.tone ?? 'neutral',\n density: 'compact',\n } satisfies MetricCardProps;\n return <MetricCard key={total.id} {...metricProps} />;\n })}\n </MetricTileGroup>\n )}\n {rows.length > 0 && (\n <div className={styles.table}>\n <div className={styles.row}>\n <span className={styles.header}>{labels.name}</span>\n <span className={styles.header}>{labels.rawCost}</span>\n <span className={styles.header}>{labels.markup}</span>\n <span className={styles.header}>{labels.charged}</span>\n <span className={styles.header}>{labels.events}</span>\n </div>\n {rows.map((row) => {\n return (\n <div className={styles.row} key={row.id}>\n <span className={cx(styles.cell, styles.label)}>\n {row.label}\n </span>\n <span className={styles.cell}>{row.rawCost ?? missing}</span>\n <span className={styles.cell}>{row.markup ?? missing}</span>\n <span className={styles.cell}>{row.charged ?? missing}</span>\n <span className={styles.cell}>\n {row.eventsCount ?? row.quantity ?? missing}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </BackofficeDetailSection>\n );\n};\n\nexport default BackofficeUsageCostBreakdown;\n"],"mappings":";;;;;;;AAqDA,IAAa,KAAgC,EAC3C,UACA,SACA,WACA,eACA,sBACoD;CACpD,IAAM,EAAE,SAAM,EAA8B,GACtC,IAAU,EAAE,qBAAqB,GACjC,IAAS,KAAgB;EAC7B,MAAM,EAAE,qBAAqB;EAC7B,SAAS,EAAE,wBAAwB;EACnC,QAAQ,EAAE,uBAAuB;EACjC,SAAS,EAAE,wBAAwB;EACnC,QAAQ,EAAE,uBAAuB;CACnC;CAUA,OARI,EAAK,WAAW,MAAM,KAAU,QAAQ,EAAO,WAAW,KAE1D,kBAAC,GAAD;EAAgC;EAC7B,UAAA,KAAc;CACQ,CAAA,IAK3B,kBAAC,GAAD;EAAgC;EAC9B,UAAA,kBAAC,OAAD;GAAK,WAAW;GAAhB,UAAA,CACG,KAAU,QAAQ,EAAO,SAAS,KACjC,kBAAC,GAAD;IAAiB,SAAQ;IAAU,WAAU;IAC1C,UAAA,EAAO,KAAK,MAAU;KAUrB,IAAM,IAAc;MAClB,GATA,EAAM,aAAa,QAAQ,EAAM,UAAU,KAAK,MAAM,KAClD;OAAE,OAAO,EAAM;OAAO,WAAW,KAAA;MAAU,IAC3C;OACE,OAAO,EAAM;OACb,WAAW,EAAM,UAAU,KAAK;OAChC,WAAW,EAAE,qBAAqB;OAClC,aAAa,EAAE,uBAAuB;MACxC;MAGJ,OAAO,EAAM;MACb,MAAM,EAAM;MACZ,MAAM,EAAM,QAAQ;MACpB,SAAS;KACX;KACA,OAAO,kBAAC,GAAD,EAA2B,GAAI,EAAc,GAA5B,EAAM,EAAsB;IACtD,CAAC;GACc,CAAA,GAElB,EAAK,SAAS,KACb,kBAAC,OAAD;IAAK,WAAW;IAAhB,UAAA,CACE,kBAAC,OAAD;KAAK,WAAW;KAAhB,UAAA;MACE,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAW,CAAA;MACnD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAc,CAAA;MACtD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAa,CAAA;MACrD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAc,CAAA;MACtD,kBAAC,QAAD;OAAM,WAAW;OAAgB,UAAA,EAAO;MAAa,CAAA;KAClD;IACJ,CAAA,GAAA,EAAK,KAAK,MAEP,kBAAC,OAAD;KAAK,WAAW;KAAhB,UAAA;MACE,kBAAC,QAAD;OAAM,WAAW,EAAG,gCAAa,WAAY;OAC1C,UAAA,EAAI;MACD,CAAA;MACN,kBAAC,QAAD;OAAM,WAAW;OAAc,UAAA,EAAI,WAAW;MAAc,CAAA;MAC5D,kBAAC,QAAD;OAAM,WAAW;OAAc,UAAA,EAAI,UAAU;MAAc,CAAA;MAC3D,kBAAC,QAAD;OAAM,WAAW;OAAc,UAAA,EAAI,WAAW;MAAc,CAAA;MAC5D,kBAAC,QAAD;OAAM,WAAW;OACd,UAAA,EAAI,eAAe,EAAI,YAAY;MAChC,CAAA;KACH;IAV4B,GAAA,EAAI,EAUhC,CAER,CACE;GAEJ,CAAA,CAAA;;CACkB,CAAA;AAE7B"}
@@ -7,24 +7,24 @@ import { useBackofficeDashboardConfig as a } from "../provider/useBackofficeLazy
7
7
  import { getWidgetLabel as o, resolveLabel as s } from "./BackofficeDashboardPage.helpers.js";
8
8
  import { loadingBody as c, tileBody as l, tileCount as u } from "./backofficeDashboardPage.css.js";
9
9
  import { Suspense as d, lazy as f, useMemo as p, useState as m } from "react";
10
- import { DashboardGrid as h, DashboardGridItem as g, DashboardPanel as _, DashboardQuickActions as v } from "@plumile/ui";
11
- import { jsx as y, jsxs as b } from "react/jsx-runtime";
12
- import { useTranslation as x } from "react-i18next";
13
- import { Spinner as S } from "@plumile/ui/backoffice/atoms/spinner/Spinner.js";
14
- import { BackofficeEmptyState as C } from "@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js";
15
- import { DetailPageTemplate as w } from "@plumile/ui/backoffice/templates/detail_page_template/DetailPageTemplate.js";
10
+ import { DashboardGrid as h, DashboardPanel as g, DashboardQuickActions as _ } from "@plumile/ui";
11
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
12
+ import { useTranslation as b } from "react-i18next";
13
+ import { Spinner as x } from "@plumile/ui/backoffice/atoms/spinner/Spinner.js";
14
+ import { BackofficeEmptyState as S } from "@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js";
15
+ import { DetailPageTemplate as C } from "@plumile/ui/backoffice/templates/detail_page_template/DetailPageTemplate.js";
16
16
  //#region src/pages/BackofficeDashboardPage.tsx
17
- var T = f(async () => ({ default: (await import("./BackofficeDashboardWidgetContent.js")).BackofficeDashboardWidgetContent })), E = {
17
+ var w = f(async () => ({ default: (await import("./BackofficeDashboardWidgetContent.js")).BackofficeDashboardWidgetContent })), T = {
18
18
  id: "24h",
19
19
  label: (e) => e("common.time.lastDay", "24 h"),
20
20
  durationMs: 864e5
21
- }, D = [
21
+ }, E = [
22
22
  {
23
23
  id: "1h",
24
24
  label: (e) => e("common.time.lastHour", "1 h"),
25
25
  durationMs: 36e5
26
26
  },
27
- E,
27
+ T,
28
28
  {
29
29
  id: "7d",
30
30
  label: (e) => e("common.time.lastSevenDays", "7 j"),
@@ -35,20 +35,20 @@ var T = f(async () => ({ default: (await import("./BackofficeDashboardWidgetCont
35
35
  label: (e) => e("common.time.lastThirtyDays", "30 j"),
36
36
  durationMs: 2592e6
37
37
  }
38
- ], O = () => {
38
+ ], D = () => {
39
39
  let { t } = e();
40
- return /* @__PURE__ */ y(C, { title: t("common.notAvailable") });
41
- }, k = () => {
40
+ return /* @__PURE__ */ v(S, { title: t("common.notAvailable") });
41
+ }, O = () => {
42
42
  let { t } = e();
43
- return /* @__PURE__ */ b("div", {
43
+ return /* @__PURE__ */ y("div", {
44
44
  className: c,
45
- children: [/* @__PURE__ */ y(S, { ariaLabel: t("common.loading") }), /* @__PURE__ */ y("span", { children: t("common.loading") })]
45
+ children: [/* @__PURE__ */ v(x, { ariaLabel: t("common.loading") }), /* @__PURE__ */ v("span", { children: t("common.loading") })]
46
46
  });
47
- }, A = (e) => e ?? "m", j = (e) => {
47
+ }, k = (e) => e ?? "m", A = (e) => {
48
48
  if (e.layout?.span != null) return e.layout.span;
49
- let t = A(e.size);
49
+ let t = k(e.size);
50
50
  return t === "s" ? 3 : t === "m" ? 4 : t === "l" ? 6 : t === "xl" ? 8 : 12;
51
- }, M = (e) => e.layout?.tabletSpan, N = (e) => e.windowPresets != null && e.windowPresets.length > 0 ? e.windowPresets : D, P = (e, t) => e.defaultWindowPresetId != null && t.some((t) => t.id === e.defaultWindowPresetId) ? e.defaultWindowPresetId : t[1]?.id ?? t[0]?.id ?? "24h", F = (e, t) => {
51
+ }, j = (e) => e.layout?.tabletSpan, M = (e) => e.windowPresets != null && e.windowPresets.length > 0 ? e.windowPresets : E, N = (e, t) => e.defaultWindowPresetId != null && t.some((t) => t.id === e.defaultWindowPresetId) ? e.defaultWindowPresetId : t[1]?.id ?? t[0]?.id ?? "24h", P = (e, t) => {
52
52
  let n = new Date(t), r = new Date(t - e.durationMs);
53
53
  return {
54
54
  id: e.id,
@@ -56,73 +56,75 @@ var T = f(async () => ({ default: (await import("./BackofficeDashboardWidgetCont
56
56
  from: r.toISOString(),
57
57
  to: n.toISOString()
58
58
  };
59
- }, I = ({ config: t }) => {
60
- let { t: r } = x(), { t: i } = e(), a = p(() => N(t), [t]), [c, l] = m(() => P(t, a)), [u, f] = m(() => Date.now()), v = s(t.title, r), b = t.subtitle == null ? void 0 : s(t.subtitle, r), S = { window: F(a.find((e) => e.id === c) ?? a[0] ?? E, u) }, C = (e) => {
59
+ }, F = ({ config: t }) => {
60
+ let { t: r } = b(), { t: i } = e(), a = p(() => M(t), [t]), [c, l] = m(() => N(t, a)), [u, f] = m(() => Date.now()), _ = s(t.title, r), y = t.subtitle == null ? void 0 : s(t.subtitle, r), x = { window: P(a.find((e) => e.id === c) ?? a[0] ?? T, u) }, S = (e) => {
61
61
  l(e), f(Date.now());
62
62
  };
63
- return /* @__PURE__ */ y(w, {
63
+ return /* @__PURE__ */ v(C, {
64
64
  header: {
65
- title: v,
66
- subtitle: b ?? i("dashboard.subtitle")
65
+ title: _,
66
+ subtitle: y ?? i("dashboard.subtitle")
67
67
  },
68
- children: /* @__PURE__ */ y(h, {
68
+ children: /* @__PURE__ */ v(h, {
69
69
  columns: 12,
70
- children: t.widgets.map((e) => {
70
+ items: t.widgets.map((e) => {
71
71
  let i = s(o(e, t), r);
72
- return /* @__PURE__ */ y(g, {
72
+ return {
73
+ key: e.id,
73
74
  minHeight: e.minHeight ?? "auto",
74
- span: j(e),
75
- tabletSpan: M(e),
76
- children: /* @__PURE__ */ y(n, {
77
- fallback: () => /* @__PURE__ */ y(_, {
75
+ span: A(e),
76
+ tabletSpan: j(e),
77
+ content: /* @__PURE__ */ v(n, {
78
+ fallback: () => /* @__PURE__ */ v(g, {
78
79
  title: i,
79
- children: /* @__PURE__ */ y(O, {})
80
+ children: /* @__PURE__ */ v(D, {})
80
81
  }),
81
- children: /* @__PURE__ */ y(d, {
82
- fallback: /* @__PURE__ */ y(_, {
82
+ children: /* @__PURE__ */ v(d, {
83
+ fallback: /* @__PURE__ */ v(g, {
83
84
  title: i,
84
- children: /* @__PURE__ */ y(k, {})
85
+ children: /* @__PURE__ */ v(O, {})
85
86
  }),
86
- children: /* @__PURE__ */ y(T, {
87
+ children: /* @__PURE__ */ v(w, {
87
88
  widget: e,
88
- context: S,
89
+ context: x,
89
90
  windowPresets: a,
90
91
  activeWindowPresetId: c,
91
- onWindowPresetChange: C
92
+ onWindowPresetChange: S
92
93
  })
93
94
  })
94
95
  })
95
- }, e.id);
96
+ };
96
97
  })
97
98
  })
98
99
  });
99
- }, L = ({ prepared: n }) => {
100
- let { t: o } = x(), { t: c } = e(), { entities: d } = t(), f = a(), p = n?.config ?? f, m = i(c);
100
+ }, I = ({ prepared: n }) => {
101
+ let { t: o } = b(), { t: c } = e(), { entities: d } = t(), f = a(), p = n?.config ?? f, m = i(c);
101
102
  if (p == null) {
102
103
  let e = Object.values(d).filter((e) => e.kind === "list-detail" && e.hasList).map((e) => ({
103
104
  config: e,
104
105
  label: s(e.label, o)
105
106
  })).sort((e, t) => e.label.localeCompare(t.label));
106
- return /* @__PURE__ */ y(r, {
107
+ return /* @__PURE__ */ v(r, {
107
108
  breadcrumb: m,
108
- children: /* @__PURE__ */ y(w, {
109
+ children: /* @__PURE__ */ v(C, {
109
110
  header: {
110
111
  title: c("dashboard.title"),
111
112
  subtitle: c("dashboard.subtitle")
112
113
  },
113
- children: /* @__PURE__ */ y(h, {
114
+ children: /* @__PURE__ */ v(h, {
114
115
  columns: 12,
115
- children: e.map(({ config: e, label: t }) => /* @__PURE__ */ y(g, {
116
+ items: e.map(({ config: e, label: t }) => ({
117
+ key: e.id,
116
118
  span: 4,
117
- children: /* @__PURE__ */ y(_, {
119
+ content: /* @__PURE__ */ v(g, {
118
120
  title: t,
119
- children: /* @__PURE__ */ b("div", {
121
+ children: /* @__PURE__ */ y("div", {
120
122
  className: l,
121
- children: [/* @__PURE__ */ y("div", {
123
+ children: [/* @__PURE__ */ v("div", {
122
124
  className: u,
123
125
  children: c("common.notAvailable")
124
- }), /* @__PURE__ */ y(v, {
125
- emptyState: /* @__PURE__ */ y(O, {}),
126
+ }), /* @__PURE__ */ v(_, {
127
+ emptyState: /* @__PURE__ */ v(D, {}),
126
128
  actions: [{
127
129
  id: e.id,
128
130
  href: e.routes.list,
@@ -131,17 +133,17 @@ var T = f(async () => ({ default: (await import("./BackofficeDashboardWidgetCont
131
133
  })]
132
134
  })
133
135
  })
134
- }, e.id))
136
+ }))
135
137
  })
136
138
  })
137
139
  });
138
140
  }
139
- return /* @__PURE__ */ y(r, {
141
+ return /* @__PURE__ */ v(r, {
140
142
  breadcrumb: m,
141
- children: /* @__PURE__ */ y(I, { config: p })
143
+ children: /* @__PURE__ */ v(F, { config: p })
142
144
  });
143
145
  };
144
146
  //#endregion
145
- export { L as BackofficeDashboardPage, L as default };
147
+ export { I as BackofficeDashboardPage, I as default };
146
148
 
147
149
  //# sourceMappingURL=BackofficeDashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeDashboardPage.js","names":[],"sources":["../../../src/pages/BackofficeDashboardPage.tsx"],"sourcesContent":["import { lazy, type JSX, Suspense, useMemo, useState } from 'react';\nimport type {\n BackofficeDashboardConfig,\n BackofficeDashboardContext,\n BackofficeDashboardWindowPreset,\n BackofficeDashboardWindowState,\n BackofficeDashboardWidget,\n BackofficeDashboardWidgetSpan,\n BackofficeDashboardWidgetTabletSpan,\n BackofficeDashboardWidgetSize,\n} from '@plumile/backoffice-core/types.js';\nimport { Spinner } from '@plumile/ui/backoffice/atoms/spinner/Spinner.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport { DetailPageTemplate } from '@plumile/ui/backoffice/templates/detail_page_template/DetailPageTemplate.js';\nimport {\n DashboardPanel,\n DashboardQuickActions,\n DashboardGrid,\n DashboardGridItem,\n} from '@plumile/ui';\nimport { useTranslation } from 'react-i18next';\n\nimport { BackofficeErrorBoundary } from '../components/backoffice/errors/BackofficeErrorBoundary.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeDashboardConfig } from '../provider/useBackofficeLazyValue.js';\nimport type { BackofficePreparedDashboardRoute } from '../router/createBackofficeRoutes.js';\nimport { BackofficeRightPageLayout } from '../components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js';\nimport { buildDashboardBreadcrumb } from '../components/backoffice/layout/breadcrumb/buildBreadcrumbs.js';\nimport {\n getWidgetLabel,\n resolveLabel,\n} from './BackofficeDashboardPage.helpers.js';\n\nimport * as styles from './backofficeDashboardPage.css.js';\n\nconst LazyBackofficeDashboardWidgetContent = lazy(async () => {\n const module = await import('./BackofficeDashboardWidgetContent.js');\n return {\n default: module.BackofficeDashboardWidgetContent,\n };\n});\n\nconst fallbackDashboardWindowPreset: BackofficeDashboardWindowPreset = {\n id: '24h',\n label: (t) => {\n return t('common.time.lastDay', '24 h');\n },\n durationMs: 24 * 60 * 60 * 1000,\n};\n\nconst defaultDashboardWindowPresets: readonly BackofficeDashboardWindowPreset[] =\n [\n {\n id: '1h',\n label: (t) => {\n return t('common.time.lastHour', '1 h');\n },\n durationMs: 60 * 60 * 1000,\n },\n fallbackDashboardWindowPreset,\n {\n id: '7d',\n label: (t) => {\n return t('common.time.lastSevenDays', '7 j');\n },\n durationMs: 7 * 24 * 60 * 60 * 1000,\n },\n {\n id: '30d',\n label: (t) => {\n return t('common.time.lastThirtyDays', '30 j');\n },\n durationMs: 30 * 24 * 60 * 60 * 1000,\n },\n ];\n\nconst DashboardUnavailableState = (): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n\n return <BackofficeEmptyState title={t('common.notAvailable')} />;\n};\n\nconst DashboardLoadingState = (): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n\n return (\n <div className={styles.loadingBody}>\n <Spinner ariaLabel={t('common.loading')} />\n <span>{t('common.loading')}</span>\n </div>\n );\n};\n\nconst resolveWidgetSize = (\n size: BackofficeDashboardWidgetSize | undefined,\n): BackofficeDashboardWidgetSize => {\n return size ?? 'm';\n};\n\nconst resolveWidgetSpan = (\n widget: BackofficeDashboardWidget,\n): BackofficeDashboardWidgetSpan => {\n if (widget.layout?.span != null) {\n return widget.layout.span;\n }\n\n const size = resolveWidgetSize(widget.size);\n if (size === 's') {\n return 3;\n }\n if (size === 'm') {\n return 4;\n }\n if (size === 'l') {\n return 6;\n }\n if (size === 'xl') {\n return 8;\n }\n return 12;\n};\n\nconst resolveWidgetTabletSpan = (\n widget: BackofficeDashboardWidget,\n): BackofficeDashboardWidgetTabletSpan | undefined => {\n return widget.layout?.tabletSpan;\n};\n\ntype DashboardContentProps = {\n config: BackofficeDashboardConfig;\n};\n\nconst resolveDashboardWindowPresets = (\n config: BackofficeDashboardConfig,\n): readonly BackofficeDashboardWindowPreset[] => {\n if (config.windowPresets != null && config.windowPresets.length > 0) {\n return config.windowPresets;\n }\n return defaultDashboardWindowPresets;\n};\n\nconst resolveDefaultDashboardWindowPresetId = (\n config: BackofficeDashboardConfig,\n presets: readonly BackofficeDashboardWindowPreset[],\n): string => {\n if (\n config.defaultWindowPresetId != null &&\n presets.some((preset) => {\n return preset.id === config.defaultWindowPresetId;\n })\n ) {\n return config.defaultWindowPresetId;\n }\n return presets[1]?.id ?? presets[0]?.id ?? '24h';\n};\n\nconst buildDashboardWindowState = (\n preset: BackofficeDashboardWindowPreset,\n nowMs: number,\n): BackofficeDashboardWindowState => {\n const to = new Date(nowMs);\n const from = new Date(nowMs - preset.durationMs);\n return {\n id: preset.id,\n label: preset.label,\n from: from.toISOString(),\n to: to.toISOString(),\n };\n};\n\nconst DashboardContent = ({ config }: DashboardContentProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const presets = useMemo(() => {\n return resolveDashboardWindowPresets(config);\n }, [config]);\n const [activeWindowPresetId, setActiveWindowPresetId] = useState(() => {\n return resolveDefaultDashboardWindowPresetId(config, presets);\n });\n const [windowNowMs, setWindowNowMs] = useState(() => {\n return Date.now();\n });\n\n const title = resolveLabel(config.title, tApp);\n const subtitle =\n config.subtitle != null ? resolveLabel(config.subtitle, tApp) : undefined;\n const activePreset =\n presets.find((preset) => {\n return preset.id === activeWindowPresetId;\n }) ??\n presets[0] ??\n fallbackDashboardWindowPreset;\n const dashboardContext: BackofficeDashboardContext = {\n window: buildDashboardWindowState(activePreset, windowNowMs),\n };\n const handleWindowPresetChange = (presetId: string): void => {\n setActiveWindowPresetId(presetId);\n setWindowNowMs(Date.now());\n };\n\n return (\n <DetailPageTemplate\n header={{\n title,\n subtitle: subtitle ?? t('dashboard.subtitle'),\n }}\n >\n <DashboardGrid columns={12}>\n {config.widgets.map((widget) => {\n const widgetTitle = resolveLabel(\n getWidgetLabel(widget, config),\n tApp,\n );\n return (\n <DashboardGridItem\n key={widget.id}\n minHeight={widget.minHeight ?? 'auto'}\n span={resolveWidgetSpan(widget)}\n tabletSpan={resolveWidgetTabletSpan(widget)}\n >\n <BackofficeErrorBoundary\n fallback={() => {\n return (\n <DashboardPanel title={widgetTitle}>\n <DashboardUnavailableState />\n </DashboardPanel>\n );\n }}\n >\n <Suspense\n fallback={\n <DashboardPanel title={widgetTitle}>\n <DashboardLoadingState />\n </DashboardPanel>\n }\n >\n <LazyBackofficeDashboardWidgetContent\n widget={widget}\n context={dashboardContext}\n windowPresets={presets}\n activeWindowPresetId={activeWindowPresetId}\n onWindowPresetChange={handleWindowPresetChange}\n />\n </Suspense>\n </BackofficeErrorBoundary>\n </DashboardGridItem>\n );\n })}\n </DashboardGrid>\n </DetailPageTemplate>\n );\n};\n\nexport type BackofficeDashboardPageProps = {\n prepared?: BackofficePreparedDashboardRoute | null;\n};\n\nexport const BackofficeDashboardPage = ({\n prepared,\n}: BackofficeDashboardPageProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { entities } = useBackofficeConfig();\n const rootDashboard = useBackofficeDashboardConfig();\n const dashboard = prepared?.config ?? rootDashboard;\n const breadcrumb = buildDashboardBreadcrumb(t);\n\n if (dashboard == null) {\n const items = Object.values(entities)\n .filter((config) => {\n return config.kind === 'list-detail' && config.hasList;\n })\n .map((config) => {\n return {\n config,\n label: resolveLabel(config.label, tApp),\n };\n })\n .sort((left, right) => {\n return left.label.localeCompare(right.label);\n });\n\n return (\n <BackofficeRightPageLayout breadcrumb={breadcrumb}>\n <DetailPageTemplate\n header={{\n title: t('dashboard.title'),\n subtitle: t('dashboard.subtitle'),\n }}\n >\n <DashboardGrid columns={12}>\n {items.map(({ config, label }) => {\n return (\n <DashboardGridItem key={config.id} span={4}>\n <DashboardPanel title={label}>\n <div className={styles.tileBody}>\n <div className={styles.tileCount}>\n {t('common.notAvailable')}\n </div>\n <DashboardQuickActions\n emptyState={<DashboardUnavailableState />}\n actions={[\n {\n id: config.id,\n href: config.routes.list,\n label: t('dashboard.actions.openList'),\n },\n ]}\n />\n </div>\n </DashboardPanel>\n </DashboardGridItem>\n );\n })}\n </DashboardGrid>\n </DetailPageTemplate>\n </BackofficeRightPageLayout>\n );\n }\n\n return (\n <BackofficeRightPageLayout breadcrumb={breadcrumb}>\n <DashboardContent config={dashboard} />\n </BackofficeRightPageLayout>\n );\n};\n\nexport default BackofficeDashboardPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BackofficeDashboardPage.js","names":[],"sources":["../../../src/pages/BackofficeDashboardPage.tsx"],"sourcesContent":["import { lazy, type JSX, Suspense, useMemo, useState } from 'react';\nimport type {\n BackofficeDashboardConfig,\n BackofficeDashboardContext,\n BackofficeDashboardWindowPreset,\n BackofficeDashboardWindowState,\n BackofficeDashboardWidget,\n BackofficeDashboardWidgetSpan,\n BackofficeDashboardWidgetTabletSpan,\n BackofficeDashboardWidgetSize,\n} from '@plumile/backoffice-core/types.js';\nimport { Spinner } from '@plumile/ui/backoffice/atoms/spinner/Spinner.js';\nimport { BackofficeEmptyState } from '@plumile/ui/backoffice/molecules/backoffice_empty_state/BackofficeEmptyState.js';\nimport { DetailPageTemplate } from '@plumile/ui/backoffice/templates/detail_page_template/DetailPageTemplate.js';\nimport {\n DashboardPanel,\n DashboardQuickActions,\n DashboardGrid,\n} from '@plumile/ui';\nimport { useTranslation } from 'react-i18next';\n\nimport { BackofficeErrorBoundary } from '../components/backoffice/errors/BackofficeErrorBoundary.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeDashboardConfig } from '../provider/useBackofficeLazyValue.js';\nimport type { BackofficePreparedDashboardRoute } from '../router/createBackofficeRoutes.js';\nimport { BackofficeRightPageLayout } from '../components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js';\nimport { buildDashboardBreadcrumb } from '../components/backoffice/layout/breadcrumb/buildBreadcrumbs.js';\nimport {\n getWidgetLabel,\n resolveLabel,\n} from './BackofficeDashboardPage.helpers.js';\n\nimport * as styles from './backofficeDashboardPage.css.js';\n\nconst LazyBackofficeDashboardWidgetContent = lazy(async () => {\n const module = await import('./BackofficeDashboardWidgetContent.js');\n return {\n default: module.BackofficeDashboardWidgetContent,\n };\n});\n\nconst fallbackDashboardWindowPreset: BackofficeDashboardWindowPreset = {\n id: '24h',\n label: (t) => {\n return t('common.time.lastDay', '24 h');\n },\n durationMs: 24 * 60 * 60 * 1000,\n};\n\nconst defaultDashboardWindowPresets: readonly BackofficeDashboardWindowPreset[] =\n [\n {\n id: '1h',\n label: (t) => {\n return t('common.time.lastHour', '1 h');\n },\n durationMs: 60 * 60 * 1000,\n },\n fallbackDashboardWindowPreset,\n {\n id: '7d',\n label: (t) => {\n return t('common.time.lastSevenDays', '7 j');\n },\n durationMs: 7 * 24 * 60 * 60 * 1000,\n },\n {\n id: '30d',\n label: (t) => {\n return t('common.time.lastThirtyDays', '30 j');\n },\n durationMs: 30 * 24 * 60 * 60 * 1000,\n },\n ];\n\nconst DashboardUnavailableState = (): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n\n return <BackofficeEmptyState title={t('common.notAvailable')} />;\n};\n\nconst DashboardLoadingState = (): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n\n return (\n <div className={styles.loadingBody}>\n <Spinner ariaLabel={t('common.loading')} />\n <span>{t('common.loading')}</span>\n </div>\n );\n};\n\nconst resolveWidgetSize = (\n size: BackofficeDashboardWidgetSize | undefined,\n): BackofficeDashboardWidgetSize => {\n return size ?? 'm';\n};\n\nconst resolveWidgetSpan = (\n widget: BackofficeDashboardWidget,\n): BackofficeDashboardWidgetSpan => {\n if (widget.layout?.span != null) {\n return widget.layout.span;\n }\n\n const size = resolveWidgetSize(widget.size);\n if (size === 's') {\n return 3;\n }\n if (size === 'm') {\n return 4;\n }\n if (size === 'l') {\n return 6;\n }\n if (size === 'xl') {\n return 8;\n }\n return 12;\n};\n\nconst resolveWidgetTabletSpan = (\n widget: BackofficeDashboardWidget,\n): BackofficeDashboardWidgetTabletSpan | undefined => {\n return widget.layout?.tabletSpan;\n};\n\ntype DashboardContentProps = {\n config: BackofficeDashboardConfig;\n};\n\nconst resolveDashboardWindowPresets = (\n config: BackofficeDashboardConfig,\n): readonly BackofficeDashboardWindowPreset[] => {\n if (config.windowPresets != null && config.windowPresets.length > 0) {\n return config.windowPresets;\n }\n return defaultDashboardWindowPresets;\n};\n\nconst resolveDefaultDashboardWindowPresetId = (\n config: BackofficeDashboardConfig,\n presets: readonly BackofficeDashboardWindowPreset[],\n): string => {\n if (\n config.defaultWindowPresetId != null &&\n presets.some((preset) => {\n return preset.id === config.defaultWindowPresetId;\n })\n ) {\n return config.defaultWindowPresetId;\n }\n return presets[1]?.id ?? presets[0]?.id ?? '24h';\n};\n\nconst buildDashboardWindowState = (\n preset: BackofficeDashboardWindowPreset,\n nowMs: number,\n): BackofficeDashboardWindowState => {\n const to = new Date(nowMs);\n const from = new Date(nowMs - preset.durationMs);\n return {\n id: preset.id,\n label: preset.label,\n from: from.toISOString(),\n to: to.toISOString(),\n };\n};\n\nconst DashboardContent = ({ config }: DashboardContentProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const presets = useMemo(() => {\n return resolveDashboardWindowPresets(config);\n }, [config]);\n const [activeWindowPresetId, setActiveWindowPresetId] = useState(() => {\n return resolveDefaultDashboardWindowPresetId(config, presets);\n });\n const [windowNowMs, setWindowNowMs] = useState(() => {\n return Date.now();\n });\n\n const title = resolveLabel(config.title, tApp);\n const subtitle =\n config.subtitle != null ? resolveLabel(config.subtitle, tApp) : undefined;\n const activePreset =\n presets.find((preset) => {\n return preset.id === activeWindowPresetId;\n }) ??\n presets[0] ??\n fallbackDashboardWindowPreset;\n const dashboardContext: BackofficeDashboardContext = {\n window: buildDashboardWindowState(activePreset, windowNowMs),\n };\n const handleWindowPresetChange = (presetId: string): void => {\n setActiveWindowPresetId(presetId);\n setWindowNowMs(Date.now());\n };\n\n return (\n <DetailPageTemplate\n header={{\n title,\n subtitle: subtitle ?? t('dashboard.subtitle'),\n }}\n >\n <DashboardGrid\n columns={12}\n items={config.widgets.map((widget) => {\n const widgetTitle = resolveLabel(\n getWidgetLabel(widget, config),\n tApp,\n );\n return {\n key: widget.id,\n minHeight: widget.minHeight ?? 'auto',\n span: resolveWidgetSpan(widget),\n tabletSpan: resolveWidgetTabletSpan(widget),\n content: (\n <BackofficeErrorBoundary\n fallback={() => {\n return (\n <DashboardPanel title={widgetTitle}>\n <DashboardUnavailableState />\n </DashboardPanel>\n );\n }}\n >\n <Suspense\n fallback={\n <DashboardPanel title={widgetTitle}>\n <DashboardLoadingState />\n </DashboardPanel>\n }\n >\n <LazyBackofficeDashboardWidgetContent\n widget={widget}\n context={dashboardContext}\n windowPresets={presets}\n activeWindowPresetId={activeWindowPresetId}\n onWindowPresetChange={handleWindowPresetChange}\n />\n </Suspense>\n </BackofficeErrorBoundary>\n ),\n };\n })}\n />\n </DetailPageTemplate>\n );\n};\n\nexport type BackofficeDashboardPageProps = {\n prepared?: BackofficePreparedDashboardRoute | null;\n};\n\nexport const BackofficeDashboardPage = ({\n prepared,\n}: BackofficeDashboardPageProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { entities } = useBackofficeConfig();\n const rootDashboard = useBackofficeDashboardConfig();\n const dashboard = prepared?.config ?? rootDashboard;\n const breadcrumb = buildDashboardBreadcrumb(t);\n\n if (dashboard == null) {\n const items = Object.values(entities)\n .filter((config) => {\n return config.kind === 'list-detail' && config.hasList;\n })\n .map((config) => {\n return {\n config,\n label: resolveLabel(config.label, tApp),\n };\n })\n .sort((left, right) => {\n return left.label.localeCompare(right.label);\n });\n\n return (\n <BackofficeRightPageLayout breadcrumb={breadcrumb}>\n <DetailPageTemplate\n header={{\n title: t('dashboard.title'),\n subtitle: t('dashboard.subtitle'),\n }}\n >\n <DashboardGrid\n columns={12}\n items={items.map(({ config, label }) => {\n return {\n key: config.id,\n span: 4,\n content: (\n <DashboardPanel title={label}>\n <div className={styles.tileBody}>\n <div className={styles.tileCount}>\n {t('common.notAvailable')}\n </div>\n <DashboardQuickActions\n emptyState={<DashboardUnavailableState />}\n actions={[\n {\n id: config.id,\n href: config.routes.list,\n label: t('dashboard.actions.openList'),\n },\n ]}\n />\n </div>\n </DashboardPanel>\n ),\n };\n })}\n />\n </DetailPageTemplate>\n </BackofficeRightPageLayout>\n );\n }\n\n return (\n <BackofficeRightPageLayout breadcrumb={breadcrumb}>\n <DashboardContent config={dashboard} />\n </BackofficeRightPageLayout>\n );\n};\n\nexport default BackofficeDashboardPage;\n"],"mappings":"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"}