@deenruv/admin-dashboard 1.0.17-dev.7 → 1.0.17-dev.8

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.
@@ -1,52 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // eslint-disable-next-line no-restricted-imports
3
3
  import { I18nextProvider } from 'react-i18next';
4
- import { useEffect } from 'react';
5
- import { createBrowserRouter, RouterProvider } from 'react-router';
4
+ import { useEffect, useMemo } from 'react';
5
+ import { createBrowserRouter, Navigate, RouterProvider } from 'react-router';
6
6
  import { AnimatePresence } from 'framer-motion';
7
7
  import { Toaster } from 'sonner';
8
8
  import i18n from './i18.js';
9
- import { Routes, PluginProvider, PluginStore, useSettings, GlobalStoreProvider, DEFAULT_CHANNEL_CODE, NotificationProvider, } from '@deenruv/react-ui-devkit';
9
+ import { Routes, PluginProvider, PluginStore, useServer, useSettings, GlobalStoreProvider, DEFAULT_CHANNEL_CODE, NotificationProvider, } from '@deenruv/react-ui-devkit';
10
10
  import { useShallow } from 'zustand/react/shallow';
11
11
  import { LanguageCode } from '@deenruv/admin-types';
12
12
  import { Root } from "./pages/Root.js";
13
13
  import { LoginScreen } from "./pages/LoginScreen.js";
14
14
  import { ErrorPage } from "./pages/Custom404.js";
15
- import * as Pages from "./pages/index.js";
16
15
  import * as resources from "./locales/index.js";
17
16
  import { ADMIN_DASHBOARD_VERSION } from "./version.js";
18
17
  import { ORDER_STATUS_NOTIFICATION } from "./notifications/OrderStatusNotification.js";
19
18
  import { SYSTEM_STATUS_NOTIFICATION } from "./notifications/SystemStatusNotification.js";
