@strapi/admin 4.12.4 → 4.12.6
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/StrapiApp.js +1 -1
- package/admin/src/components/AuthenticatedApp.js +229 -0
- package/admin/src/components/GuidedTour/Modal/index.js +1 -3
- package/admin/src/content-manager/components/Wysiwyg/WysiwygNav.js +7 -30
- package/admin/src/content-manager/hooks/useSyncRbac/index.js +10 -2
- package/admin/src/content-manager/pages/App/index.js +5 -16
- package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +1 -1
- package/admin/src/content-manager/pages/EditView/Information/index.js +1 -1
- package/admin/src/content-manager/pages/EditViewLayoutManager/index.js +2 -2
- package/admin/src/content-manager/pages/ListSettingsView/index.js +16 -41
- package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +2 -2
- package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +1 -1
- package/admin/src/content-manager/pages/ListView/index.js +27 -1
- package/admin/src/content-manager/pages/ListViewLayoutManager/index.js +2 -2
- package/admin/src/hooks/useSettingsForm/index.js +14 -3
- package/admin/src/hooks/useSettingsMenu/index.js +2 -2
- package/admin/src/hooks/useSettingsMenu/utils/formatLinks.js +1 -3
- package/admin/src/hooks/useSettingsMenu/utils/sortLinks.js +1 -3
- package/admin/src/index.js +1 -1
- package/admin/src/pages/Admin/Onboarding/index.js +1 -3
- package/admin/src/pages/Admin/index.js +80 -74
- package/admin/src/pages/App/constants.js +1 -1
- package/admin/src/pages/App/index.js +160 -122
- package/admin/src/pages/AuthPage/index.js +2 -4
- package/admin/src/pages/HomePage/index.js +1 -3
- package/admin/src/pages/InstalledPluginsPage/index.js +1 -3
- package/admin/src/pages/{InternalErrorPage/index.js → InternalErrorPage.js} +3 -4
- package/admin/src/pages/MarketplacePage/index.js +0 -1
- package/admin/src/pages/{NotFoundPage/index.js → NotFoundPage.js} +1 -3
- package/admin/src/pages/ProfilePage/index.js +2 -4
- package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
- package/admin/src/pages/SettingsPage/constants.js +67 -132
- package/admin/src/pages/SettingsPage/index.js +31 -36
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +24 -31
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +69 -35
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +11 -6
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +4 -1
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/DynamicTable/TableRows/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +1 -0
- package/admin/src/pages/UseCasePage.js +174 -0
- package/admin/src/translations/zh-Hans.json +918 -902
- package/admin/src/utils/createRoute.js +5 -7
- package/admin/src/utils/formatAPIErrors.js +1 -3
- package/admin/src/utils/getFullName.js +1 -1
- package/admin/src/utils/sortLinks.js +1 -3
- package/admin/src/utils/uniqueAdminHash.js +2 -9
- package/build/{1049.f76cb14b.chunk.js → 1049.9d69d231.chunk.js} +1 -1
- package/build/1504.eff012f7.chunk.js +95 -0
- package/build/2166.c837469a.chunk.js +1 -0
- package/build/2225.33287e1b.chunk.js +79 -0
- package/build/2237.03792b63.chunk.js +114 -0
- package/build/2379.401f56f3.chunk.js +1 -0
- package/build/2395.e6a79fbb.chunk.js +26 -0
- package/build/{9806.3392505e.chunk.js → 2747.d1442a90.chunk.js} +78 -70
- package/build/2801.31393ffe.chunk.js +1 -0
- package/build/3483.8517171f.chunk.js +1 -0
- package/build/4546.7a3c0d03.chunk.js +1 -0
- package/build/502.8dd074ff.chunk.js +1 -0
- package/build/5483.5bfbb00d.chunk.js +6 -0
- package/build/7464.592a9295.chunk.js +1 -0
- package/build/748.fd2e5afd.chunk.js +105 -0
- package/build/773.6381d62d.chunk.js +18 -0
- package/build/7826.399afe81.chunk.js +103 -0
- package/build/8261.2525d35c.chunk.js +7 -0
- package/build/8276.e519a707.chunk.js +26 -0
- package/build/8299.62b67c72.chunk.js +1 -0
- package/build/Admin-AuthPage.90d64342.chunk.js +35 -0
- package/build/Admin-AuthenticatedApp.379ac945.chunk.js +24 -0
- package/build/Admin-UseCasePage.1f757db5.chunk.js +13 -0
- package/build/Admin_GuidedTourModal.8ccf1fbc.chunk.js +12 -0
- package/build/Admin_InternalErrorPage.9de92c6d.chunk.js +9 -0
- package/build/Admin_NotFoundPage.21620424.chunk.js +9 -0
- package/build/Admin_Onboarding.dbfa32f6.chunk.js +43 -0
- package/build/Admin_homePage.2000cbe9.chunk.js +86 -0
- package/build/Admin_marketplace.ec80e29b.chunk.js +63 -0
- package/build/Admin_pluginsPage.0c6851f8.chunk.js +14 -0
- package/build/Admin_profilePage.78cd8495.chunk.js +21 -0
- package/build/Admin_settingsPage.1760c3ce.chunk.js +119 -0
- package/build/StrapiApp.221fac30.chunk.js +5 -0
- package/build/{admin-edit-roles-page.6d567273.chunk.js → admin-edit-roles-page.24bdf746.chunk.js} +1 -1
- package/build/admin-edit-users.5d10d444.chunk.js +10 -0
- package/build/admin-users.2b3e4305.chunk.js +11 -0
- package/build/api-tokens-list-page.0af7d431.chunk.js +16 -0
- package/build/audit-logs-settings-page.0f73ccf8.chunk.js +1 -0
- package/build/content-manager.fb0833bd.chunk.js +1099 -0
- package/build/{content-type-builder.40534de5.chunk.js → content-type-builder.66066281.chunk.js} +18 -18
- package/build/email-settings-page.2f7e35c0.chunk.js +11 -0
- package/build/i18n-translation-ru-json.a3dbc125.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.ee3c1938.js +2859 -0
- package/build/review-workflows-settings-create-view.d24a32b9.chunk.js +1 -0
- package/build/review-workflows-settings-edit-view.6044b022.chunk.js +1 -0
- package/build/review-workflows-settings-list-view.3f0ef4bc.chunk.js +56 -0
- package/build/runtime~main.397ee447.js +2 -0
- package/build/{sso-settings-page.12b6d8ae.chunk.js → sso-settings-page.4dba0670.chunk.js} +1 -1
- package/build/transfer-tokens-list-page.d6986b03.chunk.js +16 -0
- package/build/users-advanced-settings-page.17052d72.chunk.js +9 -0
- package/build/users-email-settings-page.3de8ea50.chunk.js +9 -0
- package/build/users-permissions-translation-zh-Hans-json.8d82c809.chunk.js +1 -0
- package/build/users-providers-settings-page.0eaa916d.chunk.js +14 -0
- package/build/users-roles-settings-page.957ad48b.chunk.js +55 -0
- package/build/webhook-edit-page.665210af.chunk.js +33 -0
- package/build/zh-Hans-json.97efd015.chunk.js +1 -0
- package/ee/admin/hooks/useAuthProviders.js +25 -0
- package/ee/admin/hooks/{useLicenseLimitNotification/index.js → useLicenseLimitNotification.js} +2 -4
- package/ee/admin/hooks/{useLicenseLimits/useLicenseLimits.js → useLicenseLimits.js} +4 -1
- package/ee/admin/pages/App/constants.js +6 -5
- package/ee/admin/pages/AuthPage/components/Login/index.js +8 -4
- package/ee/admin/pages/AuthPage/components/Providers/index.js +8 -5
- package/ee/admin/pages/HomePage/index.js +1 -1
- package/ee/admin/pages/SettingsPage/constants.js +27 -42
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
- package/package.json +10 -10
- package/admin/src/components/AuthenticatedApp/index.js +0 -118
- package/admin/src/components/AuthenticatedApp/utils/api.js +0 -85
- package/admin/src/components/AuthenticatedApp/utils/checkLatestStrapiVersion.js +0 -11
- package/admin/src/components/PluginsInitializer/index.js +0 -68
- package/admin/src/components/PluginsInitializer/init.js +0 -11
- package/admin/src/components/PluginsInitializer/reducer.js +0 -22
- package/admin/src/layouts/AppLayout/index.js +0 -33
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +0 -23
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +0 -17
- package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +0 -11
- package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +0 -5
- package/admin/src/pages/SettingsPage/utils/index.js +0 -2
- package/admin/src/pages/UseCasePage/index.js +0 -175
- package/admin/src/utils/checkFormValidity.js +0 -15
- package/admin/src/utils/getAttributesToDisplay.js +0 -19
- package/admin/src/utils/getExistingActions.js +0 -32
- package/admin/src/utils/index.js +0 -9
- package/admin/src/utils/makeUniqueRoutes.js +0 -6
- package/build/1386.879bcd90.chunk.js +0 -7
- package/build/2225.c6244756.chunk.js +0 -79
- package/build/2379.f1641312.chunk.js +0 -1
- package/build/2395.46f8d0c1.chunk.js +0 -26
- package/build/2801.5cef5ec8.chunk.js +0 -1
- package/build/3483.03c24f96.chunk.js +0 -1
- package/build/3739.63e352f1.chunk.js +0 -103
- package/build/3929.5632f24d.chunk.js +0 -114
- package/build/448.829e1344.chunk.js +0 -1
- package/build/4546.cfafae68.chunk.js +0 -1
- package/build/502.8ae8ef60.chunk.js +0 -1
- package/build/5483.6dd2e776.chunk.js +0 -6
- package/build/5542.2415a393.chunk.js +0 -63
- package/build/6691.4985ef22.chunk.js +0 -105
- package/build/7464.3e64a1d5.chunk.js +0 -1
- package/build/8276.10a3f883.chunk.js +0 -26
- package/build/9944.7af075a5.chunk.js +0 -26
- package/build/Admin-authenticatedApp.f5ece8ff.chunk.js +0 -79
- package/build/Admin_InternalErrorPage.f45f2462.chunk.js +0 -1
- package/build/Admin_homePage.ac9dfb86.chunk.js +0 -81
- package/build/Admin_marketplace.dde9c148.chunk.js +0 -55
- package/build/Admin_pluginsPage.bbe79434.chunk.js +0 -6
- package/build/Admin_profilePage.192edc52.chunk.js +0 -13
- package/build/Admin_settingsPage.97cb9d41.chunk.js +0 -111
- package/build/admin-app.91898385.chunk.js +0 -36
- package/build/admin-edit-users.79eeb125.chunk.js +0 -10
- package/build/admin-users.123aa08e.chunk.js +0 -11
- package/build/api-tokens-list-page.505bf7e0.chunk.js +0 -16
- package/build/audit-logs-settings-page.4b422831.chunk.js +0 -1
- package/build/content-manager.2af15f57.chunk.js +0 -1099
- package/build/email-settings-page.d494d1eb.chunk.js +0 -11
- package/build/i18n-translation-ru-json.401bc498.chunk.js +0 -1
- package/build/main.f13fc96c.js +0 -2856
- package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +0 -1
- package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +0 -1
- package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +0 -56
- package/build/runtime~main.bb4efc54.js +0 -2
- package/build/transfer-tokens-list-page.22147d2c.chunk.js +0 -16
- package/build/users-advanced-settings-page.f0760eb8.chunk.js +0 -9
- package/build/users-email-settings-page.ff4b32f3.chunk.js +0 -9
- package/build/users-permissions-translation-zh-Hans-json.6ab714ee.chunk.js +0 -1
- package/build/users-providers-settings-page.48de0306.chunk.js +0 -14
- package/build/users-roles-settings-page.3f9f063e.chunk.js +0 -30
- package/build/webhook-edit-page.6cb479ff.chunk.js +0 -33
- package/build/zh-Hans-json.937b395b.chunk.js +0 -1
- package/ee/admin/hooks/index.js +0 -4
- package/ee/admin/hooks/useAuthProviders/index.js +0 -50
- package/ee/admin/hooks/useAuthProviders/reducer.js +0 -26
- package/ee/admin/hooks/useLicenseLimits/index.js +0 -1
- /package/ee/admin/hooks/{useLicenseLimits/__mocks__/index.js → __mocks__/useLicenseLimits.js} +0 -0
package/admin/src/StrapiApp.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from './exposedHooks';
|
|
23
23
|
import favicon from './favicon.png';
|
|
24
24
|
import injectionZones from './injectionZones';
|
|
25
|
-
import App from './pages/App';
|
|
25
|
+
import { App } from './pages/App';
|
|
26
26
|
import languageNativeNames from './translations/languageNativeNames';
|
|
27
27
|
|
|
28
28
|
class StrapiApp {
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AppInfoProvider,
|
|
5
|
+
auth,
|
|
6
|
+
LoadingIndicatorPage,
|
|
7
|
+
useFetchClient,
|
|
8
|
+
useGuidedTour,
|
|
9
|
+
useNotification,
|
|
10
|
+
useStrapiApp,
|
|
11
|
+
} from '@strapi/helper-plugin';
|
|
12
|
+
import { useQueries } from 'react-query';
|
|
13
|
+
import { valid, lt } from 'semver';
|
|
14
|
+
|
|
15
|
+
import packageJSON from '../../../package.json';
|
|
16
|
+
import { useConfigurations } from '../hooks';
|
|
17
|
+
import { Admin } from '../pages/Admin';
|
|
18
|
+
import { getFullName } from '../utils/getFullName';
|
|
19
|
+
import { hashAdminUserEmail } from '../utils/uniqueAdminHash';
|
|
20
|
+
|
|
21
|
+
import RBACProvider from './RBACProvider';
|
|
22
|
+
|
|
23
|
+
const strapiVersion = packageJSON.version;
|
|
24
|
+
|
|
25
|
+
const checkLatestStrapiVersion = (currentPackageVersion, latestPublishedVersion) => {
|
|
26
|
+
if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return lt(currentPackageVersion, latestPublishedVersion);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const AuthenticatedApp = () => {
|
|
34
|
+
const { setGuidedTourVisibility } = useGuidedTour();
|
|
35
|
+
const toggleNotification = useNotification();
|
|
36
|
+
const userInfo = auth.getUserInfo();
|
|
37
|
+
const { get } = useFetchClient();
|
|
38
|
+
// TODO: replace with getDisplayName()
|
|
39
|
+
const [userDisplayName, setUserDisplayName] = React.useState(
|
|
40
|
+
userInfo?.userName ?? getFullName(userInfo.firstname, userInfo.lastname)
|
|
41
|
+
);
|
|
42
|
+
const [userId, setUserId] = React.useState(null);
|
|
43
|
+
const { showReleaseNotification } = useConfigurations();
|
|
44
|
+
const { plugins: appPlugins = {} } = useStrapiApp();
|
|
45
|
+
const [plugins, setPlugins] = React.useState(appPlugins);
|
|
46
|
+
const [
|
|
47
|
+
{ data: appInfos, isLoading: isLoadingAppInfos },
|
|
48
|
+
{ data: tagName },
|
|
49
|
+
{ data: permissions, isLoading: isLoadingPermissions, refetch },
|
|
50
|
+
{ data: userRoles },
|
|
51
|
+
] = useQueries([
|
|
52
|
+
{
|
|
53
|
+
queryKey: 'information',
|
|
54
|
+
async queryFn() {
|
|
55
|
+
const {
|
|
56
|
+
data: { data },
|
|
57
|
+
} = await get('/admin/information');
|
|
58
|
+
|
|
59
|
+
return data;
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
queryKey: 'strapi-release',
|
|
65
|
+
async queryFn() {
|
|
66
|
+
const res = await fetch('https://api.github.com/repos/strapi/strapi/releases/latest');
|
|
67
|
+
|
|
68
|
+
if (!res.ok) {
|
|
69
|
+
throw new Error('Failed to fetch latest Strapi version.');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { tag_name } = await res.json();
|
|
73
|
+
|
|
74
|
+
return tag_name;
|
|
75
|
+
},
|
|
76
|
+
enabled: showReleaseNotification,
|
|
77
|
+
initialData: strapiVersion,
|
|
78
|
+
onSuccess(data) {
|
|
79
|
+
const shouldUpdateStrapi = checkLatestStrapiVersion(strapiVersion, data.tag_name);
|
|
80
|
+
|
|
81
|
+
if (shouldUpdateStrapi && !JSON.parse(localStorage.getItem('STRAPI_UPDATE_NOTIF'))) {
|
|
82
|
+
toggleNotification({
|
|
83
|
+
type: 'info',
|
|
84
|
+
message: { id: 'notification.version.update.message' },
|
|
85
|
+
link: {
|
|
86
|
+
url: `https://github.com/strapi/strapi/releases/tag/${data.tag_name}`,
|
|
87
|
+
label: {
|
|
88
|
+
id: 'global.see-more',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
blockTransition: true,
|
|
92
|
+
onClose: () => localStorage.setItem('STRAPI_UPDATE_NOTIF', true),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
retry: false,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
queryKey: ['users', 'me', 'permissions'],
|
|
100
|
+
async queryFn() {
|
|
101
|
+
const {
|
|
102
|
+
data: { data },
|
|
103
|
+
} = await get('/admin/users/me/permissions');
|
|
104
|
+
|
|
105
|
+
return data;
|
|
106
|
+
},
|
|
107
|
+
initialData: [],
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
{
|
|
111
|
+
queryKey: ['users', 'me'],
|
|
112
|
+
async queryFn() {
|
|
113
|
+
const {
|
|
114
|
+
data: {
|
|
115
|
+
data: { roles },
|
|
116
|
+
},
|
|
117
|
+
} = await get('/admin/users/me');
|
|
118
|
+
|
|
119
|
+
return roles;
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
// Display the guided tour conditionally for super admins in development mode
|
|
125
|
+
React.useEffect(() => {
|
|
126
|
+
if (userRoles) {
|
|
127
|
+
const isUserSuperAdmin = userRoles.find(({ code }) => code === 'strapi-super-admin');
|
|
128
|
+
|
|
129
|
+
if (isUserSuperAdmin && appInfos?.currentEnvironment === 'development') {
|
|
130
|
+
setGuidedTourVisibility(true);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}, [userRoles, appInfos, setGuidedTourVisibility]);
|
|
134
|
+
|
|
135
|
+
// Create a hash of the users email adress and use it as ID for tracking
|
|
136
|
+
React.useEffect(() => {
|
|
137
|
+
const generateUserId = async (userInfo) => {
|
|
138
|
+
const userId = await hashAdminUserEmail(userInfo);
|
|
139
|
+
setUserId(userId);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
if (userInfo) {
|
|
143
|
+
generateUserId(userInfo);
|
|
144
|
+
}
|
|
145
|
+
}, [userInfo]);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
*
|
|
149
|
+
* I have spent some time trying to understand what is happening here, and wanted to
|
|
150
|
+
* leave that knowledge for my future me:
|
|
151
|
+
*
|
|
152
|
+
* `initializer` is an undocumented property of the `registerPlugin` API. At the time
|
|
153
|
+
* of writing it seems only to be used by the i18n plugin.
|
|
154
|
+
*
|
|
155
|
+
* How does it work?
|
|
156
|
+
*
|
|
157
|
+
* Every plugin that has an `initializer` component defined, receives the
|
|
158
|
+
* `setPlugin` function as a component prop. In the case of i18n the plugin fetches locales
|
|
159
|
+
* first and calls `setPlugin` with `pluginId` once they are loaded, which then triggers the
|
|
160
|
+
* reducer of the admin app defined above.
|
|
161
|
+
*
|
|
162
|
+
* Once all plugins are set to `isReady: true` the app renders.
|
|
163
|
+
*
|
|
164
|
+
* This API is used to block rendering of the admin app. We should remove that in v5 completely
|
|
165
|
+
* and make sure plugins can inject data into the global store before they are initialized, to avoid
|
|
166
|
+
* having a new prop-callback based communication channel between plugins and the core admin app.
|
|
167
|
+
*
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
const hasApluginNotReady = Object.values(plugins).some((plugin) => plugin.isReady === false);
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
!userDisplayName ||
|
|
174
|
+
!userId ||
|
|
175
|
+
isLoadingAppInfos ||
|
|
176
|
+
isLoadingPermissions ||
|
|
177
|
+
hasApluginNotReady
|
|
178
|
+
) {
|
|
179
|
+
const initializers = Object.keys(plugins).reduce((acc, current) => {
|
|
180
|
+
const InitializerComponent = plugins[current].initializer;
|
|
181
|
+
|
|
182
|
+
if (InitializerComponent) {
|
|
183
|
+
const key = plugins[current].pluginId;
|
|
184
|
+
|
|
185
|
+
acc.push(
|
|
186
|
+
<InitializerComponent
|
|
187
|
+
key={key}
|
|
188
|
+
setPlugin={(pluginId) => {
|
|
189
|
+
setPlugins((prev) => ({
|
|
190
|
+
...prev,
|
|
191
|
+
[pluginId]: {
|
|
192
|
+
...prev[pluginId],
|
|
193
|
+
isReady: true,
|
|
194
|
+
},
|
|
195
|
+
}));
|
|
196
|
+
}}
|
|
197
|
+
/>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return acc;
|
|
202
|
+
}, []);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<>
|
|
206
|
+
{initializers}
|
|
207
|
+
<LoadingIndicatorPage />
|
|
208
|
+
</>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<AppInfoProvider
|
|
214
|
+
{...appInfos}
|
|
215
|
+
userId={userId}
|
|
216
|
+
latestStrapiReleaseTag={tagName}
|
|
217
|
+
// TODO: setUserDisplayName should not exist and be removed, as it is only used
|
|
218
|
+
// to update the displayName immediately, in case a user updates their profile.
|
|
219
|
+
// This information should be derived from the state.
|
|
220
|
+
setUserDisplayName={setUserDisplayName}
|
|
221
|
+
shouldUpdateStrapi={checkLatestStrapiVersion(strapiVersion, tagName)}
|
|
222
|
+
userDisplayName={userDisplayName}
|
|
223
|
+
>
|
|
224
|
+
<RBACProvider permissions={permissions} refetchPermissions={refetch}>
|
|
225
|
+
<Admin />
|
|
226
|
+
</RBACProvider>
|
|
227
|
+
</AppInfoProvider>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
@@ -9,7 +9,7 @@ import Modal from './components/Modal';
|
|
|
9
9
|
import StepperModal from './components/Stepper';
|
|
10
10
|
import reducer, { initialState } from './reducer';
|
|
11
11
|
|
|
12
|
-
const GuidedTourModal = () => {
|
|
12
|
+
export const GuidedTourModal = () => {
|
|
13
13
|
const {
|
|
14
14
|
currentStep,
|
|
15
15
|
guidedTourState,
|
|
@@ -90,5 +90,3 @@ const GuidedTourModal = () => {
|
|
|
90
90
|
|
|
91
91
|
return null;
|
|
92
92
|
};
|
|
93
|
-
|
|
94
|
-
export default GuidedTourModal;
|
|
@@ -64,22 +64,16 @@ const WysiwygNav = ({
|
|
|
64
64
|
</Select>
|
|
65
65
|
|
|
66
66
|
<MainButtons>
|
|
67
|
-
<CustomIconButton disabled
|
|
68
|
-
<CustomIconButton disabled
|
|
69
|
-
<CustomIconButton
|
|
70
|
-
disabled
|
|
71
|
-
id="Underline"
|
|
72
|
-
label="Underline"
|
|
73
|
-
name="Underline"
|
|
74
|
-
icon={<Underline />}
|
|
75
|
-
/>
|
|
67
|
+
<CustomIconButton disabled label="Bold" name="Bold" icon={<Bold />} />
|
|
68
|
+
<CustomIconButton disabled label="Italic" name="Italic" icon={<Italic />} />
|
|
69
|
+
<CustomIconButton disabled label="Underline" name="Underline" icon={<Underline />} />
|
|
76
70
|
</MainButtons>
|
|
77
71
|
|
|
78
|
-
<MoreButton disabled
|
|
72
|
+
<MoreButton disabled label="More" icon={<More />} />
|
|
79
73
|
</StyledFlex>
|
|
80
74
|
|
|
81
75
|
{!isExpandMode && (
|
|
82
|
-
<Button onClick={onTogglePreviewMode} variant="tertiary"
|
|
76
|
+
<Button onClick={onTogglePreviewMode} variant="tertiary">
|
|
83
77
|
{formatMessage({
|
|
84
78
|
id: 'components.Wysiwyg.ToggleMode.markdown-mode',
|
|
85
79
|
defaultMessage: 'Markdown mode',
|
|
@@ -110,21 +104,18 @@ const WysiwygNav = ({
|
|
|
110
104
|
<MainButtons>
|
|
111
105
|
<CustomIconButton
|
|
112
106
|
onClick={() => onActionClick('Bold', editorRef)}
|
|
113
|
-
id="Bold"
|
|
114
107
|
label="Bold"
|
|
115
108
|
name="Bold"
|
|
116
109
|
icon={<Bold />}
|
|
117
110
|
/>
|
|
118
111
|
<CustomIconButton
|
|
119
112
|
onClick={() => onActionClick('Italic', editorRef)}
|
|
120
|
-
id="Italic"
|
|
121
113
|
label="Italic"
|
|
122
114
|
name="Italic"
|
|
123
115
|
icon={<Italic />}
|
|
124
116
|
/>
|
|
125
117
|
<CustomIconButton
|
|
126
118
|
onClick={() => onActionClick('Underline', editorRef)}
|
|
127
|
-
id="Underline"
|
|
128
119
|
label="Underline"
|
|
129
120
|
name="Underline"
|
|
130
121
|
icon={<Underline />}
|
|
@@ -134,37 +125,27 @@ const WysiwygNav = ({
|
|
|
134
125
|
<MoreButton
|
|
135
126
|
ref={buttonMoreRef}
|
|
136
127
|
onClick={handleTogglePopover}
|
|
137
|
-
id="more"
|
|
138
128
|
label="More"
|
|
139
129
|
icon={<More />}
|
|
140
130
|
/>
|
|
141
131
|
{visiblePopover && (
|
|
142
|
-
<Popover
|
|
143
|
-
onDismiss={handleTogglePopover}
|
|
144
|
-
centered
|
|
145
|
-
source={buttonMoreRef}
|
|
146
|
-
spacing={4}
|
|
147
|
-
id="popover"
|
|
148
|
-
>
|
|
132
|
+
<Popover onDismiss={handleTogglePopover} centered source={buttonMoreRef} spacing={4}>
|
|
149
133
|
<Flex>
|
|
150
134
|
<IconButtonGroupMargin>
|
|
151
135
|
<CustomIconButton
|
|
152
136
|
onClick={() => onActionClick('Strikethrough', editorRef, handleTogglePopover)}
|
|
153
|
-
id="Strikethrough"
|
|
154
137
|
label="Strikethrough"
|
|
155
138
|
name="Strikethrough"
|
|
156
139
|
icon={<StrikeThrough />}
|
|
157
140
|
/>
|
|
158
141
|
<CustomIconButton
|
|
159
142
|
onClick={() => onActionClick('BulletList', editorRef, handleTogglePopover)}
|
|
160
|
-
id="BulletList"
|
|
161
143
|
label="BulletList"
|
|
162
144
|
name="BulletList"
|
|
163
145
|
icon={<BulletList />}
|
|
164
146
|
/>
|
|
165
147
|
<CustomIconButton
|
|
166
148
|
onClick={() => onActionClick('NumberList', editorRef, handleTogglePopover)}
|
|
167
|
-
id="NumberList"
|
|
168
149
|
label="NumberList"
|
|
169
150
|
name="NumberList"
|
|
170
151
|
icon={<NumberList />}
|
|
@@ -173,7 +154,6 @@ const WysiwygNav = ({
|
|
|
173
154
|
<IconButtonGroup>
|
|
174
155
|
<CustomIconButton
|
|
175
156
|
onClick={() => onActionClick('Code', editorRef, handleTogglePopover)}
|
|
176
|
-
id="Code"
|
|
177
157
|
label="Code"
|
|
178
158
|
name="Code"
|
|
179
159
|
icon={<Code />}
|
|
@@ -183,14 +163,12 @@ const WysiwygNav = ({
|
|
|
183
163
|
handleTogglePopover();
|
|
184
164
|
onToggleMediaLib();
|
|
185
165
|
}}
|
|
186
|
-
id="Image"
|
|
187
166
|
label="Image"
|
|
188
167
|
name="Image"
|
|
189
168
|
icon={<Image />}
|
|
190
169
|
/>
|
|
191
170
|
<CustomLinkIconButton
|
|
192
171
|
onClick={() => onActionClick('Link', editorRef, handleTogglePopover)}
|
|
193
|
-
id="Link"
|
|
194
172
|
label="Link"
|
|
195
173
|
name="Link"
|
|
196
174
|
// eslint-disable-next-line jsx-a11y/anchor-is-valid
|
|
@@ -198,7 +176,6 @@ const WysiwygNav = ({
|
|
|
198
176
|
/>
|
|
199
177
|
<CustomIconButton
|
|
200
178
|
onClick={() => onActionClick('Quote', editorRef, handleTogglePopover)}
|
|
201
|
-
id="Quote"
|
|
202
179
|
label="Quote"
|
|
203
180
|
name="Quote"
|
|
204
181
|
icon={<Quote />}
|
|
@@ -210,7 +187,7 @@ const WysiwygNav = ({
|
|
|
210
187
|
</StyledFlex>
|
|
211
188
|
|
|
212
189
|
{onTogglePreviewMode && (
|
|
213
|
-
<Button onClick={onTogglePreviewMode} variant="tertiary"
|
|
190
|
+
<Button onClick={onTogglePreviewMode} variant="tertiary">
|
|
214
191
|
{formatMessage({
|
|
215
192
|
id: 'components.Wysiwyg.ToggleMode.preview-mode',
|
|
216
193
|
defaultMessage: 'Preview mode',
|
|
@@ -6,9 +6,10 @@ import { resetPermissions, setPermissions } from './actions';
|
|
|
6
6
|
import { selectCollectionTypePermissions, selectPermissions } from './selectors';
|
|
7
7
|
|
|
8
8
|
const useSyncRbac = (query, collectionTypeUID, containerName = 'listView') => {
|
|
9
|
+
const dispatch = useDispatch();
|
|
10
|
+
|
|
9
11
|
const collectionTypesRelatedPermissions = useSelector(selectCollectionTypePermissions);
|
|
10
12
|
const permissions = useSelector(selectPermissions);
|
|
11
|
-
const dispatch = useDispatch();
|
|
12
13
|
|
|
13
14
|
const relatedPermissions = collectionTypesRelatedPermissions[collectionTypeUID];
|
|
14
15
|
|
|
@@ -24,7 +25,14 @@ const useSyncRbac = (query, collectionTypeUID, containerName = 'listView') => {
|
|
|
24
25
|
return () => {};
|
|
25
26
|
}, [relatedPermissions, dispatch, query, containerName]);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
// Check if the permissions are related to the current collectionTypeUID
|
|
29
|
+
const isPermissionMismatch =
|
|
30
|
+
permissions?.some((permission) => permission.subject !== collectionTypeUID) ?? true;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
isValid: permissions && !isPermissionMismatch,
|
|
34
|
+
permissions,
|
|
35
|
+
};
|
|
28
36
|
};
|
|
29
37
|
|
|
30
38
|
export default useSyncRbac;
|
|
@@ -61,7 +61,7 @@ function renderDraglayerItem({ type, item }) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const
|
|
64
|
+
export const ContentManger = () => {
|
|
65
65
|
const contentTypeMatch = useRouteMatch(`/content-manager/:kind/:uid`);
|
|
66
66
|
const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } =
|
|
67
67
|
useContentManagerInitData();
|
|
@@ -123,6 +123,10 @@ const App = () => {
|
|
|
123
123
|
|
|
124
124
|
return (
|
|
125
125
|
<Layout sideNav={<LeftMenu />}>
|
|
126
|
+
<Helmet
|
|
127
|
+
title={formatMessage({ id: getTrad('plugin.name'), defaultMessage: 'Content Manager' })}
|
|
128
|
+
/>
|
|
129
|
+
|
|
126
130
|
<DragLayer renderItem={renderDraglayerItem} />
|
|
127
131
|
<ModelsContext.Provider value={{ refetchData }}>
|
|
128
132
|
<Switch>
|
|
@@ -149,18 +153,3 @@ const App = () => {
|
|
|
149
153
|
</Layout>
|
|
150
154
|
);
|
|
151
155
|
};
|
|
152
|
-
|
|
153
|
-
export { App };
|
|
154
|
-
|
|
155
|
-
export default function () {
|
|
156
|
-
const { formatMessage } = useIntl();
|
|
157
|
-
|
|
158
|
-
return (
|
|
159
|
-
<>
|
|
160
|
-
<Helmet
|
|
161
|
-
title={formatMessage({ id: getTrad('plugin.name'), defaultMessage: 'Content Manager' })}
|
|
162
|
-
/>
|
|
163
|
-
<App />
|
|
164
|
-
</>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
@@ -12,7 +12,7 @@ import { useFetchContentTypeLayout } from '../../hooks';
|
|
|
12
12
|
import { formatLayoutToApi } from '../../utils';
|
|
13
13
|
import EditSettingsView from '../EditSettingsView';
|
|
14
14
|
import EditViewLayoutManager from '../EditViewLayoutManager';
|
|
15
|
-
import ListSettingsView from '../ListSettingsView';
|
|
15
|
+
import { ListSettingsView } from '../ListSettingsView';
|
|
16
16
|
import ListViewLayout from '../ListViewLayoutManager';
|
|
17
17
|
|
|
18
18
|
import ErrorFallback from './components/ErrorFallback';
|
|
@@ -5,7 +5,7 @@ import { useCMEditViewDataManager } from '@strapi/helper-plugin';
|
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
import { useIntl } from 'react-intl';
|
|
7
7
|
|
|
8
|
-
import { getFullName } from '../../../../utils';
|
|
8
|
+
import { getFullName } from '../../../../utils/getFullName';
|
|
9
9
|
import { getTrad } from '../../../utils';
|
|
10
10
|
|
|
11
11
|
import getUnits from './utils/getUnits';
|
|
@@ -16,7 +16,7 @@ const EditViewLayoutManager = ({ layout, ...rest }) => {
|
|
|
16
16
|
const dispatch = useDispatch();
|
|
17
17
|
const [{ query }] = useQueryParams();
|
|
18
18
|
const { runHookWaterfall } = useStrapiApp();
|
|
19
|
-
const permissions = useSyncRbac(query, rest.slug, 'editView');
|
|
19
|
+
const { permissions, isValid: isValidPermissions } = useSyncRbac(query, rest.slug, 'editView');
|
|
20
20
|
|
|
21
21
|
useEffect(() => {
|
|
22
22
|
// Allow the plugins to extend the edit view layout
|
|
@@ -29,7 +29,7 @@ const EditViewLayoutManager = ({ layout, ...rest }) => {
|
|
|
29
29
|
};
|
|
30
30
|
}, [layout, dispatch, query, runHookWaterfall]);
|
|
31
31
|
|
|
32
|
-
if (!currentLayout || !
|
|
32
|
+
if (!currentLayout || !isValidPermissions) {
|
|
33
33
|
return <LoadingIndicatorPage />;
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Button,
|
|
@@ -9,13 +9,7 @@ import {
|
|
|
9
9
|
Layout,
|
|
10
10
|
Main,
|
|
11
11
|
} from '@strapi/design-system';
|
|
12
|
-
import {
|
|
13
|
-
ConfirmDialog,
|
|
14
|
-
Link,
|
|
15
|
-
useFetchClient,
|
|
16
|
-
useNotification,
|
|
17
|
-
useTracking,
|
|
18
|
-
} from '@strapi/helper-plugin';
|
|
12
|
+
import { Link, useFetchClient, useNotification, useTracking } from '@strapi/helper-plugin';
|
|
19
13
|
import { ArrowLeft, Check } from '@strapi/icons';
|
|
20
14
|
import isEqual from 'lodash/isEqual';
|
|
21
15
|
import upperFirst from 'lodash/upperFirst';
|
|
@@ -34,16 +28,14 @@ import { SortDisplayedFields } from './components/SortDisplayedFields';
|
|
|
34
28
|
import { EXCLUDED_SORT_ATTRIBUTE_TYPES } from './constants';
|
|
35
29
|
import reducer, { initialState } from './reducer';
|
|
36
30
|
|
|
37
|
-
const ListSettingsView = ({ layout, slug }) => {
|
|
31
|
+
export const ListSettingsView = ({ layout, slug }) => {
|
|
38
32
|
const { put } = useFetchClient();
|
|
39
33
|
const { formatMessage } = useIntl();
|
|
40
34
|
const { trackUsage } = useTracking();
|
|
41
35
|
const pluginsQueryParams = usePluginsQueryParams();
|
|
42
36
|
const toggleNotification = useNotification();
|
|
43
|
-
const { refetchData } = useContext(ModelsContext);
|
|
44
|
-
const [
|
|
45
|
-
const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
|
|
46
|
-
const [{ fieldToEdit, fieldForm, initialData, modifiedData }, dispatch] = useReducer(
|
|
37
|
+
const { refetchData } = React.useContext(ModelsContext);
|
|
38
|
+
const [{ fieldToEdit, fieldForm, initialData, modifiedData }, dispatch] = React.useReducer(
|
|
47
39
|
reducer,
|
|
48
40
|
initialState,
|
|
49
41
|
() => ({
|
|
@@ -101,16 +93,6 @@ const ListSettingsView = ({ layout, slug }) => {
|
|
|
101
93
|
}
|
|
102
94
|
);
|
|
103
95
|
|
|
104
|
-
const handleConfirm = async () => {
|
|
105
|
-
const { layouts, settings, metadatas } = modifiedData;
|
|
106
|
-
|
|
107
|
-
mutate({
|
|
108
|
-
layouts,
|
|
109
|
-
settings,
|
|
110
|
-
metadatas,
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
|
|
114
96
|
const handleAddField = (item) => {
|
|
115
97
|
dispatch({
|
|
116
98
|
type: 'ADD_FIELD',
|
|
@@ -134,9 +116,17 @@ const ListSettingsView = ({ layout, slug }) => {
|
|
|
134
116
|
}
|
|
135
117
|
};
|
|
136
118
|
|
|
137
|
-
const handleSubmit = (
|
|
138
|
-
|
|
139
|
-
|
|
119
|
+
const handleSubmit = (event) => {
|
|
120
|
+
event.preventDefault();
|
|
121
|
+
|
|
122
|
+
const { layouts, settings, metadatas } = modifiedData;
|
|
123
|
+
|
|
124
|
+
mutate({
|
|
125
|
+
layouts,
|
|
126
|
+
settings,
|
|
127
|
+
metadatas,
|
|
128
|
+
});
|
|
129
|
+
|
|
140
130
|
trackUsage('willSaveContentTypeLayout');
|
|
141
131
|
};
|
|
142
132
|
|
|
@@ -253,19 +243,6 @@ const ListSettingsView = ({ layout, slug }) => {
|
|
|
253
243
|
/>
|
|
254
244
|
</Flex>
|
|
255
245
|
</ContentLayout>
|
|
256
|
-
|
|
257
|
-
<ConfirmDialog
|
|
258
|
-
bodyText={{
|
|
259
|
-
id: getTrad('popUpWarning.warning.updateAllSettings'),
|
|
260
|
-
defaultMessage: 'This will modify all your settings',
|
|
261
|
-
}}
|
|
262
|
-
iconRightButton={<Check />}
|
|
263
|
-
isConfirmButtonLoading={isSubmittingForm}
|
|
264
|
-
isOpen={showWarningSubmit}
|
|
265
|
-
onToggleDialog={toggleWarningSubmit}
|
|
266
|
-
onConfirm={handleConfirm}
|
|
267
|
-
variantRightButton="success-light"
|
|
268
|
-
/>
|
|
269
246
|
</form>
|
|
270
247
|
|
|
271
248
|
{isModalFormOpen && (
|
|
@@ -305,5 +282,3 @@ ListSettingsView.propTypes = {
|
|
|
305
282
|
}).isRequired,
|
|
306
283
|
slug: PropTypes.string.isRequired,
|
|
307
284
|
};
|
|
308
|
-
|
|
309
|
-
export default ListSettingsView;
|
|
@@ -32,7 +32,7 @@ import { useSelector } from 'react-redux';
|
|
|
32
32
|
import { Link, useHistory } from 'react-router-dom';
|
|
33
33
|
import styled from 'styled-components';
|
|
34
34
|
|
|
35
|
-
import
|
|
35
|
+
import { formatAPIErrors } from '../../../../../../utils/formatAPIErrors';
|
|
36
36
|
import { getTrad, createYupSchema } from '../../../../../utils';
|
|
37
37
|
import { listViewDomain } from '../../../selectors';
|
|
38
38
|
import { Body } from '../../Body';
|
|
@@ -301,7 +301,7 @@ const SelectedEntriesModalContent = ({
|
|
|
301
301
|
onError(error) {
|
|
302
302
|
toggleNotification({
|
|
303
303
|
type: 'warning',
|
|
304
|
-
message:
|
|
304
|
+
message: formatAPIErrors(error),
|
|
305
305
|
});
|
|
306
306
|
},
|
|
307
307
|
}
|
|
@@ -23,7 +23,7 @@ import { useIntl } from 'react-intl';
|
|
|
23
23
|
import { Link, useHistory } from 'react-router-dom';
|
|
24
24
|
|
|
25
25
|
import { useEnterprise } from '../../../../../hooks/useEnterprise';
|
|
26
|
-
import { getFullName } from '../../../../../utils';
|
|
26
|
+
import { getFullName } from '../../../../../utils/getFullName';
|
|
27
27
|
import { usePluginsQueryParams } from '../../../../hooks';
|
|
28
28
|
import { getTrad } from '../../../../utils';
|
|
29
29
|
import CellContent from '../CellContent';
|
|
@@ -180,6 +180,22 @@ function ListView({
|
|
|
180
180
|
data: { results, pagination: paginationResult },
|
|
181
181
|
} = await fetchClient.get(endPoint, options);
|
|
182
182
|
|
|
183
|
+
// If user enters a page number that doesn't exist, redirect him to the last page
|
|
184
|
+
if (paginationResult.page > paginationResult.pageCount && paginationResult.pageCount > 0) {
|
|
185
|
+
const query = {
|
|
186
|
+
...params,
|
|
187
|
+
page: paginationResult.pageCount,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
push({
|
|
191
|
+
pathname,
|
|
192
|
+
state: { from: pathname },
|
|
193
|
+
search: stringify(query),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
183
199
|
notifyStatus(
|
|
184
200
|
formatMessage(
|
|
185
201
|
{
|
|
@@ -219,7 +235,17 @@ function ListView({
|
|
|
219
235
|
});
|
|
220
236
|
}
|
|
221
237
|
},
|
|
222
|
-
[
|
|
238
|
+
[
|
|
239
|
+
formatMessage,
|
|
240
|
+
getData,
|
|
241
|
+
getDataSucceeded,
|
|
242
|
+
notifyStatus,
|
|
243
|
+
push,
|
|
244
|
+
toggleNotification,
|
|
245
|
+
fetchClient,
|
|
246
|
+
params,
|
|
247
|
+
pathname,
|
|
248
|
+
]
|
|
223
249
|
);
|
|
224
250
|
|
|
225
251
|
const handleConfirmDeleteAllData = React.useCallback(
|
|
@@ -14,7 +14,7 @@ const ListViewLayout = ({ layout, ...props }) => {
|
|
|
14
14
|
const dispatch = useDispatch();
|
|
15
15
|
const { replace } = useHistory();
|
|
16
16
|
const [{ query, rawQuery }] = useQueryParams();
|
|
17
|
-
const permissions = useSyncRbac(query, props.slug, 'listView');
|
|
17
|
+
const { permissions, isValid: isValidPermissions } = useSyncRbac(query, props.slug, 'listView');
|
|
18
18
|
const redirectionLink = useFindRedirectionLink(props.slug);
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
@@ -33,7 +33,7 @@ const ListViewLayout = ({ layout, ...props }) => {
|
|
|
33
33
|
};
|
|
34
34
|
}, [dispatch]);
|
|
35
35
|
|
|
36
|
-
if (!
|
|
36
|
+
if (!isValidPermissions) {
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
|