@plumile/backoffice-react 0.1.84 → 0.1.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +113 -77
  2. package/lib/esm/{AcceptInvitationScreen-5-0EtE15.js → AcceptInvitationScreen-dnOvRx4Z.js} +2 -2
  3. package/lib/esm/{AcceptInvitationScreen-5-0EtE15.js.map → AcceptInvitationScreen-dnOvRx4Z.js.map} +1 -1
  4. package/lib/esm/{BackofficeAcceptInvitationPage-FPbn31YK.js → BackofficeAcceptInvitationPage-CGht2ka0.js} +3 -9
  5. package/lib/esm/{BackofficeAcceptInvitationPage-FPbn31YK.js.map → BackofficeAcceptInvitationPage-CGht2ka0.js.map} +1 -1
  6. package/lib/esm/{BackofficeDashboardPage-C7lIVeA1.js → BackofficeDashboardPage-h1OWb_rV.js} +31 -32
  7. package/lib/esm/BackofficeDashboardPage-h1OWb_rV.js.map +1 -0
  8. package/lib/esm/BackofficeEntityDetailPage-CIyGKwVP.js +1044 -0
  9. package/lib/esm/BackofficeEntityDetailPage-CIyGKwVP.js.map +1 -0
  10. package/lib/esm/BackofficeEntityListPage-DmZozSNk.js +402 -0
  11. package/lib/esm/BackofficeEntityListPage-DmZozSNk.js.map +1 -0
  12. package/lib/esm/{BackofficeLayoutPage-Da4y2B0i.js → BackofficeLayoutPage-DtFDn_nU.js} +2 -2
  13. package/lib/esm/BackofficeLayoutPage-DtFDn_nU.js.map +1 -0
  14. package/lib/esm/{BackofficeLoginPage-Dc61SyMV.js → BackofficeLoginPage-BvOPqbKO.js} +3 -8
  15. package/lib/esm/{BackofficeLoginPage-Dc61SyMV.js.map → BackofficeLoginPage-BvOPqbKO.js.map} +1 -1
  16. package/lib/esm/{BackofficePasswordResetCompletePage-CvoHqhBS.js → BackofficePasswordResetCompletePage-ZLhghfhC.js} +1 -2
  17. package/lib/esm/{BackofficePasswordResetCompletePage-CvoHqhBS.js.map → BackofficePasswordResetCompletePage-ZLhghfhC.js.map} +1 -1
  18. package/lib/esm/{BackofficePasswordResetRequestPage-DDNcCf3_.js → BackofficePasswordResetRequestPage-BLNHQD79.js} +1 -3
  19. package/lib/esm/{BackofficePasswordResetRequestPage-DDNcCf3_.js.map → BackofficePasswordResetRequestPage-BLNHQD79.js.map} +1 -1
  20. package/lib/esm/{BackofficeRightPageLayout-F8ipegrl.js → BackofficeRightPageLayout-DZQvIHnj.js} +2 -2
  21. package/lib/esm/{BackofficeRightPageLayout-F8ipegrl.js.map → BackofficeRightPageLayout-DZQvIHnj.js.map} +1 -1
  22. package/lib/esm/EntityIdPickerDialog-DbTnDU4v.js.map +1 -1
  23. package/lib/esm/backoffice-react.js +164 -167
  24. package/lib/esm/backoffice-react.js.map +1 -1
  25. package/lib/esm/{environment-BJeJTbIN.js → environment-BXoBq_6e.js} +72 -73
  26. package/lib/esm/environment-BXoBq_6e.js.map +1 -0
  27. package/lib/esm/{synchronizeAuthStatusQuery-Dr6AEFhi.js → synchronizeAuthStatusQuery-By_lNCnP.js} +2 -2
  28. package/lib/esm/{synchronizeAuthStatusQuery-Dr6AEFhi.js.map → synchronizeAuthStatusQuery-By_lNCnP.js.map} +1 -1
  29. package/lib/esm/{useAuth-CjdysxLB.js → useAuth-OVPPa9bO.js} +2 -2
  30. package/lib/esm/useAuth-OVPPa9bO.js.map +1 -0
  31. package/lib/esm/{useBackofficeAuth-BshabGXc.js → useBackofficeAuth-BvEoEqnB.js} +2 -2
  32. package/lib/esm/{useBackofficeAuth-BshabGXc.js.map → useBackofficeAuth-BvEoEqnB.js.map} +1 -1
  33. package/lib/types/hooks/useBackofficeSidebarPins.d.ts +4 -0
  34. package/lib/types/hooks/useBackofficeSidebarPins.d.ts.map +1 -1
  35. package/lib/types/i18n/createI18nInstance.d.ts +8 -0
  36. package/lib/types/i18n/createI18nInstance.d.ts.map +1 -1
  37. package/lib/types/i18n/mergeResourceLanguages.d.ts +4 -0
  38. package/lib/types/i18n/mergeResourceLanguages.d.ts.map +1 -1
  39. package/lib/types/modules/base64.d.ts.map +1 -1
  40. package/lib/types/pages/BackofficeDashboardPage.d.ts.map +1 -1
  41. package/lib/types/pages/BackofficeDashboardPage.helpers.d.ts +9 -0
  42. package/lib/types/pages/BackofficeDashboardPage.helpers.d.ts.map +1 -0
  43. package/lib/types/pages/BackofficeEntityDetailPage.d.ts.map +1 -1
  44. package/lib/types/pages/BackofficeEntityDetailPage.helpers.d.ts +14 -0
  45. package/lib/types/pages/BackofficeEntityDetailPage.helpers.d.ts.map +1 -0
  46. package/lib/types/pages/BackofficeEntityDetailPage.view-helpers.d.ts +150 -0
  47. package/lib/types/pages/BackofficeEntityDetailPage.view-helpers.d.ts.map +1 -0
  48. package/lib/types/pages/BackofficeEntityListPage.d.ts.map +1 -1
  49. package/lib/types/pages/BackofficeEntityListPage.helpers.d.ts +29 -0
  50. package/lib/types/pages/BackofficeEntityListPage.helpers.d.ts.map +1 -0
  51. package/lib/types/provider/entityRegistry.d.ts +5 -0
  52. package/lib/types/provider/entityRegistry.d.ts.map +1 -1
  53. package/lib/types/provider/useBackofficeEntityLoader.d.ts +5 -0
  54. package/lib/types/provider/useBackofficeEntityLoader.d.ts.map +1 -1
  55. package/lib/types/relay/envHelpers.d.ts +6 -0
  56. package/lib/types/relay/envHelpers.d.ts.map +1 -1
  57. package/lib/types/relay/environment.d.ts +26 -0
  58. package/lib/types/relay/environment.d.ts.map +1 -1
  59. package/lib/types/router/createBackofficeRoutes.d.ts +12 -1
  60. package/lib/types/router/createBackofficeRoutes.d.ts.map +1 -1
  61. package/package.json +12 -12
  62. package/lib/esm/BackofficeDashboardPage-C7lIVeA1.js.map +0 -1
  63. package/lib/esm/BackofficeEntityDetailPage-BljQmWsw.js +0 -991
  64. package/lib/esm/BackofficeEntityDetailPage-BljQmWsw.js.map +0 -1
  65. package/lib/esm/BackofficeEntityListPage-BneDsGo-.js +0 -385
  66. package/lib/esm/BackofficeEntityListPage-BneDsGo-.js.map +0 -1
  67. package/lib/esm/BackofficeLayoutPage-Da4y2B0i.js.map +0 -1
  68. package/lib/esm/environment-BJeJTbIN.js.map +0 -1
  69. package/lib/esm/useAuth-CjdysxLB.js.map +0 -1
