@strapi/admin 4.10.6 → 4.11.0-beta.0
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/content-manager/components/DynamicTable/BulkActionsBar/index.js +307 -0
- package/admin/src/content-manager/components/DynamicTable/index.js +20 -4
- package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +3 -2
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +0 -1
- package/admin/src/content-manager/pages/ListView/index.js +118 -2
- package/admin/src/content-manager/utils/index.js +2 -0
- package/admin/src/content-manager/{components/EditViewDataManagerProvider/utils → utils}/schema.js +1 -1
- package/admin/src/hooks/index.js +1 -1
- package/admin/src/hooks/useAdminUsers/__mocks__/index.js +5 -0
- package/admin/src/hooks/useAdminUsers/index.js +1 -0
- package/admin/src/hooks/useAdminUsers/useAdminUsers.js +38 -0
- package/admin/src/hooks/useContentTypes/__mocks__/index.js +6 -0
- package/admin/src/hooks/useContentTypes/index.js +1 -0
- package/admin/src/hooks/useContentTypes/useContentTypes.js +47 -0
- package/admin/src/injectionZones.js +6 -1
- package/admin/src/pages/HomePage/index.js +3 -2
- package/admin/src/pages/MarketplacePage/components/NpmPackageCard/InstallPluginButton.js +12 -8
- package/admin/src/pages/SettingsPage/components/Tokens/TokenBox/index.js +28 -26
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +36 -26
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/utils/api.js +1 -8
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/index.js +6 -7
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +54 -63
- package/admin/src/pages/SettingsPage/pages/Users/components/MagicLink/MagicLinkWrapper.js +11 -9
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js +2 -2
- package/admin/src/translations/en.json +5 -1
- package/build/3562.e0b1a0b3.chunk.js +50 -0
- package/build/5563.79950369.chunk.js +79 -0
- package/build/6970.7ea35fbd.chunk.js +1 -0
- package/build/7259.5cc67413.chunk.js +1 -0
- package/build/{Admin-authenticatedApp.0318dfb3.chunk.js → Admin-authenticatedApp.65172a0c.chunk.js} +2 -2
- package/build/{Admin_homePage.e15dcf28.chunk.js → Admin_homePage.107a9fe0.chunk.js} +9 -9
- package/build/{Admin_marketplace.f446ba2b.chunk.js → Admin_marketplace.717bd7ca.chunk.js} +11 -11
- package/build/{Admin_profilePage.1687246a.chunk.js → Admin_profilePage.a8fa3a56.chunk.js} +1 -1
- package/build/{Admin_settingsPage.f8c46a9a.chunk.js → Admin_settingsPage.bd715ed3.chunk.js} +2 -2
- package/build/admin-app.9c79b484.chunk.js +63 -0
- package/build/{admin-edit-roles-page.02c3b136.chunk.js → admin-edit-roles-page.0d12b741.chunk.js} +3 -3
- package/build/admin-edit-users.f9ce7844.chunk.js +10 -0
- package/build/{admin-roles-list.a323aa9f.chunk.js → admin-roles-list.e8bf9685.chunk.js} +1 -1
- package/build/admin-users.751b28b2.chunk.js +34 -0
- package/build/audit-logs-settings-page.3c6cea81.chunk.js +129 -0
- package/build/content-manager.bf060d8e.chunk.js +1123 -0
- package/build/{en-json.d965e364.chunk.js → en-json.19e9ff9b.chunk.js} +1 -1
- package/build/i18n-translation-en-json.1ec7becf.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.576a9d22.js +2630 -0
- package/build/review-workflows-settings.4b39b837.chunk.js +61 -0
- package/build/{runtime~main.0201a49b.js → runtime~main.96d92f16.js} +2 -2
- package/build/{sso-settings-page.c9d7c8df.chunk.js → sso-settings-page.265e3d72.chunk.js} +1 -1
- package/build/{webhook-edit-page.cb2cf1a5.chunk.js → webhook-edit-page.ddd5963d.chunk.js} +13 -13
- package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +1 -2
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js +36 -28
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +3 -3
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +32 -21
- package/ee/server/services/audit-logs.js +5 -1
- package/package.json +10 -11
- package/webpack.alias.js +0 -1
- package/admin/src/content-manager/components/DynamicTable/ConfirmDialogDeleteAll/index.js +0 -73
- package/admin/src/hooks/useModels/index.js +0 -58
- package/admin/src/hooks/useModels/reducer.js +0 -45
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/utils/api.js +0 -20
- package/build/5563.2c8334ef.chunk.js +0 -79
- package/build/6858.85d76858.chunk.js +0 -50
- package/build/6970.36d3ffff.chunk.js +0 -1
- package/build/7259.116a9960.chunk.js +0 -1
- package/build/admin-app.6d48536c.chunk.js +0 -63
- package/build/admin-edit-users.49363035.chunk.js +0 -10
- package/build/admin-users.69f4900a.chunk.js +0 -34
- package/build/audit-logs-settings-page.482909d7.chunk.js +0 -129
- package/build/content-manager.cd71cb6e.chunk.js +0 -1123
- package/build/i18n-translation-en-json.60af6722.chunk.js +0 -1
- package/build/main.adab8b96.js +0 -2630
- package/build/review-workflows-settings.26409ce4.chunk.js +0 -61
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useAPIErrorHandler, useFetchClient, useNotification } from '@strapi/helper-plugin';
|
|
2
|
+
import { useQueries } from 'react-query';
|
|
3
|
+
|
|
4
|
+
export function useContentTypes() {
|
|
5
|
+
console.log('----> read');
|
|
6
|
+
|
|
7
|
+
const { get } = useFetchClient();
|
|
8
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
9
|
+
const toggleNotification = useNotification();
|
|
10
|
+
const queries = useQueries(
|
|
11
|
+
['components', 'content-types'].map((type) => {
|
|
12
|
+
return {
|
|
13
|
+
queryKey: ['content-manager', type],
|
|
14
|
+
async queryFn() {
|
|
15
|
+
const {
|
|
16
|
+
data: { data },
|
|
17
|
+
} = await get(`/content-manager/${type}`);
|
|
18
|
+
|
|
19
|
+
return data;
|
|
20
|
+
},
|
|
21
|
+
onError(error) {
|
|
22
|
+
toggleNotification({
|
|
23
|
+
type: 'warning',
|
|
24
|
+
message: formatAPIError(error),
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const [components, contentTypes] = queries;
|
|
32
|
+
const isLoading = components.isLoading || contentTypes.isLoading;
|
|
33
|
+
|
|
34
|
+
const collectionTypes = (contentTypes?.data ?? []).filter(
|
|
35
|
+
(contentType) => contentType.kind === 'collectionType' && contentType.isDisplayed
|
|
36
|
+
);
|
|
37
|
+
const singleTypes = (contentTypes?.data ?? []).filter(
|
|
38
|
+
(contentType) => contentType.kind !== 'collectionType' && contentType.isDisplayed
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
isLoading,
|
|
43
|
+
components: components?.data ?? [],
|
|
44
|
+
collectionTypes,
|
|
45
|
+
singleTypes,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -13,7 +13,12 @@ const injectionZones = {
|
|
|
13
13
|
},
|
|
14
14
|
contentManager: {
|
|
15
15
|
editView: { informations: [], 'right-links': [] },
|
|
16
|
-
listView: {
|
|
16
|
+
listView: {
|
|
17
|
+
actions: [],
|
|
18
|
+
deleteModalAdditionalInfos: [],
|
|
19
|
+
publishModalAdditionalInfos: [],
|
|
20
|
+
unpublishModalAdditionalInfos: [],
|
|
21
|
+
},
|
|
17
22
|
},
|
|
18
23
|
};
|
|
19
24
|
|
|
@@ -11,8 +11,9 @@ import { useHistory } from 'react-router-dom';
|
|
|
11
11
|
import { LoadingIndicatorPage, useGuidedTour } from '@strapi/helper-plugin';
|
|
12
12
|
import { Layout, Main, Box, Grid, GridItem } from '@strapi/design-system';
|
|
13
13
|
import useLicenseLimitNotification from 'ee_else_ce/hooks/useLicenseLimitNotification';
|
|
14
|
+
|
|
14
15
|
import cornerOrnamentPath from './assets/corner-ornament.svg';
|
|
15
|
-
import {
|
|
16
|
+
import { useContentTypes } from '../../hooks/useContentTypes';
|
|
16
17
|
import isGuidedTourCompleted from '../../components/GuidedTour/utils/isGuidedTourCompleted';
|
|
17
18
|
import GuidedTourHomepage from '../../components/GuidedTour/Homepage';
|
|
18
19
|
import SocialLinks from './SocialLinks';
|
|
@@ -31,7 +32,7 @@ const LogoContainer = styled(Box)`
|
|
|
31
32
|
|
|
32
33
|
const HomePage = () => {
|
|
33
34
|
// Temporary until we develop the menu API
|
|
34
|
-
const { collectionTypes, singleTypes, isLoading: isLoadingForModels } =
|
|
35
|
+
const { collectionTypes, singleTypes, isLoading: isLoadingForModels } = useContentTypes();
|
|
35
36
|
const { guidedTourState, isGuidedTourVisible, isSkipped } = useGuidedTour();
|
|
36
37
|
useLicenseLimitNotification();
|
|
37
38
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
|
-
import { useNotification, useTracking } from '@strapi/helper-plugin';
|
|
4
|
+
import { useNotification, useTracking, useClipboard } from '@strapi/helper-plugin';
|
|
5
5
|
import { Box, Icon, Typography } from '@strapi/design-system';
|
|
6
6
|
import { Check } from '@strapi/icons';
|
|
7
7
|
import CardButton from './CardButton';
|
|
@@ -17,14 +17,18 @@ const InstallPluginButton = ({
|
|
|
17
17
|
const toggleNotification = useNotification();
|
|
18
18
|
const { formatMessage } = useIntl();
|
|
19
19
|
const { trackUsage } = useTracking();
|
|
20
|
+
const { copy } = useClipboard();
|
|
20
21
|
|
|
21
|
-
const handleCopy = () => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const handleCopy = async () => {
|
|
23
|
+
const didCopy = await copy(commandToCopy);
|
|
24
|
+
|
|
25
|
+
if (didCopy) {
|
|
26
|
+
trackUsage('willInstallPlugin');
|
|
27
|
+
toggleNotification({
|
|
28
|
+
type: 'success',
|
|
29
|
+
message: { id: 'admin.pages.MarketPlacePage.plugin.copy.success' },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
// Already installed
|
|
@@ -1,44 +1,46 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
|
-
import { ContentBox, useNotification, useTracking } from '@strapi/helper-plugin';
|
|
3
|
+
import { ContentBox, useNotification, useTracking, useClipboard } from '@strapi/helper-plugin';
|
|
4
4
|
import { IconButton } from '@strapi/design-system';
|
|
5
5
|
import { Duplicate, Key } from '@strapi/icons';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
|
-
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
|
8
7
|
|
|
9
8
|
const TokenBox = ({ token, tokenType }) => {
|
|
10
9
|
const { formatMessage } = useIntl();
|
|
11
10
|
const toggleNotification = useNotification();
|
|
12
11
|
const { trackUsage } = useTracking();
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
const { copy } = useClipboard();
|
|
14
|
+
|
|
15
|
+
const handleClick = (token) => async () => {
|
|
16
|
+
const didCopy = await copy(token);
|
|
17
|
+
|
|
18
|
+
if (didCopy) {
|
|
19
|
+
trackUsage.current('didCopyTokenKey', {
|
|
20
|
+
tokenType,
|
|
21
|
+
});
|
|
22
|
+
toggleNotification({
|
|
23
|
+
type: 'success',
|
|
24
|
+
message: { id: 'Settings.tokens.notification.copied' },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
14
28
|
|
|
15
29
|
return (
|
|
16
30
|
<ContentBox
|
|
17
31
|
endAction={
|
|
18
32
|
token && (
|
|
19
33
|
<span style={{ alignSelf: 'start' }}>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
text={token}
|
|
31
|
-
>
|
|
32
|
-
<IconButton
|
|
33
|
-
label={formatMessage({
|
|
34
|
-
id: 'app.component.CopyToClipboard.label',
|
|
35
|
-
defaultMessage: 'Copy to clipboard',
|
|
36
|
-
})}
|
|
37
|
-
noBorder
|
|
38
|
-
icon={<Duplicate />}
|
|
39
|
-
style={{ padding: 0, height: '1rem' }}
|
|
40
|
-
/>
|
|
41
|
-
</CopyToClipboard>
|
|
34
|
+
<IconButton
|
|
35
|
+
label={formatMessage({
|
|
36
|
+
id: 'app.component.CopyToClipboard.label',
|
|
37
|
+
defaultMessage: 'Copy to clipboard',
|
|
38
|
+
})}
|
|
39
|
+
onClick={handleClick(token)}
|
|
40
|
+
noBorder
|
|
41
|
+
icon={<Duplicate />}
|
|
42
|
+
style={{ padding: 0, height: '1rem' }}
|
|
43
|
+
/>
|
|
42
44
|
</span>
|
|
43
45
|
)
|
|
44
46
|
}
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
LoadingIndicatorPage,
|
|
18
18
|
Link,
|
|
19
19
|
} from '@strapi/helper-plugin';
|
|
20
|
-
import { useQuery } from 'react-query';
|
|
21
20
|
import { Formik } from 'formik';
|
|
22
21
|
import {
|
|
23
22
|
Box,
|
|
@@ -32,11 +31,13 @@ import {
|
|
|
32
31
|
} from '@strapi/design-system';
|
|
33
32
|
import { ArrowLeft, Check } from '@strapi/icons';
|
|
34
33
|
import MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink';
|
|
34
|
+
|
|
35
35
|
import { formatAPIErrors, getFullName } from '../../../../../utils';
|
|
36
|
-
import {
|
|
36
|
+
import { putUser } from './utils/api';
|
|
37
37
|
import layout from './utils/layout';
|
|
38
38
|
import { editValidation } from '../utils/validations/users';
|
|
39
39
|
import SelectRoles from '../components/SelectRoles';
|
|
40
|
+
import { useAdminUsers } from '../../../../../hooks/useAdminUsers';
|
|
40
41
|
|
|
41
42
|
const fieldsToPick = ['email', 'firstname', 'lastname', 'username', 'isActive', 'roles'];
|
|
42
43
|
|
|
@@ -51,26 +52,35 @@ const EditPage = ({ canUpdate }) => {
|
|
|
51
52
|
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
52
53
|
useFocusWhenNavigate();
|
|
53
54
|
|
|
54
|
-
const {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const {
|
|
56
|
+
users: [user],
|
|
57
|
+
isLoading,
|
|
58
|
+
} = useAdminUsers(
|
|
59
|
+
{ id },
|
|
60
|
+
{
|
|
61
|
+
onError(error) {
|
|
62
|
+
const { status } = error.response;
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
// Redirect the use to the homepage if is not allowed to read
|
|
65
|
+
if (status === 403) {
|
|
66
|
+
toggleNotification({
|
|
67
|
+
type: 'info',
|
|
68
|
+
message: {
|
|
69
|
+
id: 'notification.permission.not-allowed-read',
|
|
70
|
+
defaultMessage: 'You are not allowed to see this document',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
68
73
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
push('/');
|
|
75
|
+
} else {
|
|
76
|
+
toggleNotification({
|
|
77
|
+
type: 'warning',
|
|
78
|
+
message: { id: 'notification.error', defaultMessage: 'An error occured' },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
);
|
|
74
84
|
|
|
75
85
|
const handleSubmit = async (body, actions) => {
|
|
76
86
|
lockApp();
|
|
@@ -113,19 +123,18 @@ const EditPage = ({ canUpdate }) => {
|
|
|
113
123
|
unlockApp();
|
|
114
124
|
};
|
|
115
125
|
|
|
116
|
-
const isLoading = status !== 'success';
|
|
117
126
|
const headerLabel = isLoading
|
|
118
127
|
? { id: 'app.containers.Users.EditPage.header.label-loading', defaultMessage: 'Edit user' }
|
|
119
128
|
: { id: 'app.containers.Users.EditPage.header.label', defaultMessage: 'Edit {name}' };
|
|
120
129
|
|
|
121
|
-
const initialData = Object.keys(pick(
|
|
130
|
+
const initialData = Object.keys(pick(user, fieldsToPick)).reduce((acc, current) => {
|
|
122
131
|
if (current === 'roles') {
|
|
123
|
-
acc[current] = (
|
|
132
|
+
acc[current] = (user?.roles || []).map(({ id }) => id);
|
|
124
133
|
|
|
125
134
|
return acc;
|
|
126
135
|
}
|
|
127
136
|
|
|
128
|
-
acc[current] =
|
|
137
|
+
acc[current] = user?.[current];
|
|
129
138
|
|
|
130
139
|
return acc;
|
|
131
140
|
}, {});
|
|
@@ -138,6 +147,7 @@ const EditPage = ({ canUpdate }) => {
|
|
|
138
147
|
if (isLoading) {
|
|
139
148
|
return (
|
|
140
149
|
<Main aria-busy="true">
|
|
150
|
+
{/* TODO: translate */}
|
|
141
151
|
<SettingsPageTitle name="Users" />
|
|
142
152
|
<HeaderLayout
|
|
143
153
|
primaryAction={
|
|
@@ -200,9 +210,9 @@ const EditPage = ({ canUpdate }) => {
|
|
|
200
210
|
}
|
|
201
211
|
/>
|
|
202
212
|
<ContentLayout>
|
|
203
|
-
{
|
|
213
|
+
{user?.registrationToken && (
|
|
204
214
|
<Box paddingBottom={6}>
|
|
205
|
-
<MagicLink registrationToken={
|
|
215
|
+
<MagicLink registrationToken={user.registrationToken} />
|
|
206
216
|
</Box>
|
|
207
217
|
)}
|
|
208
218
|
<Flex direction="column" alignItems="stretch" gap={7}>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { getFetchClient } from '@strapi/helper-plugin';
|
|
2
2
|
|
|
3
|
-
const fetchUser = async (id) => {
|
|
4
|
-
const { get } = getFetchClient();
|
|
5
|
-
const { data } = await get(`/admin/users/${id}`);
|
|
6
|
-
|
|
7
|
-
return data.data;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
3
|
const putUser = async (id, body) => {
|
|
11
4
|
const { put } = getFetchClient();
|
|
12
5
|
|
|
@@ -15,4 +8,4 @@ const putUser = async (id, body) => {
|
|
|
15
8
|
return data.data;
|
|
16
9
|
};
|
|
17
10
|
|
|
18
|
-
export {
|
|
11
|
+
export { putUser };
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
Flex,
|
|
16
16
|
Typography,
|
|
17
17
|
} from '@strapi/design-system';
|
|
18
|
-
|
|
19
18
|
import { Formik } from 'formik';
|
|
20
19
|
import {
|
|
21
20
|
Form,
|
|
@@ -24,20 +23,21 @@ import {
|
|
|
24
23
|
useOverlayBlocker,
|
|
25
24
|
useFetchClient,
|
|
26
25
|
} from '@strapi/helper-plugin';
|
|
27
|
-
import {
|
|
26
|
+
import { useMutation } from 'react-query';
|
|
27
|
+
|
|
28
28
|
import formDataModel from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/formDataModel';
|
|
29
29
|
import roleSettingsForm from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/roleSettingsForm';
|
|
30
30
|
import MagicLink from 'ee_else_ce/pages/SettingsPage/pages/Users/components/MagicLink';
|
|
31
|
+
|
|
31
32
|
import SelectRoles from '../../components/SelectRoles';
|
|
32
33
|
import layout from './utils/layout';
|
|
33
34
|
import schema from './utils/schema';
|
|
34
35
|
import stepper from './utils/stepper';
|
|
35
36
|
|
|
36
|
-
const ModalForm = ({
|
|
37
|
+
const ModalForm = ({ onSuccess, onToggle }) => {
|
|
37
38
|
const [currentStep, setStep] = useState('create');
|
|
38
39
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
39
40
|
const [registrationToken, setRegistrationToken] = useState(null);
|
|
40
|
-
const queryClient = useQueryClient();
|
|
41
41
|
const { formatMessage } = useIntl();
|
|
42
42
|
const toggleNotification = useNotification();
|
|
43
43
|
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
@@ -50,8 +50,7 @@ const ModalForm = ({ queryName, onToggle }) => {
|
|
|
50
50
|
async onSuccess({ data }) {
|
|
51
51
|
setRegistrationToken(data.data.registrationToken);
|
|
52
52
|
|
|
53
|
-
await
|
|
54
|
-
await queryClient.refetchQueries(['ee', 'license-limit-info']);
|
|
53
|
+
await onSuccess();
|
|
55
54
|
|
|
56
55
|
goNext();
|
|
57
56
|
setIsSubmitting(false);
|
|
@@ -216,7 +215,7 @@ const ModalForm = ({ queryName, onToggle }) => {
|
|
|
216
215
|
|
|
217
216
|
ModalForm.propTypes = {
|
|
218
217
|
onToggle: PropTypes.func.isRequired,
|
|
219
|
-
|
|
218
|
+
onSuccess: PropTypes.func.isRequired,
|
|
220
219
|
};
|
|
221
220
|
|
|
222
221
|
export default ModalForm;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
+
import qs from 'qs';
|
|
2
3
|
import {
|
|
3
4
|
DynamicTable,
|
|
4
5
|
SearchURLQuery,
|
|
@@ -8,29 +9,28 @@ import {
|
|
|
8
9
|
useFocusWhenNavigate,
|
|
9
10
|
NoPermissions,
|
|
10
11
|
useAPIErrorHandler,
|
|
12
|
+
useFetchClient,
|
|
11
13
|
} from '@strapi/helper-plugin';
|
|
12
|
-
import {
|
|
13
|
-
ActionLayout,
|
|
14
|
-
ContentLayout,
|
|
15
|
-
HeaderLayout,
|
|
16
|
-
Main,
|
|
17
|
-
useNotifyAT,
|
|
18
|
-
} from '@strapi/design-system';
|
|
14
|
+
import { ActionLayout, ContentLayout, HeaderLayout, Main } from '@strapi/design-system';
|
|
19
15
|
import { useLocation } from 'react-router-dom';
|
|
20
16
|
import { useIntl } from 'react-intl';
|
|
21
|
-
import { useMutation,
|
|
17
|
+
import { useMutation, useQueryClient } from 'react-query';
|
|
22
18
|
import CreateAction from 'ee_else_ce/pages/SettingsPage/pages/Users/ListPage/CreateAction';
|
|
23
19
|
import useLicenseLimitNotification from 'ee_else_ce/hooks/useLicenseLimitNotification';
|
|
20
|
+
|
|
21
|
+
import { useAdminUsers } from '../../../../../hooks/useAdminUsers';
|
|
24
22
|
import adminPermissions from '../../../../../permissions';
|
|
25
23
|
import TableRows from './DynamicTable/TableRows';
|
|
26
24
|
import Filters from '../../../components/Filters';
|
|
27
25
|
import ModalForm from './ModalForm';
|
|
28
26
|
import PaginationFooter from './PaginationFooter';
|
|
29
|
-
import { deleteData, fetchData } from './utils/api';
|
|
30
27
|
import displayedFilters from './utils/displayedFilters';
|
|
31
28
|
import tableHeaders from './utils/tableHeaders';
|
|
32
29
|
|
|
30
|
+
const EE_LICENSE_LIMIT_QUERY_KEY = ['ee', 'license-limit-info'];
|
|
31
|
+
|
|
33
32
|
const ListPage = () => {
|
|
33
|
+
const { post } = useFetchClient();
|
|
34
34
|
const { formatAPIError } = useAPIErrorHandler();
|
|
35
35
|
const [isModalOpened, setIsModalOpen] = useState(false);
|
|
36
36
|
const {
|
|
@@ -42,8 +42,15 @@ const ListPage = () => {
|
|
|
42
42
|
const { search } = useLocation();
|
|
43
43
|
useFocusWhenNavigate();
|
|
44
44
|
useLicenseLimitNotification();
|
|
45
|
-
const {
|
|
46
|
-
|
|
45
|
+
const {
|
|
46
|
+
users,
|
|
47
|
+
pagination,
|
|
48
|
+
isError,
|
|
49
|
+
isLoading,
|
|
50
|
+
refetchQueries: refetchAdminUsers,
|
|
51
|
+
} = useAdminUsers(qs.parse(search, { ignoreQueryPrefix: true }), {
|
|
52
|
+
enabled: canRead,
|
|
53
|
+
});
|
|
47
54
|
|
|
48
55
|
const headers = tableHeaders.map((header) => ({
|
|
49
56
|
...header,
|
|
@@ -58,59 +65,33 @@ const ListPage = () => {
|
|
|
58
65
|
defaultMessage: 'Users',
|
|
59
66
|
});
|
|
60
67
|
|
|
61
|
-
const notifyLoad = () => {
|
|
62
|
-
notifyStatus(
|
|
63
|
-
formatMessage(
|
|
64
|
-
{
|
|
65
|
-
id: 'app.utils.notify.data-loaded',
|
|
66
|
-
defaultMessage: 'The {target} has loaded',
|
|
67
|
-
},
|
|
68
|
-
{ target: title }
|
|
69
|
-
)
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const { status, data, isFetching } = useQuery(queryName, () => fetchData(search, notifyLoad), {
|
|
74
|
-
enabled: canRead,
|
|
75
|
-
retry: false,
|
|
76
|
-
onError(error) {
|
|
77
|
-
toggleNotification({
|
|
78
|
-
type: 'warning',
|
|
79
|
-
message: {
|
|
80
|
-
id: 'notification.error',
|
|
81
|
-
message: formatAPIError(error),
|
|
82
|
-
defaultMessage: 'An error occured',
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
|
|
88
68
|
const handleToggle = () => {
|
|
89
69
|
setIsModalOpen((prev) => !prev);
|
|
90
70
|
};
|
|
91
71
|
|
|
92
|
-
const deleteAllMutation = useMutation(
|
|
93
|
-
async
|
|
94
|
-
await
|
|
95
|
-
|
|
96
|
-
// Toggle enabled/ disabled state on the invite button
|
|
97
|
-
await queryClient.refetchQueries(['ee', 'license-limit-info']);
|
|
72
|
+
const deleteAllMutation = useMutation(
|
|
73
|
+
async (ids) => {
|
|
74
|
+
await post('/admin/users/batch-delete', { ids });
|
|
98
75
|
},
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
message: {
|
|
103
|
-
id: 'notification.error',
|
|
104
|
-
message: formatAPIError(error),
|
|
105
|
-
defaultMessage: 'An error occured',
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
},
|
|
109
|
-
});
|
|
76
|
+
{
|
|
77
|
+
async onSuccess() {
|
|
78
|
+
await refetchAdminUsers();
|
|
110
79
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
80
|
+
// Toggle enabled/ disabled state on the invite button
|
|
81
|
+
await queryClient.refetchQueries(EE_LICENSE_LIMIT_QUERY_KEY);
|
|
82
|
+
},
|
|
83
|
+
onError(error) {
|
|
84
|
+
toggleNotification({
|
|
85
|
+
type: 'warning',
|
|
86
|
+
message: {
|
|
87
|
+
id: 'notification.error',
|
|
88
|
+
message: formatAPIError(error),
|
|
89
|
+
defaultMessage: 'An error occured',
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
);
|
|
114
95
|
|
|
115
96
|
return (
|
|
116
97
|
<Main aria-busy={isLoading}>
|
|
@@ -141,7 +122,8 @@ const ListPage = () => {
|
|
|
141
122
|
|
|
142
123
|
<ContentLayout canRead={canRead}>
|
|
143
124
|
{!canRead && <NoPermissions />}
|
|
144
|
-
{
|
|
125
|
+
{/* TODO: Replace error message with something better */}
|
|
126
|
+
{isError && <div>TODO: An error occurred</div>}
|
|
145
127
|
{canRead && (
|
|
146
128
|
<>
|
|
147
129
|
<DynamicTable
|
|
@@ -150,23 +132,32 @@ const ListPage = () => {
|
|
|
150
132
|
onConfirmDeleteAll={deleteAllMutation.mutateAsync}
|
|
151
133
|
onConfirmDelete={(id) => deleteAllMutation.mutateAsync([id])}
|
|
152
134
|
headers={headers}
|
|
153
|
-
rows={
|
|
135
|
+
rows={users}
|
|
154
136
|
withBulkActions
|
|
155
137
|
withMainAction={canDelete}
|
|
156
138
|
>
|
|
157
139
|
<TableRows
|
|
158
140
|
canDelete={canDelete}
|
|
159
141
|
headers={headers}
|
|
160
|
-
rows={
|
|
142
|
+
rows={users}
|
|
161
143
|
withBulkActions
|
|
162
144
|
withMainAction={canDelete}
|
|
163
145
|
/>
|
|
164
146
|
</DynamicTable>
|
|
165
|
-
|
|
147
|
+
|
|
148
|
+
{pagination && <PaginationFooter pagination={pagination} />}
|
|
166
149
|
</>
|
|
167
150
|
)}
|
|
168
151
|
</ContentLayout>
|
|
169
|
-
{isModalOpened &&
|
|
152
|
+
{isModalOpened && (
|
|
153
|
+
<ModalForm
|
|
154
|
+
onSuccess={async () => {
|
|
155
|
+
await refetchAdminUsers();
|
|
156
|
+
await queryClient.refetchQueries(EE_LICENSE_LIMIT_QUERY_KEY);
|
|
157
|
+
}}
|
|
158
|
+
onToggle={handleToggle}
|
|
159
|
+
/>
|
|
160
|
+
)}
|
|
170
161
|
</Main>
|
|
171
162
|
);
|
|
172
163
|
};
|
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { IconButton } from '@strapi/design-system';
|
|
4
|
-
import { useNotification, ContentBox } from '@strapi/helper-plugin';
|
|
4
|
+
import { useNotification, ContentBox, useClipboard } from '@strapi/helper-plugin';
|
|
5
5
|
import { Duplicate } from '@strapi/icons';
|
|
6
|
-
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
|
7
6
|
import { useIntl } from 'react-intl';
|
|
8
7
|
|
|
9
8
|
const MagicLinkWrapper = ({ children, target }) => {
|
|
10
9
|
const toggleNotification = useNotification();
|
|
11
10
|
const { formatMessage } = useIntl();
|
|
12
|
-
|
|
13
|
-
const handleCopy = () => {
|
|
14
|
-
toggleNotification({ type: 'info', message: { id: 'notification.link-copied' } });
|
|
15
|
-
};
|
|
11
|
+
const { copy } = useClipboard();
|
|
16
12
|
|
|
17
13
|
const copyLabel = formatMessage({
|
|
18
14
|
id: 'app.component.CopyToClipboard.label',
|
|
19
15
|
defaultMessage: 'Copy to clipboard',
|
|
20
16
|
});
|
|
21
17
|
|
|
18
|
+
const handleClick = async () => {
|
|
19
|
+
const didCopy = await copy(target);
|
|
20
|
+
|
|
21
|
+
if (didCopy) {
|
|
22
|
+
toggleNotification({ type: 'info', message: { id: 'notification.link-copied' } });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
22
26
|
return (
|
|
23
27
|
<ContentBox
|
|
24
28
|
endAction={
|
|
25
|
-
<
|
|
26
|
-
<IconButton label={copyLabel} noBorder icon={<Duplicate />} />
|
|
27
|
-
</CopyToClipboard>
|
|
29
|
+
<IconButton label={copyLabel} noBorder icon={<Duplicate />} onClick={handleClick} />
|
|
28
30
|
}
|
|
29
31
|
title={target}
|
|
30
32
|
titleEllipsis
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { Main } from '@strapi/design-system';
|
|
15
15
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
|
16
16
|
import { useHistory, useRouteMatch } from 'react-router-dom';
|
|
17
|
-
import {
|
|
17
|
+
import { useContentTypes } from '../../../../../hooks/useContentTypes';
|
|
18
18
|
import WebhookForm from './components/WebhookForm';
|
|
19
19
|
import cleanData from './utils/formatData';
|
|
20
20
|
|
|
@@ -27,7 +27,7 @@ const EditView = () => {
|
|
|
27
27
|
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
28
28
|
const toggleNotification = useNotification();
|
|
29
29
|
const queryClient = useQueryClient();
|
|
30
|
-
const { isLoading: isLoadingForModels, collectionTypes } =
|
|
30
|
+
const { isLoading: isLoadingForModels, collectionTypes } = useContentTypes();
|
|
31
31
|
const { put, get, post } = useFetchClient();
|
|
32
32
|
|
|
33
33
|
const isCreating = id === 'create';
|
|
@@ -795,7 +795,9 @@
|
|
|
795
795
|
"content-manager.plugin.description.long": "Quick way to see, edit and delete the data in your database.",
|
|
796
796
|
"content-manager.plugin.description.short": "Quick way to see, edit and delete the data in your database.",
|
|
797
797
|
"content-manager.popUpWarning.bodyMessage.contentType.delete": "Are you sure to delete Content-Type?",
|
|
798
|
-
"content-manager.popUpWarning.bodyMessage.contentType.delete.all": "Are you sure to delete
|
|
798
|
+
"content-manager.popUpWarning.bodyMessage.contentType.delete.all": "Are you sure you want to delete these entries?",
|
|
799
|
+
"content-manager.popUpWarning.bodyMessage.contentType.publish.all": "Are you sure you want to publish these entries?",
|
|
800
|
+
"content-manager.popUpWarning.bodyMessage.contentType.unpublish.all": "Are you sure you want to unpublish these entries?",
|
|
799
801
|
"content-manager.popUpWarning.warning.has-draft-relations.title": "Confirmation",
|
|
800
802
|
"content-manager.popUpWarning.warning.publish-question": "Do you still want to publish?",
|
|
801
803
|
"content-manager.popUpWarning.warning.unpublish": "If you don't publish this content, it will automatically turn into a Draft.",
|
|
@@ -818,6 +820,8 @@
|
|
|
818
820
|
"content-manager.success.record.save": "Saved",
|
|
819
821
|
"content-manager.success.record.unpublish": "Unpublished",
|
|
820
822
|
"content-manager.utils.data-loaded": "The {number, plural, =1 {entry has} other {entries have}} successfully been loaded",
|
|
823
|
+
"content-manager.listView.validation.errors.title": "Action required",
|
|
824
|
+
"content-manager.listView.validation.errors.message": "Please make sure all fields are valid before publishing (required field, min/max character limit, etc.)",
|
|
821
825
|
"dark": "Dark",
|
|
822
826
|
"form.button.continue": "Continue",
|
|
823
827
|
"form.button.done": "Done",
|