runid-lys 0.6.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 CHANGED
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - `RouteProvider` exposing the active route, the route map and helpers via `useRouteInfo`, wiring page context and chatbot auto-open, and rendering project-supplied private/public templates
13
+ - `useRouteAccess` hook centralizing route permission checks (supports `string` and `string[]` any-of semantics for `mainWebserviceName`)
14
+ - Export `RouteProvider`, `useRouteInfo`, `useRouteAccess`, and related types (`RouteContextValue`, `RouteProviderProps`, `RouteTemplateProps`) from `runid-lys/providers`
15
+
16
+ ### Changed
17
+
18
+ - `RouteInterface.mainWebserviceName` and `PageDescriptionType.mainWebserviceName` accept `string | string[]` (any-of) in addition to `string`
19
+ - `useRestrictedLink` delegates permission checking to `useRouteAccess` so single/array semantics stay in one place
20
+
21
+ ### Fixed
22
+
23
+ - Empty-string URL query params are no longer coerced to `0` when forwarded to the chatbot page context
24
+
10
25
  ## [0.6.0] - 2026-05-14
11
26
 
12
27
  ### Added
@@ -1,4 +1,6 @@
1
- import { createContext, useContext } from "react";
1
+ import { jsx, Fragment } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect } from "react";
3
+ import { Navigate } from "react-router-dom";
2
4
  const ChatbotContext = createContext(null);
