runid-lys 0.5.0 → 0.7.0
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/CHANGELOG.md +22 -0
- package/dist/{hooks-CvhFUowR.js → PublicAppTemplate-DLKcJZVR.js} +23 -2
- package/dist/PublicAppTemplate-DLKcJZVR.js.map +1 -0
- package/dist/{constants-BLmcEnm4.js → constants-sdhUzJ0l.js} +131 -27
- package/dist/{constants-BLmcEnm4.js.map → constants-sdhUzJ0l.js.map} +1 -1
- package/dist/{i18nTools-BDTofggT.js → i18nTools-C1k2y9xe.js} +2 -2
- package/dist/{i18nTools-BDTofggT.js.map → i18nTools-C1k2y9xe.js.map} +1 -1
- package/dist/index.js +25 -23
- package/dist/index.js.map +1 -1
- package/dist/providers/RouteProvider/hooks.d.ts +22 -0
- package/dist/providers/RouteProvider/index.d.ts +45 -0
- package/dist/providers/hooks/useRestrictedLink.d.ts +3 -2
- package/dist/providers/hooks/useRouteAccess.d.ts +25 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +23 -20
- package/dist/templates/index.js +1 -1
- package/dist/tools/index.js +2 -2
- package/dist/{translationTools-RWoOzX2m.js → translationTools-CKk0l3jr.js} +5 -2
- package/dist/translationTools-CKk0l3jr.js.map +1 -0
- package/dist/types/descriptionTypes.d.ts +11 -1
- package/dist/types/routeTypes.d.ts +15 -1
- package/package.json +1 -1
- package/dist/PublicAppTemplate-B93G2Smc.js +0 -26
- package/dist/PublicAppTemplate-B93G2Smc.js.map +0 -1
- package/dist/hooks-CvhFUowR.js.map +0 -1
- package/dist/translationTools-RWoOzX2m.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as isEmpty } from "./translationTools-
|
|
1
|
+
import { l as isEmpty } from "./translationTools-CKk0l3jr.js";
|
|
2
2
|
const generateI18nTable = (locale, table, prefix = "") => {
|
|
3
3
|
let generatedTable = {};
|
|
4
4
|
Object.entries(table).forEach(([key, value]) => {
|
|
@@ -47,4 +47,4 @@ export {
|
|
|
47
47
|
generateI18nMessage as g,
|
|
48
48
|
mergeI18nMessages as m
|
|
49
49
|
};
|
|
50
|
-
//# sourceMappingURL=i18nTools-
|
|
50
|
+
//# sourceMappingURL=i18nTools-C1k2y9xe.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18nTools-
|
|
1
|
+
{"version":3,"file":"i18nTools-C1k2y9xe.js","sources":["../src/tools/i18nTools.ts"],"sourcesContent":["/**\n * Centralized i18n utility functions\n */\nimport {isEmpty} from \"./validationTools\";\n\n/**\n * Generate translation table for a specified language\n * @param locale - Target language code\n * @param table - Translation data structure to traverse (heterogeneous nested object)\n * @param prefix - Translation key prefix for namespacing\n */\nconst generateI18nTable = (\n locale: string,\n table: Record<string, unknown>,\n prefix: string=''\n) => {\n let generatedTable: { [key: string] : string} = {};\n Object.entries(table).forEach(([key, value]) => {\n // ending condition\n if(key === locale)\n generatedTable[prefix] = value as string\n // recursive loop\n else if (typeof value == 'object' && !isEmpty(value)) {\n let newPrefix: string;\n if(key !== \"translation\") {\n newPrefix = prefix ? prefix + '.' + key : key;\n } else {\n newPrefix = prefix;\n }\n\n generatedTable = {\n ...generateI18nTable(locale, value as Record<string, unknown>, newPrefix),\n ...generatedTable\n }\n }\n });\n\n return generatedTable\n};\n\n/**\n * Generate translation table for all specified languages\n * @param locales - Array of language codes to generate translations for\n * @param table - Translation data structure to traverse (any nested object structure)\n * @param prefix - Translation key prefix for namespacing\n */\nexport const generateI18nMessage = (\n locales: string[],\n table: Record<string, unknown>,\n prefix: string=''\n) => {\n\n const translationTable: {[local: string] : { [key: string] : string}} = {};\n\n locales.forEach((locale: string)=>{\n translationTable[locale] = generateI18nTable(locale, table, prefix);\n });\n return translationTable;\n};\n\n/**\n * Merge multiple translation tables for specified languages\n * @param locales - Array of language codes\n * @param messages - Translation tables to merge\n */\nexport const mergeI18nMessages = (\n locales: string[],\n ...messages: {[p: string]: {[p: string]: string}}[]\n) => {\n const mergedMessage: {[p: string]: {[p: string]: string}} = {};\n\n locales.forEach((locale)=>{\n messages.forEach((message)=>{\n if (!(locale in mergedMessage)) {\n mergedMessage[locale] = {};\n }\n\n if(locale in message) {\n mergedMessage[locale] = {\n ...mergedMessage[locale],\n ...message[locale]\n }\n }\n });\n });\n\n return mergedMessage;\n};\n"],"names":[],"mappings":";AAWA,MAAM,oBAAoB,CACtB,QACA,OACA,SAAe,OACd;AACD,MAAI,iBAA4C,CAAA;AAChD,SAAO,QAAQ,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAO;AAE7C,QAAG,QAAQ;AACP,qBAAe,MAAM,IAAI;AAAA,aAEpB,OAAO,SAAS,YAAY,CAAC,QAAQ,KAAK,GAAG;AAClD,UAAI;AACJ,UAAG,QAAQ,eAAe;AACtB,oBAAY,SAAS,SAAS,MAAM,MAAM;AAAA,MAC9C,OAAO;AACH,oBAAY;AAAA,MAChB;AAEA,uBAAiB;AAAA,QACb,GAAG,kBAAkB,QAAQ,OAAkC,SAAS;AAAA,QACxE,GAAG;AAAA,MAAA;AAAA,IAEX;AAAA,EACJ,CAAC;AAED,SAAO;AACX;AAQO,MAAM,sBAAsB,CAC/B,SACA,OACA,SAAe,OACd;AAED,QAAM,mBAAkE,CAAA;AAExE,UAAQ,QAAQ,CAAC,WAAiB;AAC9B,qBAAiB,MAAM,IAAI,kBAAkB,QAAQ,OAAO,MAAM;AAAA,EACtE,CAAC;AACD,SAAO;AACX;AAOO,MAAM,oBAAoB,CAC7B,YACG,aACF;AACD,QAAM,gBAAsD,CAAA;AAE5D,UAAQ,QAAQ,CAAC,WAAS;AACtB,aAAS,QAAQ,CAAC,YAAU;AACxB,UAAI,EAAE,UAAU,gBAAgB;AAC5B,sBAAc,MAAM,IAAI,CAAA;AAAA,MAC5B;AAEA,UAAG,UAAU,SAAS;AAClB,sBAAc,MAAM,IAAI;AAAA,UACpB,GAAG,cAAc,MAAM;AAAA,UACvB,GAAG,QAAQ,MAAM;AAAA,QAAA;AAAA,MAEzB;AAAA,IACJ,CAAC;AAAA,EACL,CAAC;AAED,SAAO;AACX;"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { I18nLocaleEnum } from "./types/index.js";
|
|
2
|
-
import { c, a, b, d, e, f, g, h, i, j, k, l, m, n, p, s, t, v } from "./translationTools-
|
|
3
|
-
import { g as g2, m as m2 } from "./i18nTools-
|
|
4
|
-
import { A, C, a as a2, b as b2, c as c2, E, F, G, L, d as d2, e as e2, f as f2, g as g3, P, R, S, U, W, u,
|
|
5
|
-
import { u as u2, a as a3 } from "./
|
|
2
|
+
import { c, a, b, d, e, f, g, h, i, j, k, l, m, n, p, s, t, v } from "./translationTools-CKk0l3jr.js";
|
|
3
|
+
import { g as g2, m as m2 } from "./i18nTools-C1k2y9xe.js";
|
|
4
|
+
import { A, C, a as a2, b as b2, c as c2, E, F, G, L, d as d2, e as e2, f as f2, g as g3, P, R, h as h2, S, U, W, u, i as i2, j as j2, k as k2, l as l2, m as m3, n as n2, o, p as p2, q, r, s as s2, t as t2, v as v2, w, x, y, z, B, D, H } from "./constants-sdhUzJ0l.js";
|
|
5
|
+
import { P as P2, u as u2, a as a3 } from "./PublicAppTemplate-DLKcJZVR.js";
|
|
6
6
|
import { R as R2, c as c3, a as a4 } from "./RelayEnvironment-D880U9SM.js";
|
|
7
|
-
import { P as P2 } from "./PublicAppTemplate-B93G2Smc.js";
|
|
8
7
|
import { e as e3, i as i3 } from "./errors-BOacmKM0.js";
|
|
9
8
|
import { messagesTranslations } from "./i18n/index.js";
|
|
10
9
|
export {
|
|
@@ -26,6 +25,7 @@ export {
|
|
|
26
25
|
P2 as PublicAppTemplate,
|
|
27
26
|
R as RefreshSignalContext,
|
|
28
27
|
R2 as RelayEnvironment,
|
|
28
|
+
h2 as RouteProvider,
|
|
29
29
|
S as SignalProvider,
|
|
30
30
|
U as UrlQueriesProvider,
|
|
31
31
|
W as WebserviceAccessProvider,
|
|
@@ -55,25 +55,27 @@ export {
|
|
|
55
55
|
t as toSnakeCase,
|
|
56
56
|
u as useAlertMessages,
|
|
57
57
|
u2 as useChatbot,
|
|
58
|
-
|
|
58
|
+
i2 as useClientId,
|
|
59
59
|
a3 as useConnectedUserInfo,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
j2 as useDialogWithUpdates,
|
|
61
|
+
k2 as useFilterLabels,
|
|
62
|
+
l2 as useLocale,
|
|
63
|
+
m3 as useLysDialog,
|
|
64
|
+
n2 as useLysLoadingFallback,
|
|
65
|
+
o as useLysMutation,
|
|
66
|
+
p2 as useLysQuery,
|
|
67
|
+
q as usePageContext,
|
|
68
|
+
r as usePermissionCheck,
|
|
69
|
+
s2 as useRefreshSignal,
|
|
70
|
+
t2 as useRestrictedLink,
|
|
71
|
+
v2 as useRouteAccess,
|
|
72
|
+
w as useRouteInfo,
|
|
73
|
+
x as useSignal,
|
|
74
|
+
y as useSignalRefresh,
|
|
75
|
+
z as useSignalSubscription,
|
|
76
|
+
B as useUrlQueries,
|
|
77
|
+
D as useWebserviceAccess,
|
|
76
78
|
v as validators,
|
|
77
|
-
|
|
79
|
+
H as webserviceAccessProviderConfig
|
|
78
80
|
};
|
|
79
81
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RouteInterface } from '../../types/routeTypes';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of the value exposed by the route context.
|
|
4
|
+
*/
|
|
5
|
+
export interface RouteContextValue {
|
|
6
|
+
/** Currently active route (the one matching the URL). */
|
|
7
|
+
route: RouteInterface | null;
|
|
8
|
+
/** Default route used as fallback for authenticated users (e.g. home page). */
|
|
9
|
+
defaultPrivateRoute: RouteInterface | null;
|
|
10
|
+
/** Default route used as fallback for anonymous users (e.g. login page). */
|
|
11
|
+
defaultPublicRoute: RouteInterface | null;
|
|
12
|
+
/** All known routes keyed by route name for O(1) lookup. */
|
|
13
|
+
allRoutes: Record<string, RouteInterface>;
|
|
14
|
+
/** Look up a route by its name. */
|
|
15
|
+
getRouteByName: (name: string) => RouteInterface | undefined;
|
|
16
|
+
}
|
|
17
|
+
declare const RouteContext: import('react').Context<RouteContextValue>;
|
|
18
|
+
/**
|
|
19
|
+
* Hook to access the active route, default routes and the route map.
|
|
20
|
+
*/
|
|
21
|
+
declare const useRouteInfo: () => RouteContextValue;
|
|
22
|
+
export { RouteContext, useRouteInfo };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RouteInterface } from '../../types/routeTypes';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Shape expected from any template component plugged into `RouteProvider`.
|
|
5
|
+
*
|
|
6
|
+
* Templates receive the same triplet (active route + default routes) so they
|
|
7
|
+
* can render the page chrome and trigger any post-mount redirects.
|
|
8
|
+
*/
|
|
9
|
+
export interface RouteTemplateProps {
|
|
10
|
+
route: RouteInterface;
|
|
11
|
+
defaultPrivateRoute: RouteInterface;
|
|
12
|
+
defaultPublicRoute: RouteInterface;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export interface RouteProviderProps {
|
|
16
|
+
route: RouteInterface;
|
|
17
|
+
routes: RouteInterface[];
|
|
18
|
+
defaultPrivateRoute: RouteInterface;
|
|
19
|
+
defaultPublicRoute: RouteInterface;
|
|
20
|
+
/**
|
|
21
|
+
* Template used when the active route's `type` is `"private"`.
|
|
22
|
+
* Projects inject their own private template (e.g. with sidebar/topbar)
|
|
23
|
+
* because the layout is project-specific.
|
|
24
|
+
*/
|
|
25
|
+
privateTemplate: React.ComponentType<RouteTemplateProps>;
|
|
26
|
+
/**
|
|
27
|
+
* Optional override for public pages. Defaults to the generic
|
|
28
|
+
* `PublicAppTemplate` shipped with lys-front (handles connected-user
|
|
29
|
+
* redirects).
|
|
30
|
+
*/
|
|
31
|
+
publicTemplate?: React.ComponentType<RouteTemplateProps>;
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generic route provider:
|
|
36
|
+
* - Exposes the active route, the route map and helpers via `useRouteInfo`.
|
|
37
|
+
* - Wires the chatbot's `pageContext` to the current route + URL params.
|
|
38
|
+
* - Auto-opens the chatbot for routes flagged with `autoOpenChatbot`.
|
|
39
|
+
* - Renders the project-supplied template matching the route type.
|
|
40
|
+
*
|
|
41
|
+
* The two templates are injected as props so projects keep ownership of their
|
|
42
|
+
* page chrome (sidebar, navbar, branding…) while reusing all the route plumbing.
|
|
43
|
+
*/
|
|
44
|
+
declare const RouteProvider: React.FC<RouteProviderProps>;
|
|
45
|
+
export default RouteProvider;
|
|
@@ -6,8 +6,9 @@ export interface RestrictedLink {
|
|
|
6
6
|
/**
|
|
7
7
|
* Hook to check route permission and provide navigation callback.
|
|
8
8
|
*
|
|
9
|
-
* Combines permission checking (via WebserviceAccessProvider
|
|
10
|
-
*
|
|
9
|
+
* Combines permission checking (via WebserviceAccessProvider — delegated to
|
|
10
|
+
* `useRouteAccess` so the single/array `mainWebserviceName` semantics stay
|
|
11
|
+
* in one place) with navigation (via react-router) for a given route.
|
|
11
12
|
*
|
|
12
13
|
* Usage:
|
|
13
14
|
* ```tsx
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { RouteInterface } from '../../types/routeTypes';
|
|
2
|
+
/**
|
|
3
|
+
* Hook that returns a function reporting whether the current user has
|
|
4
|
+
* access to a given route.
|
|
5
|
+
*
|
|
6
|
+
* The returned function accepts either a `RouteInterface` (when the caller
|
|
7
|
+
* already has the route resolved) or a route name (the hook performs the
|
|
8
|
+
* lookup against the `RouteProvider`'s map). `undefined` always returns
|
|
9
|
+
* `false`.
|
|
10
|
+
*
|
|
11
|
+
* Permission semantics for `route.mainWebserviceName`:
|
|
12
|
+
* - `undefined` → no permission gate → access granted.
|
|
13
|
+
* - `string` → access requires that single webservice.
|
|
14
|
+
* - `string[]` → any-of: access granted as soon as the user has at least
|
|
15
|
+
* one of the listed webservices.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const hasAccess = useRouteAccess();
|
|
20
|
+
* hasAccess(route); // route already resolved
|
|
21
|
+
* hasAccess("AdministrationPage"); // resolved internally via RouteProvider
|
|
22
|
+
* hasAccess(undefined); // false
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const useRouteAccess: () => (routeOrName: RouteInterface | string | undefined) => boolean;
|
|
@@ -12,6 +12,7 @@ export { default as SignalProvider } from './SignalProvider';
|
|
|
12
12
|
export { default as LysQueryProvider } from './LysQueryProvider';
|
|
13
13
|
export { default as LysMutationProvider } from './LysMutationProvider';
|
|
14
14
|
export { default as ClientProvider } from './ClientProvider';
|
|
15
|
+
export { default as RouteProvider } from './RouteProvider';
|
|
15
16
|
export { useAlertMessages } from './AlertMessageProvider/hooks';
|
|
16
17
|
export { useLocale } from './LocaleProvider/hooks';
|
|
17
18
|
export { useLysDialog, useDialogWithUpdates } from './LysDialogProvider/hooks';
|
|
@@ -28,6 +29,10 @@ export { useLysMutation } from './LysMutationProvider/hooks';
|
|
|
28
29
|
export { usePermissionCheck } from './hooks/usePermissionCheck';
|
|
29
30
|
export { useRestrictedLink } from './hooks/useRestrictedLink';
|
|
30
31
|
export type { RestrictedLink } from './hooks/useRestrictedLink';
|
|
32
|
+
export { useRouteAccess } from './hooks/useRouteAccess';
|
|
33
|
+
export { useRouteInfo } from './RouteProvider/hooks';
|
|
34
|
+
export type { RouteContextValue } from './RouteProvider/hooks';
|
|
35
|
+
export type { RouteProviderProps, RouteTemplateProps } from './RouteProvider';
|
|
31
36
|
export { useClientId } from './ClientProvider/hooks';
|
|
32
37
|
export type { ClientContextValue, ClientProviderProps } from './ClientProvider/types';
|
|
33
38
|
export { default as LysLoadingContext, useLysLoadingFallback } from './LysQueryProvider/LysLoadingContext';
|
package/dist/providers/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A, C, a, b, c, E, F, G, L, d, e, f, g, P, R, S, U, W, u,
|
|
2
|
-
import { u as u2, a as a2 } from "../
|
|
1
|
+
import { A, C, a, b, c, E, F, G, L, d, e, f, g, P, R, h, S, U, W, u, i, j, k, l, m, n, o, p, q, r, s, t, v, w, x, y, z, B, D, H } from "../constants-sdhUzJ0l.js";
|
|
2
|
+
import { u as u2, a as a2 } from "../PublicAppTemplate-DLKcJZVR.js";
|
|
3
3
|
import { c as c2 } from "../RelayEnvironment-D880U9SM.js";
|
|
4
4
|
export {
|
|
5
5
|
A as AlertMessageProvider,
|
|
@@ -17,30 +17,33 @@ export {
|
|
|
17
17
|
g as LysQueryProvider,
|
|
18
18
|
P as PageContextProvider,
|
|
19
19
|
R as RefreshSignalContext,
|
|
20
|
+
h as RouteProvider,
|
|
20
21
|
S as SignalProvider,
|
|
21
22
|
U as UrlQueriesProvider,
|
|
22
23
|
W as WebserviceAccessProvider,
|
|
23
24
|
c2 as clearRelayCache,
|
|
24
25
|
u as useAlertMessages,
|
|
25
26
|
u2 as useChatbot,
|
|
26
|
-
|
|
27
|
+
i as useClientId,
|
|
27
28
|
a2 as useConnectedUserInfo,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
j as useDialogWithUpdates,
|
|
30
|
+
k as useFilterLabels,
|
|
31
|
+
l as useLocale,
|
|
32
|
+
m as useLysDialog,
|
|
33
|
+
n as useLysLoadingFallback,
|
|
34
|
+
o as useLysMutation,
|
|
35
|
+
p as useLysQuery,
|
|
36
|
+
q as usePageContext,
|
|
37
|
+
r as usePermissionCheck,
|
|
38
|
+
s as useRefreshSignal,
|
|
39
|
+
t as useRestrictedLink,
|
|
40
|
+
v as useRouteAccess,
|
|
41
|
+
w as useRouteInfo,
|
|
42
|
+
x as useSignal,
|
|
43
|
+
y as useSignalRefresh,
|
|
44
|
+
z as useSignalSubscription,
|
|
45
|
+
B as useUrlQueries,
|
|
46
|
+
D as useWebserviceAccess,
|
|
47
|
+
H as webserviceAccessProviderConfig
|
|
45
48
|
};
|
|
46
49
|
//# sourceMappingURL=index.js.map
|
package/dist/templates/index.js
CHANGED
package/dist/tools/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c, a, b, d, e, f, g, h, i, j, k, l, m, n, p, s, t, v } from "../translationTools-
|
|
2
|
-
import { g as g2, m as m2 } from "../i18nTools-
|
|
1
|
+
import { c, a, b, d, e, f, g, h, i, j, k, l, m, n, p, s, t, v } from "../translationTools-CKk0l3jr.js";
|
|
2
|
+
import { g as g2, m as m2 } from "../i18nTools-C1k2y9xe.js";
|
|
3
3
|
export {
|
|
4
4
|
c as checkOperationsPermission,
|
|
5
5
|
a as cleanParameters,
|
|
@@ -199,6 +199,7 @@ const generateUrlByRoute = (route, parameters = {}, queryParameters = {}) => {
|
|
|
199
199
|
return generateUrl(route.path, parameters, queryParameters);
|
|
200
200
|
};
|
|
201
201
|
const generateRouteFromDescription = (pageDescription, defaultTransPrefix = "lys.components.pages.") => {
|
|
202
|
+
var _a, _b;
|
|
202
203
|
return {
|
|
203
204
|
name: pageDescription.name,
|
|
204
205
|
transPrefix: defaultTransPrefix + lowerCaseFirstLetter(pageDescription.name) + ".",
|
|
@@ -208,7 +209,9 @@ const generateRouteFromDescription = (pageDescription, defaultTransPrefix = "lys
|
|
|
208
209
|
type: pageDescription.type,
|
|
209
210
|
breadcrumbs: pageDescription.breadcrumbs,
|
|
210
211
|
options: pageDescription.options,
|
|
211
|
-
mainWebserviceName: pageDescription.mainWebserviceName
|
|
212
|
+
mainWebserviceName: pageDescription.mainWebserviceName,
|
|
213
|
+
autoOpenChatbot: (_a = pageDescription.chatbotBehaviour) == null ? void 0 : _a.autoOpenOnEnter,
|
|
214
|
+
showChatbotWelcome: (_b = pageDescription.chatbotBehaviour) == null ? void 0 : _b.showWelcomeMessage
|
|
212
215
|
};
|
|
213
216
|
};
|
|
214
217
|
const generateRouteTable = (appDescription, defaultTransPrefix = "lys.components.pages.") => {
|
|
@@ -304,4 +307,4 @@ export {
|
|
|
304
307
|
toSnakeCase as t,
|
|
305
308
|
validators as v
|
|
306
309
|
};
|
|
307
|
-
//# sourceMappingURL=translationTools-
|
|
310
|
+
//# sourceMappingURL=translationTools-CKk0l3jr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translationTools-CKk0l3jr.js","sources":["../src/tools/stringTools.ts","../src/tools/validationTools.ts","../src/tools/relayTools.ts","../src/tools/routeTools.ts","../src/tools/translationTools.ts"],"sourcesContent":["/**\n * Convert first letter of string to lowercase\n */\nexport const lowerCaseFirstLetter = (str: string) => {\n return str.charAt(0).toLowerCase() + str.slice(1);\n}\n\n/**\n * Combine multiple classnames into a single string\n * Filters out falsy values\n */\nexport const cn = (...classes: (string | undefined | null | false)[]) => {\n return classes.filter(Boolean).join(' ');\n}\n\n/**\n * Convert camelCase string to snake_case\n */\nexport const toSnakeCase = (str: string): string => {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Convert number to string without scientific notation\n */\nexport const numberToString = (value: number | string | null | undefined): string => {\n if (value == null) return \"\";\n const num = typeof value === \"string\" ? parseFloat(value) : value;\n if (isNaN(num)) return \"\";\n return num.toLocaleString(\"fullwide\", {useGrouping: false, maximumFractionDigits: 20});\n}\n","/**\n * Validation utilities for form fields\n */\n\n/**\n * Check if a value is empty\n */\nexport const isEmpty = (value: unknown): boolean => {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === 'object') return Object.keys(value).length === 0;\n return false;\n};\n\n/**\n * Password validation regex patterns\n * Exported for reuse in other components\n */\nexport const passwordRegex = {\n lowercase: /^(?=.*[a-z]).*$/,\n uppercase: /^(?=.*[A-Z]).*$/,\n number: /^(?=.*[0-9]).*$/,\n minLength8: /^.{8,}$/,\n minLength12: /^.{12,}$/,\n specialChar: /[#?!@$%^&*-]/,\n};\n\n/**\n * Email validation regex\n */\nexport const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/**\n * Validator function type\n */\nexport type ValidatorFunction = (value: string | number | string[] | undefined) => boolean;\n\n/**\n * Validator with error message\n */\nexport interface Validator {\n method: ValidatorFunction;\n errorMessage: string;\n}\n\n/**\n * Pre-built validators\n */\nexport const validators = {\n /**\n * Validate that a field is not empty\n */\n required: (errorMessage: string): Validator => ({\n method: (value) => !isEmpty(value),\n errorMessage,\n }),\n\n /**\n * Validate email format\n */\n email: (errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true; // Use required validator separately\n return emailRegex.test(String(value));\n },\n errorMessage,\n }),\n\n /**\n * Validate minimum length\n */\n minLength: (min: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return String(value).length >= min;\n },\n errorMessage,\n }),\n\n /**\n * Validate maximum length\n */\n maxLength: (max: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return String(value).length <= max;\n },\n errorMessage,\n }),\n\n /**\n * Validate pattern\n */\n pattern: (regex: RegExp, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return regex.test(String(value));\n },\n errorMessage,\n }),\n\n /**\n * Validate minimum value for numbers\n */\n min: (min: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return Number(value) >= min;\n },\n errorMessage,\n }),\n\n /**\n * Validate maximum value for numbers\n */\n max: (max: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return Number(value) <= max;\n },\n errorMessage,\n }),\n\n /**\n * Custom validator\n */\n custom: (method: ValidatorFunction, errorMessage: string): Validator => ({\n method,\n errorMessage,\n }),\n};\n\n/**\n * Clean parameters by trimming strings and converting empty strings to undefined\n */\nexport const cleanParameters = (parameters: Record<string, unknown>): Record<string, unknown> => {\n const newParameters: Record<string, unknown> = {};\n\n Object.keys(parameters).forEach((key) => {\n const element = parameters[key];\n if (typeof element === \"object\" && element !== null && !Array.isArray(element)) {\n newParameters[key] = cleanParameters(element as Record<string, unknown>);\n } else if (typeof element === \"string\") {\n if (isEmpty(element)) {\n newParameters[key] = undefined;\n } else {\n newParameters[key] = element.trim();\n }\n } else {\n newParameters[key] = element;\n }\n });\n\n return newParameters;\n};\n\n/**\n * Get nested value from object using dot notation\n */\nexport const getNestedValue = (\n obj: Record<string, unknown>,\n path: string\n): string | number | string[] | undefined => {\n const keys = path.split(\".\");\n let result: unknown = obj;\n\n for (const key of keys) {\n if (result !== undefined && typeof result === \"object\" && result !== null && !Array.isArray(result)) {\n result = (result as Record<string, unknown>)[key];\n } else {\n return undefined;\n }\n }\n\n return result as string | number | string[] | undefined;\n};\n\n/**\n * Set nested value in object using dot notation\n */\nexport const setNestedValue = (\n obj: Record<string, unknown>,\n path: string,\n value: unknown\n): Record<string, unknown> => {\n const keys = path.split(\".\");\n const newObj: Record<string, unknown> = { ...obj };\n let current: Record<string, unknown> = newObj;\n\n keys.forEach((key, index) => {\n if (index === keys.length - 1) {\n current[key] = value;\n } else {\n if (!current[key] || typeof current[key] !== \"object\") {\n current[key] = {};\n } else {\n current[key] = { ...(current[key] as Record<string, unknown>) };\n }\n current = current[key] as Record<string, unknown>;\n }\n });\n\n return newObj;\n};\n","import {GraphQLTaggedNode} from \"relay-runtime\";\n\n/**\n * Extract operation names from a GraphQL query or mutation\n * Used for permission checking based on webservice names\n */\nexport function extractOperationNames(node: GraphQLTaggedNode): string[] {\n const operationNames: string[] = [];\n\n if ('operation' in node && node.operation) {\n const operation = node.operation as unknown as Record<string, unknown>;\n if ('selections' in operation && Array.isArray(operation.selections)) {\n operation.selections.forEach((selection) => {\n if (selection && typeof selection === 'object' && 'name' in selection) {\n operationNames.push(selection.name as string);\n }\n });\n }\n }\n\n return operationNames;\n}\n\n/**\n * Check if user has permission to access all operations\n * Note: checkWebserviceAccess handles snake_case conversion internally\n */\nexport function checkOperationsPermission(\n operationNames: string[],\n checkWebserviceAccess: (name: string) => boolean\n): boolean {\n if (!operationNames.length) {\n return false;\n }\n\n return operationNames.every(operationName =>\n checkWebserviceAccess(operationName)\n );\n}\n","import {RouteInterface} from \"../types/routeTypes\";\nimport {PageDescriptionType} from \"../types/descriptionTypes\";\nimport {lowerCaseFirstLetter} from \"./stringTools\";\nimport {isEmpty} from \"./validationTools\";\nimport type {AppDescription} from \"../types/relayTypes\";\n\n/**\n * Generate URL by replacing path parameters with provided values\n * @param path - URL path with placeholders (e.g., \"/user/:id\")\n * @param parameters - Object with path parameter values to substitute\n * @param queryParameters - Object with query parameter values to append\n * @returns Generated URL with replaced parameters and query string\n */\nexport const generateUrl = (\n path: string,\n parameters: {[key: string]: string} = {},\n queryParameters: {[key: string]: string} = {}\n) => {\n if (!isEmpty(parameters) && !isEmpty(path)) {\n const splitPath = path.split('/');\n Object.keys(splitPath).forEach(pathKey => {\n Object.keys(parameters).forEach(key => {\n if ( splitPath[parseInt(pathKey)] === ':' + key) {\n splitPath[parseInt(pathKey)] = parameters[key];\n }\n });\n });\n path = splitPath.join('/');\n }\n\n // Append query parameters if provided\n if (!isEmpty(queryParameters)) {\n const queryString = new URLSearchParams(queryParameters).toString();\n path = `${path}?${queryString}`;\n }\n\n return path;\n}\n\n/**\n * Generate URL from route using path and query parameters\n */\nexport const generateUrlByRoute = (\n route: RouteInterface,\n parameters: {[key: string]: string} = {},\n queryParameters: {[key: string]: string} = {}\n) => {\n return generateUrl(route.path, parameters, queryParameters)\n}\n\n/**\n * Convert page description to route interface\n */\nexport const generateRouteFromDescription = (\n pageDescription: PageDescriptionType,\n defaultTransPrefix: string = \"lys.components.pages.\"\n): RouteInterface => {\n return {\n name: pageDescription.name,\n transPrefix: defaultTransPrefix + lowerCaseFirstLetter(pageDescription.name) + \".\",\n path: pageDescription.path,\n component: pageDescription.component,\n template: pageDescription.template,\n type: pageDescription.type,\n breadcrumbs: pageDescription.breadcrumbs,\n options: pageDescription.options,\n mainWebserviceName: pageDescription.mainWebserviceName,\n autoOpenChatbot: pageDescription.chatbotBehaviour?.autoOpenOnEnter,\n showChatbotWelcome: pageDescription.chatbotBehaviour?.showWelcomeMessage,\n }\n}\n\n/**\n * Generate route table from app description\n */\nexport const generateRouteTable = (\n appDescription: AppDescription,\n defaultTransPrefix: string = \"lys.components.pages.\"\n): RouteInterface[] => {\n const pages: {[key: string]: PageDescriptionType} = appDescription?.components?.pages ?? {}\n\n return Object.keys(pages).map((pageName) => {\n const pageDescription: PageDescriptionType = pages[pageName];\n\n return generateRouteFromDescription(pageDescription, defaultTransPrefix)\n })\n}\n","import {useMemo} from \"react\";\nimport {useIntl} from \"react-intl\";\nimport {ComponentDescriptionType} from \"../types/descriptionTypes\";\nimport {TranslationType} from \"../types/i18nTypes\";\nimport {I18nLocaleEnum} from \"../types/i18nTypes\";\n\n/**\n * Infers component type from component name based on naming convention\n * - ends with \"Feature\" -> \"features\"\n * - ends with \"Element\" -> \"elements\"\n * - ends with \"Page\" -> \"pages\"\n * - ends with \"Restricted\" -> \"restrictedFeatures\"\n * - ends with \"Provider\" -> \"providers\"\n */\nconst inferComponentType = (componentName: string): string => {\n if (componentName.endsWith(\"Feature\")) return \"features\";\n if (componentName.endsWith(\"Element\")) return \"elements\";\n if (componentName.endsWith(\"Page\")) return \"pages\";\n if (componentName.endsWith(\"Restricted\")) return \"restrictedFeatures\";\n if (componentName.endsWith(\"Provider\")) return \"providers\";\n\n throw new Error(\n `Cannot infer component type from \"${componentName}\". ` +\n `Component name must end with: Feature, Element, Page, Restricted, or Provider`\n );\n};\n\n/**\n * Converts component name to translation key format\n * LoginFeature -> loginFeature\n * ButtonElement -> buttonElement\n */\nconst toTranslationKey = (componentName: string): string => {\n return componentName.charAt(0).toLowerCase() + componentName.slice(1);\n};\n\n/**\n * Creates a component translation configuration with typed helper hook\n *\n * Supports all languages defined in I18nLocaleEnum. TypeScript will enforce\n * that all translations include every language.\n *\n * @param componentName - Component name (e.g., \"LoginFeature\", \"ButtonElement\")\n * @param translations - Translation object with keys in format {key: Record<I18nLocaleEnum, string>}\n * @param pathBase - Base path for translations (default: \"lys.components.\")\n * @returns Object with config for i18n system and useTranslations hook\n *\n * @example\n * ```typescript\n * // In LoginFeature/translations.ts\n * const {config, useTranslations} = createComponentTranslations(\n * \"LoginFeature\",\n * {\n * email: {en: \"Email\", fr: \"Email\"},\n * password: {en: \"Password\", fr: \"Mot de passe\"}\n * }\n * );\n *\n * export const loginFeatureConfig = config;\n * export const useLoginTranslations = useTranslations;\n *\n * // In LoginFeature/index.tsx\n * const {t} = useLoginTranslations();\n * const label = t(\"email\"); // Type-safe!\n * ```\n */\nexport const createComponentTranslations = <\n T extends Record<string, Record<I18nLocaleEnum, string>>,\n TCommonKey extends string = string\n>(\n componentName: string,\n translations: T,\n pathBase: string = \"lys.components.\"\n) => {\n const componentType = inferComponentType(componentName);\n const translationKey = toTranslationKey(componentName);\n const translationPath = `${pathBase}${componentType}.${translationKey}`;\n\n return {\n /**\n * Configuration object for the i18n system\n * Export this in your features/elements/pages/restrictedFeatures index\n */\n config: {\n translation: translations as TranslationType\n } satisfies ComponentDescriptionType,\n\n /**\n * React hook to use translations in your component\n * Returns an object with type-safe `t()` and `common()` functions\n *\n * @returns Object containing:\n * - t(key, values?): Component-specific translations with optional interpolation\n * - common(key, values?): Shared common translations with optional interpolation\n */\n useTranslations: () => {\n const intl = useIntl();\n\n return useMemo(() => {\n /**\n * Translate a component-specific key\n * @param key - Translation key (autocompleted)\n * @param options - Optional: values for interpolation, fallbackToKey to return raw key if not found\n */\n const t = (key: keyof T, options?: {\n values?: Record<string, string | number>,\n fallbackToKey?: boolean\n }): string => {\n const id = `${translationPath}.${String(key)}`;\n const result = intl.formatMessage({id}, options?.values);\n if (options?.fallbackToKey && result === id) {\n return String(key);\n }\n return result;\n };\n\n /**\n * Translate a common/shared key\n * @param key - Common translation key (autocompleted)\n * @param options - Optional: values for interpolation, fallbackToKey to return raw key if not found\n */\n const common = (key: TCommonKey, options?: {\n values?: Record<string, string | number>,\n fallbackToKey?: boolean\n }): string => {\n const id = `lys.services.i18n.common.${String(key)}`;\n const result = intl.formatMessage({id}, options?.values);\n if (options?.fallbackToKey && result === id) {\n return String(key);\n }\n return result;\n };\n\n return {t, common};\n }, [intl]);\n },\n\n /**\n * Generated translation path (for debugging)\n */\n translationPath,\n\n /**\n * Available translation keys (for reference)\n */\n translationKeys: Object.keys(translations) as Array<keyof T>\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,10 @@ export interface ComponentDescriptionType {
|
|
|
7
7
|
export interface ChatbotBehaviourType {
|
|
8
8
|
prompt?: string;
|
|
9
9
|
contextTools?: Record<string, string>;
|
|
10
|
+
/** Mapped to `RouteInterface.autoOpenChatbot`. */
|
|
11
|
+
autoOpenOnEnter?: boolean;
|
|
12
|
+
/** Mapped to `RouteInterface.showChatbotWelcome`. */
|
|
13
|
+
showWelcomeMessage?: boolean;
|
|
10
14
|
}
|
|
11
15
|
export type PageDescriptionType = ComponentDescriptionType & {
|
|
12
16
|
name: string;
|
|
@@ -18,7 +22,13 @@ export type PageDescriptionType = ComponentDescriptionType & {
|
|
|
18
22
|
options?: {
|
|
19
23
|
[key: string]: string | number | boolean;
|
|
20
24
|
};
|
|
21
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Webservice(s) gating access to the page.
|
|
27
|
+
* - `string`: single webservice — user needs access to it.
|
|
28
|
+
* - `string[]`: any-of semantics — user needs access to at least one.
|
|
29
|
+
* - `undefined`: page has no permission gate.
|
|
30
|
+
*/
|
|
31
|
+
mainWebserviceName?: string | string[] | undefined;
|
|
22
32
|
description?: string;
|
|
23
33
|
chatbotBehaviour?: ChatbotBehaviourType;
|
|
24
34
|
extraWebservices?: string[];
|
|
@@ -14,6 +14,20 @@ export interface RouteInterface {
|
|
|
14
14
|
options?: {
|
|
15
15
|
[key: string]: string | number | boolean;
|
|
16
16
|
};
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Webservice(s) gating access to the route.
|
|
19
|
+
* - `string`: single webservice — user needs access to it.
|
|
20
|
+
* - `string[]`: any-of semantics — user needs access to at least one.
|
|
21
|
+
* - `undefined`: route has no permission gate.
|
|
22
|
+
*/
|
|
23
|
+
mainWebserviceName?: string | string[] | undefined;
|
|
18
24
|
description?: string;
|
|
25
|
+
/** If true, the chatbot is automatically opened when the user enters this route. */
|
|
26
|
+
autoOpenChatbot?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* If true, an empty-conversation welcome message is shown in the chatbot.
|
|
29
|
+
* The message is resolved against the translation key `<transPrefix>chatbotWelcome`;
|
|
30
|
+
* if no translation exists, react-intl displays the key as-is.
|
|
31
|
+
*/
|
|
32
|
+
showChatbotWelcome?: boolean;
|
|
19
33
|
}
|
package/package.json
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { Navigate } from "react-router-dom";
|
|
4
|
-
import { a as useConnectedUserInfo, u as useChatbot } from "./hooks-CvhFUowR.js";
|
|
5
|
-
const PublicAppTemplate = ({
|
|
6
|
-
route,
|
|
7
|
-
defaultPrivateRoute,
|
|
8
|
-
children
|
|
9
|
-
}) => {
|
|
10
|
-
var _a;
|
|
11
|
-
const { user } = useConnectedUserInfo();
|
|
12
|
-
const { setIsChatbotEnabled } = useChatbot();
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
setIsChatbotEnabled(false);
|
|
15
|
-
return () => setIsChatbotEnabled(true);
|
|
16
|
-
}, [setIsChatbotEnabled]);
|
|
17
|
-
const isOpened = ((_a = route.options) == null ? void 0 : _a.opened) === true;
|
|
18
|
-
if (user && !isOpened) {
|
|
19
|
-
return /* @__PURE__ */ jsx(Navigate, { to: defaultPrivateRoute.path, replace: true });
|
|
20
|
-
}
|
|
21
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
22
|
-
};
|
|
23
|
-
export {
|
|
24
|
-
PublicAppTemplate as P
|
|
25
|
-
};
|
|
26
|
-
//# sourceMappingURL=PublicAppTemplate-B93G2Smc.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PublicAppTemplate-B93G2Smc.js","sources":["../src/templates/PublicAppTemplate.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {useEffect} from \"react\";\nimport {Navigate} from \"react-router-dom\";\nimport {useConnectedUserInfo} from \"../providers/ConnectedUserProvider/hooks\";\nimport {useChatbot} from \"../providers/ChatbotProvider/hooks\";\nimport {RouteInterface} from \"../types/routeTypes\";\n\ninterface PublicAppTemplateProps {\n route: RouteInterface\n defaultPrivateRoute: RouteInterface\n defaultPublicRoute: RouteInterface\n children: React.ReactNode\n}\n\n/**\n * Public app template\n * Wraps public pages and redirects authenticated users to private area\n * Unless route.options?.opened is true (public pages accessible when connected)\n */\nconst PublicAppTemplate: React.ComponentType<PublicAppTemplateProps> = (\n {\n route,\n defaultPrivateRoute,\n children\n }) => {\n\n /*******************************************************************************************************************\n * HOOKS\n ******************************************************************************************************************/\n\n const {user} = useConnectedUserInfo();\n const {setIsChatbotEnabled} = useChatbot();\n\n /*******************************************************************************************************************\n * EFFECTS\n ******************************************************************************************************************/\n\n // Disable chatbot on public pages\n useEffect(() => {\n setIsChatbotEnabled(false);\n return () => setIsChatbotEnabled(true);\n }, [setIsChatbotEnabled]);\n\n /*******************************************************************************************************************\n * RENDER\n ******************************************************************************************************************/\n\n // Redirect authenticated users to private area (unless page is opened)\n const isOpened = route.options?.opened === true;\n if (user && !isOpened) {\n return <Navigate to={defaultPrivateRoute.path} replace />;\n }\n\n return (\n <>\n {children}\n </>\n );\n};\n\nexport default PublicAppTemplate;\n"],"names":[],"mappings":";;;;AAmBA,MAAM,oBAAiE,CACnE;AAAA,EACI;AAAA,EACA;AAAA,EACA;AACJ,MAAM;;AAMN,QAAM,EAAC,KAAA,IAAQ,qBAAA;AACf,QAAM,EAAC,oBAAA,IAAuB,WAAA;AAO9B,YAAU,MAAM;AACZ,wBAAoB,KAAK;AACzB,WAAO,MAAM,oBAAoB,IAAI;AAAA,EACzC,GAAG,CAAC,mBAAmB,CAAC;AAOxB,QAAM,aAAW,WAAM,YAAN,mBAAe,YAAW;AAC3C,MAAI,QAAQ,CAAC,UAAU;AACnB,+BAAQ,UAAA,EAAS,IAAI,oBAAoB,MAAM,SAAO,MAAC;AAAA,EAC3D;AAEA,yCAES,UACL;AAER;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-CvhFUowR.js","sources":["../src/providers/ChatbotProvider/hooks.ts","../src/providers/ConnectedUserProvider/hooks.ts"],"sourcesContent":["import {createContext, useContext} from \"react\";\nimport {ChatbotContextValue} from \"./types\";\n\nexport const ChatbotContext = createContext<ChatbotContextValue | null>(null);\n\nexport const useChatbot = (): ChatbotContextValue => {\n const context = useContext(ChatbotContext);\n if (!context) {\n throw new Error(\"useChatbot must be used within a ChatbotProvider\");\n }\n return context;\n};\n","import {createContext, useContext} from \"react\";\nimport {ConnectedUserInterface} from \"./types\";\n\n/**\n * Connected user context\n */\nconst ConnectedUserContext = createContext<{\n user: ConnectedUserInterface | undefined\n push(webservice: () => void): void\n login: [(login: string, password: string) => void, boolean],\n logout: [() => void, boolean],\n refresh: [() => void, boolean],\n handleSessionExpired: (onRefreshSuccess?: () => void) => void\n}>({\n user: undefined,\n push: () => {\n console.warn(\"ConnectedUserProvider not initialized: push\")\n },\n login: [() => {\n console.warn(\"ConnectedUserProvider not initialized: login\")\n }, false],\n logout: [() => {\n console.warn(\"ConnectedUserProvider not initialized: logout\")\n }, false],\n refresh: [() => {\n console.warn(\"ConnectedUserProvider not initialized: refresh\")\n }, false],\n handleSessionExpired: () => {\n console.warn(\"ConnectedUserProvider not initialized: handleSessionExpired\")\n }\n});\n\n/**\n * Hook to access connected user info\n */\nfunction useConnectedUserInfo() {\n return useContext(ConnectedUserContext)\n}\n\nexport {\n ConnectedUserContext,\n useConnectedUserInfo\n}\n"],"names":[],"mappings":";AAGO,MAAM,iBAAiB,cAA0C,IAAI;AAErE,MAAM,aAAa,MAA2B;AACjD,QAAM,UAAU,WAAW,cAAc;AACzC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACtE;AACA,SAAO;AACX;ACLA,MAAM,uBAAuB,cAO1B;AAAA,EACC,MAAM;AAAA,EACN,MAAM,MAAM;AACR,YAAQ,KAAK,6CAA6C;AAAA,EAC9D;AAAA,EACA,OAAO,CAAC,MAAM;AACV,YAAQ,KAAK,8CAA8C;AAAA,EAC/D,GAAG,KAAK;AAAA,EACR,QAAQ,CAAC,MAAM;AACX,YAAQ,KAAK,+CAA+C;AAAA,EAChE,GAAG,KAAK;AAAA,EACR,SAAS,CAAC,MAAM;AACZ,YAAQ,KAAK,gDAAgD;AAAA,EACjE,GAAG,KAAK;AAAA,EACR,sBAAsB,MAAM;AACxB,YAAQ,KAAK,6DAA6D;AAAA,EAC9E;AACJ,CAAC;AAKD,SAAS,uBAAuB;AAC5B,SAAO,WAAW,oBAAoB;AAC1C;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"translationTools-RWoOzX2m.js","sources":["../src/tools/stringTools.ts","../src/tools/validationTools.ts","../src/tools/relayTools.ts","../src/tools/routeTools.ts","../src/tools/translationTools.ts"],"sourcesContent":["/**\n * Convert first letter of string to lowercase\n */\nexport const lowerCaseFirstLetter = (str: string) => {\n return str.charAt(0).toLowerCase() + str.slice(1);\n}\n\n/**\n * Combine multiple classnames into a single string\n * Filters out falsy values\n */\nexport const cn = (...classes: (string | undefined | null | false)[]) => {\n return classes.filter(Boolean).join(' ');\n}\n\n/**\n * Convert camelCase string to snake_case\n */\nexport const toSnakeCase = (str: string): string => {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Convert number to string without scientific notation\n */\nexport const numberToString = (value: number | string | null | undefined): string => {\n if (value == null) return \"\";\n const num = typeof value === \"string\" ? parseFloat(value) : value;\n if (isNaN(num)) return \"\";\n return num.toLocaleString(\"fullwide\", {useGrouping: false, maximumFractionDigits: 20});\n}\n","/**\n * Validation utilities for form fields\n */\n\n/**\n * Check if a value is empty\n */\nexport const isEmpty = (value: unknown): boolean => {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === 'object') return Object.keys(value).length === 0;\n return false;\n};\n\n/**\n * Password validation regex patterns\n * Exported for reuse in other components\n */\nexport const passwordRegex = {\n lowercase: /^(?=.*[a-z]).*$/,\n uppercase: /^(?=.*[A-Z]).*$/,\n number: /^(?=.*[0-9]).*$/,\n minLength8: /^.{8,}$/,\n minLength12: /^.{12,}$/,\n specialChar: /[#?!@$%^&*-]/,\n};\n\n/**\n * Email validation regex\n */\nexport const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/**\n * Validator function type\n */\nexport type ValidatorFunction = (value: string | number | string[] | undefined) => boolean;\n\n/**\n * Validator with error message\n */\nexport interface Validator {\n method: ValidatorFunction;\n errorMessage: string;\n}\n\n/**\n * Pre-built validators\n */\nexport const validators = {\n /**\n * Validate that a field is not empty\n */\n required: (errorMessage: string): Validator => ({\n method: (value) => !isEmpty(value),\n errorMessage,\n }),\n\n /**\n * Validate email format\n */\n email: (errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true; // Use required validator separately\n return emailRegex.test(String(value));\n },\n errorMessage,\n }),\n\n /**\n * Validate minimum length\n */\n minLength: (min: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return String(value).length >= min;\n },\n errorMessage,\n }),\n\n /**\n * Validate maximum length\n */\n maxLength: (max: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return String(value).length <= max;\n },\n errorMessage,\n }),\n\n /**\n * Validate pattern\n */\n pattern: (regex: RegExp, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return regex.test(String(value));\n },\n errorMessage,\n }),\n\n /**\n * Validate minimum value for numbers\n */\n min: (min: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return Number(value) >= min;\n },\n errorMessage,\n }),\n\n /**\n * Validate maximum value for numbers\n */\n max: (max: number, errorMessage: string): Validator => ({\n method: (value) => {\n if (isEmpty(value)) return true;\n return Number(value) <= max;\n },\n errorMessage,\n }),\n\n /**\n * Custom validator\n */\n custom: (method: ValidatorFunction, errorMessage: string): Validator => ({\n method,\n errorMessage,\n }),\n};\n\n/**\n * Clean parameters by trimming strings and converting empty strings to undefined\n */\nexport const cleanParameters = (parameters: Record<string, unknown>): Record<string, unknown> => {\n const newParameters: Record<string, unknown> = {};\n\n Object.keys(parameters).forEach((key) => {\n const element = parameters[key];\n if (typeof element === \"object\" && element !== null && !Array.isArray(element)) {\n newParameters[key] = cleanParameters(element as Record<string, unknown>);\n } else if (typeof element === \"string\") {\n if (isEmpty(element)) {\n newParameters[key] = undefined;\n } else {\n newParameters[key] = element.trim();\n }\n } else {\n newParameters[key] = element;\n }\n });\n\n return newParameters;\n};\n\n/**\n * Get nested value from object using dot notation\n */\nexport const getNestedValue = (\n obj: Record<string, unknown>,\n path: string\n): string | number | string[] | undefined => {\n const keys = path.split(\".\");\n let result: unknown = obj;\n\n for (const key of keys) {\n if (result !== undefined && typeof result === \"object\" && result !== null && !Array.isArray(result)) {\n result = (result as Record<string, unknown>)[key];\n } else {\n return undefined;\n }\n }\n\n return result as string | number | string[] | undefined;\n};\n\n/**\n * Set nested value in object using dot notation\n */\nexport const setNestedValue = (\n obj: Record<string, unknown>,\n path: string,\n value: unknown\n): Record<string, unknown> => {\n const keys = path.split(\".\");\n const newObj: Record<string, unknown> = { ...obj };\n let current: Record<string, unknown> = newObj;\n\n keys.forEach((key, index) => {\n if (index === keys.length - 1) {\n current[key] = value;\n } else {\n if (!current[key] || typeof current[key] !== \"object\") {\n current[key] = {};\n } else {\n current[key] = { ...(current[key] as Record<string, unknown>) };\n }\n current = current[key] as Record<string, unknown>;\n }\n });\n\n return newObj;\n};\n","import {GraphQLTaggedNode} from \"relay-runtime\";\n\n/**\n * Extract operation names from a GraphQL query or mutation\n * Used for permission checking based on webservice names\n */\nexport function extractOperationNames(node: GraphQLTaggedNode): string[] {\n const operationNames: string[] = [];\n\n if ('operation' in node && node.operation) {\n const operation = node.operation as unknown as Record<string, unknown>;\n if ('selections' in operation && Array.isArray(operation.selections)) {\n operation.selections.forEach((selection) => {\n if (selection && typeof selection === 'object' && 'name' in selection) {\n operationNames.push(selection.name as string);\n }\n });\n }\n }\n\n return operationNames;\n}\n\n/**\n * Check if user has permission to access all operations\n * Note: checkWebserviceAccess handles snake_case conversion internally\n */\nexport function checkOperationsPermission(\n operationNames: string[],\n checkWebserviceAccess: (name: string) => boolean\n): boolean {\n if (!operationNames.length) {\n return false;\n }\n\n return operationNames.every(operationName =>\n checkWebserviceAccess(operationName)\n );\n}\n","import {RouteInterface} from \"../types/routeTypes\";\nimport {PageDescriptionType} from \"../types/descriptionTypes\";\nimport {lowerCaseFirstLetter} from \"./stringTools\";\nimport {isEmpty} from \"./validationTools\";\nimport type {AppDescription} from \"../types/relayTypes\";\n\n/**\n * Generate URL by replacing path parameters with provided values\n * @param path - URL path with placeholders (e.g., \"/user/:id\")\n * @param parameters - Object with path parameter values to substitute\n * @param queryParameters - Object with query parameter values to append\n * @returns Generated URL with replaced parameters and query string\n */\nexport const generateUrl = (\n path: string,\n parameters: {[key: string]: string} = {},\n queryParameters: {[key: string]: string} = {}\n) => {\n if (!isEmpty(parameters) && !isEmpty(path)) {\n const splitPath = path.split('/');\n Object.keys(splitPath).forEach(pathKey => {\n Object.keys(parameters).forEach(key => {\n if ( splitPath[parseInt(pathKey)] === ':' + key) {\n splitPath[parseInt(pathKey)] = parameters[key];\n }\n });\n });\n path = splitPath.join('/');\n }\n\n // Append query parameters if provided\n if (!isEmpty(queryParameters)) {\n const queryString = new URLSearchParams(queryParameters).toString();\n path = `${path}?${queryString}`;\n }\n\n return path;\n}\n\n/**\n * Generate URL from route using path and query parameters\n */\nexport const generateUrlByRoute = (\n route: RouteInterface,\n parameters: {[key: string]: string} = {},\n queryParameters: {[key: string]: string} = {}\n) => {\n return generateUrl(route.path, parameters, queryParameters)\n}\n\n/**\n * Convert page description to route interface\n */\nexport const generateRouteFromDescription = (\n pageDescription: PageDescriptionType,\n defaultTransPrefix: string = \"lys.components.pages.\"\n): RouteInterface => {\n return {\n name: pageDescription.name,\n transPrefix: defaultTransPrefix + lowerCaseFirstLetter(pageDescription.name) + \".\",\n path: pageDescription.path,\n component: pageDescription.component,\n template: pageDescription.template,\n type: pageDescription.type,\n breadcrumbs: pageDescription.breadcrumbs,\n options: pageDescription.options,\n mainWebserviceName: pageDescription.mainWebserviceName,\n }\n}\n\n/**\n * Generate route table from app description\n */\nexport const generateRouteTable = (\n appDescription: AppDescription,\n defaultTransPrefix: string = \"lys.components.pages.\"\n): RouteInterface[] => {\n const pages: {[key: string]: PageDescriptionType} = appDescription?.components?.pages ?? {}\n\n return Object.keys(pages).map((pageName) => {\n const pageDescription: PageDescriptionType = pages[pageName];\n\n return generateRouteFromDescription(pageDescription, defaultTransPrefix)\n })\n}\n","import {useMemo} from \"react\";\nimport {useIntl} from \"react-intl\";\nimport {ComponentDescriptionType} from \"../types/descriptionTypes\";\nimport {TranslationType} from \"../types/i18nTypes\";\nimport {I18nLocaleEnum} from \"../types/i18nTypes\";\n\n/**\n * Infers component type from component name based on naming convention\n * - ends with \"Feature\" -> \"features\"\n * - ends with \"Element\" -> \"elements\"\n * - ends with \"Page\" -> \"pages\"\n * - ends with \"Restricted\" -> \"restrictedFeatures\"\n * - ends with \"Provider\" -> \"providers\"\n */\nconst inferComponentType = (componentName: string): string => {\n if (componentName.endsWith(\"Feature\")) return \"features\";\n if (componentName.endsWith(\"Element\")) return \"elements\";\n if (componentName.endsWith(\"Page\")) return \"pages\";\n if (componentName.endsWith(\"Restricted\")) return \"restrictedFeatures\";\n if (componentName.endsWith(\"Provider\")) return \"providers\";\n\n throw new Error(\n `Cannot infer component type from \"${componentName}\". ` +\n `Component name must end with: Feature, Element, Page, Restricted, or Provider`\n );\n};\n\n/**\n * Converts component name to translation key format\n * LoginFeature -> loginFeature\n * ButtonElement -> buttonElement\n */\nconst toTranslationKey = (componentName: string): string => {\n return componentName.charAt(0).toLowerCase() + componentName.slice(1);\n};\n\n/**\n * Creates a component translation configuration with typed helper hook\n *\n * Supports all languages defined in I18nLocaleEnum. TypeScript will enforce\n * that all translations include every language.\n *\n * @param componentName - Component name (e.g., \"LoginFeature\", \"ButtonElement\")\n * @param translations - Translation object with keys in format {key: Record<I18nLocaleEnum, string>}\n * @param pathBase - Base path for translations (default: \"lys.components.\")\n * @returns Object with config for i18n system and useTranslations hook\n *\n * @example\n * ```typescript\n * // In LoginFeature/translations.ts\n * const {config, useTranslations} = createComponentTranslations(\n * \"LoginFeature\",\n * {\n * email: {en: \"Email\", fr: \"Email\"},\n * password: {en: \"Password\", fr: \"Mot de passe\"}\n * }\n * );\n *\n * export const loginFeatureConfig = config;\n * export const useLoginTranslations = useTranslations;\n *\n * // In LoginFeature/index.tsx\n * const {t} = useLoginTranslations();\n * const label = t(\"email\"); // Type-safe!\n * ```\n */\nexport const createComponentTranslations = <\n T extends Record<string, Record<I18nLocaleEnum, string>>,\n TCommonKey extends string = string\n>(\n componentName: string,\n translations: T,\n pathBase: string = \"lys.components.\"\n) => {\n const componentType = inferComponentType(componentName);\n const translationKey = toTranslationKey(componentName);\n const translationPath = `${pathBase}${componentType}.${translationKey}`;\n\n return {\n /**\n * Configuration object for the i18n system\n * Export this in your features/elements/pages/restrictedFeatures index\n */\n config: {\n translation: translations as TranslationType\n } satisfies ComponentDescriptionType,\n\n /**\n * React hook to use translations in your component\n * Returns an object with type-safe `t()` and `common()` functions\n *\n * @returns Object containing:\n * - t(key, values?): Component-specific translations with optional interpolation\n * - common(key, values?): Shared common translations with optional interpolation\n */\n useTranslations: () => {\n const intl = useIntl();\n\n return useMemo(() => {\n /**\n * Translate a component-specific key\n * @param key - Translation key (autocompleted)\n * @param options - Optional: values for interpolation, fallbackToKey to return raw key if not found\n */\n const t = (key: keyof T, options?: {\n values?: Record<string, string | number>,\n fallbackToKey?: boolean\n }): string => {\n const id = `${translationPath}.${String(key)}`;\n const result = intl.formatMessage({id}, options?.values);\n if (options?.fallbackToKey && result === id) {\n return String(key);\n }\n return result;\n };\n\n /**\n * Translate a common/shared key\n * @param key - Common translation key (autocompleted)\n * @param options - Optional: values for interpolation, fallbackToKey to return raw key if not found\n */\n const common = (key: TCommonKey, options?: {\n values?: Record<string, string | number>,\n fallbackToKey?: boolean\n }): string => {\n const id = `lys.services.i18n.common.${String(key)}`;\n const result = intl.formatMessage({id}, options?.values);\n if (options?.fallbackToKey && result === id) {\n return String(key);\n }\n return result;\n };\n\n return {t, common};\n }, [intl]);\n },\n\n /**\n * Generated translation path (for debugging)\n */\n translationPath,\n\n /**\n * Available translation keys (for reference)\n */\n translationKeys: Object.keys(translations) as Array<keyof T>\n };\n};\n"],"names":[],"mappings":"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"}
|