@strapi/admin 4.10.0-beta.0 → 4.10.0-beta.1
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/.eslintignore +4 -0
- package/.eslintrc.js +14 -0
- package/admin/src/components/LanguageProvider/index.js +1 -1
- package/admin/src/components/LocalesProvider/__mocks__/useLocalesProvider.js +7 -0
- package/admin/src/components/LocalesProvider/index.js +2 -3
- package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +3 -6
- package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +2 -0
- package/admin/src/content-manager/components/DynamicTable/index.js +11 -29
- package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +12 -6
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findAllAndReplace.js +10 -3
- package/admin/src/content-manager/components/InputUID/endActionStyle.js +4 -13
- package/admin/src/content-manager/components/InputUID/index.js +95 -72
- package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +4 -8
- package/admin/src/content-manager/pages/App/LeftMenu/index.js +56 -35
- package/admin/src/content-manager/pages/App/actions.js +19 -7
- package/admin/src/content-manager/pages/App/constants.js +3 -3
- package/admin/src/content-manager/pages/App/index.js +5 -4
- package/admin/src/content-manager/pages/App/reducer.js +7 -6
- package/admin/src/content-manager/pages/App/selectors.js +3 -0
- package/admin/src/content-manager/pages/App/{useModels.js → useContentManagerInitData.js} +29 -28
- package/admin/src/content-manager/pages/App/utils/generateModelsLinks.js +2 -2
- package/admin/src/content-manager/pages/App/utils/getContentTypeLinks.js +17 -15
- package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +4 -5
- package/admin/src/content-manager/pages/EditSettingsView/index.js +4 -0
- package/admin/src/content-manager/pages/EditSettingsView/reducer.js +6 -7
- package/admin/src/content-manager/pages/EditSettingsView/utils/layout.js +1 -30
- package/admin/src/content-manager/pages/EditView/DeleteLink/index.js +5 -11
- package/admin/src/content-manager/pages/EditView/index.js +2 -7
- package/admin/src/content-manager/pages/ListSettingsView/index.js +1 -0
- package/admin/src/content-manager/sharedReducers/crudReducer/actions.js +6 -0
- package/admin/src/content-manager/sharedReducers/crudReducer/constants.js +1 -0
- package/admin/src/content-manager/sharedReducers/crudReducer/reducer.js +5 -0
- package/admin/src/hooks/useConfigurations/__mocks__/index.js +7 -0
- package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +7 -8
- package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -0
- package/admin/src/hooks/useRegenerate/index.js +12 -7
- package/admin/src/pages/AuthPage/components/Register/index.js +46 -38
- package/admin/src/pages/HomePage/SocialLinks.js +1 -1
- package/admin/src/pages/MarketplacePage/components/EmptyNpmPackageSearch/index.js +3 -3
- package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +42 -9
- package/admin/src/pages/MarketplacePage/components/NpmPackagesPagination/index.js +26 -0
- package/admin/src/pages/MarketplacePage/components/OfflineLayout/index.js +45 -0
- package/admin/src/pages/MarketplacePage/index.js +80 -175
- package/admin/src/pages/MarketplacePage/utils/useMarketplaceData.js +85 -0
- package/admin/src/pages/SettingsPage/components/Tokens/FormHead/index.js +4 -0
- package/admin/src/pages/SettingsPage/components/Tokens/Regenerate/index.js +5 -3
- package/admin/src/pages/SettingsPage/components/Tokens/TokenTypeSelect/index.js +7 -5
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +12 -4
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +21 -2
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/components/FormTransferTokenContainer/index.js +41 -0
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +53 -9
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +1 -0
- package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +27 -5
- package/admin/src/translations/en.json +51 -49
- package/admin/src/translations/ru.json +51 -19
- package/build/1387.84b454d3.chunk.js +1 -0
- package/build/1657.45231968.chunk.js +168 -0
- package/build/3081.bcf9a12f.chunk.js +108 -0
- package/build/462.8fff7f3b.chunk.js +71 -0
- package/build/4628.20631dd1.chunk.js +1 -0
- package/build/5542.b8240e3f.chunk.js +70 -0
- package/build/5563.905daa13.chunk.js +79 -0
- package/build/6404.68405699.chunk.js +100 -0
- package/build/7259.b7d00cea.chunk.js +1 -0
- package/build/8694.6522968d.chunk.js +247 -0
- package/build/Admin-authenticatedApp.52c88751.chunk.js +79 -0
- package/build/Admin_InternalErrorPage.15c6bf07.chunk.js +1 -0
- package/build/Admin_homePage.f9309c6d.chunk.js +73 -0
- package/build/Admin_marketplace.56bc1008.chunk.js +31 -0
- package/build/Admin_pluginsPage.f6b52ee9.chunk.js +6 -0
- package/build/Admin_profilePage.9112cffc.chunk.js +15 -0
- package/build/Admin_settingsPage.257b3477.chunk.js +79 -0
- package/build/Upload_ConfigureTheView.eaaec495.chunk.js +1 -0
- package/build/admin-app.dfaeea5d.chunk.js +110 -0
- package/build/admin-edit-roles-page.4f1858e9.chunk.js +280 -0
- package/build/admin-edit-users.7e14d85f.chunk.js +10 -0
- package/build/admin-roles-list.329c1f63.chunk.js +31 -0
- package/build/admin-users.d02de059.chunk.js +34 -0
- package/build/api-tokens-create-page.97595e12.chunk.js +1 -0
- package/build/api-tokens-edit-page.cd36e30e.chunk.js +1 -0
- package/build/api-tokens-list-page.6757c7b9.chunk.js +16 -0
- package/build/audit-logs-settings-page.19d90bda.chunk.js +76 -0
- package/build/content-manager.def692c2.chunk.js +1130 -0
- package/build/content-type-builder-list-view.9c2c020c.chunk.js +214 -0
- package/build/content-type-builder-translation-en-json.510e88ca.chunk.js +1 -0
- package/build/content-type-builder.5e1f4afc.chunk.js +126 -0
- package/build/email-settings-page.1095e1ab.chunk.js +10 -0
- package/build/en-json.08303b37.chunk.js +1 -0
- package/build/{highlight.js.26ef649f.chunk.js → highlight.js.28a1547e.chunk.js} +2 -2
- package/build/i18n-settings-page.7d80aae0.chunk.js +60 -0
- package/build/index.html +1 -1
- package/build/main.120be100.js +2280 -0
- package/build/review-workflows-settings.9092ed72.chunk.js +106 -0
- package/build/ru-json.e0662702.chunk.js +1 -0
- package/build/{runtime~main.5a95bee6.js → runtime~main.112b3101.js} +2 -2
- package/build/sso-settings-page.1dd4886e.chunk.js +1 -0
- package/build/transfer-tokens-create-page.ec2ca215.chunk.js +1 -0
- package/build/transfer-tokens-edit-page.22bf28e5.chunk.js +1 -0
- package/build/transfer-tokens-list-page.cf8c77f2.chunk.js +16 -0
- package/build/upload-settings.945fdcfa.chunk.js +13 -0
- package/build/{upload-translation-th-json.3847dae0.chunk.js → upload-translation-th-json.98d35574.chunk.js} +1 -1
- package/build/upload.a86b1054.chunk.js +33 -0
- package/build/users-advanced-settings-page.5b5a9baa.chunk.js +8 -0
- package/build/users-email-settings-page.e5506eb4.chunk.js +23 -0
- package/build/users-providers-settings-page.e32089c2.chunk.js +28 -0
- package/build/users-roles-settings-page.2f85dcec.chunk.js +30 -0
- package/build/webhook-edit-page.213f0075.chunk.js +75 -0
- package/build/webhook-list-page.5beb2a5c.chunk.js +71 -0
- package/{admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/ReviewWorkflowsStage.js → ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/ReviewWorkflowsStageEE.js} +2 -2
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +45 -0
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +3 -0
- package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +61 -18
- package/ee/admin/hooks/useLicenseLimitNotification/index.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js +6 -3
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js +15 -5
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js +52 -45
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +8 -4
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +2 -2
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +2 -2
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +2 -1
- package/ee/server/content-types/workflow/index.js +0 -3
- package/ee/server/content-types/workflow-stage/index.js +0 -5
- package/ee/server/controllers/workflows/stages/index.js +8 -1
- package/ee/server/register.js +3 -1
- package/ee/server/services/audit-logs.js +75 -16
- package/ee/server/services/review-workflows/entity-service-decorator.js +17 -5
- package/ee/server/services/review-workflows/review-workflows.js +27 -91
- package/ee/server/services/review-workflows/stages.js +108 -7
- package/ee/server/utils/persisted-tables.js +114 -22
- package/ee/server/utils/review-workflows.js +9 -0
- package/jest.config.front.js +1 -6
- package/package.json +24 -22
- package/server/controllers/transfer/runner.js +4 -2
- package/server/middlewares/data-transfer.js +4 -1
- package/server/routes/transfer.js +13 -4
- package/server/services/constants.js +4 -0
- package/server/services/transfer/permission.js +1 -1
- package/server/services/transfer/token.js +33 -31
- package/server/validation/transfer/token.js +10 -2
- package/webpack.config.js +6 -2
- package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +0 -1
- package/admin/src/content-manager/pages/App/LeftMenu/utils/index.js +0 -1
- package/admin/src/content-manager/pages/App/LeftMenu/utils/matchByTitle.js +0 -24
- package/build/2263.4c5916f9.chunk.js +0 -98
- package/build/4049.64715f20.chunk.js +0 -1
- package/build/4649.213b8a3b.chunk.js +0 -30
- package/build/6985.66cca29c.chunk.js +0 -1
- package/build/7259.aefb51e8.chunk.js +0 -1
- package/build/8469.853c822b.chunk.js +0 -1
- package/build/9505.dbe702ab.chunk.js +0 -14
- package/build/9816.01ee964f.chunk.js +0 -2
- package/build/Admin-authenticatedApp.f50ad423.chunk.js +0 -79
- package/build/Admin_InternalErrorPage.4ad8b0df.chunk.js +0 -1
- package/build/Admin_homePage.1411fb7c.chunk.js +0 -68
- package/build/Admin_marketplace.02608d56.chunk.js +0 -22
- package/build/Admin_pluginsPage.15e3b0fd.chunk.js +0 -1
- package/build/Admin_profilePage.76afeca0.chunk.js +0 -15
- package/build/Admin_settingsPage.147755cd.chunk.js +0 -9
- package/build/Upload_ConfigureTheView.34dde278.chunk.js +0 -1
- package/build/admin-app.55dd7921.chunk.js +0 -112
- package/build/admin-edit-roles-page.cf543488.chunk.js +0 -216
- package/build/admin-edit-users.31c20712.chunk.js +0 -10
- package/build/admin-roles-list.489c501f.chunk.js +0 -2
- package/build/admin-users.3e111a7d.chunk.js +0 -11
- package/build/api-tokens-create-page.4328b852.chunk.js +0 -1
- package/build/api-tokens-edit-page.bce5050f.chunk.js +0 -1
- package/build/api-tokens-list-page.93f24348.chunk.js +0 -16
- package/build/audit-logs-settings-page.7be97e82.chunk.js +0 -1
- package/build/content-manager.4480ae88.chunk.js +0 -1137
- package/build/content-type-builder-list-view.cf38fe2f.chunk.js +0 -191
- package/build/content-type-builder-translation-en-json.7961593e.chunk.js +0 -1
- package/build/content-type-builder.af9abf1e.chunk.js +0 -126
- package/build/email-settings-page.4bdbef9a.chunk.js +0 -3
- package/build/en-json.697b4bcf.chunk.js +0 -1
- package/build/i18n-settings-page.2bb5be96.chunk.js +0 -1
- package/build/main.af8c0f31.js +0 -3790
- package/build/review-workflows-settings.7a7dc773.chunk.js +0 -57
- package/build/ru-json.6a01cea6.chunk.js +0 -1
- package/build/sso-settings-page.272b87c8.chunk.js +0 -1
- package/build/transfer-tokens-create-page.a1f14bb1.chunk.js +0 -1
- package/build/transfer-tokens-edit-page.00ee1c74.chunk.js +0 -1
- package/build/transfer-tokens-list-page.ce37354b.chunk.js +0 -16
- package/build/upload-settings.0875e973.chunk.js +0 -1
- package/build/upload.c7da1611.chunk.js +0 -13
- package/build/users-advanced-settings-page.1d3c14c7.chunk.js +0 -1
- package/build/users-email-settings-page.e8db68c4.chunk.js +0 -1
- package/build/users-providers-settings-page.14cac425.chunk.js +0 -1
- package/build/users-roles-settings-page.2ea4de84.chunk.js +0 -30
- package/build/webhook-edit-page.329141a5.chunk.js +0 -23
- package/build/webhook-list-page.029957a4.chunk.js +0 -1
- package/ee/server/migrations/review-workflows.js +0 -39
- package/ee/server/utils/test.js +0 -11
- /package/admin/src/{content-manager/components/InputUID/useDebounce.js → hooks/useDebounce/index.js} +0 -0
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import { Helmet } from 'react-helmet';
|
|
4
|
-
import matchSorter from 'match-sorter';
|
|
5
4
|
import {
|
|
6
|
-
AnErrorOccurred,
|
|
7
5
|
CheckPagePermissions,
|
|
8
6
|
useFocusWhenNavigate,
|
|
9
7
|
useTracking,
|
|
10
|
-
LoadingIndicatorPage,
|
|
11
8
|
useNotification,
|
|
12
9
|
useAppInfos,
|
|
13
10
|
useQueryParams,
|
|
@@ -18,8 +15,6 @@ import {
|
|
|
18
15
|
Main,
|
|
19
16
|
Searchbar,
|
|
20
17
|
Box,
|
|
21
|
-
useNotifyAT,
|
|
22
|
-
Typography,
|
|
23
18
|
Flex,
|
|
24
19
|
Tabs,
|
|
25
20
|
Tab,
|
|
@@ -28,39 +23,25 @@ import {
|
|
|
28
23
|
TabPanel,
|
|
29
24
|
} from '@strapi/design-system';
|
|
30
25
|
|
|
31
|
-
import EmptyNpmPackageSearch from './components/EmptyNpmPackageSearch';
|
|
32
26
|
import PageHeader from './components/PageHeader';
|
|
33
|
-
import useFetchMarketplaceProviders from '../../hooks/useFetchMarketplaceProviders';
|
|
34
|
-
import useFetchMarketplacePlugins from '../../hooks/useFetchMarketplacePlugins';
|
|
35
27
|
import adminPermissions from '../../permissions';
|
|
36
|
-
import offlineCloud from '../../assets/images/icon_offline-cloud.svg';
|
|
37
28
|
import useNavigatorOnLine from '../../hooks/useNavigatorOnLine';
|
|
38
29
|
import MissingPluginBanner from './components/MissingPluginBanner';
|
|
39
30
|
import NpmPackagesGrid from './components/NpmPackagesGrid';
|
|
40
31
|
import SortSelect from './components/SortSelect';
|
|
41
32
|
import NpmPackagesFilters from './components/NpmPackagesFilters';
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
{
|
|
47
|
-
threshold: matchSorter.rankings.WORD_STARTS_WITH,
|
|
48
|
-
key: 'attributes.name',
|
|
49
|
-
},
|
|
50
|
-
{ threshold: matchSorter.rankings.WORD_STARTS_WITH, key: 'attributes.description' },
|
|
51
|
-
],
|
|
52
|
-
baseSort: (a, b) => (a.index < b.index ? -1 : 1),
|
|
53
|
-
});
|
|
54
|
-
};
|
|
33
|
+
import NpmPackagesPagination from './components/NpmPackagesPagination';
|
|
34
|
+
import useDebounce from '../../hooks/useDebounce';
|
|
35
|
+
import OfflineLayout from './components/OfflineLayout';
|
|
36
|
+
import useMarketplaceData from './utils/useMarketplaceData';
|
|
55
37
|
|
|
56
38
|
const MarketPlacePage = () => {
|
|
57
39
|
const { formatMessage } = useIntl();
|
|
58
40
|
const { trackUsage } = useTracking();
|
|
59
|
-
const { notifyStatus } = useNotifyAT();
|
|
60
41
|
const trackUsageRef = useRef(trackUsage);
|
|
61
42
|
const toggleNotification = useNotification();
|
|
62
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
63
43
|
const [{ query }, setQuery] = useQueryParams();
|
|
44
|
+
const debouncedSearch = useDebounce(query?.search, 500) || '';
|
|
64
45
|
|
|
65
46
|
const { autoReload: isInDevelopmentMode, dependencies, useYarn, strapiVersion } = useAppInfos();
|
|
66
47
|
const isOnline = useNavigatorOnLine();
|
|
@@ -74,33 +55,6 @@ const MarketPlacePage = () => {
|
|
|
74
55
|
|
|
75
56
|
useFocusWhenNavigate();
|
|
76
57
|
|
|
77
|
-
const marketplaceTitle = formatMessage({
|
|
78
|
-
id: 'global.marketplace',
|
|
79
|
-
defaultMessage: 'Marketplace',
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const notifyMarketplaceLoad = () => {
|
|
83
|
-
notifyStatus(
|
|
84
|
-
formatMessage(
|
|
85
|
-
{
|
|
86
|
-
id: 'app.utils.notify.data-loaded',
|
|
87
|
-
defaultMessage: 'The {target} has loaded',
|
|
88
|
-
},
|
|
89
|
-
{ target: marketplaceTitle }
|
|
90
|
-
)
|
|
91
|
-
);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const { status: marketplaceProvidersStatus, data: marketplaceProvidersResponse } =
|
|
95
|
-
useFetchMarketplaceProviders(notifyMarketplaceLoad, tabQuery.provider);
|
|
96
|
-
|
|
97
|
-
const { status: marketplacePluginsStatus, data: marketplacePluginsResponse } =
|
|
98
|
-
useFetchMarketplacePlugins(notifyMarketplaceLoad, tabQuery.plugin);
|
|
99
|
-
|
|
100
|
-
const isLoading = [marketplacePluginsStatus, marketplaceProvidersStatus].includes('loading');
|
|
101
|
-
|
|
102
|
-
const hasFailed = [marketplacePluginsStatus, marketplaceProvidersStatus].includes('error');
|
|
103
|
-
|
|
104
58
|
useEffect(() => {
|
|
105
59
|
trackUsageRef.current('didGoToMarketplace');
|
|
106
60
|
}, []);
|
|
@@ -118,94 +72,50 @@ const MarketPlacePage = () => {
|
|
|
118
72
|
}
|
|
119
73
|
}, [toggleNotification, isInDevelopmentMode]);
|
|
120
74
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
justifyContent="center"
|
|
131
|
-
style={{ paddingTop: '120px' }}
|
|
132
|
-
>
|
|
133
|
-
<Box paddingBottom={2}>
|
|
134
|
-
<Typography textColor="neutral700" variant="alpha">
|
|
135
|
-
{formatMessage({
|
|
136
|
-
id: 'admin.pages.MarketPlacePage.offline.title',
|
|
137
|
-
defaultMessage: 'You are offline',
|
|
138
|
-
})}
|
|
139
|
-
</Typography>
|
|
140
|
-
</Box>
|
|
141
|
-
<Box paddingBottom={6}>
|
|
142
|
-
<Typography textColor="neutral700" variant="epsilon">
|
|
143
|
-
{formatMessage({
|
|
144
|
-
id: 'admin.pages.MarketPlacePage.offline.subtitle',
|
|
145
|
-
defaultMessage:
|
|
146
|
-
'You need to be connected to the Internet to access Strapi Market.',
|
|
147
|
-
})}
|
|
148
|
-
</Typography>
|
|
149
|
-
</Box>
|
|
150
|
-
<img src={offlineCloud} alt="offline" style={{ width: '88px', height: '88px' }} />
|
|
151
|
-
</Flex>
|
|
152
|
-
</Main>
|
|
153
|
-
</Layout>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (hasFailed) {
|
|
158
|
-
return (
|
|
159
|
-
<Layout>
|
|
160
|
-
<ContentLayout>
|
|
161
|
-
<Box paddingTop={8}>
|
|
162
|
-
<AnErrorOccurred />
|
|
163
|
-
</Box>
|
|
164
|
-
</ContentLayout>
|
|
165
|
-
</Layout>
|
|
166
|
-
);
|
|
167
|
-
}
|
|
75
|
+
const {
|
|
76
|
+
pluginsResponse,
|
|
77
|
+
providersResponse,
|
|
78
|
+
pluginsStatus,
|
|
79
|
+
providersStatus,
|
|
80
|
+
possibleCollections,
|
|
81
|
+
possibleCategories,
|
|
82
|
+
pagination,
|
|
83
|
+
} = useMarketplaceData({ npmPackageType, debouncedSearch, query, tabQuery });
|
|
168
84
|
|
|
169
|
-
if (
|
|
170
|
-
return
|
|
171
|
-
<Layout>
|
|
172
|
-
<Main aria-busy>
|
|
173
|
-
<LoadingIndicatorPage />
|
|
174
|
-
</Main>
|
|
175
|
-
</Layout>
|
|
176
|
-
);
|
|
85
|
+
if (!isOnline) {
|
|
86
|
+
return <OfflineLayout />;
|
|
177
87
|
}
|
|
178
88
|
|
|
179
|
-
// Search for plugins and providers that match the search query
|
|
180
|
-
const pluginSearchResults = matchSearch(marketplacePluginsResponse.data, searchQuery);
|
|
181
|
-
const providerSearchResults = matchSearch(marketplaceProvidersResponse.data, searchQuery);
|
|
182
|
-
const emptySearchMessage = formatMessage(
|
|
183
|
-
{
|
|
184
|
-
id: 'admin.pages.MarketPlacePage.search.empty',
|
|
185
|
-
defaultMessage: 'No result for "{target}"',
|
|
186
|
-
},
|
|
187
|
-
{ target: searchQuery }
|
|
188
|
-
);
|
|
189
|
-
|
|
190
89
|
const handleTabChange = (selected) => {
|
|
191
90
|
const selectedTab = selected === 0 ? 'plugin' : 'provider';
|
|
192
91
|
const hasTabQuery = tabQuery[selectedTab] && Object.keys(tabQuery[selectedTab]).length;
|
|
193
92
|
|
|
194
93
|
if (hasTabQuery) {
|
|
195
|
-
setQuery({
|
|
94
|
+
setQuery({
|
|
95
|
+
// Keep filters and search
|
|
96
|
+
...tabQuery[selectedTab],
|
|
97
|
+
search: query?.search || '',
|
|
98
|
+
// Set tab and reset page
|
|
99
|
+
npmPackageType: selectedTab,
|
|
100
|
+
page: 1,
|
|
101
|
+
});
|
|
196
102
|
} else {
|
|
197
103
|
setQuery({
|
|
104
|
+
// Set tab
|
|
198
105
|
npmPackageType: selectedTab,
|
|
199
106
|
// Clear filters
|
|
200
107
|
collections: [],
|
|
201
108
|
categories: [],
|
|
202
109
|
sort: 'name:asc',
|
|
110
|
+
page: 1,
|
|
111
|
+
// Keep search
|
|
112
|
+
search: query?.search || '',
|
|
203
113
|
});
|
|
204
114
|
}
|
|
205
115
|
};
|
|
206
116
|
|
|
207
117
|
const handleSelectChange = (update) => {
|
|
208
|
-
setQuery(update);
|
|
118
|
+
setQuery({ ...update, page: 1 });
|
|
209
119
|
setTabQuery((prev) => ({
|
|
210
120
|
...prev,
|
|
211
121
|
[npmPackageType]: { ...prev[npmPackageType], ...update },
|
|
@@ -213,19 +123,13 @@ const MarketPlacePage = () => {
|
|
|
213
123
|
};
|
|
214
124
|
|
|
215
125
|
const handleSelectClear = (filterType) => {
|
|
216
|
-
setQuery({ [filterType]: [] }, 'remove');
|
|
126
|
+
setQuery({ [filterType]: [], page: null }, 'remove');
|
|
217
127
|
setTabQuery((prev) => ({ ...prev, [npmPackageType]: {} }));
|
|
218
128
|
};
|
|
219
129
|
|
|
220
130
|
// Check if plugins and providers are installed already
|
|
221
131
|
const installedPackageNames = Object.keys(dependencies);
|
|
222
132
|
|
|
223
|
-
const possibleCollections =
|
|
224
|
-
npmPackageType === 'plugin'
|
|
225
|
-
? marketplacePluginsResponse.meta.collections
|
|
226
|
-
: marketplaceProvidersResponse.meta.collections;
|
|
227
|
-
const possibleCategories = marketplacePluginsResponse.meta.categories;
|
|
228
|
-
|
|
229
133
|
return (
|
|
230
134
|
<Layout>
|
|
231
135
|
<Main>
|
|
@@ -237,27 +141,6 @@ const MarketPlacePage = () => {
|
|
|
237
141
|
/>
|
|
238
142
|
<PageHeader isOnline={isOnline} npmPackageType={npmPackageType} />
|
|
239
143
|
<ContentLayout>
|
|
240
|
-
<Box width="25%" paddingBottom={4}>
|
|
241
|
-
<Searchbar
|
|
242
|
-
name="searchbar"
|
|
243
|
-
onClear={() => setSearchQuery('')}
|
|
244
|
-
value={searchQuery}
|
|
245
|
-
onChange={(e) => setSearchQuery(e.target.value)}
|
|
246
|
-
clearLabel={formatMessage({
|
|
247
|
-
id: 'admin.pages.MarketPlacePage.search.clear',
|
|
248
|
-
defaultMessage: 'Clear the search',
|
|
249
|
-
})}
|
|
250
|
-
placeholder={formatMessage({
|
|
251
|
-
id: 'admin.pages.MarketPlacePage.search.placeholder',
|
|
252
|
-
defaultMessage: 'Search',
|
|
253
|
-
})}
|
|
254
|
-
>
|
|
255
|
-
{formatMessage({
|
|
256
|
-
id: 'admin.pages.MarketPlacePage.search.placeholder',
|
|
257
|
-
defaultMessage: 'Search',
|
|
258
|
-
})}
|
|
259
|
-
</Searchbar>
|
|
260
|
-
</Box>
|
|
261
144
|
<TabGroup
|
|
262
145
|
label={formatMessage({
|
|
263
146
|
id: 'admin.pages.MarketPlacePage.tab-group.label',
|
|
@@ -268,24 +151,49 @@ const MarketPlacePage = () => {
|
|
|
268
151
|
initialSelectedTabIndex={['plugin', 'provider'].indexOf(npmPackageType)}
|
|
269
152
|
onTabChange={handleTabChange}
|
|
270
153
|
>
|
|
271
|
-
<
|
|
154
|
+
<Flex justifyContent="space-between" paddingBottom={4}>
|
|
272
155
|
<Tabs>
|
|
273
156
|
<Tab>
|
|
274
157
|
{formatMessage({
|
|
275
158
|
id: 'admin.pages.MarketPlacePage.plugins',
|
|
276
159
|
defaultMessage: 'Plugins',
|
|
277
160
|
})}{' '}
|
|
278
|
-
|
|
161
|
+
{pluginsStatus === 'success'
|
|
162
|
+
? `(${pluginsResponse.meta.pagination.total})`
|
|
163
|
+
: '...'}
|
|
279
164
|
</Tab>
|
|
280
165
|
<Tab>
|
|
281
166
|
{formatMessage({
|
|
282
167
|
id: 'admin.pages.MarketPlacePage.providers',
|
|
283
168
|
defaultMessage: 'Providers',
|
|
284
169
|
})}{' '}
|
|
285
|
-
|
|
170
|
+
{providersStatus === 'success'
|
|
171
|
+
? `(${providersResponse.meta.pagination.total})`
|
|
172
|
+
: '...'}
|
|
286
173
|
</Tab>
|
|
287
174
|
</Tabs>
|
|
288
|
-
|
|
175
|
+
<Box width="25%">
|
|
176
|
+
<Searchbar
|
|
177
|
+
name="searchbar"
|
|
178
|
+
onClear={() => setQuery({ search: '', page: 1 })}
|
|
179
|
+
value={query?.search}
|
|
180
|
+
onChange={(e) => setQuery({ search: e.target.value, page: 1 })}
|
|
181
|
+
clearLabel={formatMessage({
|
|
182
|
+
id: 'admin.pages.MarketPlacePage.search.clear',
|
|
183
|
+
defaultMessage: 'Clear the search',
|
|
184
|
+
})}
|
|
185
|
+
placeholder={formatMessage({
|
|
186
|
+
id: 'admin.pages.MarketPlacePage.search.placeholder',
|
|
187
|
+
defaultMessage: 'Search',
|
|
188
|
+
})}
|
|
189
|
+
>
|
|
190
|
+
{formatMessage({
|
|
191
|
+
id: 'admin.pages.MarketPlacePage.search.placeholder',
|
|
192
|
+
defaultMessage: 'Search',
|
|
193
|
+
})}
|
|
194
|
+
</Searchbar>
|
|
195
|
+
</Box>
|
|
196
|
+
</Flex>
|
|
289
197
|
<Flex paddingBottom={4} gap={2}>
|
|
290
198
|
<SortSelect
|
|
291
199
|
sortQuery={query?.sort || 'name:asc'}
|
|
@@ -304,36 +212,33 @@ const MarketPlacePage = () => {
|
|
|
304
212
|
<TabPanels>
|
|
305
213
|
{/* Plugins panel */}
|
|
306
214
|
<TabPanel>
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
/>
|
|
318
|
-
)}
|
|
215
|
+
<NpmPackagesGrid
|
|
216
|
+
npmPackages={pluginsResponse?.data}
|
|
217
|
+
status={pluginsStatus}
|
|
218
|
+
installedPackageNames={installedPackageNames}
|
|
219
|
+
useYarn={useYarn}
|
|
220
|
+
isInDevelopmentMode={isInDevelopmentMode}
|
|
221
|
+
npmPackageType="plugin"
|
|
222
|
+
strapiAppVersion={strapiVersion}
|
|
223
|
+
debouncedSearch={debouncedSearch}
|
|
224
|
+
/>
|
|
319
225
|
</TabPanel>
|
|
320
226
|
{/* Providers panel */}
|
|
321
227
|
<TabPanel>
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
/>
|
|
332
|
-
)}
|
|
228
|
+
<NpmPackagesGrid
|
|
229
|
+
npmPackages={providersResponse?.data}
|
|
230
|
+
status={providersStatus}
|
|
231
|
+
installedPackageNames={installedPackageNames}
|
|
232
|
+
useYarn={useYarn}
|
|
233
|
+
isInDevelopmentMode={isInDevelopmentMode}
|
|
234
|
+
npmPackageType="provider"
|
|
235
|
+
debouncedSearch={debouncedSearch}
|
|
236
|
+
/>
|
|
333
237
|
</TabPanel>
|
|
334
238
|
</TabPanels>
|
|
335
239
|
</TabGroup>
|
|
336
|
-
<
|
|
240
|
+
{pagination && <NpmPackagesPagination pagination={pagination} />}
|
|
241
|
+
<Box paddingTop={8}>
|
|
337
242
|
<MissingPluginBanner />
|
|
338
243
|
</Box>
|
|
339
244
|
</ContentLayout>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import { useNotifyAT } from '@strapi/design-system';
|
|
4
|
+
import useFetchMarketplacePlugins from '../../../hooks/useFetchMarketplacePlugins';
|
|
5
|
+
import useFetchMarketplaceProviders from '../../../hooks/useFetchMarketplaceProviders';
|
|
6
|
+
|
|
7
|
+
function useMarketplaceData({ npmPackageType, debouncedSearch, query, tabQuery }) {
|
|
8
|
+
const { notifyStatus } = useNotifyAT();
|
|
9
|
+
const { formatMessage } = useIntl();
|
|
10
|
+
const marketplaceTitle = formatMessage({
|
|
11
|
+
id: 'global.marketplace',
|
|
12
|
+
defaultMessage: 'Marketplace',
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const notifyMarketplaceLoad = () => {
|
|
16
|
+
notifyStatus(
|
|
17
|
+
formatMessage(
|
|
18
|
+
{
|
|
19
|
+
id: 'app.utils.notify.data-loaded',
|
|
20
|
+
defaultMessage: 'The {target} has loaded',
|
|
21
|
+
},
|
|
22
|
+
{ target: marketplaceTitle }
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const paginationParams = {
|
|
28
|
+
page: query?.page || 1,
|
|
29
|
+
pageSize: query?.pageSize || 24,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const { data: pluginsResponse, status: pluginsStatus } = useFetchMarketplacePlugins(
|
|
33
|
+
notifyMarketplaceLoad,
|
|
34
|
+
{
|
|
35
|
+
...tabQuery.plugin,
|
|
36
|
+
pagination: paginationParams,
|
|
37
|
+
search: debouncedSearch,
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const { data: providersResponse, status: providersStatus } = useFetchMarketplaceProviders(
|
|
42
|
+
notifyMarketplaceLoad,
|
|
43
|
+
{
|
|
44
|
+
...tabQuery.provider,
|
|
45
|
+
pagination: paginationParams,
|
|
46
|
+
search: debouncedSearch,
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const npmPackageTypeResponse = npmPackageType === 'plugin' ? pluginsResponse : providersResponse;
|
|
51
|
+
const npmPackageTypeStatus = npmPackageType === 'plugin' ? pluginsStatus : providersStatus;
|
|
52
|
+
|
|
53
|
+
const [possibleCollections, setPossibleCollections] = useState({});
|
|
54
|
+
const [possibleCategories, setPossibleCategories] = useState({});
|
|
55
|
+
|
|
56
|
+
// Keep possible filters up to date, but don't lose them while loading
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (npmPackageTypeStatus === 'success') {
|
|
59
|
+
setPossibleCollections(npmPackageTypeResponse.meta.collections);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (pluginsStatus === 'success') {
|
|
63
|
+
setPossibleCategories(pluginsResponse.meta.categories);
|
|
64
|
+
}
|
|
65
|
+
}, [
|
|
66
|
+
pluginsResponse?.meta.categories,
|
|
67
|
+
pluginsStatus,
|
|
68
|
+
npmPackageTypeResponse?.meta.collections,
|
|
69
|
+
npmPackageTypeStatus,
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
const { pagination } = npmPackageTypeStatus === 'success' ? npmPackageTypeResponse.meta : {};
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
pluginsResponse,
|
|
76
|
+
providersResponse,
|
|
77
|
+
pluginsStatus,
|
|
78
|
+
providersStatus,
|
|
79
|
+
possibleCollections,
|
|
80
|
+
possibleCategories,
|
|
81
|
+
pagination,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default useMarketplaceData;
|
|
@@ -15,6 +15,7 @@ const FormHead = ({
|
|
|
15
15
|
isSubmitting,
|
|
16
16
|
backUrl,
|
|
17
17
|
regenerateUrl,
|
|
18
|
+
onErrorRegenerate,
|
|
18
19
|
}) => {
|
|
19
20
|
const { formatMessage } = useIntl();
|
|
20
21
|
const handleRegenerate = (newKey) => {
|
|
@@ -35,6 +36,7 @@ const FormHead = ({
|
|
|
35
36
|
backUrl={regenerateUrl}
|
|
36
37
|
onRegenerate={handleRegenerate}
|
|
37
38
|
idToRegenerate={token?.id}
|
|
39
|
+
onError={onErrorRegenerate}
|
|
38
40
|
/>
|
|
39
41
|
)}
|
|
40
42
|
<Button
|
|
@@ -95,10 +97,12 @@ FormHead.propTypes = {
|
|
|
95
97
|
label: PropTypes.string,
|
|
96
98
|
}).isRequired,
|
|
97
99
|
regenerateUrl: PropTypes.string.isRequired,
|
|
100
|
+
onErrorRegenerate: PropTypes.func,
|
|
98
101
|
};
|
|
99
102
|
|
|
100
103
|
FormHead.defaultProps = {
|
|
101
104
|
token: undefined,
|
|
105
|
+
onErrorRegenerate: undefined,
|
|
102
106
|
};
|
|
103
107
|
|
|
104
108
|
export default FormHead;
|
|
@@ -6,13 +6,14 @@ import { Refresh } from '@strapi/icons';
|
|
|
6
6
|
import { ConfirmDialog } from '@strapi/helper-plugin';
|
|
7
7
|
import { useRegenerate } from '../../../../../hooks';
|
|
8
8
|
|
|
9
|
-
export const Regenerate = ({ onRegenerate, idToRegenerate, backUrl }) => {
|
|
9
|
+
export const Regenerate = ({ onRegenerate, idToRegenerate, backUrl, onError }) => {
|
|
10
10
|
const { formatMessage } = useIntl();
|
|
11
11
|
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
|
12
12
|
const { regenerateData, isLoadingConfirmation } = useRegenerate(
|
|
13
13
|
backUrl,
|
|
14
14
|
idToRegenerate,
|
|
15
|
-
onRegenerate
|
|
15
|
+
onRegenerate,
|
|
16
|
+
onError
|
|
16
17
|
);
|
|
17
18
|
const handleConfirmRegeneration = async () => {
|
|
18
19
|
regenerateData();
|
|
@@ -62,12 +63,13 @@ export const Regenerate = ({ onRegenerate, idToRegenerate, backUrl }) => {
|
|
|
62
63
|
);
|
|
63
64
|
};
|
|
64
65
|
|
|
65
|
-
Regenerate.defaultProps = { onRegenerate() {} };
|
|
66
|
+
Regenerate.defaultProps = { onRegenerate() {}, onError: undefined };
|
|
66
67
|
|
|
67
68
|
Regenerate.propTypes = {
|
|
68
69
|
onRegenerate: PropTypes.func,
|
|
69
70
|
idToRegenerate: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
|
70
71
|
backUrl: PropTypes.string.isRequired,
|
|
72
|
+
onError: PropTypes.func,
|
|
71
73
|
};
|
|
72
74
|
|
|
73
75
|
export default Regenerate;
|
|
@@ -4,21 +4,21 @@ import { useIntl } from 'react-intl';
|
|
|
4
4
|
|
|
5
5
|
import { Select, Option } from '@strapi/design-system';
|
|
6
6
|
|
|
7
|
-
const TokenTypeSelect = ({ errors, values, onChange, canEditInputs, options, label }) => {
|
|
7
|
+
const TokenTypeSelect = ({ name, errors, values, onChange, canEditInputs, options, label }) => {
|
|
8
8
|
const { formatMessage } = useIntl();
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
11
|
<Select
|
|
12
|
-
name=
|
|
12
|
+
name={name}
|
|
13
13
|
label={formatMessage({
|
|
14
14
|
id: label.id,
|
|
15
15
|
defaultMessage: label.defaultMessage,
|
|
16
16
|
})}
|
|
17
|
-
value={values
|
|
17
|
+
value={values && values[name]}
|
|
18
18
|
error={
|
|
19
|
-
errors
|
|
19
|
+
errors[name]
|
|
20
20
|
? formatMessage(
|
|
21
|
-
errors
|
|
21
|
+
errors[name]?.id ? errors[name] : { id: errors[name], defaultMessage: errors[name] }
|
|
22
22
|
)
|
|
23
23
|
: null
|
|
24
24
|
}
|
|
@@ -38,6 +38,7 @@ const TokenTypeSelect = ({ errors, values, onChange, canEditInputs, options, lab
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
TokenTypeSelect.propTypes = {
|
|
41
|
+
name: PropTypes.string,
|
|
41
42
|
options: PropTypes.arrayOf(
|
|
42
43
|
PropTypes.shape({
|
|
43
44
|
label: PropTypes.shape({
|
|
@@ -62,6 +63,7 @@ TokenTypeSelect.propTypes = {
|
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
TokenTypeSelect.defaultProps = {
|
|
66
|
+
name: 'type',
|
|
65
67
|
errors: {},
|
|
66
68
|
options: [],
|
|
67
69
|
};
|
|
@@ -4,8 +4,9 @@ import { Box, Flex, Td, Tr, Typography, IconButton } from '@strapi/design-system
|
|
|
4
4
|
import { stopPropagation, onRowClick, pxToRem } from '@strapi/helper-plugin';
|
|
5
5
|
import { useIntl } from 'react-intl';
|
|
6
6
|
|
|
7
|
-
const RoleRow = ({ id, name, description, usersCount, icons, rowIndex }) => {
|
|
7
|
+
const RoleRow = ({ id, name, description, usersCount, icons, rowIndex, canUpdate }) => {
|
|
8
8
|
const { formatMessage } = useIntl();
|
|
9
|
+
const [, editObject] = icons;
|
|
9
10
|
|
|
10
11
|
const usersCountText = formatMessage(
|
|
11
12
|
{
|
|
@@ -19,9 +20,11 @@ const RoleRow = ({ id, name, description, usersCount, icons, rowIndex }) => {
|
|
|
19
20
|
<Tr
|
|
20
21
|
aria-rowindex={rowIndex}
|
|
21
22
|
key={id}
|
|
22
|
-
{...
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
{...(canUpdate
|
|
24
|
+
? onRowClick({
|
|
25
|
+
fn: editObject.onClick,
|
|
26
|
+
})
|
|
27
|
+
: {})}
|
|
25
28
|
>
|
|
26
29
|
<Td maxWidth={pxToRem(130)}>
|
|
27
30
|
<Typography ellipsis textColor="neutral800">
|
|
@@ -58,6 +61,11 @@ RoleRow.propTypes = {
|
|
|
58
61
|
usersCount: PropTypes.number.isRequired,
|
|
59
62
|
icons: PropTypes.array.isRequired,
|
|
60
63
|
rowIndex: PropTypes.number.isRequired,
|
|
64
|
+
canUpdate: PropTypes.bool,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
RoleRow.defaultProps = {
|
|
68
|
+
canUpdate: false,
|
|
61
69
|
};
|
|
62
70
|
|
|
63
71
|
export default RoleRow;
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
useQueryParams,
|
|
10
10
|
useRBAC,
|
|
11
11
|
useFocusWhenNavigate,
|
|
12
|
+
useFilter,
|
|
13
|
+
useCollator,
|
|
12
14
|
} from '@strapi/helper-plugin';
|
|
13
15
|
import { Plus, Trash, Duplicate, Pencil } from '@strapi/icons';
|
|
14
16
|
import {
|
|
@@ -27,7 +29,6 @@ import {
|
|
|
27
29
|
VisuallyHidden,
|
|
28
30
|
} from '@strapi/design-system';
|
|
29
31
|
import get from 'lodash/get';
|
|
30
|
-
import matchSorter from 'match-sorter';
|
|
31
32
|
import { useIntl } from 'react-intl';
|
|
32
33
|
import { useHistory } from 'react-router-dom';
|
|
33
34
|
import { useRolesList } from '../../../../../hooks';
|
|
@@ -38,6 +39,7 @@ import reducer, { initialState } from './reducer';
|
|
|
38
39
|
|
|
39
40
|
const useSortedRoles = () => {
|
|
40
41
|
useFocusWhenNavigate();
|
|
42
|
+
const { locale } = useIntl();
|
|
41
43
|
const {
|
|
42
44
|
isLoading: isLoadingForPermissions,
|
|
43
45
|
allowedActions: { canCreate, canDelete, canRead, canUpdate },
|
|
@@ -46,7 +48,23 @@ const useSortedRoles = () => {
|
|
|
46
48
|
const { getData, roles, isLoading } = useRolesList(false);
|
|
47
49
|
const [{ query }] = useQueryParams();
|
|
48
50
|
const _q = query?._q || '';
|
|
49
|
-
|
|
51
|
+
|
|
52
|
+
const { includes } = useFilter(locale, {
|
|
53
|
+
sensitivity: 'base',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @type {Intl.Collator}
|
|
58
|
+
*/
|
|
59
|
+
const formatter = useCollator(locale, {
|
|
60
|
+
sensitivity: 'base',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const sortedRoles = (roles || [])
|
|
64
|
+
.filter((role) => includes(role.name, _q) || includes(role.description, _q))
|
|
65
|
+
.sort(
|
|
66
|
+
(a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
|
|
67
|
+
);
|
|
50
68
|
|
|
51
69
|
useEffect(() => {
|
|
52
70
|
if (!isLoadingForPermissions && canRead) {
|
|
@@ -356,6 +374,7 @@ const RoleListPage = () => {
|
|
|
356
374
|
usersCount={role.usersCount}
|
|
357
375
|
icons={getIcons(role)}
|
|
358
376
|
rowIndex={index + 2}
|
|
377
|
+
canUpdate={canUpdate}
|
|
359
378
|
/>
|
|
360
379
|
))}
|
|
361
380
|
</Tbody>
|