20
- const firstLetterToLowerCase = (str) => str.charAt(0).toLowerCase() + str.slice(1);
21
- const getRoute = (name, key) => {
22
- const route = Routes[name];
23
- if (typeof route !== 'object')
24
- return route;
25
- if (key.includes('DetailPage') && 'route' in route)
26
- return route.route;
27
- if (key.includes('ListPage') && 'list' in route)
28
- return route.list;
29
- return null;
30
- };
31
- const getName = (key) => {
32
- if (key.includes('DetailPage'))
33
- return firstLetterToLowerCase(key.replace('DetailPage', ''));
34
- if (key.includes('ListPage'))
35
- return firstLetterToLowerCase(key.replace('ListPage', ''));
36
- return firstLetterToLowerCase(key);
37
- };
38
- const DeenruvPaths = Object.entries(Pages).flatMap(([key, Component]) => {
39
- const name = getName(key);
40
- const path = getRoute(name, key);
41
- const paths = [];
42
- if (path)
43
- paths.push({ path, element: _jsx(Component, {}) });
44
- const route = Routes[name];
45
- if (key.includes('DetailPage') && typeof route === 'object' && 'new' in route) {
46
- paths.push({ path: route.new, element: _jsx(Component, {}) });
47
- }
48
- return paths;
49
- });
19
+ import { AdminAccessProvider, builtInAdminRoutes, getDefaultAdminRoute, getPermittedAdminRoutes, } from "./access/index.js";
50
20
  const loadTranslations = () => {
51
21
  Object.entries(resources).forEach(([lang, value]) => {
52
22
  Object.entries(value).forEach(([, translations]) => {
@@ -76,13 +46,6 @@ export const DeenruvAdminPanel = ({ plugins, settings }) => {
76
46
  };
77
47
  pluginsStore.install(plugins, i18n);
78
48
  loadTranslations();
79
- const router = createBrowserRouter([
80
- {
81
- element: _jsx(Root, { allPaths: [...DeenruvPaths].map((path) => path.path).filter(Boolean) }),
82
- errorElement: _jsx(ErrorPage, {}),
83
- children: [...DeenruvPaths, ...pluginsStore.routes],
84
- },
85
- ]);
86
49
  const { theme, isLoggedIn, ...context } = useSettings(useShallow((p) => ({
87
50
  theme: p.theme,
88
51
  isLoggedIn: p.isLoggedIn,
@@ -90,6 +53,32 @@ export const DeenruvAdminPanel = ({ plugins, settings }) => {
90
53
  language: p.language,
91
54
  translationsLanguage: p.translationsLanguage,
92
55
  })));
56
+ const userPermissions = useServer((p) => p.userPermissions);
57
+ const pluginRoutes = useMemo(() => pluginsStore.routes.map((route) => ({
58
+ id: `plugin.${route.plugin.name}.${route.path}`,
59
+ path: route.path,
60
+ element: route.element,
61
+ ...route.access,
62
+ search: { menuKey: `${route.plugin.name} - ${route.path}`, type: 'plugin' },
63
+ })), [plugins]);
64
+ const permittedRoutes = useMemo(() => getPermittedAdminRoutes([...builtInAdminRoutes, ...pluginRoutes], userPermissions), [pluginRoutes, userPermissions]);
65
+ const defaultRoute = getDefaultAdminRoute(permittedRoutes);
66
+ const router = useMemo(() => {
67
+ const routerChildren = permittedRoutes.map(({ path, element }) => ({ path, element }));
68
+ if (defaultRoute && !permittedRoutes.some((route) => route.path === Routes.dashboard)) {
69
+ routerChildren.push({ path: Routes.dashboard, element: _jsx(Navigate, { to: defaultRoute.path, replace: true }) });
70
+ }
71
+ if (defaultRoute) {
72
+ routerChildren.push({ path: '*', element: _jsx(Navigate, { to: defaultRoute.path, replace: true }) });
73
+ }
74
+ return createBrowserRouter([
75
+ {
76
+ element: _jsx(Root, { allPaths: permittedRoutes.map((route) => route.path).filter(Boolean) }),
77
+ errorElement: _jsx(ErrorPage, {}),
78
+ children: routerChildren,
79
+ },
80
+ ]);
81
+ }, [defaultRoute, permittedRoutes]);
93
82
  useEffect(() => {
94
83
  const root = window.document.documentElement;
95
84
  root.classList.remove('light', 'dark');
@@ -101,7 +90,7 @@ export const DeenruvAdminPanel = ({ plugins, settings }) => {
101
90
  root.classList.add(theme);
102
91
  }
103
92
  }, [theme]);
104
- return (_jsx(GlobalStoreProvider, { ...settings, children: _jsxs(I18nextProvider, { i18n: i18n, defaultNS: 'common', children: [_jsx(AnimatePresence, { children: isLoggedIn ? (_jsx(PluginProvider, { plugins: pluginsStore, context: context, children: _jsx(NotificationProvider, { notifications: [ORDER_STATUS_NOTIFICATION, SYSTEM_STATUS_NOTIFICATION].concat(pluginsStore.notifications), children: _jsx(RouterProvider, { router: router }) }) })) : (_jsx(LoginScreen, {})) }), _jsx(Toaster, { theme: theme, className: "toaster group", richColors: true, expand: true, position: "bottom-right", toastOptions: {
93
+ return (_jsx(GlobalStoreProvider, { ...settings, children: _jsxs(I18nextProvider, { i18n: i18n, defaultNS: 'common', children: [_jsx(AnimatePresence, { children: isLoggedIn ? (_jsx(AdminAccessProvider, { value: { routes: permittedRoutes, defaultRoute }, children: _jsx(PluginProvider, { plugins: pluginsStore, context: context, children: _jsx(NotificationProvider, { notifications: [ORDER_STATUS_NOTIFICATION, SYSTEM_STATUS_NOTIFICATION].concat(pluginsStore.notifications), children: _jsx(RouterProvider, { router: router }) }) }) })) : (_jsx(LoginScreen, {})) }), _jsx(Toaster, { theme: theme, className: "toaster group", richColors: true, expand: true, position: "bottom-right", toastOptions: {
105
94
  classNames: {
106
95
  toast: 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg group-[.toaster]:p-4',
107
96
  title: 'group-[.toast]:font-semibold group-[.toast]:text-foreground',
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from 'react';
3
+ const AdminAccessContext = createContext(null);
4
+ export const AdminAccessProvider = ({ children, value, }) => (_jsx(AdminAccessContext.Provider, { value: value, children: children }));
5
+ export const useAdminAccess = () => {
6
+ const context = useContext(AdminAccessContext);
7
+ if (!context)
8
+ throw new Error('useAdminAccess must be used within AdminAccessProvider');
9
+ return context;
10
+ };
@@ -0,0 +1,300 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Permission } from '@deenruv/admin-types';
3
+ import { Routes } from '@deenruv/react-ui-devkit';
4
+ import { BarChart, Barcode, Coins, Cog, CreditCard, Flag, Folder, Globe, Globe2, Images, MapPin, Percent, ScanBarcode, Server, ShoppingCart, Store, Tag, Truck, UserCog, UserRoundSearch, Users, UsersRound, } from 'lucide-react';
5
+ import { AdminsDetailPage, AdminsListPage, AdminsProvisionPage, AssetsListPage, ChannelsDetailPage, ChannelsListPage, CollectionsDetailPage, CollectionsListPage, CountriesDetailPage, CountriesListPage, CustomerGroupsDetailPage, CustomerGroupsListPage, CustomersDetailPage, CustomersListPage, Dashboard, Extensions, FacetsDetailPage, FacetsListPage, GlobalSettings, OrdersDetailPage, OrdersListPage, PaymentMethodsDetailPage, PaymentMethodsListPage, ProductVariantDetailPage, ProductVariantsListPage, ProductsDetailPage, ProductsListPage, PromotionsDetailPage, PromotionsListPage, RolesDetailPage, RolesListPage, SellersDetailPage, SellersListPage, ShippingMethodsDetailPage, ShippingMethodsListPage, Status, StockLocationsDetailPage, StockLocationsListPage, TaxCategoriesDetailPage, TaxCategoriesListPage, TaxRatesDetailPage, TaxRatesListPage, ZonesDetailPage, ZonesListPage, } from "../pages/index.js";
6
+ export const adminNavigationGroups = [
7
+ { id: 'shop-group', labelKey: 'shop' },
8
+ { id: 'assortment-group', labelKey: 'assortment' },
9
+ { id: 'users-group', labelKey: 'users' },
10
+ { id: 'promotions-group', labelKey: 'promotions' },
11
+ { id: 'shipping-group', labelKey: 'shipping' },
12
+ { id: 'settings-group', labelKey: 'settings' },
13
+ ];
14
+ const createCrudRouteDefinitions = ({ id, menuKey, routes, listElement, detailElement, readPermissions, createPermissions, nav, }) => {
15
+ const definitions = [
16
+ {
17
+ id: `${id}.list`,
18
+ path: routes.list,
19
+ element: listElement(),
20
+ requiredPermissions: readPermissions,
21
+ nav,
22
+ search: { menuKey, type: 'list' },
23
+ },
24
+ ];
25
+ if (routes.route && detailElement) {
26
+ definitions.push({
27
+ id: `${id}.detail`,
28
+ path: routes.route,
29
+ element: detailElement(),
30
+ requiredPermissions: readPermissions,
31
+ });
32
+ }
33
+ if (routes.new && detailElement) {
34
+ definitions.push({
35
+ id: `${id}.create`,
36
+ path: routes.new,
37
+ element: detailElement(),
38
+ requiredPermissions: createPermissions,
39
+ search: { menuKey, type: 'new' },
40
+ });
41
+ }
42
+ return definitions;
43
+ };
44
+ export const builtInAdminRoutes = [
45
+ {
46
+ id: 'dashboard',
47
+ path: Routes.dashboard,
48
+ element: _jsx(Dashboard, {}),
49
+ nav: { groupId: 'shop-group', linkId: 'link-dashboard', menuKey: 'dashboard', icon: BarChart },
50
+ search: { menuKey: 'dashboard', type: 'default' },
51
+ },
52
+ ...createCrudRouteDefinitions({
53
+ id: 'orders',
54
+ menuKey: 'orders',
55
+ routes: Routes.orders,
56
+ listElement: () => _jsx(OrdersListPage, {}),
57
+ detailElement: () => _jsx(OrdersDetailPage, {}),
58
+ readPermissions: [Permission.ReadOrder],
59
+ createPermissions: [Permission.CreateOrder],
60
+ nav: { groupId: 'shop-group', linkId: 'link-orders', menuKey: 'orders', icon: ShoppingCart },
61
+ }),
62
+ ...createCrudRouteDefinitions({
63
+ id: 'customers',
64
+ menuKey: 'customers',
65
+ routes: Routes.customers,
66
+ listElement: () => _jsx(CustomersListPage, {}),
67
+ detailElement: () => _jsx(CustomersDetailPage, {}),
68
+ readPermissions: [Permission.ReadCustomer],
69
+ createPermissions: [Permission.CreateCustomer],
70
+ nav: { groupId: 'shop-group', linkId: 'link-customers', menuKey: 'customers', icon: UserRoundSearch },
71
+ }),
72
+ ...createCrudRouteDefinitions({
73
+ id: 'customerGroups',
74
+ menuKey: 'customerGroups',
75
+ routes: Routes.customerGroups,
76
+ listElement: () => _jsx(CustomerGroupsListPage, {}),
77
+ detailElement: () => _jsx(CustomerGroupsDetailPage, {}),
78
+ readPermissions: [Permission.ReadCustomerGroup],
79
+ createPermissions: [Permission.CreateCustomerGroup],
80
+ nav: { groupId: 'shop-group', linkId: 'link-customerGroups', menuKey: 'customerGroups', icon: UsersRound },
81
+ }),
82
+ ...createCrudRouteDefinitions({
83
+ id: 'products',
84
+ menuKey: 'products',
85
+ routes: Routes.products,
86
+ listElement: () => _jsx(ProductsListPage, {}),
87
+ detailElement: () => _jsx(ProductsDetailPage, {}),
88
+ readPermissions: [Permission.ReadProduct, Permission.ReadCatalog],
89
+ createPermissions: [Permission.CreateProduct],
90
+ nav: { groupId: 'assortment-group', linkId: 'link-products', menuKey: 'products', icon: Barcode },
91
+ }),
92
+ ...createCrudRouteDefinitions({
93
+ id: 'productVariants',
94
+ menuKey: 'productVariants',
95
+ routes: Routes.productVariants,
96
+ listElement: () => _jsx(ProductVariantsListPage, {}),
97
+ detailElement: () => _jsx(ProductVariantDetailPage, {}),
98
+ readPermissions: [Permission.ReadProduct, Permission.ReadCatalog],
99
+ createPermissions: [Permission.CreateProduct],
100
+ nav: {
101
+ groupId: 'assortment-group',
102
+ linkId: 'link-product-variants',
103
+ menuKey: 'productVariants',
104
+ icon: ScanBarcode,
105
+ },
106
+ }),
107
+ ...createCrudRouteDefinitions({
108
+ id: 'collections',
109
+ menuKey: 'collections',
110
+ routes: Routes.collections,
111
+ listElement: () => _jsx(CollectionsListPage, {}),
112
+ detailElement: () => _jsx(CollectionsDetailPage, {}),
113
+ readPermissions: [Permission.ReadCollection, Permission.ReadCatalog],
114
+ createPermissions: [Permission.CreateCollection],
115
+ nav: { groupId: 'assortment-group', linkId: 'link-collections', menuKey: 'collections', icon: Folder },
116
+ }),
117
+ ...createCrudRouteDefinitions({
118
+ id: 'facets',
119
+ menuKey: 'facets',
120
+ routes: Routes.facets,
121
+ listElement: () => _jsx(FacetsListPage, {}),
122
+ detailElement: () => _jsx(FacetsDetailPage, {}),
123
+ readPermissions: [Permission.ReadFacet, Permission.ReadCatalog],
124
+ createPermissions: [Permission.CreateFacet],
125
+ nav: { groupId: 'assortment-group', linkId: 'link-facets', menuKey: 'facets', icon: Tag },
126
+ }),
127
+ {
128
+ id: 'assets.list',
129
+ path: Routes.assets.list,
130
+ element: _jsx(AssetsListPage, {}),
131
+ requiredPermissions: [Permission.ReadAsset, Permission.ReadCatalog],
132
+ nav: { groupId: 'assortment-group', linkId: 'link-assets', menuKey: 'assets', icon: Images },
133
+ search: { menuKey: 'assets', type: 'list' },
134
+ },
135
+ ...createCrudRouteDefinitions({
136
+ id: 'admins',
137
+ menuKey: 'admins',
138
+ routes: Routes.admins,
139
+ listElement: () => _jsx(AdminsListPage, {}),
140
+ detailElement: () => _jsx(AdminsDetailPage, {}),
141
+ readPermissions: [Permission.ReadAdministrator],
142
+ createPermissions: [Permission.CreateAdministrator],
143
+ nav: { groupId: 'users-group', linkId: 'link-admins', menuKey: 'admins', icon: UserCog },
144
+ }),
145
+ {
146
+ id: 'admins.provision',
147
+ path: Routes.admins.provision,
148
+ element: _jsx(AdminsProvisionPage, {}),
149
+ requiredPermissions: [Permission.CreateAdministrator],
150
+ search: { menuKey: 'adminProvision', type: 'new' },
151
+ },
152
+ ...createCrudRouteDefinitions({
153
+ id: 'roles',
154
+ menuKey: 'roles',
155
+ routes: Routes.roles,
156
+ listElement: () => _jsx(RolesListPage, {}),
157
+ detailElement: () => _jsx(RolesDetailPage, {}),
158
+ readPermissions: [Permission.ReadAdministrator],
159
+ createPermissions: [Permission.CreateAdministrator],
160
+ nav: { groupId: 'users-group', linkId: 'link-roles', menuKey: 'roles', icon: Users },
161
+ }),
162
+ ...createCrudRouteDefinitions({
163
+ id: 'sellers',
164
+ menuKey: 'sellers',
165
+ routes: Routes.sellers,
166
+ listElement: () => _jsx(SellersListPage, {}),
167
+ detailElement: () => _jsx(SellersDetailPage, {}),
168
+ readPermissions: [Permission.ReadSeller],
169
+ createPermissions: [Permission.CreateSeller],
170
+ nav: { groupId: 'users-group', linkId: 'link-sellers', menuKey: 'sellers', icon: Store },
171
+ }),
172
+ ...createCrudRouteDefinitions({
173
+ id: 'promotions',
174
+ menuKey: 'promotions',
175
+ routes: Routes.promotions,
176
+ listElement: () => _jsx(PromotionsListPage, {}),
177
+ detailElement: () => _jsx(PromotionsDetailPage, {}),
178
+ readPermissions: [Permission.ReadPromotion],
179
+ createPermissions: [Permission.CreatePromotion],
180
+ nav: { groupId: 'promotions-group', linkId: 'link-promotions', menuKey: 'promotions', icon: ShoppingCart },
181
+ }),
182
+ ...createCrudRouteDefinitions({
183
+ id: 'paymentMethods',
184
+ menuKey: 'paymentMethods',
185
+ routes: Routes.paymentMethods,
186
+ listElement: () => _jsx(PaymentMethodsListPage, {}),
187
+ detailElement: () => _jsx(PaymentMethodsDetailPage, {}),
188
+ readPermissions: [Permission.ReadPaymentMethod],
189
+ createPermissions: [Permission.CreatePaymentMethod],
190
+ nav: {
191
+ groupId: 'shipping-group',
192
+ linkId: 'link-payment-methods',
193
+ menuKey: 'paymentMethods',
194
+ icon: CreditCard,
195
+ },
196
+ }),
197
+ ...createCrudRouteDefinitions({
198
+ id: 'shippingMethods',
199
+ menuKey: 'shippingMethods',
200
+ routes: Routes.shippingMethods,
201
+ listElement: () => _jsx(ShippingMethodsListPage, {}),
202
+ detailElement: () => _jsx(ShippingMethodsDetailPage, {}),
203
+ readPermissions: [Permission.ReadShippingMethod],
204
+ createPermissions: [Permission.CreateShippingMethod],
205
+ nav: {
206
+ groupId: 'shipping-group',
207
+ linkId: 'link-shipping-methods',
208
+ menuKey: 'shippingMethods',
209
+ icon: Truck,
210
+ },
211
+ }),
212
+ ...createCrudRouteDefinitions({
213
+ id: 'stockLocations',
214
+ menuKey: 'stock',
215
+ routes: Routes.stockLocations,
216
+ listElement: () => _jsx(StockLocationsListPage, {}),
217
+ detailElement: () => _jsx(StockLocationsDetailPage, {}),
218
+ readPermissions: [Permission.ReadStockLocation],
219
+ createPermissions: [Permission.CreateStockLocation],
220
+ nav: { groupId: 'shipping-group', linkId: 'link-stock', menuKey: 'stock', icon: MapPin },
221
+ }),
222
+ ...createCrudRouteDefinitions({
223
+ id: 'channels',
224
+ menuKey: 'channels',
225
+ routes: Routes.channels,
226
+ listElement: () => _jsx(ChannelsListPage, {}),
227
+ detailElement: () => _jsx(ChannelsDetailPage, {}),
228
+ readPermissions: [Permission.ReadChannel],
229
+ createPermissions: [Permission.CreateChannel],
230
+ nav: { groupId: 'settings-group', linkId: 'link-channels', menuKey: 'channels', icon: Globe2 },
231
+ }),
232
+ ...createCrudRouteDefinitions({
233
+ id: 'zones',
234
+ menuKey: 'zones',
235
+ routes: Routes.zones,
236
+ listElement: () => _jsx(ZonesListPage, {}),
237
+ detailElement: () => _jsx(ZonesDetailPage, {}),
238
+ readPermissions: [Permission.ReadZone],
239
+ createPermissions: [Permission.CreateZone],
240
+ nav: { groupId: 'settings-group', linkId: 'link-zones', menuKey: 'zones', icon: Globe },
241
+ }),
242
+ ...createCrudRouteDefinitions({
243
+ id: 'countries',
244
+ menuKey: 'countries',
245
+ routes: Routes.countries,
246
+ listElement: () => _jsx(CountriesListPage, {}),
247
+ detailElement: () => _jsx(CountriesDetailPage, {}),
248
+ readPermissions: [Permission.ReadCountry],
249
+ createPermissions: [Permission.CreateCountry],
250
+ nav: { groupId: 'settings-group', linkId: 'link-countries', menuKey: 'countries', icon: Flag },
251
+ }),
252
+ ...createCrudRouteDefinitions({
253
+ id: 'taxCategories',
254
+ menuKey: 'taxCategories',
255
+ routes: Routes.taxCategories,
256
+ listElement: () => _jsx(TaxCategoriesListPage, {}),
257
+ detailElement: () => _jsx(TaxCategoriesDetailPage, {}),
258
+ readPermissions: [Permission.ReadTaxCategory],
259
+ createPermissions: [Permission.CreateTaxCategory],
260
+ nav: {
261
+ groupId: 'settings-group',
262
+ linkId: 'link-tax-categories',
263
+ menuKey: 'taxCategories',
264
+ icon: Coins,
265
+ },
266
+ }),
267
+ ...createCrudRouteDefinitions({
268
+ id: 'taxRates',
269
+ menuKey: 'taxRates',
270
+ routes: Routes.taxRates,
271
+ listElement: () => _jsx(TaxRatesListPage, {}),
272
+ detailElement: () => _jsx(TaxRatesDetailPage, {}),
273
+ readPermissions: [Permission.ReadTaxRate],
274
+ createPermissions: [Permission.CreateTaxRate],
275
+ nav: { groupId: 'settings-group', linkId: 'link-tax-rates', menuKey: 'taxRates', icon: Percent },
276
+ }),
277
+ {
278
+ id: 'settings.global',
279
+ path: Routes.globalSettings,
280
+ element: _jsx(GlobalSettings, {}),
281
+ requiredPermissions: [Permission.ReadSettings],
282
+ nav: { groupId: 'settings-group', linkId: 'link-global-settings', menuKey: 'globalSettings', icon: Cog },
283
+ search: { menuKey: 'globalSettings', type: 'default' },
284
+ },
285
+ {
286
+ id: 'system.status',
287
+ path: Routes.status,
288
+ element: _jsx(Status, {}),
289
+ requiredPermissions: [Permission.ReadSystem],
290
+ nav: { groupId: 'settings-group', linkId: 'link-system-status', menuKey: 'systemStatus', icon: Server },
291
+ search: { menuKey: 'systemStatus', type: 'default' },
292
+ },
293
+ {
294
+ id: 'extensions',
295
+ path: Routes.extensions,
296
+ element: _jsx(Extensions, {}),
297
+ requiredPermissions: [Permission.ReadSettings],
298
+ search: { menuKey: 'extensions', type: 'default' },
299
+ },
300
+ ];
@@ -0,0 +1,5 @@
1
+ export * from './access-context.js';
2
+ export * from './built-in-routes.js';
3
+ export * from './permission-access.js';
4
+ export * from './permission-routes.js';
5
+ export * from './types.js';
@@ -0,0 +1,9 @@
1
+ export const hasRequiredPermissions = ({ requiredPermissions, permissionMatch = 'any', userPermissions, }) => {
2
+ if (!requiredPermissions?.length)
3
+ return true;
4
+ if (permissionMatch === 'all') {
5
+ return requiredPermissions.every((permission) => userPermissions.includes(permission));
6
+ }
7
+ return requiredPermissions.some((permission) => userPermissions.includes(permission));
8
+ };
9
+ export const canAccessAdminItem = ({ item, userPermissions, }) => hasRequiredPermissions({ ...item, userPermissions });
@@ -0,0 +1,3 @@
1
+ import { canAccessAdminItem } from './permission-access.js';
2
+ export const getPermittedAdminRoutes = (routes, userPermissions) => routes.filter((route) => canAccessAdminItem({ item: route, userPermissions }));
3
+ export const getDefaultAdminRoute = (routes) => routes.find((route) => route.id === 'dashboard') || routes.find((route) => route.nav) || routes[0];
@@ -0,0 +1 @@
1
+ export {};
@@ -1,16 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, usePluginStore, Routes, useGlobalSearch, capitalizeFirstLetter, useTranslation, } from '@deenruv/react-ui-devkit';
2
+ import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, useGlobalSearch, capitalizeFirstLetter, useTranslation, useServer, } from '@deenruv/react-ui-devkit';
3
3
  import { useEffect, useMemo } from 'react';
4
4
  import { useNavigate } from 'react-router';
5
5
  import { LayoutDashboard, ListPlus, FileText, Puzzle, ArrowRight } from 'lucide-react';
6
+ import { canAccessAdminItem, useAdminAccess } from "../access/index.js";
6
7
  export const GlobalSearch = () => {
7
8
  const { t, tEntity } = useTranslation('common');
8
- const { plugins } = usePluginStore();
9
+ const { routes } = useAdminAccess();
10
+ const userPermissions = useServer((p) => p.userPermissions);
9
11
  const isOpen = useGlobalSearch((s) => s.isOpen);
10
12
  const toggle = useGlobalSearch((s) => s.toggle);
11
13
  const close = useGlobalSearch((s) => s.close);
12
14
  const navigate = useNavigate();
15
+ const isEnabled = true;
13
16
  useEffect(() => {
17
+ if (!isEnabled)
18
+ return;
14
19
  const handleKeyDown = (e) => {
15
20
  if ((e.metaKey || e.ctrlKey) && e.key === ' ') {
16
21
  e.preventDefault();
@@ -19,63 +24,33 @@ export const GlobalSearch = () => {
19
24
  };
20
25
  document.addEventListener('keydown', handleKeyDown);
21
26
  return () => document.removeEventListener('keydown', handleKeyDown);
22
- }, [toggle]);
27
+ }, [isEnabled, toggle]);
23
28
  const allRoutes = useMemo(() => {
24
- const routes = [];
25
- Object.entries(Routes).forEach(([key, value]) => {
26
- if (typeof value === 'object' && value !== null) {
27
- const children = [];
28
- if ('new' in value && typeof value.new === 'string') {
29
- children.push({
30
- name: capitalizeFirstLetter(t(`menu.${key}`)),
31
- path: value.new,
32
- type: 'new',
33
- description: tEntity('Utwórz', key),
34
- });
35
- }
36
- if ('list' in value && typeof value.list === 'string') {
37
- children.push({
38
- name: capitalizeFirstLetter(t(`menu.${key}`)),
39
- path: value.list,
40
- type: 'list',
41
- description: tEntity('Zobacz wszystkie', key, 'many'),
42
- });
43
- }
44
- routes.push({ name: key, children });
45
- }
46
- else if (typeof value === 'string') {
47
- routes.push({
48
- name: capitalizeFirstLetter(t(`menu.${key}`)),
49
- path: value,
50
- type: 'default',
51
- description: `${t('globalSearch.navigateTo')} ${t(`menu.${key}`)}`,
52
- });
53
- }
54
- });
55
- plugins.forEach((plugin) => {
56
- plugin.pages?.forEach((page, pageIndex) => {
57
- if (page.path) {
58
- routes.push({
59
- name: `${plugin.name} - ${page.path || 'Page'}`,
60
- path: page.path,
61
- type: 'plugin',
62
- description: t('globalSearch.accessPlugin', { pluginName: plugin.name }),
63
- });
64
- }
65
- });
29
+ return routes
30
+ .filter((route) => route.search)
31
+ .filter((route) => canAccessAdminItem({ item: route, userPermissions }))
32
+ .map((route) => {
33
+ const search = route.search;
34
+ const isPlugin = search.type === 'plugin';
35
+ const translatedName = isPlugin ? search.menuKey : capitalizeFirstLetter(t(`menu.${search.menuKey}`));
36
+ const description = search.type === 'new'
37
+ ? tEntity('Utwórz', search.menuKey)
38
+ : search.type === 'list'
39
+ ? tEntity('Zobacz wszystkie', search.menuKey, 'many')
40
+ : search.type === 'plugin'
41
+ ? t('globalSearch.accessPlugin', { pluginName: search.menuKey })
42
+ : `${t('globalSearch.navigateTo')} ${t(`menu.${search.menuKey}`)}`;
43
+ return {
44
+ id: route.id,
45
+ name: translatedName,
46
+ path: route.path,
47
+ type: search.type,
48
+ description,
49
+ };
66
50
  });
67
- return routes.flatMap((route, routeIndex) => route.children?.length
68
- ? route.children.map((child, childIndex) => ({
69
- ...child,
70
- id: `${routeIndex}-${childIndex}-${child.type}-${route.name}`,
71
- }))
72
- : [
73
- {
74
- ...route,
75
- id: `${routeIndex}-main-${route.name}`,
76
- },
77
- ]);
78
- }, [plugins]);
51
+ }, [routes, t, tEntity, userPermissions]);
52
+ if (!isEnabled)
53
+ return null;
79
54
  // Group routes by type for better organization
80
55
  const groupedRoutes = useMemo(() => {
81
56
  const core = [];