package/README.md CHANGED
@@ -1,84 +1,122 @@
1
1
  # @plumile/backoffice-react
2
2
 
3
- React provider and pages for Plumile backoffice.
3
+ React provider, auth screens, routing scaffolds, and Relay helpers for
4
+ Plumile-style backoffice applications.
4
5
 
5
- ## Role
6
+ ## Status
6
7
 
7
- `@plumile/backoffice-react` is the optional React composition layer for
8
- data-driven backoffice applications.
8
+ Specialized public package. This package is best suited to teams building a
9
+ Plumile-style backoffice with entity manifests, Relay, and the shared UI layer.
9
10
 
10
- It builds on top of:
11
+ ## Purpose
11
12
 
12
- - `@plumile/ui` for visual components
13
- - `@plumile/backoffice-core` for manifests, facets and shared types
13
+ `@plumile/backoffice-react` is the React integration layer on top of:
14
14
 
15
- It should contain:
15
+ - `@plumile/backoffice-core` for manifests, facets, and shared types
16
+ - `@plumile/ui` for the visual system
17
+ - `@plumile/router` for internal routing and instrumentation
16
18
 
17
- - providers
18
- - auth flows and generic auth pages
19
+ It contains:
20
+
21
+ - `BackofficeProvider`
22
+ - auth screens and login flow helpers
19
23
  - routing and page scaffolds
20
24
  - backoffice hooks
21
- - Relay integration helpers
22
- - entity registry and facet loading
25
+ - Relay environment and mutation helpers
26
+ - entity loading helpers and related UI building blocks
23
27
 
24
- It should not become:
28
+ It does not try to become:
25
29
 
26
- - a second UI component library
27
- - a container for product-specific business components
28
- - a replacement for app-level domain code
30
+ - a generic React application framework
31
+ - a second standalone component library
32
+ - a container for product-specific business logic
29
33
 
30
- ## Instrumentation
34
+ ## Installation
31
35
 
32
- `BackofficeProvider` forwards router instrumentations to the internal
33
- `createRouter(...)` call.
36
+ ```bash
37
+ npm install @plumile/backoffice-react
38
+ ```
34
39
 
35
- Use this when you want to expose:
40
+ Peer dependencies:
36
41
 
37
- - the Plumile Router DevTools bridge
38
- - Performance Timeline marks and measures in Chrome DevTools
42
+ ```bash
43
+ npm install react react-dom react-i18next i18next react-relay relay-runtime
44
+ ```
39
45
 
40
- Example:
46
+ This package also depends on the Plumile router, UI, and backoffice-core
47
+ packages.
41
48
 
42
- ```ts
43
- import {
44
- createDevtoolsBridgeInstrumentation,
45
- createPerformanceTimelineInstrumentation,
46
- } from '@plumile/router';
47
- import { BackofficeProvider } from '@plumile/backoffice-react';
49
+ ## Main Public Surface
48
50
 
49
- const instrumentations = [
50
- createDevtoolsBridgeInstrumentation(),
51
- createPerformanceTimelineInstrumentation(),
52
- ];
51
+ ### Provider and configuration
53
52
 
54
- <BackofficeProvider
55
- entityManifest={entityManifest}
56
- auth={auth}
57
- graphql={graphql}
58
- instrumentations={instrumentations}
59
- />;
60
- ```
53
+ - `BackofficeProvider`
54
+ - `useBackofficeConfig`
55
+ - `createBackofficeLazyValue`
56
+ - config types such as `BackofficeAuthConfig` and `BackofficeGraphQLConfig`
61
57
 
62
- This remains optional. If `instrumentations` is omitted, backoffice routing
63
- behaves exactly as before.
58
+ ### Auth and session flows
64
59
 
65
- ## Examples
60
+ - `LoginFlow`
61
+ - `AcceptInvitationScreen`
62
+ - `PasswordResetRequestScreen`
63
+ - `PasswordResetCompleteScreen`
64
+ - `VerifyEmailScreen`
65
+ - `createUseAuth`
66
66
 
67
- ### Performance Timeline only
67
+ ### Hooks and backoffice helpers
68
68
 
69
- ```ts
70
- import { createPerformanceTimelineInstrumentation } from '@plumile/router';
69
+ - `useBackofficeListUrlState`
70
+ - `useConditionalSubscription`
71
+ - `useCopyToClipboard`
72
+ - `useRefetchNeededReload`
73
+
74
+ ### Relay and mutation helpers
75
+
76
+ - `RelayProvider`
77
+ - `configureRelayEnvironment`
78
+ - `getEnvironment`
79
+ - `resetRelayStore`
80
+ - `resolveMutationOutcome`
81
+ - `resolveAgentStartOutcome`
82
+ - `requireField`
83
+ - `requireLinkedRecordId`
84
+
85
+ ### Backoffice-specific UI scaffolds
86
+
87
+ - `BackofficeOverviewLayout`
88
+ - `BackofficeTabbedDetailShell`
89
+ - detail and filter components
90
+ - picker and layout helpers
91
+
92
+ For the complete export list, see [`src/index.ts`](./src/index.ts).
93
+
94
+ ## Quick Start
95
+
96
+ ```tsx
71
97
  import { BackofficeProvider } from '@plumile/backoffice-react';
72
98
 
73
- <BackofficeProvider
74
- entityManifest={entityManifest}
75
- auth={auth}
76
- graphql={graphql}
77
- instrumentations={[createPerformanceTimelineInstrumentation()]}
78
- />;
99
+ export function App(): JSX.Element {
100
+ return (
101
+ <BackofficeProvider
102
+ entityManifest={entityManifest}
103
+ auth={auth}
104
+ graphql={graphql}
105
+ />
106
+ );
107
+ }
79
108
  ```
80
109
 
81
- ### DevTools bridge + Performance Timeline in development
110
+ ## Instrumentation
111
+
112
+ `BackofficeProvider` forwards router instrumentations to the internal
113
+ `createRouter(...)` call. This is useful when you want to expose:
114
+
115
+ - the Plumile Router DevTools bridge
116
+ - Performance Timeline marks and measures in Chrome DevTools
117
+ - custom router instrumentation for local diagnostics
118
+
119
+ Example:
82
120
 
83
121
  ```ts
