strapi-plugin-comments 2.0.3 → 2.0.4
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/hooks/useConfig.js +11 -5
- package/admin/src/pages/Settings/components/RestartAlert/styles.js +8 -0
- package/admin/src/pages/Settings/index.js +39 -5
- package/admin/src/pages/Settings/utils/api.js +11 -1
- package/admin/src/translations/en.json +7 -0
- package/admin/src/utils/handleAPIError.js +3 -2
- package/package.json +2 -2
- package/server/controllers/admin.js +9 -0
- package/server/routes/admin.js +8 -0
- package/server/services/admin.js +5 -8
- package/server/services/client.js +2 -1
- package/server/services/common.js +1 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
|
2
|
-
import { fetchConfig, restoreConfig, updateConfig } from '../pages/Settings/utils/api';
|
|
2
|
+
import { fetchConfig, restartStrapi, restoreConfig, updateConfig } from '../pages/Settings/utils/api';
|
|
3
3
|
import pluginId from '../pluginId';
|
|
4
|
-
import { getMessage } from '../utils';
|
|
5
4
|
|
|
6
5
|
const useConfig = (toggleNotification) => {
|
|
7
6
|
const queryClient = useQueryClient();
|
|
@@ -18,8 +17,10 @@ const useConfig = (toggleNotification) => {
|
|
|
18
17
|
callback();
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
const handleSuccess = (type, callback = () => {}) => {
|
|
22
|
-
|
|
20
|
+
const handleSuccess = (type, callback = () => {}, invalidateQueries = true) => {
|
|
21
|
+
if (invalidateQueries) {
|
|
22
|
+
queryClient.invalidateQueries('get-config');
|
|
23
|
+
};
|
|
23
24
|
toggleNotification({
|
|
24
25
|
type: 'success',
|
|
25
26
|
message: `${pluginId}.page.settings.notification.${type}.success`,
|
|
@@ -37,7 +38,12 @@ const useConfig = (toggleNotification) => {
|
|
|
37
38
|
onError: () => handleError('restore'),
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
const restartMutation = useMutation(restartStrapi, {
|
|
42
|
+
onSuccess: () => handleSuccess('restart', () => {}, false),
|
|
43
|
+
onError: () => handleError('restart'),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return { fetch, restartMutation, submitMutation, restoreMutation };
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
export default useConfig;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useRef, useMemo, useState } from 'react';
|
|
2
2
|
import { useQuery } from 'react-query';
|
|
3
3
|
import { Formik } from 'formik';
|
|
4
|
-
import { capitalize, first, orderBy, isEmpty } from 'lodash';
|
|
4
|
+
import { capitalize, first, orderBy, isEmpty, isEqual } from 'lodash';
|
|
5
5
|
import {
|
|
6
6
|
CheckPermissions,
|
|
7
7
|
LoadingIndicatorPage,
|
|
@@ -27,13 +27,14 @@ import {
|
|
|
27
27
|
CardBody,
|
|
28
28
|
CardContent,
|
|
29
29
|
} from '@strapi/design-system/Card';
|
|
30
|
-
import { Check, Refresh } from '@strapi/icons';
|
|
30
|
+
import { Check, Refresh, Play } from '@strapi/icons';
|
|
31
31
|
|
|
32
32
|
import pluginPermissions from '../../permissions';
|
|
33
33
|
import useConfig from '../../hooks/useConfig';
|
|
34
34
|
import { fetchAllContentTypes, fetchRoles } from './utils/api';
|
|
35
35
|
import { getMessage, parseRegExp } from '../../utils';
|
|
36
36
|
import ConfirmationDialog from '../../components/ConfirmationDialog';
|
|
37
|
+
import { RestartAlert } from './components/RestartAlert/styles';
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
const Settings = () => {
|
|
@@ -56,8 +57,9 @@ const Settings = () => {
|
|
|
56
57
|
} = useRBAC(viewPermissions);
|
|
57
58
|
|
|
58
59
|
const [restoreConfigmationVisible, setRestoreConfigmationVisible] = useState(false);
|
|
60
|
+
const [restartRequired, setRestartRequired] = useState(false);
|
|
59
61
|
|
|
60
|
-
const { fetch, submitMutation, restoreMutation } = useConfig(toggleNotification);
|
|
62
|
+
const { fetch, restartMutation, submitMutation, restoreMutation } = useConfig(toggleNotification);
|
|
61
63
|
const { data: configData, isLoading: isConfigLoading, err: configErr } = fetch;
|
|
62
64
|
|
|
63
65
|
const { data: allCollectionsData, isLoading: areCollectionsLoading, err: collectionsErr } = useQuery(
|
|
@@ -131,7 +133,13 @@ const Settings = () => {
|
|
|
131
133
|
const handleUpdateConfiguration = async (form) => {
|
|
132
134
|
if (canChange) {
|
|
133
135
|
lockApp();
|
|
134
|
-
|
|
136
|
+
const payload = preparePayload(form);
|
|
137
|
+
await submitMutation.mutateAsync(payload);
|
|
138
|
+
const enabledCollectionsChanged = !isEqual(payload.enabledCollections, configData?.enabledCollections);
|
|
139
|
+
const gqlAuthChanged = !isEqual(payload.gql?.auth, configData?.gql?.auth);
|
|
140
|
+
if (enabledCollectionsChanged || gqlAuthChanged) {
|
|
141
|
+
setRestartRequired(true);
|
|
142
|
+
}
|
|
135
143
|
unlockApp();
|
|
136
144
|
}
|
|
137
145
|
};
|
|
@@ -142,11 +150,22 @@ const Settings = () => {
|
|
|
142
150
|
lockApp();
|
|
143
151
|
await restoreMutation.mutateAsync();
|
|
144
152
|
unlockApp();
|
|
153
|
+
setRestartRequired(true);
|
|
145
154
|
setRestoreConfigmationVisible(false);
|
|
146
155
|
}
|
|
147
156
|
};
|
|
148
157
|
const handleRestoreCancel = () => setRestoreConfigmationVisible(false);
|
|
149
158
|
|
|
159
|
+
const handleRestart = async () => {
|
|
160
|
+
if (canChange) {
|
|
161
|
+
lockApp();
|
|
162
|
+
await restartMutation.mutateAsync();
|
|
163
|
+
setRestartRequired(false);
|
|
164
|
+
unlockApp();
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const handleRestartDiscard = () => setRestartRequired(false);
|
|
168
|
+
|
|
150
169
|
const boxDefaultProps = {
|
|
151
170
|
background: "neutral0",
|
|
152
171
|
hasRadius: true,
|
|
@@ -175,7 +194,7 @@ const Settings = () => {
|
|
|
175
194
|
subtitle={getMessage('page.settings.header.description')}
|
|
176
195
|
primaryAction={
|
|
177
196
|
<CheckPermissions permissions={pluginPermissions.settingsChange}>
|
|
178
|
-
<Button type="submit" startIcon={<Check />} >
|
|
197
|
+
<Button type="submit" startIcon={<Check />} disabled={restartRequired} >
|
|
179
198
|
{getMessage('page.settings.actions.submit')}
|
|
180
199
|
</Button>
|
|
181
200
|
</CheckPermissions>
|
|
@@ -183,6 +202,15 @@ const Settings = () => {
|
|
|
183
202
|
/>
|
|
184
203
|
<ContentLayout>
|
|
185
204
|
<Stack size={6}>
|
|
205
|
+
{ restartRequired && (
|
|
206
|
+
<RestartAlert
|
|
207
|
+
closeLabel={getMessage('page.settings.actions.restart.alert.cancel')}
|
|
208
|
+
title={getMessage('page.settings.actions.restart.alert.title')}
|
|
209
|
+
action={<Box><Button onClick={handleRestart} startIcon={<Play />}>{getMessage('page.settings.actions.restart')}</Button></Box>}
|
|
210
|
+
onClose={handleRestartDiscard}>
|
|
211
|
+
{ getMessage('page.settings.actions.restart.alert.description')}
|
|
212
|
+
</RestartAlert>)}
|
|
213
|
+
|
|
186
214
|
<Box {...boxDefaultProps}>
|
|
187
215
|
<Stack size={4}>
|
|
188
216
|
<Typography variant="delta" as="h2">
|
|
@@ -198,6 +226,7 @@ const Settings = () => {
|
|
|
198
226
|
onClear={() => setFieldValue('enabledCollections', [], false)}
|
|
199
227
|
value={values.enabledCollections}
|
|
200
228
|
onChange={(value) => setFieldValue('enabledCollections', value, false)}
|
|
229
|
+
disabled={restartRequired}
|
|
201
230
|
multi
|
|
202
231
|
withTags
|
|
203
232
|
>
|
|
@@ -214,6 +243,7 @@ const Settings = () => {
|
|
|
214
243
|
onClear={() => setFieldValue('moderatorRoles', [], false)}
|
|
215
244
|
value={values.moderatorRoles}
|
|
216
245
|
onChange={(value) => setFieldValue('moderatorRoles', value, false)}
|
|
246
|
+
disabled={restartRequired}
|
|
217
247
|
multi
|
|
218
248
|
withTags
|
|
219
249
|
>
|
|
@@ -230,6 +260,7 @@ const Settings = () => {
|
|
|
230
260
|
onChange={({ target: { checked } }) => setFieldValue('badWords', checked, false)}
|
|
231
261
|
onLabel={getMessage('compontents.toogle.enabled')}
|
|
232
262
|
offLabel={getMessage('compontents.toogle.disabled')}
|
|
263
|
+
disabled={restartRequired}
|
|
233
264
|
/>
|
|
234
265
|
</GridItem>
|
|
235
266
|
{ isGQLPluginEnabled && (<GridItem col={6} xs={12}>
|
|
@@ -241,6 +272,7 @@ const Settings = () => {
|
|
|
241
272
|
onChange={({ target: { checked } }) => setFieldValue('gqlAuthEnabled', checked, false)}
|
|
242
273
|
onLabel={getMessage('compontents.toogle.enabled')}
|
|
243
274
|
offLabel={getMessage('compontents.toogle.disabled')}
|
|
275
|
+
disabled={restartRequired}
|
|
244
276
|
/>
|
|
245
277
|
</GridItem>) }
|
|
246
278
|
</Grid>
|
|
@@ -272,6 +304,7 @@ const Settings = () => {
|
|
|
272
304
|
onChange={({ target: { checked } }) => setFieldValue('approvalFlow', changeApprovalFlowFor(uid, values.approvalFlow, checked), [])}
|
|
273
305
|
onLabel={getMessage('compontents.toogle.enabled')}
|
|
274
306
|
offLabel={getMessage('compontents.toogle.disabled')}
|
|
307
|
+
disabled={restartRequired}
|
|
275
308
|
/>
|
|
276
309
|
{ !isEmpty(stringAttributes) && (<Select
|
|
277
310
|
name={`collectionSettings-${uid}-entryLabel`}
|
|
@@ -283,6 +316,7 @@ const Settings = () => {
|
|
|
283
316
|
onChange={(value) => setFieldValue('entryLabel', changeEntryLabelFor(uid, values.entryLabel, value))}
|
|
284
317
|
multi
|
|
285
318
|
withTags
|
|
319
|
+
disabled={restartRequired}
|
|
286
320
|
>
|
|
287
321
|
{ stringAttributes.map(key =>
|
|
288
322
|
(<Option key={`collectionSettings-${uid}-entryLabel-${key}`} value={key}>{ capitalize(key.split('_').join(' ')) }</Option>))}
|
|
@@ -7,7 +7,7 @@ export const fetchConfig = async (toggleNotification) => {
|
|
|
7
7
|
|
|
8
8
|
return data;
|
|
9
9
|
} catch (err) {
|
|
10
|
-
handleAPIError(err, toggleNotification);
|
|
10
|
+
handleAPIError(err, toggleNotification, 'page.settings.notification.fetch.error');
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
13
|
|
|
@@ -43,6 +43,16 @@ export const fetchAllContentTypes = async (toggleNotification) => {
|
|
|
43
43
|
export const fetchRoles = async (toggleNotification) => {
|
|
44
44
|
try {
|
|
45
45
|
const { data } = await axiosInstance.get(`/admin/roles`);
|
|
46
|
+
return data;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
handleAPIError(err, toggleNotification);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const restartStrapi = async (toggleNotification) => {
|
|
53
|
+
try {
|
|
54
|
+
const { data } = await axiosInstance.get(getApiURL(`settings/restart`));
|
|
55
|
+
|
|
46
56
|
return data;
|
|
47
57
|
} catch (err) {
|
|
48
58
|
handleAPIError(err, toggleNotification);
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
"page.settings.header.description": "Configure your comments moderation capabilities",
|
|
87
87
|
"page.settings.actions.submit": "Save",
|
|
88
88
|
"page.settings.actions.restore": "Restore",
|
|
89
|
+
"page.settings.actions.restart": "Restart Strapi",
|
|
89
90
|
"page.settings.section.general": "General configuration",
|
|
90
91
|
"page.settings.section.collections": "Collection(s) configuration",
|
|
91
92
|
"page.settings.section.restore": "Restore default configuration",
|
|
@@ -108,10 +109,16 @@
|
|
|
108
109
|
"page.settings.actions.restore.confirmation.header": "Restore default configuration",
|
|
109
110
|
"page.settings.actions.restore.confirmation.description": "You're about to restore plugin configuration to it default values. It might have destructive impact on already collected content. Do you really want to proceed?",
|
|
110
111
|
"page.settings.actions.restore.confirmation.button.confirm": "Yes, I want to restore",
|
|
112
|
+
"page.settings.actions.restart.alert.title": "Strapi requires restart",
|
|
113
|
+
"page.settings.actions.restart.alert.description": "You've made a configuration changes which requires your Strapi application to be restarted to take an effect in GraphQL schema. Do it manually or by using below trigger.",
|
|
114
|
+
"page.settings.actions.restart.alert.close": "Discard",
|
|
115
|
+
"page.settings.notification.fetch.error": "Failed to fetch configuration. Retrying...",
|
|
111
116
|
"page.settings.notification.submit.success": "Configuration has been saved successfully",
|
|
112
117
|
"page.settings.notification.submit.error": "Failed to save configuration. Try again.",
|
|
113
118
|
"page.settings.notification.restore.success": "Configuration has been restored successfully",
|
|
114
119
|
"page.settings.notification.restore.error": "Failed to restore configuration. Try again.",
|
|
120
|
+
"page.settings.notification.restart.success": "Application has been restarted successfully",
|
|
121
|
+
"page.settings.notification.restart.error": "Failed to restart your application. Try to do it manually.",
|
|
115
122
|
"page.settings.loading": "Fetching configuration...",
|
|
116
123
|
"compontents.confirmation.dialog.header": "Confirmation",
|
|
117
124
|
"compontents.confirmation.dialog.description": "Do you really want to perform this action?",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import pluginId from "../pluginId";
|
|
1
2
|
|
|
2
|
-
const handleAPIError = (err = null, toggleNotification = null) => {
|
|
3
|
+
const handleAPIError = (err = null, toggleNotification = null, message = 'app.components.notification.error') => {
|
|
3
4
|
toggleNotification({
|
|
4
5
|
type: 'warning',
|
|
5
|
-
message:
|
|
6
|
+
message: `${pluginId}.${message}`,
|
|
6
7
|
});
|
|
7
8
|
|
|
8
9
|
if (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-comments",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "Strapi - Comments plugin",
|
|
5
5
|
"strapi": {
|
|
6
6
|
"name": "comments",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"prepare": "husky install",
|
|
13
|
-
"publish": "npm publish --tag latest",
|
|
13
|
+
"publish:latest": "npm publish --tag latest",
|
|
14
14
|
"test:unit": "jest --verbose --coverage"
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
@@ -43,6 +43,15 @@ module.exports = {
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
|
|
46
|
+
async settingsRestart(ctx) {
|
|
47
|
+
try {
|
|
48
|
+
await this.getService().restart();
|
|
49
|
+
return ctx.send({ status: 200 });
|
|
50
|
+
} catch (e) {
|
|
51
|
+
throwError(ctx, e);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
46
55
|
async findAll(ctx) {
|
|
47
56
|
return this.getService()
|
|
48
57
|
.findAll(ctx.query);
|
package/server/routes/admin.js
CHANGED
package/server/services/admin.js
CHANGED
|
@@ -75,19 +75,16 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
|
|
|
75
75
|
|
|
76
76
|
async restoreConfig() {
|
|
77
77
|
const pluginStore = await this.getCommonService().getPluginStore();
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
await pluginStore.delete({key: 'config'})
|
|
81
|
-
await pluginStore.set({
|
|
82
|
-
key: 'config',
|
|
83
|
-
value: {
|
|
84
|
-
...defaultConfig,
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
80
|
|
|
88
81
|
return this.config();
|
|
89
82
|
},
|
|
90
83
|
|
|
84
|
+
async restart() {
|
|
85
|
+
setImmediate(() => strapi.reload());
|
|
86
|
+
},
|
|
87
|
+
|
|
91
88
|
// Find all comments
|
|
92
89
|
async findAll({ related, entity, ...query }) {
|
|
93
90
|
const { _q, orderBy, pageSize = 10, page = 1, filters, ...rest } = parseParams(query);
|
|
@@ -38,7 +38,8 @@ module.exports = ({ strapi }) => ({
|
|
|
38
38
|
throw new PluginError(400, `Relation for field "related" does not exist. Check your payload please.`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const
|
|
41
|
+
const approvalFlow = await this.getCommonService().getConfig(CONFIG_PARAMS.APPROVAL_FLOW, []);
|
|
42
|
+
const isApprovalFlowEnabled = approvalFlow.includes(uid) ||
|
|
42
43
|
relatedEntity.requireCommentsApproval;
|
|
43
44
|
|
|
44
45
|
const linkToThread = !isNil(threadOf) ? await this.getCommonService().findOne({
|
|
@@ -26,7 +26,7 @@ module.exports = ({ strapi }) => ({
|
|
|
26
26
|
|
|
27
27
|
let result;
|
|
28
28
|
if (config && !useLocal) {
|
|
29
|
-
result = queryProp ? get(config, queryProp) : config
|
|
29
|
+
result = queryProp ? get(config, queryProp, defaultValue) : config;
|
|
30
30
|
} else {
|
|
31
31
|
result = this.getLocalConfig(queryProp, defaultValue);
|
|
32
32
|
}
|