update header dependency
This commit is contained in:
parent
8348d3b36f
commit
07a4fd3bbc
184
dist/chunks/permission-DL7ciWwc.js
vendored
184
dist/chunks/permission-DL7ciWwc.js
vendored
@ -1,184 +0,0 @@
|
||||
import { jsx as y } from "react/jsx-runtime";
|
||||
import { createContext as L, useState as K, useRef as O, useCallback as h, useEffect as k, useMemo as T, useContext as R } from "react";
|
||||
import { useQuery as b } from "@tanstack/react-query";
|
||||
import F from "keycloak-js";
|
||||
let x = null, r = null, E = null, C = !1;
|
||||
const G = L(null), _ = ({ url: e, realm: s, clientId: t }) => (r || (r = new F({
|
||||
url: e,
|
||||
realm: s,
|
||||
clientId: t
|
||||
})), r), j = (e) => (x = e, x), ee = () => C, J = () => !!(r != null && r.authenticated), Q = () => (r == null ? void 0 : r.token) ?? null, te = async (e = 30) => r ? r.updateToken(e) : !1, U = (e) => r == null ? void 0 : r.logout(e), re = (e) => r == null ? void 0 : r.login(e), W = ({ config: e, initOptions: s = {} } = {}) => {
|
||||
const t = e ?? x;
|
||||
if (!(t != null && t.url) || !(t != null && t.realm) || !(t != null && t.clientId))
|
||||
throw new Error("Keycloak config is required.");
|
||||
j(t);
|
||||
const n = _(t);
|
||||
return E || (E = n.init({
|
||||
onLoad: "login-required",
|
||||
checkLoginIframe: !1,
|
||||
flow: "implicit",
|
||||
...s
|
||||
}).then((o) => (C = !0, o)).catch((o) => {
|
||||
throw C = !0, o;
|
||||
})), E;
|
||||
}, se = ({
|
||||
children: e,
|
||||
config: s,
|
||||
initOptions: t,
|
||||
loading: n = null
|
||||
}) => {
|
||||
const [o, m] = K(!1), [p, w] = K(!1), [u, c] = K(null), l = O(!1), i = h(() => {
|
||||
r && (w(!!r.authenticated), c(r.token ?? null));
|
||||
}, []);
|
||||
k(() => (l.current = !0, W({ config: s, initOptions: t }).then((a) => {
|
||||
l.current && (w(!!a), c((r == null ? void 0 : r.token) ?? null), m(!0));
|
||||
}).catch(() => {
|
||||
l.current && (w(!1), c(null), m(!0));
|
||||
}), () => {
|
||||
l.current = !1;
|
||||
}), [s, t]);
|
||||
const P = h(() => r == null ? void 0 : r.login(), []), d = h((a) => r == null ? void 0 : r.logout(a), []), f = h(
|
||||
async (a = 30) => {
|
||||
if (!r) return !1;
|
||||
const z = await r.updateToken(a);
|
||||
return i(), z;
|
||||
},
|
||||
[i]
|
||||
), S = T(
|
||||
() => ({
|
||||
initialized: o,
|
||||
authenticated: p,
|
||||
token: u,
|
||||
login: P,
|
||||
logout: d,
|
||||
updateToken: f
|
||||
}),
|
||||
[o, p, u, P, d, f]
|
||||
);
|
||||
return o ? /* @__PURE__ */ y(G.Provider, { value: S, children: e }) : n;
|
||||
}, B = L(null), v = "permissions", Y = (e) => (e == null ? void 0 : e.storageKey) || v, ne = ({
|
||||
user: e = null,
|
||||
children: s,
|
||||
config: t,
|
||||
loading: n = /* @__PURE__ */ y("div", { children: "Loading permissions..." }),
|
||||
errorFallback: o = /* @__PURE__ */ y("div", { children: "Error loading permissions" })
|
||||
}) => {
|
||||
const m = Y(t), [p, w] = K(
|
||||
() => $(m)
|
||||
), { data: u, isLoading: c, error: l } = V(t), i = u ?? p;
|
||||
k(() => {
|
||||
u && (D(m, u), w(u));
|
||||
}, [u, m]);
|
||||
const P = T(
|
||||
() => I(i),
|
||||
[i]
|
||||
), d = h(
|
||||
(a = "") => M(P, a),
|
||||
[P]
|
||||
), f = h((a = "") => !d(a), [d]), S = T(
|
||||
() => ({
|
||||
user: e,
|
||||
can: d,
|
||||
cannot: f,
|
||||
permissions: i,
|
||||
isLoading: c,
|
||||
error: l
|
||||
}),
|
||||
[e, d, f, i, c, l]
|
||||
);
|
||||
return l && !i ? o : c && !i ? n : /* @__PURE__ */ y(B.Provider, { value: S, children: s });
|
||||
}, $ = (e = v) => {
|
||||
if (!(typeof window > "u"))
|
||||
try {
|
||||
const s = localStorage.getItem(e);
|
||||
return s ? JSON.parse(s) : void 0;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}, D = (e = v, s) => {
|
||||
if (!(typeof window > "u"))
|
||||
try {
|
||||
localStorage.setItem(e, JSON.stringify(s));
|
||||
} catch {
|
||||
}
|
||||
}, oe = (e = v) => {
|
||||
if (!(typeof window > "u"))
|
||||
try {
|
||||
localStorage.removeItem(e);
|
||||
} catch {
|
||||
}
|
||||
}, I = (e) => e ? new Set(e.map((s) => s.name)) : /* @__PURE__ */ new Set(), M = (e, s = "") => {
|
||||
if (!s) return !1;
|
||||
if (e.has(s) || [...e].some((n) => n.startsWith(s))) return !0;
|
||||
let t = s;
|
||||
for (; t.includes(":"); )
|
||||
if (t = t.slice(0, t.lastIndexOf(":")), e.has(`${t}:*`)) return !0;
|
||||
return !1;
|
||||
}, q = {
|
||||
all: ["permissions"],
|
||||
list: (e) => [...q.all, e]
|
||||
}, N = async (e) => {
|
||||
if (!(e != null && e.url) || !(e != null && e.clientId))
|
||||
throw new Error("Permission config requires url and clientId.");
|
||||
const s = Q(), t = new URL(e.url);
|
||||
t.searchParams.set("client_id", e.clientId);
|
||||
const n = await fetch(t.toString(), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
...s ? { Authorization: `Bearer ${s}` } : {}
|
||||
}
|
||||
});
|
||||
if (!n.ok)
|
||||
throw new Error("Failed to load permissions");
|
||||
return n.json();
|
||||
}, A = () => {
|
||||
const e = R(B);
|
||||
if (!e)
|
||||
throw new Error("usePermission must be used within PermissionProvider");
|
||||
return e;
|
||||
}, V = (e) => b({
|
||||
queryKey: q.list(e == null ? void 0 : e.clientId),
|
||||
queryFn: () => N(e),
|
||||
enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && J(),
|
||||
staleTime: 1 / 0,
|
||||
refetchOnWindowFocus: !1,
|
||||
refetchOnReconnect: !1
|
||||
}), ie = ({
|
||||
perm: e,
|
||||
children: s,
|
||||
fallback: t = /* @__PURE__ */ y("div", { children: "You are not allowed to do this" })
|
||||
}) => {
|
||||
const { can: n } = A();
|
||||
return n(e) ? s : t;
|
||||
}, ae = ({ children: e }) => {
|
||||
const { can: s, permissions: t } = A();
|
||||
return t && s("admin") ? e : null;
|
||||
}, ue = ({ children: e, forceNoAccess: s = !1 }) => {
|
||||
const { can: t, isLoading: n } = A();
|
||||
return k(() => {
|
||||
n || (s || !t("panel_access")) && U();
|
||||
}, [n, t, s]), e;
|
||||
};
|
||||
export {
|
||||
ae as A,
|
||||
ie as C,
|
||||
se as K,
|
||||
ne as P,
|
||||
te as a,
|
||||
J as b,
|
||||
W as c,
|
||||
ue as d,
|
||||
M as e,
|
||||
oe as f,
|
||||
Q as g,
|
||||
I as h,
|
||||
ee as i,
|
||||
$ as j,
|
||||
N as k,
|
||||
U as l,
|
||||
re as m,
|
||||
V as n,
|
||||
q as p,
|
||||
D as s,
|
||||
A as u
|
||||
};
|
||||
17
dist/core-runtime.js
vendored
Normal file
17
dist/core-runtime.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
import { createContext as e, useContext as n } from "react";
|
||||
const s = e(null), i = () => {
|
||||
const t = n(s);
|
||||
if (!t)
|
||||
throw new Error("usePermission must be used within PermissionProvider");
|
||||
return t;
|
||||
};
|
||||
let o = null;
|
||||
const u = (t) => {
|
||||
o = typeof t == "function" ? t : null;
|
||||
}, c = (t) => o == null ? void 0 : o(t);
|
||||
export {
|
||||
s as PermissionContext,
|
||||
c as logoutKeycloakFromRuntime,
|
||||
u as setKeycloakLogoutHandler,
|
||||
i as usePermission
|
||||
};
|
||||
669
dist/core.js
vendored
669
dist/core.js
vendored
File diff suppressed because one or more lines are too long
251
dist/layout.js
vendored
251
dist/layout.js
vendored
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
||||
import Keycloak from "keycloak-js";
|
||||
import { setKeycloakLogoutHandler } from "./runtime.jsx";
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
@ -63,6 +64,8 @@ export const logoutKeycloak = (options) => {
|
||||
return keycloakInstance?.logout(options);
|
||||
};
|
||||
|
||||
setKeycloakLogoutHandler(logoutKeycloak);
|
||||
|
||||
export const loginKeycloak = (options) => {
|
||||
return keycloakInstance?.login(options);
|
||||
};
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { PermissionContext, usePermission } from "./runtime.jsx";
|
||||
import {
|
||||
getKeycloakToken,
|
||||
isKeycloakAuthenticated,
|
||||
logoutKeycloak,
|
||||
} from "./keycloak.jsx";
|
||||
|
||||
// contexts
|
||||
|
||||
const PermissionContext = createContext(null);
|
||||
|
||||
// storage keys
|
||||
|
||||
const DEFAULT_STORAGE_KEY = "permissions";
|
||||
@ -178,15 +173,7 @@ export const getPermissions = async (config) => {
|
||||
|
||||
// hooks
|
||||
|
||||
export const usePermission = () => {
|
||||
const context = useContext(PermissionContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error("usePermission must be used within PermissionProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
export { usePermission } from "./runtime.jsx";
|
||||
|
||||
export const usePermissionsQuery = (config) => {
|
||||
return useQuery({
|
||||
|
||||
27
src/core/runtime.jsx
Normal file
27
src/core/runtime.jsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
// Lightweight shared runtime for layout/core integration.
|
||||
// IMPORTANT: keep this module free of optional dependencies such as
|
||||
// @tanstack/react-query and keycloak-js. `uikit/layout` imports it directly.
|
||||
|
||||
export const PermissionContext = createContext(null);
|
||||
|
||||
export const usePermission = () => {
|
||||
const context = useContext(PermissionContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error("usePermission must be used within PermissionProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
let keycloakLogoutHandler = null;
|
||||
|
||||
export const setKeycloakLogoutHandler = (handler) => {
|
||||
keycloakLogoutHandler = typeof handler === "function" ? handler : null;
|
||||
};
|
||||
|
||||
export const logoutKeycloakFromRuntime = (options) => {
|
||||
return keycloakLogoutHandler?.(options);
|
||||
};
|
||||
@ -20,42 +20,12 @@ import {
|
||||
useDisclosure,
|
||||
} from "@chakra-ui/react";
|
||||
import { Children, forwardRef, isValidElement, useRef } from "react";
|
||||
import { logoutKeycloak } from "../core/keycloak.jsx";
|
||||
import { usePermission } from "../core/permission.jsx";
|
||||
|
||||
const EllipsisIcon = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<circle cx="12" cy="12" r="1" />
|
||||
<circle cx="19" cy="12" r="1" />
|
||||
<circle cx="5" cy="12" r="1" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const LogOutIcon = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path d="m16 17 5-5-5-5" />
|
||||
<path d="M21 12H9" />
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
||||
</svg>
|
||||
);
|
||||
import { FiMoreHorizontal } from "react-icons/fi/index.js";
|
||||
import { IoExit } from "react-icons/io5/index.js";
|
||||
import {
|
||||
logoutKeycloakFromRuntime,
|
||||
usePermission,
|
||||
} from "../core/runtime.jsx";
|
||||
|
||||
const normalizeSidebarPath = (value = "") => {
|
||||
const path = String(value).split(/[?#]/)[0] || "";
|
||||
@ -101,34 +71,11 @@ const DesktopNavItem = ({
|
||||
onNavigate,
|
||||
}) => {
|
||||
const commonProps = {
|
||||
variant: "ghost",
|
||||
position: "relative",
|
||||
bg: "transparent",
|
||||
|
||||
_before: isActive
|
||||
? {
|
||||
content: '""',
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
insetInlineStart: 0,
|
||||
insetInlineEnd: 0,
|
||||
bg: "gray.200",
|
||||
borderRadius: "md",
|
||||
zIndex: 0,
|
||||
}
|
||||
: undefined,
|
||||
|
||||
sx: {
|
||||
"> svg": {
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
},
|
||||
},
|
||||
|
||||
variant: isActive ? "solid" : "ghost",
|
||||
colorScheme: isActive ? "blue" : undefined,
|
||||
icon: <Icon as={item.icon} />,
|
||||
fontSize: "xl",
|
||||
size: { base: "sm", lg: "md" },
|
||||
size: { base: "sm", lg: "lg" },
|
||||
"aria-label": item.title,
|
||||
"aria-current": isActive ? "page" : undefined,
|
||||
};
|
||||
@ -149,7 +96,11 @@ const DesktopNavItem = ({
|
||||
: { as: "a", href: item.path };
|
||||
|
||||
content = (
|
||||
<IconButton {...commonProps} {...linkProps} onClick={onNavigate} />
|
||||
<IconButton
|
||||
{...commonProps}
|
||||
{...linkProps}
|
||||
onClick={onNavigate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -260,7 +211,8 @@ const SidebarRoot = ({
|
||||
);
|
||||
const hasExit = Boolean(exitElement);
|
||||
const logoutTitle = exitElement?.props?.title || "خروج";
|
||||
const logoutIcon = exitElement?.props?.icon || LogOutIcon;
|
||||
const logoutIcon = exitElement?.props?.icon || IoExit;
|
||||
|
||||
|
||||
const resolvedCurrentPath =
|
||||
currentPath ??
|
||||
@ -272,7 +224,9 @@ const SidebarRoot = ({
|
||||
const secondaryItems = items.slice(primaryMobileCount);
|
||||
|
||||
const disabled = (item) => {
|
||||
const permissions = Array.isArray(item?.perm) ? item.perm : [item?.perm];
|
||||
const permissions = Array.isArray(item?.perm)
|
||||
? item.perm
|
||||
: [item?.perm];
|
||||
|
||||
return permissions.filter(Boolean).some((permission) => cannot(permission));
|
||||
};
|
||||
@ -288,7 +242,7 @@ const SidebarRoot = ({
|
||||
|
||||
const handleLogout = () => {
|
||||
onClose();
|
||||
logoutKeycloak();
|
||||
logoutKeycloakFromRuntime();
|
||||
};
|
||||
|
||||
return (
|
||||
@ -401,7 +355,7 @@ const SidebarRoot = ({
|
||||
color={isSecondaryItemActive ? "blue.600" : "gray.600"}
|
||||
bg={isSecondaryItemActive ? "blue.50" : "transparent"}
|
||||
>
|
||||
<Icon as={EllipsisIcon} boxSize={5} />
|
||||
<Icon as={FiMoreHorizontal} boxSize={5} />
|
||||
<Text
|
||||
fontSize="10px"
|
||||
fontWeight={isSecondaryItemActive ? "bold" : "medium"}
|
||||
|
||||
@ -96,6 +96,8 @@ export default defineConfig(({ mode }) => {
|
||||
|
||||
core: path.resolve(process.cwd(), "src/core/index.js"),
|
||||
|
||||
"core-runtime": path.resolve(process.cwd(), "src/core/runtime.jsx"),
|
||||
|
||||
table: path.resolve(process.cwd(), "src/table/index.js"),
|
||||
|
||||
form: path.resolve(process.cwd(), "src/form/index.js"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user