@eintrek/erp-shell 0.1.57 → 0.1.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -86,6 +86,16 @@ Shell now owns the **shapes + helpers** for navigation; apps own the data.
86
86
  - Components: `NavTools` (reads Tool[] + buildUrlWithCode internally),
87
87
  `AppBreadcrumb` (accepts `labels` prop so per-app Thai overrides stay local).
88
88
 
89
+ Sidebar highlight (0.1.58, `resolveSidebarNav`): an entry is lit only on
90
+ its own page — its URL or one of its `subPages`, exactly, after the org code,
91
+ ignoring a trailing slash — and at most one entry is lit. A record, a create
92
+ or an edit page below a menu page lights nothing; the group holding it (the
93
+ deepest URL the path sits below) opens. A page that should keep its entry lit
94
+ (a list's tab that is its own route) goes in that entry's `subPages`, with a
95
+ `permissionRouteKey` the user holds (usually the entry's own), since the
96
+ permission filter drops a sub-page without one. `getActiveModule` stays the
97
+ longest prefix; `getActiveSubModule` is exact like the sidebar.
98
+
89
99
  Each app's `navigation-data.ts` now (1) imports types/helpers from shell,
90
100
  (2) declares its own `navigationData` const + `breadcrumbLabels`, (3) wraps
91
101
  `getActiveModule`/`getActiveSubModule` to keep the 1-arg signature, and
package/dist/index.d.ts CHANGED
@@ -38,7 +38,7 @@ export { PermissionProvider, type PermissionProviderProps, type PermissionProbe,
38
38
  export { getRequiredChildGroups, normalizePathnameForPermissionRules, resolveUiRoutePermission, type UiRoutePermissionLookup, } from "./auth/permission-utils";
39
39
  export * from "./navigation/navigation-helpers";
40
40
  export type { Module, SubPage, SubModule, Tool, Company, NavigationData, } from "./navigation/navigation-types";
41
- export { canAccessNavPermissionRoute, filterNavigationToolsByPermission, filterNavigationModulesByPermission, getActiveModule, getActiveSubModule, buildUrlWithCode, resolveActiveNav, type ActiveNavEntry, type ResolveActiveNavOptions, } from "./navigation/navigation-data-helpers";
41
+ export { canAccessNavPermissionRoute, filterNavigationToolsByPermission, filterNavigationModulesByPermission, getActiveModule, getActiveSubModule, buildUrlWithCode, resolveActiveNav, resolveSidebarNav, type ActiveNavEntry, type SidebarNavState, type ResolveActiveNavOptions, } from "./navigation/navigation-data-helpers";
42
42
  export { ThemeProvider } from "./providers/theme-provider";
43
43
  export { FeatureFlagsProvider, useFeatureFlags, useFeatureFlag, type FeatureFlags, } from "./providers/feature-flags-provider";
44
44
  export { ReactQueryProvider } from "./providers/react-query-provider";
package/dist/index.esm.js CHANGED
@@ -759,10 +759,23 @@ function longestMatch(path, modules) {
759
759
  function getActiveModule(pathname, modules) {
760
760
  return longestMatch(pathBelowCode(pathname), modules)?.module.id ?? null;
761
761
  }
762
- /** Find the active sub-module id from `pathname`, by the same rule. */
762
+ /**
763
+ * Find the active sub-module id from `pathname`: the page whose own URL — or
764
+ * one of whose listed `subPages` — is the path itself (below the org code,
765
+ * ignoring a trailing slash). A record, a create or an edit page below a page
766
+ * is no page of the menu, so it has no active sub-module (0.1.58); the module
767
+ * (`getActiveModule`) still says where it belongs.
768
+ *
769
+ * Equal URLs in two modules go to the active module's page.
770
+ */
763
771
  function getActiveSubModule(pathname, modules) {
764
- // Null when the module's own URL is the best match: no page of it is.
765
- return longestMatch(pathBelowCode(pathname), modules)?.sub?.id ?? null;
772
+ const path = strip(pathBelowCode(pathname));
773
+ const isPage = (url) => isMenuPath(url) && strip(url) === path;
774
+ const pagesOf = (m) => (m.subModules ?? []).filter(sub => isPage(sub.url) || (sub.subPages ?? []).some(p => isPage(p.url)));
775
+ const moduleId = getActiveModule(pathname, modules);
776
+ const own = modules.find(m => m.id === moduleId);
777
+ const hit = (own ? pagesOf(own)[0] : undefined) ?? modules.flatMap(pagesOf)[0];
778
+ return hit?.id ?? null;
766
779
  }
767
780
  /** Prepend `code` (org code) to a relative URL so `/sales` → `/O25.../sales`.
768
781
  * Absolute `http(s)://` URLs are left intact; optional `{code}` placeholder is replaced.
@@ -785,100 +798,138 @@ function buildUrlWithCode(code, url) {
785
798
  return `${base}${query}${hash}`;
786
799
  }
787
800
  const strip = (p) => (p.length > 1 ? p.replace(/\/+$/, "") : p);
801
+ /** A URL the path can be compared with: not query-only, not another site. */
802
+ const isMenuPath = (url) => !!url && !url.includes("?") && !/^https?:\/\//i.test(url);
788
803
  /** Same check as `isPathActive`: the page itself or one below it. */
789
804
  const pathIsAtOrBelow = (pathname, url) => pathname === url || pathname.startsWith(url + "/");
790
805
  /** "/O1/" and "/O1" are the same page; a query string never is. */
791
806
  function samePage(pathname, url) {
792
807
  if (url.includes("?"))
793
808
  return false;
794
- return strip(pathname) === strip(url);
809
+ return strip(pathname.split("?")[0]) === strip(url);
795
810
  }
796
811
  /**
797
- * How long the URL that makes `url` cover `pathname` is — or -1 when it does
798
- * not. The organisation's home ("/" → "/O1") covers only itself: every page
799
- * sits below it, and a dashboard is not the parent of every page.
812
+ * How long `url` is when it is the page `pathname` shows (ignoring a trailing
813
+ * slash), or -1. Compared with and without the org code, as the menu URLs
814
+ * are written either way.
800
815
  */
801
- function coverLength(pathname, url, code) {
816
+ function pageLength(pathname, url, code) {
817
+ if (!isMenuPath(url))
818
+ return -1;
802
819
  const built = buildUrlWithCode(code, url);
803
- const isRoot = url === "/" || (!!code && strip(built) === `/${code}`);
804
- if (isRoot) {
805
- return samePage(pathname, built) || samePage(pathname, url)
806
- ? strip(built).length
807
- : -1;
808
- }
809
- if (pathIsAtOrBelow(pathname, built))
820
+ if (samePage(pathname, built))
821
+ return strip(built).length;
822
+ if (samePage(pathname, url))
823
+ return strip(url).length;
824
+ return -1;
825
+ }
826
+ /**
827
+ * How long the URL that makes `url` cover `pathname` is — the page itself or
828
+ * one below it — or -1. The organisation's home ("/" → "/O1") covers only
829
+ * itself: every page sits below it, and a dashboard is not the parent of
830
+ * every page.
831
+ */
832
+ function coverLength(pathname, url, code) {
833
+ if (!isMenuPath(url))
834
+ return -1;
835
+ const path = strip(pathname.split("?")[0]);
836
+ const built = strip(buildUrlWithCode(code, url));
837
+ const isRoot = url === "/" || (!!code && built === `/${code}`);
838
+ if (isRoot)
839
+ return pageLength(path, url, code);
840
+ if (pathIsAtOrBelow(path, built))
810
841
  return built.length;
811
- if (pathIsAtOrBelow(pathname, url))
812
- return url.length;
842
+ const raw = strip(url);
843
+ if (pathIsAtOrBelow(path, raw))
844
+ return raw.length;
813
845
  return -1;
814
846
  }
815
847
  /**
816
- * Pick the single sidebar entry for `pathname`: the longest URL that covers
817
- * the path, across every group. Before 0.1.57 the longest match was taken in
818
- * each group separately, so /project/schedule lit both "โครงการ" (/project,
819
- * under โครงการ) and "ภาพรวมแผน" (/project/schedule, under แผนงาน).
848
+ * Where `pathname` sits in the sidebar: the entry to light and the group to
849
+ * open.
850
+ *
851
+ * Lit (0.1.58): only the entry whose own page this is — its URL or one of its
852
+ * `subPages`, exactly. A record, a create or an edit page below a menu page
853
+ * (Plannex /project/detail/<id>/schedule under "โครงการ" /project) lights
854
+ * nothing; an app lists such a page in `subPages` when it should keep its
855
+ * entry lit. At most one entry across every group (0.1.57).
856
+ *
857
+ * Open: the lit entry's group, or else the group with the deepest URL the
858
+ * path sits below.
820
859
  *
821
860
  * Equal lengths go to the group the app marks active (`item.isActive`, from
822
861
  * its `activeModule`), then to a page over a group row, then to the first in
823
862
  * menu order.
824
863
  */
825
- function resolveActiveNav(items, pathname, { code, workspace = false, highlightActiveModule = false } = {}) {
826
- const path = pathname ?? "";
864
+ function resolveSidebarNav(items, pathname, { code, highlightActiveModule = false } = {}) {
865
+ const path = (pathname ?? "").split("?")[0];
827
866
  // The app named a one-line module as the current one: that is the answer.
828
867
  if (highlightActiveModule) {
829
868
  const leaf = items.findIndex(item => !item.subModules?.length && !!item.isActive);
830
- if (leaf >= 0)
831
- return { item: leaf, sub: null, subPage: null };
832
- }
833
- let best = null;
834
- const consider = (c) => {
835
- if (!best) {
836
- best = c;
837
- return;
838
- }
839
- if (c.length !== best.length) {
840
- if (c.length > best.length)
841
- best = c;
842
- return;
869
+ if (leaf >= 0) {
870
+ return {
871
+ active: { item: leaf, sub: null, subPage: null },
872
+ open: { item: leaf, sub: null },
873
+ };
843
874
  }
875
+ }
876
+ const better = (c, best) => {
877
+ if (!best)
878
+ return true;
879
+ if (c.length !== best.length)
880
+ return c.length > best.length;
844
881
  const cActive = !!items[c.item].isActive;
845
882
  const bActive = !!items[best.item].isActive;
846
- if (cActive !== bActive) {
847
- if (cActive)
848
- best = c;
883
+ if (cActive !== bActive)
884
+ return cActive;
885
+ // The same sub-item by its own URL and by a listed page: the page.
886
+ if (c.item === best.item && c.sub === best.sub) {
887
+ return c.subPage !== null && best.subPage === null;
888
+ }
889
+ return c.sub !== null && best.sub === null;
890
+ };
891
+ let exact = null;
892
+ let within = null;
893
+ const consider = (c, isExact) => {
894
+ if (c.length < 0)
849
895
  return;
896
+ if (isExact) {
897
+ if (better(c, exact))
898
+ exact = c;
899
+ }
900
+ else if (better(c, within)) {
901
+ within = c;
850
902
  }
851
- if (c.sub !== null && best.sub === null)
852
- best = c;
853
903
  };
854
904
  items.forEach((item, i) => {
855
- const itemUrl = buildUrlWithCode(code, item.url);
856
905
  const subs = item.subModules ?? [];
906
+ const row = { item: i, sub: null, subPage: null };
857
907
  // The row itself: only on its own URL. A one-line item under
858
908
  // highlightActiveModule is lit by isActive alone (handled above).
859
909
  if (!(highlightActiveModule && subs.length === 0)) {
860
- const own = workspace ? samePage(path, itemUrl) : path === itemUrl;
861
- if (own)
862
- consider({ item: i, sub: null, subPage: null, length: strip(itemUrl).length });
910
+ consider({ ...row, length: pageLength(path, item.url, code) }, true);
863
911
  }
912
+ consider({ ...row, length: coverLength(path, item.url, code) }, false);
864
913
  subs.forEach((sub, j) => {
865
- // The sub-item counts by its own URL or by the longest of its pages.
866
- let subPage = null;
867
- let pageLength = -1;
914
+ const entry = { item: i, sub: j };
915
+ consider({ ...entry, subPage: null, length: pageLength(path, sub.url, code) }, true);
916
+ consider({ ...entry, subPage: null, length: coverLength(path, sub.url, code) }, false);
868
917
  (sub.subPages ?? []).forEach((page, k) => {
869
- const l = coverLength(path, page.url, code);
870
- if (l > pageLength) {
871
- pageLength = l;
872
- subPage = k;
873
- }
918
+ consider({ ...entry, subPage: k, length: pageLength(path, page.url, code) }, true);
919
+ consider({ ...entry, subPage: k, length: coverLength(path, page.url, code) }, false);
874
920
  });
875
- const length = Math.max(coverLength(path, sub.url, code), pageLength);
876
- if (length >= 0)
877
- consider({ item: i, sub: j, subPage, length });
878
921
  });
879
922
  });
880
- const found = best;
881
- return found ? { item: found.item, sub: found.sub, subPage: found.subPage } : null;
923
+ const lit = exact;
924
+ const holder = lit ?? within;
925
+ return {
926
+ active: lit ? { item: lit.item, sub: lit.sub, subPage: lit.subPage } : null,
927
+ open: holder ? { item: holder.item, sub: holder.sub } : null,
928
+ };
929
+ }
930
+ /** The entry lit for `pathname` — `resolveSidebarNav(...).active`. */
931
+ function resolveActiveNav(items, pathname, options = {}) {
932
+ return resolveSidebarNav(items, pathname, options).active;
882
933
  }
883
934
 
884
935
  function NavTools({ tools, closeOnNavigation = false }) {
@@ -1365,7 +1416,7 @@ function platformApiBase(app) {
1365
1416
  * This package's version, attached to help messages so the back office can
1366
1417
  * tell which shell a report came from. Keep in step with package.json.
1367
1418
  */
1368
- const SHELL_VERSION = "0.1.57";
1419
+ const SHELL_VERSION = "0.1.58";
1369
1420
 
1370
1421
  const HELP_APP_LABEL = {
1371
1422
  platform: "แพลตฟอร์ม",
@@ -1923,12 +1974,11 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
1923
1974
  setOpen(false);
1924
1975
  };
1925
1976
  const code = orgCode ?? params?.code;
1926
- // The one entry that stands for this page — the longest matching URL
1927
- // across every group, not per group (which lit /project and
1928
- // /project/schedule together).
1929
- const active = resolveActiveNav(items, pathname, {
1977
+ // The one entry lit for this page — only on that entry's own page, never
1978
+ // on a record or a form below it — and the group holding the page, which
1979
+ // opens either way.
1980
+ const { active, open } = resolveSidebarNav(items, pathname, {
1930
1981
  code,
1931
- workspace,
1932
1982
  highlightActiveModule,
1933
1983
  });
1934
1984
  const states = items.map((item, i) => {
@@ -1938,36 +1988,32 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
1938
1988
  itemUrl,
1939
1989
  activeSub: mine?.sub ?? null,
1940
1990
  activeSubPage: mine?.subPage ?? null,
1941
- hasActiveSubItem: mine?.sub != null,
1991
+ openSub: open?.item === i ? open.sub : null,
1942
1992
  isItemActive: !!mine && mine.sub === null,
1943
1993
  };
1944
1994
  });
1945
- // A group opens when its page becomes current and otherwise stays as the
1995
+ // A group opens when the page moves into it and otherwise stays as the
1946
1996
  // user left it. defaultOpen alone decided once, on the first render — and
1947
1997
  // on a direct load the sub-items arrive after permissions do, so the group
1948
1998
  // holding the current page stayed shut.
1949
- const activeKey = items
1950
- .filter((_, i) => states[i].isItemActive || states[i].hasActiveSubItem)
1951
- .map(item => item.id)
1952
- .join(",");
1953
- const [openIds, setOpenIds] = React.useState(() => new Set(activeKey ? activeKey.split(",") : []));
1999
+ const openId = open ? (items[open.item]?.id ?? "") : "";
2000
+ const [openIds, setOpenIds] = React.useState(() => new Set(openId ? [openId] : []));
1954
2001
  React.useEffect(() => {
1955
- if (!activeKey)
2002
+ if (!openId)
1956
2003
  return;
1957
2004
  setOpenIds(prev => {
1958
- const ids = activeKey.split(",");
1959
- if (ids.every(id => prev.has(id)))
2005
+ if (prev.has(openId))
1960
2006
  return prev;
1961
2007
  const next = new Set(prev);
1962
- ids.forEach(id => next.add(id));
2008
+ next.add(openId);
1963
2009
  return next;
1964
2010
  });
1965
- }, [activeKey]);
1966
- const setItemOpen = (id, open) => setOpenIds(prev => {
1967
- if (prev.has(id) === open)
2011
+ }, [openId]);
2012
+ const setItemOpen = (id, isOpen) => setOpenIds(prev => {
2013
+ if (prev.has(id) === isOpen)
1968
2014
  return prev;
1969
2015
  const next = new Set(prev);
1970
- if (open)
2016
+ if (isOpen)
1971
2017
  next.add(id);
1972
2018
  else
1973
2019
  next.delete(id);
@@ -1978,7 +2024,7 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
1978
2024
  item.group &&
1979
2025
  item.group !== items[index - 1]?.group ? (jsx("li", { className: "list-none px-3 pb-2.5 text-xs text-muted-foreground" +
1980
2026
  (index > 0 ? " pt-5" : ""), children: item.group }, `group-${item.id}`)) : null;
1981
- const { itemUrl, activeSub, activeSubPage, isItemActive } = states[index];
2027
+ const { itemUrl, activeSub, activeSubPage, openSub, isItemActive } = states[index];
1982
2028
  const IconComp = item.icon;
1983
2029
  const workspaceButton = workspace
1984
2030
  ? "h-auto gap-3 rounded-[10px] px-3 py-2.5 text-xs " +
@@ -1988,7 +2034,7 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
1988
2034
  : "";
1989
2035
  const icon = workspace && IconComp ? (jsx(IconComp, { className: "size-[18px] shrink-0" })) : null;
1990
2036
  const badge = workspace && item.badge !== undefined && item.badge !== "" ? (jsx("span", { className: "ml-auto min-w-5 rounded-[5px] bg-primary/15 px-1 text-center text-xs leading-5 font-bold tabular-nums text-primary", children: item.badge })) : null;
1991
- return (jsxs(React.Fragment, { children: [groupHeading, jsx(Collapsible, { asChild: true, open: openIds.has(item.id), onOpenChange: open => setItemOpen(item.id, open), className: "group/collapsible", children: jsxs(SidebarMenuItem, { children: [jsx(CollapsibleTrigger, { asChild: true, children: jsx(SidebarMenuButton, { asChild: !item.subModules || item.subModules.length === 0, isActive: isItemActive, className: "data-[state=open]:text-sidebar-accent-foreground " +
2037
+ return (jsxs(React.Fragment, { children: [groupHeading, jsx(Collapsible, { asChild: true, open: openIds.has(item.id), onOpenChange: isOpen => setItemOpen(item.id, isOpen), className: "group/collapsible", children: jsxs(SidebarMenuItem, { children: [jsx(CollapsibleTrigger, { asChild: true, children: jsx(SidebarMenuButton, { asChild: !item.subModules || item.subModules.length === 0, isActive: isItemActive, className: "data-[state=open]:text-sidebar-accent-foreground " +
1992
2038
  workspaceButton, children: item.subModules && item.subModules.length > 0 ? (jsxs(Fragment$1, { children: [icon, jsx("span", { id: item.id, children: item.titleTh }), jsx(ChevronRight, { className: "ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" })] })) : (jsxs(Link, { href: itemUrl, prefetch: false, className: "flex items-center w-full min-w-0 flex-1 " +
1993
2039
  (workspace ? "gap-3" : "gap-2"), onClick: handleNavLinkClick, "aria-current": isItemActive ? "page" : undefined, children: [icon, jsx("span", { id: item.id, className: "flex-1 truncate", title: item.titleTh, children: item.titleTh }), badge] })) }) }), item.subModules && item.subModules.length > 0 && (jsx(CollapsibleContent, { children: jsx(SidebarMenuSub, { className: workspace
1994
2040
  ? "mx-0 mt-1 mb-3 ml-[21px] gap-0.5 border-l border-sidebar-border pl-2.5 [&_a]:h-auto [&_a]:gap-[11px] [&_a]:px-3 [&_a]:py-2 [&_a]:text-xs [&_svg]:!size-[17px]"
@@ -2002,7 +2048,7 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
2002
2048
  if (subItem.isCollapsible &&
2003
2049
  subItem.subPages &&
2004
2050
  subItem.subPages.length > 0) {
2005
- return (jsx(Collapsible, { asChild: true, defaultOpen: isSubItemActive, className: "group/sub-collapsible", children: jsxs(SidebarMenuSubItem, { children: [jsx(CollapsibleTrigger, { asChild: true, children: jsxs(SidebarMenuSubButton, { className: "w-full", isActive: isSubItemActive, children: [SubIcon && (jsx(SubIcon, { className: "sidebar-submodule-icon flex-shrink-0" })), jsx("span", { className: "flex-1 truncate", title: subItem.titleTh, children: subItem.titleTh }), jsx(ChevronDown, { className: "ml-auto size-4 transition-transform duration-200 group-data-[state=open]/sub-collapsible:rotate-180" })] }) }), jsx(CollapsibleContent, { children: jsx(SidebarMenuSub, { className: "ml-4", children: subItem.subPages.map((subPage, subPageIndex) => {
2051
+ return (jsx(Collapsible, { asChild: true, defaultOpen: isSubItemActive || openSub === subIndex, className: "group/sub-collapsible", children: jsxs(SidebarMenuSubItem, { children: [jsx(CollapsibleTrigger, { asChild: true, children: jsxs(SidebarMenuSubButton, { className: "w-full", isActive: isSubItemActive, children: [SubIcon && (jsx(SubIcon, { className: "sidebar-submodule-icon flex-shrink-0" })), jsx("span", { className: "flex-1 truncate", title: subItem.titleTh, children: subItem.titleTh }), jsx(ChevronDown, { className: "ml-auto size-4 transition-transform duration-200 group-data-[state=open]/sub-collapsible:rotate-180" })] }) }), jsx(CollapsibleContent, { children: jsx(SidebarMenuSub, { className: "ml-4", children: subItem.subPages.map((subPage, subPageIndex) => {
2006
2052
  const subPageUrl = buildUrlWithCode(code, subPage.url);
2007
2053
  const isSubPageActive = isSubItemActive &&
2008
2054
  activeSubPage === subPageIndex;
@@ -3721,5 +3767,5 @@ const getAxiosErrorMessage = (error) => {
3721
3767
  return String(error);
3722
3768
  };
3723
3769
 
3724
- export { AccessDenied, ApiError, AppBreadcrumb, AppLayoutShell, AppSidebar, EMPLOYEE_RECORD_OK_EVENT, EMPLOYEE_RECORD_REQUIRED, EMPLOYEE_RECORD_REQUIRED_EVENT, EmployeeRequiredGate, FeatureFlagsProvider, HeaderBackground, HelpButton, HelpDialogHost, NavMain, NavTools, NavUser, OWNER_CHIP, OrganizationSwitcher, PLAN_FEATURES, PermissionGateShell, PermissionProvider, PermissionRulesProvider, ReactQueryProvider, SHELL_VERSION, SessionBackedProfileCacheSeeder, SessionRefreshTrigger, SidebarContent, SidebarFooter, SidebarHeader, SidebarHelpCard, SidebarHelpLink, SidebarProvider, SidebarTrigger, TapMenu, ThemeProvider, WORKSPACE_HEADER_VARS, WORKSPACE_LIGHT_HEADER_VARS, WorkspaceBrand, instance as axiosInstance, buildSystemLinks, buildUrlWithCode, canAccessNavPermissionRoute, clearAccessTokenCache, clearOrganizationId, closeHelp, decodeJWT, describeAttached, describeBrowser, detectHelpApp, filterNavigationModulesByPermission, filterNavigationToolsByPermission, getAccessToken, getActiveModule, getActiveSubModule, getAxiosErrorMessage, getOrganizationId, getQueryClientConfig, getRequiredChildGroups, hasPlanFeature, isLikelyTransientNetworkError, isPathActive, myRolesQueryKey, normalizePathnameForPermissionRules, openHelp, parseMyRoles, resolveActiveNav, resolveUiRoutePermission, roleSummary, runGlobalRequestPrecheck, runWithTransientRetry, setOrganizationId, toApiError, unwrapApiResponse, updateOrganizationId, useClearOrgOnUserChange, useFeatureFlag, useFeatureFlags, useInvalidateQueriesOnOrgChange, useKeycloakRoles, useMyRoles, useOrganizationIdState, usePermissionRules, useSessionRefresh, useSidebar, useSidebarToggle };
3770
+ export { AccessDenied, ApiError, AppBreadcrumb, AppLayoutShell, AppSidebar, EMPLOYEE_RECORD_OK_EVENT, EMPLOYEE_RECORD_REQUIRED, EMPLOYEE_RECORD_REQUIRED_EVENT, EmployeeRequiredGate, FeatureFlagsProvider, HeaderBackground, HelpButton, HelpDialogHost, NavMain, NavTools, NavUser, OWNER_CHIP, OrganizationSwitcher, PLAN_FEATURES, PermissionGateShell, PermissionProvider, PermissionRulesProvider, ReactQueryProvider, SHELL_VERSION, SessionBackedProfileCacheSeeder, SessionRefreshTrigger, SidebarContent, SidebarFooter, SidebarHeader, SidebarHelpCard, SidebarHelpLink, SidebarProvider, SidebarTrigger, TapMenu, ThemeProvider, WORKSPACE_HEADER_VARS, WORKSPACE_LIGHT_HEADER_VARS, WorkspaceBrand, instance as axiosInstance, buildSystemLinks, buildUrlWithCode, canAccessNavPermissionRoute, clearAccessTokenCache, clearOrganizationId, closeHelp, decodeJWT, describeAttached, describeBrowser, detectHelpApp, filterNavigationModulesByPermission, filterNavigationToolsByPermission, getAccessToken, getActiveModule, getActiveSubModule, getAxiosErrorMessage, getOrganizationId, getQueryClientConfig, getRequiredChildGroups, hasPlanFeature, isLikelyTransientNetworkError, isPathActive, myRolesQueryKey, normalizePathnameForPermissionRules, openHelp, parseMyRoles, resolveActiveNav, resolveSidebarNav, resolveUiRoutePermission, roleSummary, runGlobalRequestPrecheck, runWithTransientRetry, setOrganizationId, toApiError, unwrapApiResponse, updateOrganizationId, useClearOrgOnUserChange, useFeatureFlag, useFeatureFlags, useInvalidateQueriesOnOrgChange, useKeycloakRoles, useMyRoles, useOrganizationIdState, usePermissionRules, useSessionRefresh, useSidebar, useSidebarToggle };
3725
3771
  //# sourceMappingURL=index.esm.js.map