@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.
- package/dist/DeenruvAdminPanel.js +31 -42
- package/dist/access/access-context.js +10 -0
- package/dist/access/built-in-routes.js +300 -0
- package/dist/access/index.js +5 -0
- package/dist/access/permission-access.js +9 -0
- package/dist/access/permission-routes.js +3 -0
- package/dist/access/types.js +1 -0
- package/dist/components/GlobalSearch.js +32 -57
- package/dist/components/Menu/Navigation.js +36 -212
- package/dist/components/Menu/NavigationFooter.js +6 -3
- package/dist/components/Menu/index.js +40 -4
- package/dist/locales/en/admins.json +62 -0
- package/dist/locales/en/common.json +1 -0
- package/dist/locales/pl/admins.json +62 -0
- package/dist/locales/pl/common.json +1 -0
- package/dist/pages/Root.js +30 -14
- package/dist/pages/admins/List.js +8 -3
- package/dist/pages/admins/Provision.js +173 -0
- package/dist/pages/admins/Provision.logic.js +53 -0
- package/dist/pages/admins/index.js +1 -0
- package/dist/version.js +1 -1
- package/package.json +5 -5
|
@@ -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
|
-
|
|
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,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,
|
|
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 {
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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 = [];
|