@flowselections/admin-installatietechniek 1.0.3 → 1.0.5
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/dist-lib/components/AdminForInstallatieTechniek.d.ts +4 -0
- package/dist-lib/components/AdminForInstallatieTechniek.d.ts.map +1 -1
- package/dist-lib/components/AdminForInstallatieTechniek.js +223 -197
- package/dist-lib/components/ModuleAccessGuard.d.ts +15 -0
- package/dist-lib/components/ModuleAccessGuard.d.ts.map +1 -0
- package/dist-lib/components/ModuleAccessGuard.js +40 -0
- package/dist-lib/hooks/useModulePermission.d.ts +11 -4
- package/dist-lib/hooks/useModulePermission.d.ts.map +1 -1
- package/dist-lib/hooks/useModulePermission.js +33 -26
- package/dist-lib/index.d.ts +3 -3
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -1
- package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/auth-attacher.js +5 -1
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +978 -133
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/auth-middleware.js +21 -7
- package/dist-lib/integrations/supabase/client.d.ts +978 -133
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +978 -133
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +987 -137
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/admin.functions.d.ts +78644 -2655
- package/dist-lib/lib/admin.functions.d.ts.map +1 -1
- package/dist-lib/lib/admin.functions.js +351 -174
- package/dist-lib/lib/moduleDiscovery.d.ts +7 -2
- package/dist-lib/lib/moduleDiscovery.d.ts.map +1 -1
- package/dist-lib/lib/moduleDiscovery.js +26 -11
- package/dist-lib/lib/permissions.server.d.ts +14 -0
- package/dist-lib/lib/permissions.server.d.ts.map +1 -0
- package/dist-lib/lib/permissions.server.js +26 -0
- package/package.json +1 -1
- package/dist-lib/hooks/useModuleOrder.d.ts +0 -30
- package/dist-lib/hooks/useModuleOrder.d.ts.map +0 -1
- package/dist-lib/hooks/useModuleOrder.js +0 -99
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface ModuleAccessGuardProps {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
featureId?: string;
|
|
4
|
+
fallback?: React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Rendert alleen kinderen als de ingelogde gebruiker toegang heeft tot de
|
|
8
|
+
* huidige module. Tijdens laden een skeleton; bij onvoldoende recht een nette
|
|
9
|
+
* "geen toegang"-kaart. Modules die niet geregistreerd zijn worden altijd
|
|
10
|
+
* toegestaan (default-allow), zodat bestaande shells zonder aanpassingen
|
|
11
|
+
* blijven werken.
|
|
12
|
+
*/
|
|
13
|
+
export declare function ModuleAccessGuard({ children, featureId, fallback }: ModuleAccessGuardProps): import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=ModuleAccessGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModuleAccessGuard.d.ts","sourceRoot":"","sources":["../../src/components/ModuleAccessGuard.tsx"],"names":[],"mappings":"AAKA,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAYD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,SAAc,EAAE,QAAQ,EAAE,EAAE,sBAAsB,+BAwC/F"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRouterState } from "@tanstack/react-router";
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@flowselections/core";
|
|
4
|
+
import { ShieldAlert } from "lucide-react";
|
|
5
|
+
import { useModulePermission } from "../hooks/useModulePermission";
|
|
6
|
+
const EXCLUDED_SEGMENTS = new Set(["admin-installatietechniek", "instellingen"]);
|
|
7
|
+
function deriveModuleId(pathname) {
|
|
8
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
9
|
+
const first = segments[0];
|
|
10
|
+
if (!first || first.startsWith("$") || first.startsWith("_"))
|
|
11
|
+
return null;
|
|
12
|
+
if (EXCLUDED_SEGMENTS.has(first))
|
|
13
|
+
return null;
|
|
14
|
+
return first;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rendert alleen kinderen als de ingelogde gebruiker toegang heeft tot de
|
|
18
|
+
* huidige module. Tijdens laden een skeleton; bij onvoldoende recht een nette
|
|
19
|
+
* "geen toegang"-kaart. Modules die niet geregistreerd zijn worden altijd
|
|
20
|
+
* toegestaan (default-allow), zodat bestaande shells zonder aanpassingen
|
|
21
|
+
* blijven werken.
|
|
22
|
+
*/
|
|
23
|
+
export function ModuleAccessGuard({ children, featureId = "", fallback }) {
|
|
24
|
+
const pathname = useRouterState({ select: (s) => s.location.pathname });
|
|
25
|
+
const moduleId = deriveModuleId(pathname);
|
|
26
|
+
// Als we geen module kunnen afleiden (bijv. admin of instellingen), toon
|
|
27
|
+
// altijd de inhoud.
|
|
28
|
+
if (!moduleId)
|
|
29
|
+
return _jsx(_Fragment, { children: children });
|
|
30
|
+
const { permission, loading, canView } = useModulePermission(moduleId, featureId);
|
|
31
|
+
if (loading) {
|
|
32
|
+
return (_jsxs("div", { className: "flex-1 p-6", children: [_jsx("div", { className: "h-6 w-48 animate-pulse rounded bg-muted mb-4" }), _jsx("div", { className: "h-32 animate-pulse rounded bg-muted" })] }));
|
|
33
|
+
}
|
|
34
|
+
if (!canView) {
|
|
35
|
+
if (fallback)
|
|
36
|
+
return _jsx(_Fragment, { children: fallback });
|
|
37
|
+
return (_jsx("div", { className: "flex-1 flex items-center justify-center p-6", children: _jsxs(Card, { className: "max-w-md w-full", children: [_jsxs(CardHeader, { className: "flex flex-row items-center gap-3", children: [_jsx(ShieldAlert, { className: "h-6 w-6 text-destructive" }), _jsx(CardTitle, { children: "Geen toegang" })] }), _jsx(CardContent, { children: _jsx("p", { className: "text-sm text-muted-foreground", children: "Je hebt geen toegang tot deze module. Neem contact op met een beheerder als je denkt dat dit niet klopt." }) })] }) }));
|
|
38
|
+
}
|
|
39
|
+
return _jsx(_Fragment, { children: children });
|
|
40
|
+
}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
export type ModulePermission = "none" | "view" | "edit";
|
|
2
2
|
/**
|
|
3
3
|
* Haalt de effectieve rechten van de ingelogde gebruiker op voor alle
|
|
4
|
-
* geregistreerde modules. Persoonlijke uitzonderingen winnen
|
|
4
|
+
* geregistreerde modules en onderdelen. Persoonlijke uitzonderingen winnen
|
|
5
|
+
* van rolrechten. Gedeelde cache via React Query; één keer per sessie.
|
|
5
6
|
*/
|
|
6
7
|
export declare function useMyModulePermissions(): {
|
|
7
|
-
permissions: Record<string, ModulePermission
|
|
8
|
+
permissions: NoInfer<Record<string, ModulePermission>>;
|
|
8
9
|
loading: boolean;
|
|
9
10
|
};
|
|
10
|
-
/** Effectief recht voor één module: "none" | "view" | "edit". */
|
|
11
|
-
export declare function useModulePermission(moduleId: string): {
|
|
11
|
+
/** Effectief recht voor één module of onderdeel: "none" | "view" | "edit". */
|
|
12
|
+
export declare function useModulePermission(moduleId: string, featureId?: string): {
|
|
12
13
|
permission: ModulePermission;
|
|
13
14
|
canView: boolean;
|
|
14
15
|
canEdit: boolean;
|
|
15
16
|
loading: boolean;
|
|
16
17
|
};
|
|
18
|
+
/** Invalidatie-aanhaker voor auth-wijzigingen. */
|
|
19
|
+
export declare function invalidateModulePermissions(queryClient: {
|
|
20
|
+
invalidateQueries: (options: {
|
|
21
|
+
queryKey: string[];
|
|
22
|
+
}) => Promise<void>;
|
|
23
|
+
}): Promise<void>;
|
|
17
24
|
//# sourceMappingURL=useModulePermission.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModulePermission.d.ts","sourceRoot":"","sources":["../../src/hooks/useModulePermission.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"useModulePermission.d.ts","sourceRoot":"","sources":["../../src/hooks/useModulePermission.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAMxD;;;;GAIG;AACH,wBAAgB,sBAAsB;;;EAmBrC;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAK;;;;;EAgBnE;AAED,kDAAkD;AAClD,wBAAgB,2BAA2B,CAAC,WAAW,EAAE;IACvD,iBAAiB,EAAE,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvE,iBAEA"}
|
|
@@ -1,38 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
2
|
import { supabase } from "../integrations/supabase/client";
|
|
3
|
+
const cellKey = (moduleId, featureId) => `${moduleId}::${featureId}`;
|
|
4
|
+
const permissionQueryKey = ["my-module-permissions"];
|
|
3
5
|
/**
|
|
4
6
|
* Haalt de effectieve rechten van de ingelogde gebruiker op voor alle
|
|
5
|
-
* geregistreerde modules. Persoonlijke uitzonderingen winnen
|
|
7
|
+
* geregistreerde modules en onderdelen. Persoonlijke uitzonderingen winnen
|
|
8
|
+
* van rolrechten. Gedeelde cache via React Query; één keer per sessie.
|
|
6
9
|
*/
|
|
7
10
|
export function useMyModulePermissions() {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
let cancelled = false;
|
|
12
|
-
(async () => {
|
|
11
|
+
const { data, isLoading } = useQuery({
|
|
12
|
+
queryKey: permissionQueryKey,
|
|
13
|
+
queryFn: async () => {
|
|
13
14
|
const { data, error } = await supabase.rpc("my_module_permissions");
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
const rows = Array.isArray(data)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
setPermissions(map);
|
|
15
|
+
if (error)
|
|
16
|
+
throw error;
|
|
17
|
+
const rows = Array.isArray(data)
|
|
18
|
+
? data
|
|
19
|
+
: [];
|
|
20
|
+
const map = {};
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
map[cellKey(row.module_id, row.feature_id ?? "")] = row.permission;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}, []);
|
|
30
|
-
return { permissions, loading };
|
|
24
|
+
return map;
|
|
25
|
+
},
|
|
26
|
+
staleTime: 5 * 60 * 1000,
|
|
27
|
+
});
|
|
28
|
+
return { permissions: data ?? {}, loading: isLoading };
|
|
31
29
|
}
|
|
32
|
-
/** Effectief recht voor één module: "none" | "view" | "edit". */
|
|
33
|
-
export function useModulePermission(moduleId) {
|
|
30
|
+
/** Effectief recht voor één module of onderdeel: "none" | "view" | "edit". */
|
|
31
|
+
export function useModulePermission(moduleId, featureId = "") {
|
|
34
32
|
const { permissions, loading } = useMyModulePermissions();
|
|
35
|
-
const
|
|
33
|
+
const exact = permissions[cellKey(moduleId, featureId)];
|
|
34
|
+
const moduleFallback = permissions[cellKey(moduleId, "")];
|
|
35
|
+
// Niet geregistreerde modules zijn default toegestaan (edit) zodat
|
|
36
|
+
// bestaande shells blijven werken totdat een beheerder expliciet rechten
|
|
37
|
+
// instelt en enforce aanzet.
|
|
38
|
+
const permission = exact ?? moduleFallback ?? "edit";
|
|
36
39
|
return {
|
|
37
40
|
permission,
|
|
38
41
|
canView: permission === "view" || permission === "edit",
|
|
@@ -40,3 +43,7 @@ export function useModulePermission(moduleId) {
|
|
|
40
43
|
loading,
|
|
41
44
|
};
|
|
42
45
|
}
|
|
46
|
+
/** Invalidatie-aanhaker voor auth-wijzigingen. */
|
|
47
|
+
export function invalidateModulePermissions(queryClient) {
|
|
48
|
+
return queryClient.invalidateQueries({ queryKey: permissionQueryKey });
|
|
49
|
+
}
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export type { AdminForInstallatieTechniekProps, AdminModuleInput } from './compo
|
|
|
5
5
|
export { useModulePermission, useMyModulePermissions } from './hooks/useModulePermission';
|
|
6
6
|
export type { ModulePermission } from './hooks/useModulePermission';
|
|
7
7
|
export { useDiscoveredModules } from './lib/moduleDiscovery';
|
|
8
|
-
export type { DiscoveredModule } from './lib/moduleDiscovery';
|
|
9
|
-
export {
|
|
10
|
-
export
|
|
8
|
+
export type { DiscoveredModule, DiscoveredFeature } from './lib/moduleDiscovery';
|
|
9
|
+
export { ModuleAccessGuard } from './components/ModuleAccessGuard';
|
|
10
|
+
export { requireModulePermission } from './lib/permissions.server';
|
|
11
11
|
export declare const adminInstallatietechniekModule: FlowModule;
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist-lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,YAAY,EAAE,gCAAgC,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACnH,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1F,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,YAAY,EAAE,gCAAgC,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACnH,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1F,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,eAAO,MAAM,8BAA8B,EAAE,UAY5C,CAAC"}
|
package/dist-lib/index.js
CHANGED
|
@@ -6,7 +6,8 @@ export * from './_core-safelist';
|
|
|
6
6
|
export { AdminForInstallatieTechniek } from './components/AdminForInstallatieTechniek';
|
|
7
7
|
export { useModulePermission, useMyModulePermissions } from './hooks/useModulePermission';
|
|
8
8
|
export { useDiscoveredModules } from './lib/moduleDiscovery';
|
|
9
|
-
export {
|
|
9
|
+
export { ModuleAccessGuard } from './components/ModuleAccessGuard';
|
|
10
|
+
export { requireModulePermission } from './lib/permissions.server';
|
|
10
11
|
export const adminInstallatietechniekModule = {
|
|
11
12
|
id: "admin-installatietechniek",
|
|
12
13
|
name: "Admin Installatietechniek",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-attacher.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/auth-attacher.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"auth-attacher.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/auth-attacher.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,kBAAkB,mHAY9B,CAAA"}
|
|
@@ -7,6 +7,10 @@ export const attachSupabaseAuth = createMiddleware({ type: 'function' }).client(
|
|
|
7
7
|
const { data } = await supabase.auth.getSession();
|
|
8
8
|
const token = data.session?.access_token;
|
|
9
9
|
return next({
|
|
10
|
-
|
|
10
|
+
// `x-sb-auth` is een fallback: sommige preview-proxies overschrijven de
|
|
11
|
+
// Authorization-header, waardoor de server een ongeldig token zag.
|
|
12
|
+
headers: token
|
|
13
|
+
? { Authorization: `Bearer ${token}`, 'x-sb-auth': token }
|
|
14
|
+
: {},
|
|
11
15
|
});
|
|
12
16
|
});
|