@strapi/admin 4.9.0 → 4.9.2
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/admin/src/components/LanguageProvider/index.js +1 -1
- 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/EditViewDataManagerProvider/reducer.js +9 -5
- package/admin/src/content-manager/components/InputUID/index.js +1 -1
- 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/hooks/useFetchMarketplacePlugins/utils/api.js +7 -8
- package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -0
- 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/pages/Roles/ListPage/components/RoleRow/index.js +12 -4
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +21 -2
- package/admin/src/translations/en.json +51 -50
- package/admin/src/translations/ru.json +51 -19
- package/build/{Admin-authenticatedApp.31bf88ef.chunk.js → Admin-authenticatedApp.217db666.chunk.js} +5 -5
- package/build/{Admin_homePage.da2181fe.chunk.js → Admin_homePage.f9309c6d.chunk.js} +1 -1
- package/build/Admin_marketplace.56bc1008.chunk.js +31 -0
- package/build/{Admin_settingsPage.cb63220f.chunk.js → Admin_settingsPage.1dbfc9ce.chunk.js} +1 -1
- package/build/{admin-app.8cde5b22.chunk.js → admin-app.558af642.chunk.js} +6 -6
- package/build/admin-roles-list.329c1f63.chunk.js +31 -0
- package/build/audit-logs-settings-page.19d90bda.chunk.js +76 -0
- package/build/content-manager.d1565bfc.chunk.js +1132 -0
- package/build/content-type-builder-translation-en-json.6c8e69ab.chunk.js +1 -0
- package/build/content-type-builder.9d780e7f.chunk.js +126 -0
- package/build/en-json.cf600231.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.ef8db4a2.js +2280 -0
- package/build/ru-json.e0662702.chunk.js +1 -0
- package/build/{runtime~main.7cdc9956.js → runtime~main.3a92d953.js} +1 -1
- package/build/users-roles-settings-page.2f85dcec.chunk.js +30 -0
- 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/package.json +20 -20
- package/webpack.config.js +5 -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/9347.058ddb22.chunk.js +0 -1
- package/build/Admin_marketplace.d99044eb.chunk.js +0 -31
- package/build/admin-roles-list.97e198f9.chunk.js +0 -31
- package/build/audit-logs-settings-page.ca9a3c46.chunk.js +0 -76
- package/build/content-manager.de0ee3e5.chunk.js +0 -1132
- package/build/content-type-builder-translation-en-json.e577d595.chunk.js +0 -1
- package/build/content-type-builder.ec5ac7ab.chunk.js +0 -126
- package/build/en-json.b052667a.chunk.js +0 -1
- package/build/main.d40f9ca1.js +0 -2280
- package/build/ru-json.6a01cea6.chunk.js +0 -1
- package/build/users-roles-settings-page.a5c5b0df.chunk.js +0 -30
- /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;
|
|
@@ -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>
|