3
5
  const useChatbot = () => {
4
6
  const context = useContext(ChatbotContext);
@@ -28,10 +30,29 @@ const ConnectedUserContext = createContext({
28
30
  function useConnectedUserInfo() {
29
31
  return useContext(ConnectedUserContext);
30
32
  }
33
+ const PublicAppTemplate = ({
34
+ route,
35
+ defaultPrivateRoute,
36
+ children
37
+ }) => {
38
+ var _a;
39
+ const { user } = useConnectedUserInfo();
40
+ const { setIsChatbotEnabled } = useChatbot();
41
+ useEffect(() => {
42
+ setIsChatbotEnabled(false);
43
+ return () => setIsChatbotEnabled(true);
44
+ }, [setIsChatbotEnabled]);
45
+ const isOpened = ((_a = route.options) == null ? void 0 : _a.opened) === true;
46
+ if (user && !isOpened) {
47
+ return /* @__PURE__ */ jsx(Navigate, { to: defaultPrivateRoute.path, replace: true });
48
+ }
49
+ return /* @__PURE__ */ jsx(Fragment, { children });
50
+ };
31
51
  export {
32
52
  ChatbotContext as C,
53
+ PublicAppTemplate as P,
33
54
  useConnectedUserInfo as a,
34
55
  ConnectedUserContext as b,
35
56
  useChatbot as u
36
57
  };
37
- //# sourceMappingURL=hooks-CvhFUowR.js.map
58
+ //# sourceMappingURL=PublicAppTemplate-DLKcJZVR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PublicAppTemplate-DLKcJZVR.js","sources":["../src/providers/ChatbotProvider/hooks.ts","../src/providers/ConnectedUserProvider/hooks.ts","../src/templates/PublicAppTemplate.tsx"],"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","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":";;;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;AClBA,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;"}
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4
4
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
5
5
  import * as React from "react";
6
6
  import React__default, { createContext, useContext, useMemo, useState, useCallback, useRef, useEffect, useReducer, forwardRef, Suspense, useImperativeHandle, useTransition } from "react";
7
- import { C as ChatbotContext, b as ConnectedUserContext, a as useConnectedUserInfo } from "./hooks-CvhFUowR.js";
7
+ import { C as ChatbotContext, b as ConnectedUserContext, a as useConnectedUserInfo, u as useChatbot, P as PublicAppTemplate } from "./PublicAppTemplate-DLKcJZVR.js";
8
8
  import { useSearchParams, useLocation, matchPath, useNavigate } from "react-router-dom";
9
9
  import { usePreloadedQuery, useFragment, useMutation, useQueryLoader } from "react-relay";
10
10
  import { IntlProvider, useIntl } from "react-intl";
@@ -2155,16 +2155,117 @@ const ClientProvider = ({ children, routes }) => {
2155
2155
  return /* @__PURE__ */ jsx(ClientContext.Provider, { value, children });
2156
2156
  };
2157
2157
  ClientProvider.displayName = "ClientProvider";
2158
+ const RouteContext = createContext({
2159
+ route: null,
2160
+ defaultPrivateRoute: null,
2161
+ defaultPublicRoute: null,
2162
+ allRoutes: {},
2163
+ getRouteByName: () => void 0
2164
+ });
2165
+ const useRouteInfo = () => useContext(RouteContext);
2166
+ const RouteProvider = ({
2167
+ route,
2168
+ routes,
2169
+ defaultPrivateRoute,
2170
+ defaultPublicRoute,
2171
+ privateTemplate: PrivateTemplate,
2172
+ publicTemplate: PublicTemplate = PublicAppTemplate,
2173
+ children
2174
+ }) => {
2175
+ const { setPageContext } = usePageContext();
2176
+ const { appliedParams } = useUrlQueries();
2177
+ const { setIsChatbotMode } = useChatbot();
2178
+ useEffect(() => {
2179
+ const params = {};
2180
+ let orderByField = null;
2181
+ let orderDir = null;
2182
+ appliedParams.forEach((value, key) => {
2183
+ if (key === "orderBy") {
2184
+ orderByField = value;
2185
+ return;
2186
+ }
2187
+ if (key === "orderDir") {
2188
+ orderDir = value;
2189
+ return;
2190
+ }
2191
+ if (value !== "" && !isNaN(Number(value))) {
2192
+ params[key] = Number(value);
2193
+ } else {
2194
+ params[key] = value;
2195
+ }
2196
+ });
2197
+ if (orderByField) {
2198
+ const isAscending = orderDir !== "DESC";
2199
+ params.orderBy = { [orderByField]: isAscending };
2200
+ }
2201
+ setPageContext(route.name, params);
2202
+ }, [route.name, appliedParams, setPageContext]);
2203
+ useEffect(() => {
2204
+ if (route.autoOpenChatbot) {
2205
+ setIsChatbotMode(true);
2206
+ }
2207
+ }, [route.name, route.autoOpenChatbot, setIsChatbotMode]);
2208
+ const allRoutes = useMemo(() => {
2209
+ const routesMap = {};
2210
+ routes.forEach((r) => {
2211
+ routesMap[r.name] = r;
2212
+ });
2213
+ return routesMap;
2214
+ }, [routes]);
2215
+ const getRouteByName = useCallback(
2216
+ (name) => allRoutes[name],
2217
+ [allRoutes]
2218
+ );
2219
+ return /* @__PURE__ */ jsxs(RouteContext.Provider, { value: {
2220
+ route,
2221
+ defaultPrivateRoute,
2222
+ defaultPublicRoute,
2223
+ allRoutes,
2224
+ getRouteByName
2225
+ }, children: [
2226
+ route.type === "public" && /* @__PURE__ */ jsx(
2227
+ PublicTemplate,
2228
+ {
2229
+ route,
2230
+ defaultPublicRoute,
2231
+ defaultPrivateRoute,
2232
+ children
2233
+ }
2234
+ ),
2235
+ route.type === "private" && /* @__PURE__ */ jsx(
2236
+ PrivateTemplate,
2237
+ {
2238
+ route,
2239
+ defaultPublicRoute,
2240
+ defaultPrivateRoute,
2241
+ children
2242
+ }
2243
+ )
2244
+ ] });
2245
+ };
2246
+ const useRouteAccess = () => {
2247
+ const { checkWebserviceAccess } = useWebserviceAccess();
2248
+ const { getRouteByName } = useRouteInfo();
2249
+ return useCallback(
2250
+ (routeOrName) => {
2251
+ if (!routeOrName) return false;
2252
+ const route = typeof routeOrName === "string" ? getRouteByName(routeOrName) : routeOrName;
2253
+ if (!route) return false;
2254
+ if (!route.mainWebserviceName) return true;
2255
+ if (Array.isArray(route.mainWebserviceName)) {
2256
+ return route.mainWebserviceName.some(checkWebserviceAccess);
2257
+ }
2258
+ return checkWebserviceAccess(route.mainWebserviceName);
2259
+ },
2260
+ [checkWebserviceAccess, getRouteByName]
2261
+ );
2262
+ };
2158
2263
  const EMPTY_PARAMS = {};
2159
2264
  function useRestrictedLink(route, parameters = EMPTY_PARAMS, queryParameters = EMPTY_PARAMS) {
2160
- const { checkWebserviceAccess } = useWebserviceAccess();
2265
+ const hasAccess = useRouteAccess();
2161
2266
  const routerNavigate = useNavigate();
2162
2267
  const [, startTransition] = useTransition();
2163
- const hasPermission = useMemo(() => {
2164
- if (!route) return false;
2165
- if (!route.mainWebserviceName) return true;
2166
- return checkWebserviceAccess(route.mainWebserviceName);
2167
- }, [route, checkWebserviceAccess]);
2268
+ const hasPermission = useMemo(() => hasAccess(route), [hasAccess, route]);
2168
2269
  const navigate = useCallback(() => {
2169
2270
  if (!route) return;
2170
2271
  startTransition(() => {
@@ -2179,10 +2280,13 @@ function useRestrictedLink(route, parameters = EMPTY_PARAMS, queryParameters = E
2179
2280
  const GRAPHQL_ERROR = "GraphQL Error";
2180
2281
  export {
2181
2282
  AlertMessageProvider as A,
2283
+ useUrlQueries as B,
2182
2284
  ChatbotProvider as C,
2285
+ useWebserviceAccess as D,
2183
2286
  ErrorBoundaryProvider as E,
2184
2287
  FilterLabelsProvider as F,
2185
2288
  GRAPHQL_ERROR as G,
2289
+ webserviceAccessProviderConfig as H,
2186
2290
  LocaleProvider as L,
2187
2291
  PageContextProvider as P,
2188
2292
  RefreshSignalContext as R,
@@ -2196,24 +2300,24 @@ export {
2196
2300
  LysLoadingContext as e,
2197
2301
  LysMutationProvider as f,
2198
2302
  LysQueryProvider as g,
2199
- useClientId as h,
2200
- useDialogWithUpdates as i,
2201
- useFilterLabels as j,
2202
- useLocale as k,
2203
- useLysDialog as l,
2204
- useLysLoadingFallback as m,
2205
- useLysMutation as n,
2206
- useLysQuery as o,
2207
- usePageContext as p,
2208
- usePermissionCheck as q,
2209
- useRefreshSignal as r,
2210
- useRestrictedLink as s,
2211
- useSignal as t,
2303
+ RouteProvider as h,
2304
+ useClientId as i,
2305
+ useDialogWithUpdates as j,
2306
+ useFilterLabels as k,
2307
+ useLocale as l,
2308
+ useLysDialog as m,
2309
+ useLysLoadingFallback as n,
2310
+ useLysMutation as o,
2311
+ useLysQuery as p,
2312
+ usePageContext as q,
2313
+ usePermissionCheck as r,
2314
+ useRefreshSignal as s,
2315
+ useRestrictedLink as t,
2212
2316
  useAlertMessages as u,
2213
- useSignalRefresh as v,
2214
- useSignalSubscription as w,
2215
- useUrlQueries as x,
2216
- useWebserviceAccess as y,
2217
- webserviceAccessProviderConfig as z
2317
+ useRouteAccess as v,
2318
+ useRouteInfo as w,
2319
+ useSignal as x,
2320
+ useSignalRefresh as y,
2321
+ useSignalSubscription as z
2218
2322
  };
2219
- //# sourceMappingURL=constants-BMsk7KvD.js.map
2323
+ //# sourceMappingURL=constants-sdhUzJ0l.js.map