84
122
  import {
@@ -87,12 +125,10 @@ import {
87
125
  } from '@plumile/router';
88
126
  import { BackofficeProvider } from '@plumile/backoffice-react';
89
127
 
90
- const instrumentations = [];
91
-
92
- if (import.meta.env.DEV) {
93
- instrumentations.push(createDevtoolsBridgeInstrumentation());
94
- instrumentations.push(createPerformanceTimelineInstrumentation());
95
- }
128
+ const instrumentations = [
129
+ createDevtoolsBridgeInstrumentation(),
130
+ createPerformanceTimelineInstrumentation(),
131
+ ];
96
132
 
97
133
  <BackofficeProvider
98
134
  entityManifest={entityManifest}
@@ -102,25 +138,25 @@ if (import.meta.env.DEV) {
102
138
  />;
103
139
  ```
104
140
 
105
- ### With additional custom instrumentation
141
+ If `instrumentations` is omitted, routing still works normally.
106
142
 
107
- ```ts
108
- import {
109
- createConsoleLoggerInstrumentation,
110
- createDevtoolsBridgeInstrumentation,
111
- createPerformanceTimelineInstrumentation,
112
- } from '@plumile/router';
143
+ ## Validation Notes
113
144
 
114
- const instrumentations = [
115
- createDevtoolsBridgeInstrumentation(),
116
- createPerformanceTimelineInstrumentation(),
117
- createConsoleLoggerInstrumentation({ label: 'backoffice-router' }),
118
- ];
119
- ```
145
+ - public helpers that are pure or mostly pure should have focused unit tests
146
+ - provider behavior should remain covered by React tests
147
+ - package documentation should describe the main composition flows rather than
148
+ every low-level implementation detail
149
+
150
+ ## Limitations
151
+
152
+ - this package assumes Plumile entity manifests and backoffice routing concepts
153
+ - Relay integration is built around Plumile conventions, not every possible
154
+ Relay application architecture
155
+ - consumers should keep domain-specific business components outside this package
120
156
 
121
- In practice, this is useful to inspect:
157
+ ## Related Docs
122
158
 
123
- - route navigations
124
- - route preloads
125
- - route `prepare` durations
126
- - backoffice page transitions driven by the internal router
159
+ - [Backoffice Core README](../backoffice-core/README.md)
160
+ - [UI README](../ui/README.md)
161
+ - [Router README](../router/README.md)
162
+ - [Documentation Index](../../docs/index.md)
@@ -1,5 +1,5 @@
1
1
  import { a as e, d as t, f as n, s as r } from "./loginPage.css-CBJ1Ozm5.js";
2
- import { o as i } from "./useAuth-CjdysxLB.js";
2
+ import { o as i } from "./useAuth-OVPPa9bO.js";
3
3
  import { t as a } from "./AuthPanel-DiHejPoq.js";
4
4
  import { useCallback as o, useMemo as s, useState as c } from "react";
5
5
  import { AuthLayout as l, Button as u, FormError as d, FormField as f } from "@plumile/ui";
@@ -113,4 +113,4 @@ var h = ({ auth: h, onSuccessRedirect: g, onBackToLogin: _, token: v }) => {
113
113
  //#endregion
114
114
  export { h as t };
115
115
 
116
- //# sourceMappingURL=AcceptInvitationScreen-5-0EtE15.js.map
116
+ //# sourceMappingURL=AcceptInvitationScreen-dnOvRx4Z.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AcceptInvitationScreen-5-0EtE15.js","names":[],"sources":["../../src/auth/pages/AcceptInvitationScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\nimport { MfaChallengeForm } from '../login/MfaChallengeForm.js';\nimport AuthPanel from '../login/AuthPanel.js';\nimport * as styles from '../login/loginPage.css.js';\n\ntype AcceptanceState = 'pending' | 'mfa' | 'completed' | 'error' | 'idle';\n\ntype Props = {\n auth: UseAuthReturn;\n onSuccessRedirect: () => void;\n onBackToLogin: () => void;\n token?: string;\n};\n\nexport const AcceptInvitationScreen = ({\n auth,\n onSuccessRedirect,\n onBackToLogin,\n token,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const { acceptInvitation } = auth;\n const [status, setStatus] = useState<AcceptanceState>('idle');\n const [password, setPassword] = useState('');\n const [passwordConfirmation, setPasswordConfirmation] = useState('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (resolvedToken === '') {\n setErrorMessage(t('auth.acceptInvitation.errors.missingToken'));\n setStatus('error');\n return;\n }\n\n if (password !== passwordConfirmation) {\n setErrorMessage(t('auth.acceptInvitation.errors.passwordMismatch'));\n setStatus('error');\n return;\n }\n\n setStatus('pending');\n setErrorMessage(null);\n setIsSubmitting(true);\n\n // eslint-disable-next-line no-void\n void acceptInvitation({\n token: resolvedToken,\n password,\n passwordConfirmation,\n })\n .then((result) => {\n if (result === 'mfa-required') {\n setStatus('mfa');\n return;\n }\n setStatus('completed');\n onSuccessRedirect();\n })\n .catch((error) => {\n setStatus('error');\n if (error instanceof Error) {\n setErrorMessage(error.message);\n } else if (typeof error === 'string') {\n setErrorMessage(error);\n } else {\n setErrorMessage(t('auth.acceptInvitation.errors.default'));\n }\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [\n acceptInvitation,\n onSuccessRedirect,\n password,\n passwordConfirmation,\n resolvedToken,\n t,\n ],\n );\n\n const handleMfaSuccess = useCallback(() => {\n setStatus('completed');\n onSuccessRedirect();\n }, [onSuccessRedirect]);\n\n const handleRetry = useCallback(() => {\n setStatus('idle');\n setErrorMessage(null);\n setIsSubmitting(false);\n }, []);\n\n if (status === 'mfa') {\n return (\n <AuthLayout\n title={t('auth.acceptInvitation.mfaTitle')}\n subtitle={t('auth.acceptInvitation.mfaSubtitle')}\n >\n <MfaChallengeForm\n auth={auth}\n onSuccess={handleMfaSuccess}\n onBack={() => {\n auth.reset();\n handleRetry();\n }}\n />\n </AuthLayout>\n );\n }\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.acceptInvitation.status.success')}\n </p>\n </div>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.acceptInvitation.subtitle')}>\n <form className={styles.formSurface} onSubmit={handleSubmit} noValidate>\n {errorMessage != null ? <FormError>{errorMessage}</FormError> : null}\n <FormField\n label={t('auth.acceptInvitation.form.passwordLabel')}\n name=\"password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.passwordPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.acceptInvitation.form.confirmLabel')}\n name=\"password-confirmation\"\n type=\"password\"\n value={passwordConfirmation}\n onChange={(event) => {\n setPasswordConfirmation(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.confirmPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {status === 'pending'\n ? t('auth.acceptInvitation.status.workingButton')\n : t('auth.acceptInvitation.form.submit')}\n </Button>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.acceptInvitation.actions.backToLogin')}\n </Button>\n </form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.acceptInvitation.title')}>{content}</AuthLayout>\n );\n};\n"],"mappings":";;;;;;;AA0BA,IAAa,KAA0B,EACrC,SACA,sBACA,kBACA,eACwB;CACxB,IAAM,EAAE,SAAM,GAAsB,EAC9B,EAAE,wBAAqB,GACvB,CAAC,GAAQ,KAAa,EAA0B,OAAO,EACvD,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAsB,KAA2B,EAAS,GAAG,EAC9D,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAc,KAAmB,EAAwB,KAAK,EAE/D,IAAgB,QAChB,MAGA,OAAO,SAAW,MACb,KAEM,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAC5C,IAAI,QAAQ,IAAI,KAC7B,CAAC,EAAM,CAAC,EAEL,IAAe,GAClB,MAAsC;AAErC,MADA,EAAM,gBAAgB,EAClB,MAAkB,IAAI;AAExB,GADA,EAAgB,EAAE,4CAA4C,CAAC,EAC/D,EAAU,QAAQ;AAClB;;AAGF,MAAI,MAAa,GAAsB;AAErC,GADA,EAAgB,EAAE,gDAAgD,CAAC,EACnE,EAAU,QAAQ;AAClB;;AAQG,EALL,EAAU,UAAU,EACpB,EAAgB,KAAK,EACrB,EAAgB,GAAK,EAGhB,EAAiB;GACpB,OAAO;GACP;GACA;GACD,CAAC,CACC,MAAM,MAAW;AAChB,OAAI,MAAW,gBAAgB;AAC7B,MAAU,MAAM;AAChB;;AAGF,GADA,EAAU,YAAY,EACtB,GAAmB;IACnB,CACD,OAAO,MAAU;AAEhB,GADA,EAAU,QAAQ,EACd,aAAiB,QACnB,EAAgB,EAAM,QAAQ,GAE9B,EADS,OAAO,KAAU,WACV,IAEA,EAAE,uCAAuC,CAAC;IAE5D,CACD,cAAc;AACb,KAAgB,GAAM;IACtB;IAEN;EACE;EACA;EACA;EACA;EACA;EACA;EACD,CACF,EAEK,IAAmB,QAAkB;AAEzC,EADA,EAAU,YAAY,EACtB,GAAmB;IAClB,CAAC,EAAkB,CAAC,EAEjB,IAAc,QAAkB;AAGpC,EAFA,EAAU,OAAO,EACjB,EAAgB,KAAK,EACrB,EAAgB,GAAM;IACrB,EAAE,CAAC;AAEN,KAAI,MAAW,MACb,QACE,kBAAC,GAAD;EACE,OAAO,EAAE,iCAAiC;EAC1C,UAAU,EAAE,oCAAoC;YAEhD,kBAAC,GAAD;GACQ;GACN,WAAW;GACX,cAAc;AAEZ,IADA,EAAK,OAAO,EACZ,GAAa;;GAEf,CAAA;EACS,CAAA;CAIjB,IAAI;AA2DJ,QA1DA,AASE,IATE,MAAW,cAEX,kBAAC,OAAD;EAAK,WAAW;YACd,kBAAC,KAAD;GAAG,WAAW;aACX,EAAE,uCAAuC;GACxC,CAAA;EACA,CAAA,GAIN,kBAAC,GAAD;EAAW,aAAa,EAAE,iCAAiC;YACzD,kBAAC,QAAD;GAAM,WAAW;GAAoB,UAAU;GAAc,YAAA;aAA7D;IACG,KAAgB,OAA+C,OAAxC,kBAAC,GAAD,EAAA,UAAY,GAAyB,CAAA;IAC7D,kBAAC,GAAD;KACE,OAAO,EAAE,2CAA2C;KACpD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAGnB,MAFA,EAAY,EAAM,OAAO,MAAM,EAC/B,EAAgB,KAAK,EACjB,MAAW,WACb,EAAU,OAAO;;KAGrB,aAAa,EAAE,iDAAiD;KAChE,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KACE,OAAO,EAAE,0CAA0C;KACnD,MAAK;KACL,MAAK;KACL,OAAO;KACP,WAAW,MAAU;AAGnB,MAFA,EAAwB,EAAM,OAAO,MAAM,EAC3C,EAAgB,KAAK,EACjB,MAAW,WACb,EAAU,OAAO;;KAGrB,aAAa,EAAE,gDAAgD;KAC/D,cAAa;KACb,UAAA;KACA,CAAA;IACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,WAAW;eAE3B,EADH,MAAW,YACN,+CACA,oCAAoC;KACnC,CAAA;IACT,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAY,SAAS;eAChD,EAAE,4CAA4C;KACxC,CAAA;IACJ;;EACG,CAAA,EAKd,kBAAC,GAAD;EAAY,OAAO,EAAE,8BAA8B;YAAG;EAAqB,CAAA"}
1
+ {"version":3,"file":"AcceptInvitationScreen-dnOvRx4Z.js","names":[],"sources":["../../src/auth/pages/AcceptInvitationScreen.tsx"],"sourcesContent":["/* eslint-disable no-ternary */\nimport {\n useCallback,\n useMemo,\n useState,\n type FormEvent,\n type JSX,\n} from 'react';\nimport { useSharedTranslation } from '../../i18n/useSharedTranslation.js';\n\nimport { AuthLayout, Button, FormError, FormField } from '@plumile/ui';\n\nimport type { UseAuthReturn } from '../../hooks/useAuth.js';\nimport { MfaChallengeForm } from '../login/MfaChallengeForm.js';\nimport AuthPanel from '../login/AuthPanel.js';\nimport * as styles from '../login/loginPage.css.js';\n\ntype AcceptanceState = 'pending' | 'mfa' | 'completed' | 'error' | 'idle';\n\ntype Props = {\n auth: UseAuthReturn;\n onSuccessRedirect: () => void;\n onBackToLogin: () => void;\n token?: string;\n};\n\nexport const AcceptInvitationScreen = ({\n auth,\n onSuccessRedirect,\n onBackToLogin,\n token,\n}: Props): JSX.Element => {\n const { t } = useSharedTranslation();\n const { acceptInvitation } = auth;\n const [status, setStatus] = useState<AcceptanceState>('idle');\n const [password, setPassword] = useState('');\n const [passwordConfirmation, setPasswordConfirmation] = useState('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const resolvedToken = useMemo(() => {\n if (token != null) {\n return token;\n }\n if (typeof window === 'undefined') {\n return '';\n }\n const params = new URLSearchParams(window.location.search);\n return params.get('token') ?? '';\n }, [token]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (resolvedToken === '') {\n setErrorMessage(t('auth.acceptInvitation.errors.missingToken'));\n setStatus('error');\n return;\n }\n\n if (password !== passwordConfirmation) {\n setErrorMessage(t('auth.acceptInvitation.errors.passwordMismatch'));\n setStatus('error');\n return;\n }\n\n setStatus('pending');\n setErrorMessage(null);\n setIsSubmitting(true);\n\n // eslint-disable-next-line no-void\n void acceptInvitation({\n token: resolvedToken,\n password,\n passwordConfirmation,\n })\n .then((result) => {\n if (result === 'mfa-required') {\n setStatus('mfa');\n return;\n }\n setStatus('completed');\n onSuccessRedirect();\n })\n .catch((error) => {\n setStatus('error');\n if (error instanceof Error) {\n setErrorMessage(error.message);\n } else if (typeof error === 'string') {\n setErrorMessage(error);\n } else {\n setErrorMessage(t('auth.acceptInvitation.errors.default'));\n }\n })\n .finally(() => {\n setIsSubmitting(false);\n });\n },\n [\n acceptInvitation,\n onSuccessRedirect,\n password,\n passwordConfirmation,\n resolvedToken,\n t,\n ],\n );\n\n const handleMfaSuccess = useCallback(() => {\n setStatus('completed');\n onSuccessRedirect();\n }, [onSuccessRedirect]);\n\n const handleRetry = useCallback(() => {\n setStatus('idle');\n setErrorMessage(null);\n setIsSubmitting(false);\n }, []);\n\n if (status === 'mfa') {\n return (\n <AuthLayout\n title={t('auth.acceptInvitation.mfaTitle')}\n subtitle={t('auth.acceptInvitation.mfaSubtitle')}\n >\n <MfaChallengeForm\n auth={auth}\n onSuccess={handleMfaSuccess}\n onBack={() => {\n auth.reset();\n handleRetry();\n }}\n />\n </AuthLayout>\n );\n }\n\n let content: JSX.Element;\n if (status === 'completed') {\n content = (\n <div className={styles.stack}>\n <p className={styles.helper}>\n {t('auth.acceptInvitation.status.success')}\n </p>\n </div>\n );\n } else {\n content = (\n <AuthPanel description={t('auth.acceptInvitation.subtitle')}>\n <form className={styles.formSurface} onSubmit={handleSubmit} noValidate>\n {errorMessage != null ? <FormError>{errorMessage}</FormError> : null}\n <FormField\n label={t('auth.acceptInvitation.form.passwordLabel')}\n name=\"password\"\n type=\"password\"\n value={password}\n onChange={(event) => {\n setPassword(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.passwordPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <FormField\n label={t('auth.acceptInvitation.form.confirmLabel')}\n name=\"password-confirmation\"\n type=\"password\"\n value={passwordConfirmation}\n onChange={(event) => {\n setPasswordConfirmation(event.target.value);\n setErrorMessage(null);\n if (status === 'error') {\n setStatus('idle');\n }\n }}\n placeholder={t('auth.acceptInvitation.form.confirmPlaceholder')}\n autoComplete=\"new-password\"\n required\n />\n <Button type=\"submit\" isLoading={isSubmitting}>\n {status === 'pending'\n ? t('auth.acceptInvitation.status.workingButton')\n : t('auth.acceptInvitation.form.submit')}\n </Button>\n <Button type=\"button\" variant=\"secondary\" onClick={onBackToLogin}>\n {t('auth.acceptInvitation.actions.backToLogin')}\n </Button>\n </form>\n </AuthPanel>\n );\n }\n\n return (\n <AuthLayout title={t('auth.acceptInvitation.title')}>{content}</AuthLayout>\n );\n};\n"],"mappings":"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"}
@@ -1,12 +1,6 @@
1
- import "./environment-BJeJTbIN.js";
2
- import "./useRelayEnvironment-vQ86aW-n.js";
3
1
  import { n as e } from "./BackofficeConfigContext-R0t1owTI.js";
4
- import "./loginPage.css-CBJ1Ozm5.js";
5
- import "./useAuth-CjdysxLB.js";
6
- import "./AuthPanel-DiHejPoq.js";
7
- import { t } from "./AcceptInvitationScreen-5-0EtE15.js";
8
- import "./mutationResult-CcQMY13J.js";
9
- import { t as n } from "./useBackofficeAuth-BshabGXc.js";
2
+ import { t } from "./AcceptInvitationScreen-dnOvRx4Z.js";
3
+ import { t as n } from "./useBackofficeAuth-BvEoEqnB.js";
10
4
  import { t as r } from "./backofficeAuthPaths-BiJvoI5Q.js";
11
5
  import { useCallback as i, useContext as a } from "react";
12
6
  import { RoutingContext as o } from "@plumile/router";
@@ -27,4 +21,4 @@ var c = () => {
27
21
  //#endregion
28
22
  export { c as BackofficeAcceptInvitationPage, c as default };
29
23
 
30
- //# sourceMappingURL=BackofficeAcceptInvitationPage-FPbn31YK.js.map
24
+ //# sourceMappingURL=BackofficeAcceptInvitationPage-CGht2ka0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeAcceptInvitationPage-FPbn31YK.js","names":[],"sources":["../../src/pages/BackofficeAcceptInvitationPage.tsx"],"sourcesContent":["import { useCallback, useContext, type JSX } from 'react';\nimport { RoutingContext } from '@plumile/router';\n\nimport { AcceptInvitationScreen } from '../auth/pages/AcceptInvitationScreen.js';\nimport { useBackofficeAuth } from '../hooks/useBackofficeAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\n\nexport const BackofficeAcceptInvitationPage = (): JSX.Element => {\n const routerContext = useContext(RoutingContext);\n const { basePath } = useBackofficeConfig();\n const auth = useBackofficeAuth();\n\n const handleSuccessRedirect = useCallback(() => {\n routerContext?.history.push({ pathname: basePath });\n }, [basePath, routerContext?.history]);\n\n const handleBackToLogin = useCallback(() => {\n routerContext?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n }, [basePath, routerContext?.history]);\n\n return (\n <AcceptInvitationScreen\n auth={auth}\n onSuccessRedirect={handleSuccessRedirect}\n onBackToLogin={handleBackToLogin}\n />\n );\n};\n\nexport default BackofficeAcceptInvitationPage;\n"],"mappings":";;;;;;;;;;;;;;AAQA,IAAa,UAAoD;CAC/D,IAAM,IAAgB,EAAW,EAAe,EAC1C,EAAE,gBAAa,GAAqB;AAW1C,QACE,kBAAC,GAAD;EACQ,MAZG,GAAmB;EAa5B,mBAX0B,QAAkB;AAC9C,MAAe,QAAQ,KAAK,EAAE,UAAU,GAAU,CAAC;KAClD,CAAC,GAAU,GAAe,QAAQ,CAAC;EAUlC,eARsB,QAAkB;AAC1C,MAAe,QAAQ,KAAK,EAAE,UAAU,EAAuB,EAAS,EAAE,CAAC;KAC1E,CAAC,GAAU,GAAe,QAAQ,CAAC;EAOlC,CAAA"}
1
+ {"version":3,"file":"BackofficeAcceptInvitationPage-CGht2ka0.js","names":[],"sources":["../../src/pages/BackofficeAcceptInvitationPage.tsx"],"sourcesContent":["import { useCallback, useContext, type JSX } from 'react';\nimport { RoutingContext } from '@plumile/router';\n\nimport { AcceptInvitationScreen } from '../auth/pages/AcceptInvitationScreen.js';\nimport { useBackofficeAuth } from '../hooks/useBackofficeAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\n\nexport const BackofficeAcceptInvitationPage = (): JSX.Element => {\n const routerContext = useContext(RoutingContext);\n const { basePath } = useBackofficeConfig();\n const auth = useBackofficeAuth();\n\n const handleSuccessRedirect = useCallback(() => {\n routerContext?.history.push({ pathname: basePath });\n }, [basePath, routerContext?.history]);\n\n const handleBackToLogin = useCallback(() => {\n routerContext?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n }, [basePath, routerContext?.history]);\n\n return (\n <AcceptInvitationScreen\n auth={auth}\n onSuccessRedirect={handleSuccessRedirect}\n onBackToLogin={handleBackToLogin}\n />\n );\n};\n\nexport default BackofficeAcceptInvitationPage;\n"],"mappings":";;;;;;;;AAQA,IAAa,UAAoD;CAC/D,IAAM,IAAgB,EAAW,EAAe,EAC1C,EAAE,gBAAa,GAAqB;AAW1C,QACE,kBAAC,GAAD;EACQ,MAZG,GAAmB;EAa5B,mBAX0B,QAAkB;AAC9C,MAAe,QAAQ,KAAK,EAAE,UAAU,GAAU,CAAC;KAClD,CAAC,GAAU,GAAe,QAAQ,CAAC;EAUlC,eARsB,QAAkB;AAC1C,MAAe,QAAQ,KAAK,EAAE,UAAU,EAAuB,EAAS,EAAE,CAAC;KAC1E,CAAC,GAAU,GAAe,QAAQ,CAAC;EAOlC,CAAA"}
@@ -1,7 +1,6 @@
1
1
  import { n as e } from "./BackofficeConfigContext-R0t1owTI.js";
2
2
  import { n as t, t as n } from "./useBackofficeReactTranslation-WfXU8kCf.js";
3
- import { n as r, t as i } from "./BackofficeRightPageLayout-F8ipegrl.js";
4
- import "./BackofficeTopbarPortalContext-iD7dm4_h.js";
3
+ import { n as r, t as i } from "./BackofficeRightPageLayout-DZQvIHnj.js";
5
4
  import { a } from "./useBackofficeLazyValue-Dnii1_dE.js";
6
5
  import { t as o } from "./buildBreadcrumbs-CqF9Nh6x.js";
7
6
  import { Suspense as s } from "react";
@@ -10,8 +9,8 @@ import { Link as l } from "@plumile/router";
10
9
  import { DataTable as u, DetailPageTemplate as d, InfoTile as f } from "@plumile/ui";
11
10
  import * as p from "react-relay";
12
11
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
13
- //#region src/pages/backofficeDashboardPage.css.ts
14
- var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v = "txvbqba7 txvbqbamy txvbqbehy", y = "txvbqb9ip txvbqbajy txvbqbqi7 txvbqb8vg", { useLazyLoadQuery: b } = p, x = (e, t) => e(t), S = (e, t) => {
12
+ //#region src/pages/BackofficeDashboardPage.helpers.ts
13
+ var g = (e, t) => e(t), _ = (e, t) => {
15
14
  switch (e.kind) {
16
15
  case "entityCount":
17
16
  case "shortcut": return e.label;
@@ -19,23 +18,23 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
19
18
  case "textBlock": return e.title;
20
19
  default: return t.title;
21
20
  }
22
- }, C = (e) => "query" in e && e.query != null, w = ({ widget: t, globalData: i }) => {
21
+ }, v = (e) => "query" in e && e.query != null, y = "txvbqb9iy txvbqbbz7 txvbqbaop", b = "txvbqb9ip txvbqbai7 txvbqbao7", x = "txvbqba7 txvbqbamy txvbqbehy", S = "txvbqb9ip txvbqbajy txvbqbqi7 txvbqb8vg", { useLazyLoadQuery: C } = p, w = ({ widget: t, globalData: i }) => {
23
22
  let { t: a } = c(), { t: o } = n(), { entities: s } = e(), d = (e) => "resolve" in t && t.resolve != null ? t.resolve(e) : null;
24
23
  if (t.kind === "textBlock") return /* @__PURE__ */ m(f, {
25
- title: x(t.title, a),
24
+ title: g(t.title, a),
26
25
  children: /* @__PURE__ */ m("div", {
27
- className: _,
28
- children: x(t.body, a)
26
+ className: b,
27
+ children: g(t.body, a)
29
28
  })
30
29
  });
31
30
  if (t.kind === "shortcut") {
32
31
  let e = s[t.entityId];
33
32
  if (e == null) return null;
34
- let n = x(t.label, a);
33
+ let n = g(t.label, a);
35
34
  return e.kind === "tool" ? /* @__PURE__ */ m(f, {
36
35
  title: n,
37
36
  children: /* @__PURE__ */ m("div", {
38
- className: y,
37
+ className: S,
39
38
  children: /* @__PURE__ */ m(l, {
40
39
  to: e.routes.list,
41
40
  children: o("dashboard.actions.openTool")
@@ -44,7 +43,7 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
44
43
  }) : /* @__PURE__ */ m(f, {
45
44
  title: n,
46
45
  children: /* @__PURE__ */ m("div", {
47
- className: y,
46
+ className: S,
48
47
  children: /* @__PURE__ */ m(l, {
49
48
  to: e.routes.list,
50
49
  children: o("dashboard.actions.openList")
@@ -64,7 +63,7 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
64
63
  }
65
64
  });
66
65
  return /* @__PURE__ */ m(f, {
67
- title: x(t.title, a),
66
+ title: g(t.title, a),
68
67
  children: /* @__PURE__ */ m(u, {
69
68
  columns: n,
70
69
  rows: e.rows,
@@ -83,14 +82,14 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
83
82
  if (e?.kind !== "list-detail") return null;
84
83
  let n = d(i), r = o("common.notAvailable");
85
84
  return typeof n?.count == "number" && (r = n.count), /* @__PURE__ */ m(f, {
86
- title: x(t.label, a),
85
+ title: g(t.label, a),
87
86
  children: /* @__PURE__ */ h("div", {
88
- className: _,
87
+ className: b,
89
88
  children: [/* @__PURE__ */ m("div", {
90
- className: v,
89
+ className: x,
91
90
  children: r
92
91
  }), /* @__PURE__ */ m("div", {
93
- className: y,
92
+ className: S,
94
93
  children: /* @__PURE__ */ m(l, {
95
94
  to: e.routes.list,
96
95
  children: o("dashboard.actions.openList")
@@ -102,34 +101,34 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
102
101
  return null;
103
102
  }, T = ({ widget: e }) => /* @__PURE__ */ m(w, {
104
103
  widget: e,
105
- globalData: b(e.query, {}, { fetchPolicy: "store-or-network" })
104
+ globalData: C(e.query, {}, { fetchPolicy: "store-or-network" })
106
105
  }), E = ({ config: e, globalData: r }) => {
107
106
  let { t: i } = c(), { t: a } = n();
108
107
  return /* @__PURE__ */ m(d, {
109
108
  header: {
110
- title: x(e.title, i),
111
- subtitle: (e.subtitle == null ? void 0 : x(e.subtitle, i)) ?? a("dashboard.subtitle")
109
+ title: g(e.title, i),
110
+ subtitle: (e.subtitle == null ? void 0 : g(e.subtitle, i)) ?? a("dashboard.subtitle")
112
111
  },
113
112
  children: /* @__PURE__ */ m("div", {
114
- className: g,
113
+ className: y,
115
114
  children: e.widgets.map((n) => {
116
- let o = C(n) ? /* @__PURE__ */ m(T, { widget: n }) : /* @__PURE__ */ m(w, {
115
+ let o = v(n) ? /* @__PURE__ */ m(T, { widget: n }) : /* @__PURE__ */ m(w, {
117
116
  widget: n,
118
117
  globalData: r
119
118
  });
120
119
  return /* @__PURE__ */ m(t, {
121
120
  fallback: () => /* @__PURE__ */ m(f, {
122
- title: x(S(n, e), i),
121
+ title: g(_(n, e), i),
123
122
  children: /* @__PURE__ */ m("div", {
124
- className: _,
123
+ className: b,
125
124
  children: a("common.notAvailable")
126
125
  })
127
126
  }),
128
127
  children: /* @__PURE__ */ m(s, {
129
128
  fallback: /* @__PURE__ */ m(f, {
130
- title: x(S(n, e), i),
129
+ title: g(_(n, e), i),
131
130
  children: /* @__PURE__ */ m("div", {
132
- className: _,
131
+ className: b,
133
132
  children: a("common.loading")
134
133
  })
135
134
  }),
@@ -141,13 +140,13 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
141
140
  });
142
141
  }, D = ({ config: e }) => /* @__PURE__ */ m(E, {
143
142
  config: e,
144
- globalData: b(e.query, {}, { fetchPolicy: "store-or-network" })
143
+ globalData: C(e.query, {}, { fetchPolicy: "store-or-network" })
145
144
  }), O = () => {
146
145
  let { t } = c(), { t: r } = n(), { entities: s } = e(), u = a(), p = o(r);
147
146
  if (u == null) {
148
147
  let e = Object.values(s).filter((e) => e.kind === "list-detail" && e.hasList).map((e) => ({
149
148
  config: e,
150
- label: x(e.label, t)
149
+ label: g(e.label, t)
151
150
  })).sort((e, t) => e.label.localeCompare(t.label));
152
151
  return /* @__PURE__ */ m(i, {
153
152
  breadcrumb: p,
@@ -157,16 +156,16 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
157
156
  subtitle: r("dashboard.subtitle")
158
157
  },
159
158
  children: /* @__PURE__ */ m("div", {
160
- className: g,
159
+ className: y,
161
160
  children: e.map(({ config: e, label: t }) => /* @__PURE__ */ m(f, {
162
161
  title: t,
163
162
  children: /* @__PURE__ */ h("div", {
164
- className: _,
163
+ className: b,
165
164
  children: [/* @__PURE__ */ m("div", {
166
- className: v,
165
+ className: x,
167
166
  children: r("common.notAvailable")
168
167
  }), /* @__PURE__ */ m("div", {
169
- className: y,
168
+ className: S,
170
169
  children: /* @__PURE__ */ m(l, {
171
170
  to: e.routes.list,
172
171
  children: r("dashboard.actions.openList")
@@ -192,4 +191,4 @@ var g = "txvbqb9iy txvbqbbz7 txvbqbaop", _ = "txvbqb9ip txvbqbai7 txvbqbao7", v
192
191
  //#endregion
193
192
  export { O as BackofficeDashboardPage, O as default };
194
193
 
195
- //# sourceMappingURL=BackofficeDashboardPage-C7lIVeA1.js.map
194
+ //# sourceMappingURL=BackofficeDashboardPage-h1OWb_rV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackofficeDashboardPage-h1OWb_rV.js","names":[],"sources":["../../src/pages/BackofficeDashboardPage.helpers.ts","../../src/pages/backofficeDashboardPage.css.ts","../../src/pages/BackofficeDashboardPage.tsx"],"sourcesContent":["import type {\n BackofficeDashboardConfig,\n BackofficeDashboardWidget,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type { TFunction } from 'i18next';\nimport type { GraphQLTaggedNode } from 'relay-runtime';\n\nexport const resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nexport const getWidgetLabel = (\n widget: BackofficeDashboardWidget,\n config: BackofficeDashboardConfig,\n): I18nLabel => {\n switch (widget.kind) {\n case 'entityCount':\n case 'shortcut':\n return widget.label;\n case 'tablePreview':\n case 'textBlock':\n return widget.title;\n default:\n return config.title;\n }\n};\n\nexport const hasWidgetQuery = (\n widget: BackofficeDashboardWidget,\n): widget is BackofficeDashboardWidget & { query: GraphQLTaggedNode } => {\n return 'query' in widget && widget.query != null;\n};\n","import { sprinkles } from '@plumile/ui';\n\nexport const tilesGrid = sprinkles({\n display: 'grid',\n gridTemplateColumns: 'autoFillMinmax320',\n gap: 4,\n});\n\nexport const tileBody = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n});\n\nexport const tileCount = sprinkles({\n fontSize: '3xl',\n fontWeight: 'bold',\n lineHeight: 1,\n});\n\nexport const links = sprinkles({\n display: 'flex',\n flexWrap: 'wrap',\n rowGap: 2,\n columnGap: 3,\n});\n","/* eslint-disable no-ternary */\nimport { type JSX, Suspense } from 'react';\nimport { Link } from '@plumile/router';\nimport type {\n BackofficeDashboardConfig,\n BackofficeDashboardWidget,\n} from '@plumile/backoffice-core/types.js';\nimport { DataTable, DetailPageTemplate, InfoTile } from '@plumile/ui';\nimport { useTranslation } from 'react-i18next';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLTaggedNode, OperationType } from 'relay-runtime';\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 { buildDataTableColumns } from '../components/backoffice/columns/buildDataTableColumns.js';\nimport { BackofficeRightPageLayout } from '../components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js';\nimport { buildDashboardBreadcrumb } from '../components/backoffice/layout/breadcrumb/buildBreadcrumbs.js';\nimport {\n getWidgetLabel,\n hasWidgetQuery,\n resolveLabel,\n} from './BackofficeDashboardPage.helpers.js';\n\nimport * as styles from './backofficeDashboardPage.css.js';\n\nconst { useLazyLoadQuery } = ReactRelay;\n\ntype WidgetContentProps = {\n widget: BackofficeDashboardWidget;\n globalData: unknown;\n};\n\nconst WidgetContent = ({\n widget,\n globalData,\n}: WidgetContentProps): JSX.Element | null => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { entities } = useBackofficeConfig();\n\n const resolveData = (data: unknown): unknown => {\n if ('resolve' in widget && widget.resolve != null) {\n return widget.resolve(data);\n }\n return null;\n };\n\n if (widget.kind === 'textBlock') {\n const title = resolveLabel(widget.title, tApp);\n const body = resolveLabel(widget.body, tApp);\n return (\n <InfoTile title={title}>\n <div className={styles.tileBody}>{body}</div>\n </InfoTile>\n );\n }\n\n if (widget.kind === 'shortcut') {\n const entity = entities[widget.entityId];\n if (entity == null) {\n return null;\n }\n const title = resolveLabel(widget.label, tApp);\n if (entity.kind === 'tool') {\n return (\n <InfoTile title={title}>\n <div className={styles.links}>\n <Link to={entity.routes.list}>\n {t('dashboard.actions.openTool')}\n </Link>\n </div>\n </InfoTile>\n );\n }\n return (\n <InfoTile title={title}>\n <div className={styles.links}>\n <Link to={entity.routes.list}>{t('dashboard.actions.openList')}</Link>\n </div>\n </InfoTile>\n );\n }\n\n if (widget.kind === 'tablePreview') {\n const resolved = resolveData(globalData) as {\n columns: readonly unknown[];\n rows: readonly unknown[];\n } | null;\n if (resolved == null) {\n return null;\n }\n const columns = buildDataTableColumns(resolved.columns as never, {\n tApp,\n t,\n resolveEntityHref: (entityId, refId) => {\n const entityConfig = entities[entityId];\n if (entityConfig == null) {\n return null;\n }\n return entityConfig.routes.detail(refId);\n },\n });\n const title = resolveLabel(widget.title, tApp);\n return (\n <InfoTile title={title}>\n <DataTable\n columns={columns}\n rows={resolved.rows}\n getRowId={(row, index) => {\n if (row != null && typeof row === 'object') {\n const record = row as Record<string, unknown>;\n const { id } = record;\n if (typeof id === 'string' && id.trim() !== '') {\n return id;\n }\n }\n return String(index);\n }}\n />\n </InfoTile>\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (widget.kind === 'entityCount') {\n const entityManifest = entities[widget.entityId];\n if (entityManifest?.kind !== 'list-detail') {\n return null;\n }\n const resolved = resolveData(globalData) as { count: number | null } | null;\n let countLabel: number | string = t('common.notAvailable');\n if (typeof resolved?.count === 'number') {\n countLabel = resolved.count;\n }\n const title = resolveLabel(widget.label, tApp);\n return (\n <InfoTile title={title}>\n <div className={styles.tileBody}>\n <div className={styles.tileCount}>{countLabel}</div>\n <div className={styles.links}>\n <Link to={entityManifest.routes.list}>\n {t('dashboard.actions.openList')}\n </Link>\n </div>\n </div>\n </InfoTile>\n );\n }\n\n return null;\n};\n\ntype WidgetWithQueryProps = {\n widget: BackofficeDashboardWidget & { query: GraphQLTaggedNode };\n};\n\nconst WidgetWithQuery = ({ widget }: WidgetWithQueryProps): JSX.Element => {\n const data = useLazyLoadQuery<OperationType>(\n widget.query,\n {},\n {\n fetchPolicy: 'store-or-network',\n },\n );\n\n return <WidgetContent widget={widget} globalData={data} />;\n};\n\ntype DashboardContentProps = {\n config: BackofficeDashboardConfig;\n globalData: unknown;\n};\n\nconst DashboardContent = ({\n config,\n globalData,\n}: DashboardContentProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n\n const title = resolveLabel(config.title, tApp);\n const subtitle =\n config.subtitle != null ? resolveLabel(config.subtitle, tApp) : undefined;\n\n return (\n <DetailPageTemplate\n header={{\n title,\n subtitle: subtitle ?? t('dashboard.subtitle'),\n }}\n >\n <div className={styles.tilesGrid}>\n {config.widgets.map((widget) => {\n const content = hasWidgetQuery(widget) ? (\n <WidgetWithQuery widget={widget} />\n ) : (\n <WidgetContent widget={widget} globalData={globalData} />\n );\n\n return (\n <BackofficeErrorBoundary\n key={widget.id}\n fallback={() => {\n return (\n <InfoTile\n title={resolveLabel(getWidgetLabel(widget, config), tApp)}\n >\n <div className={styles.tileBody}>\n {t('common.notAvailable')}\n </div>\n </InfoTile>\n );\n }}\n >\n <Suspense\n fallback={\n <InfoTile\n title={resolveLabel(getWidgetLabel(widget, config), tApp)}\n >\n <div className={styles.tileBody}>{t('common.loading')}</div>\n </InfoTile>\n }\n >\n {content}\n </Suspense>\n </BackofficeErrorBoundary>\n );\n })}\n </div>\n </DetailPageTemplate>\n );\n};\n\ntype DashboardWithQueryProps = {\n config: BackofficeDashboardConfig;\n};\n\nconst DashboardWithQuery = ({\n config,\n}: DashboardWithQueryProps): JSX.Element => {\n const data = useLazyLoadQuery<OperationType>(\n config.query as never,\n {},\n { fetchPolicy: 'store-or-network' },\n );\n\n return <DashboardContent config={config} globalData={data} />;\n};\n\nexport const BackofficeDashboardPage = (): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { entities } = useBackofficeConfig();\n const dashboard = useBackofficeDashboardConfig();\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 <div className={styles.tilesGrid}>\n {items.map(({ config, label }) => {\n return (\n <InfoTile key={config.id} title={label}>\n <div className={styles.tileBody}>\n <div className={styles.tileCount}>\n {t('common.notAvailable')}\n </div>\n <div className={styles.links}>\n <Link to={config.routes.list}>\n {t('dashboard.actions.openList')}\n </Link>\n </div>\n </div>\n </InfoTile>\n );\n })}\n </div>\n </DetailPageTemplate>\n </BackofficeRightPageLayout>\n );\n }\n\n if (dashboard.query != null) {\n return (\n <BackofficeRightPageLayout breadcrumb={breadcrumb}>\n <DashboardWithQuery config={dashboard} />\n </BackofficeRightPageLayout>\n );\n }\n\n return (\n <BackofficeRightPageLayout breadcrumb={breadcrumb}>\n <DashboardContent config={dashboard} globalData={null} />\n </BackofficeRightPageLayout>\n );\n};\n\nexport default BackofficeDashboardPage;\n"],"mappings":"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"}