strapi-plugin-navigation 2.0.1 → 2.0.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.
@@ -0,0 +1,311 @@
1
+ import React, { useState } from 'react';
2
+ import { Formik } from 'formik';
3
+ import { isEmpty, capitalize, isEqual } from 'lodash';
4
+
5
+ import {
6
+ CheckPermissions,
7
+ LoadingIndicatorPage,
8
+ Form,
9
+ useOverlayBlocker,
10
+ useAutoReloadOverlayBlocker,
11
+ } from '@strapi/helper-plugin';
12
+ import { Main } from '@strapi/design-system/Main';
13
+ import { ContentLayout, HeaderLayout } from '@strapi/design-system/Layout';
14
+ import { Button } from '@strapi/design-system/Button';
15
+ import { Box } from '@strapi/design-system/Box';
16
+ import { Stack } from '@strapi/design-system/Stack';
17
+ import { Typography } from '@strapi/design-system/Typography';
18
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
19
+ import { ToggleInput } from '@strapi/design-system/ToggleInput';
20
+ import { NumberInput } from '@strapi/design-system/NumberInput';
21
+ import { Select, Option } from '@strapi/design-system/Select';
22
+ import { Check, Refresh, Play } from '@strapi/icons';
23
+ import { SettingsPageTitle } from '@strapi/helper-plugin';
24
+ import {
25
+ Card,
26
+ CardBody,
27
+ CardContent,
28
+ } from '@strapi/design-system/Card';
29
+
30
+ import permissions from '../../permissions';
31
+ import useNavigationConfig from '../../hooks/useNavigationConfig';
32
+ import useAllContentTypes from '../../hooks/useAllContentTypes';
33
+ import { navigationItemAdditionalFields } from '../View/utils/enums';
34
+ import ConfirmationDialog from '../../components/ConfirmationDialog';
35
+ import RestartAlert from '../../components/RestartAlert';
36
+ import { getMessage } from '../../utils';
37
+
38
+ const SettingsPage = () => {
39
+ const { lockApp, unlockApp } = useOverlayBlocker();
40
+ const { lockAppWithAutoreload, unlockAppWithAutoreload } = useAutoReloadOverlayBlocker();
41
+ const [isRestorePopupOpen, setIsRestorePopupOpen] = useState(false);
42
+ const [isRestartRequired, setIsRestartRequired] = useState(false);
43
+ const { data: navigationConfigData, isLoading: isConfigLoading, err: configErr, submitMutation, restoreMutation, restartMutation } = useNavigationConfig();
44
+ const { data: allContentTypesData, isLoading: isContentTypesLoading, err: contentTypesErr } = useAllContentTypes();
45
+ const isLoading = isConfigLoading || isContentTypesLoading;
46
+ const isError = configErr || contentTypesErr;
47
+
48
+ const preparePayload = ({ selectedContentTypes, nameFields, audienceFieldChecked, allowedLevels }) => ({
49
+ contentTypes: selectedContentTypes,
50
+ contentTypesNameFields: nameFields,
51
+ additionalFields: audienceFieldChecked ? [navigationItemAdditionalFields.AUDIENCE] : [],
52
+ allowedLevels: allowedLevels,
53
+ gql: {
54
+ navigationItemRelated: selectedContentTypes.map(uid => allContentTypes.find(ct => ct.uid === uid).info.displayName)
55
+ }
56
+ })
57
+ const onSave = async (form) => {
58
+ lockApp();
59
+ const payload = preparePayload(form);
60
+ await submitMutation({ body: payload });
61
+ const isContentTypesChanged = !isEqual(payload.contentTypes, navigationConfigData.contentTypes);
62
+ if (isContentTypesChanged && navigationConfigData.isGQLPluginEnabled) {
63
+ setIsRestartRequired(true);
64
+ }
65
+ unlockApp();
66
+ }
67
+
68
+ const onPopupClose = async (isConfirmed) => {
69
+ setIsRestorePopupOpen(false);
70
+ if (isConfirmed) {
71
+ lockApp();
72
+ await restoreMutation();
73
+ unlockApp();
74
+ setIsRestartRequired(true);
75
+ }
76
+ }
77
+
78
+ const handleRestart = async () => {
79
+ lockAppWithAutoreload();
80
+ await restartMutation();
81
+ setIsRestartRequired(false);
82
+ unlockAppWithAutoreload();
83
+ };
84
+ const handleRestartDiscard = () => setIsRestartRequired(false);
85
+
86
+ const prepareNameFieldFor = (uid, current, value) => ({
87
+ ...current,
88
+ [uid]: value && !isEmpty(value) ? [...value] : undefined,
89
+ });
90
+
91
+ if (isLoading || isError) {
92
+ return (
93
+ <>
94
+ <SettingsPageTitle
95
+ name={getMessage('Settings.email.plugin.title', 'Configuration')}
96
+ />
97
+ <LoadingIndicatorPage>
98
+ Fetching plugin config...
99
+ </LoadingIndicatorPage>
100
+ </>
101
+ )
102
+ }
103
+
104
+ const allContentTypes = !isLoading && Object.values(allContentTypesData).filter(item => item.uid.includes('api::'));
105
+ const selectedContentTypes = navigationConfigData?.contentTypes.map(item => item.uid);
106
+ const audienceFieldChecked = navigationConfigData?.additionalFields.includes(navigationItemAdditionalFields.AUDIENCE);
107
+ const allowedLevels = navigationConfigData?.allowedLevels;
108
+ const nameFields = navigationConfigData?.contentTypesNameFields
109
+
110
+ return (
111
+ <>
112
+ <SettingsPageTitle
113
+ name={getMessage('Settings.email.plugin.title', 'Configuration')}
114
+ />
115
+ <Main labelledBy="title">
116
+ <Formik
117
+ initialValues={{
118
+ selectedContentTypes,
119
+ audienceFieldChecked,
120
+ allowedLevels,
121
+ nameFields,
122
+ }}
123
+ onSubmit={onSave}
124
+ >
125
+ {({ handleSubmit, setFieldValue, values }) => (
126
+ <Form noValidate onSubmit={handleSubmit}>
127
+ <HeaderLayout
128
+ title={getMessage('pages.settings.header.title')}
129
+ subtitle={getMessage('pages.settings.header.description')}
130
+ primaryAction={
131
+ <CheckPermissions permissions={permissions.access}>
132
+ <Button type="submit" startIcon={<Check />} disabled={isRestartRequired}>
133
+ {getMessage('pages.settings.actions.submit')}
134
+ </Button>
135
+ </CheckPermissions>
136
+ }
137
+ />
138
+ <ContentLayout>
139
+ <Stack size={7}>
140
+ {isRestartRequired && (
141
+ <RestartAlert
142
+ closeLabel={getMessage('pages.settings.actions.restart.alert.cancel')}
143
+ title={getMessage('pages.settings.actions.restart.alert.title')}
144
+ action={<Box><Button onClick={handleRestart} startIcon={<Play />}>{getMessage('pages.settings.actions.restart')}</Button></Box>}
145
+ onClose={handleRestartDiscard}>
146
+ {getMessage('pages.settings.actions.restart.alert.description')}
147
+ </RestartAlert>)}
148
+ <Box
149
+ background="neutral0"
150
+ hasRadius
151
+ shadow="filterShadow"
152
+ padding={6}
153
+ >
154
+ <Stack size={4}>
155
+ <Typography variant="delta" as="h2">
156
+ {getMessage('pages.settings.general.title')}
157
+ </Typography>
158
+ <Grid gap={4}>
159
+ <GridItem col={12} s={12} xs={12}>
160
+ <Select
161
+ name="selectedContentTypes"
162
+ label={getMessage('pages.settings.form.contentTypes.label')}
163
+ placeholder={getMessage('pages.settings.form.contentTypes.placeholder')}
164
+ hint={getMessage('pages.settings.form.contentTypes.hint')}
165
+ onClear={() => setFieldValue('selectedContentTypes', [], false)}
166
+ value={values.selectedContentTypes}
167
+ onChange={(value) => setFieldValue('selectedContentTypes', value, false)}
168
+ multi
169
+ withTags
170
+ disabled={isRestartRequired}
171
+ >
172
+ {allContentTypes.map((item) => <Option key={item.uid} value={item.uid}>{item.info.displayName}</Option>)}
173
+ </Select>
174
+ </GridItem>
175
+ <GridItem col={3} s={6} xs={12}>
176
+ <NumberInput
177
+ name="allowedLevels"
178
+ label={getMessage('pages.settings.form.allowedLevels.label')}
179
+ placeholder={getMessage('pages.settings.form.allowedLevels.placeholder')}
180
+ hint={getMessage('pages.settings.form.allowedLevels.hint')}
181
+ onValueChange={(value) => setFieldValue('allowedLevels', value, false)}
182
+ value={values.allowedLevels}
183
+ disabled={isRestartRequired}
184
+ />
185
+ </GridItem>
186
+ </Grid>
187
+ </Stack>
188
+ </Box>
189
+ <Box
190
+ background="neutral0"
191
+ hasRadius
192
+ shadow="filterShadow"
193
+ padding={6}
194
+ >
195
+ <Stack size={4}>
196
+ <Typography variant="delta" as="h2">
197
+ {getMessage('pages.settings.additional.title')}
198
+ </Typography>
199
+ <Grid gap={4}>
200
+ <GridItem col={6} s={12} xs={12}>
201
+ <ToggleInput
202
+ name="audienceFieldChecked"
203
+ label={getMessage('pages.settings.form.audience.label')}
204
+ hint={getMessage('pages.settings.form.audience.hint')}
205
+ checked={values.audienceFieldChecked}
206
+ onChange={({ target: { checked } }) => setFieldValue('audienceFieldChecked', checked, false)}
207
+ onLabel="Enabled"
208
+ offLabel="Disabled"
209
+ disabled={isRestartRequired}
210
+ />
211
+ </GridItem>
212
+ </Grid>
213
+ </Stack>
214
+ </Box>
215
+ {!isEmpty(values.selectedContentTypes) && (
216
+ <Box
217
+ background="neutral0"
218
+ hasRadius
219
+ shadow="filterShadow"
220
+ padding={6}
221
+ >
222
+ <Stack size={4}>
223
+ <Typography variant="delta" as="h2">
224
+ {getMessage('pages.settings.nameField.title')}
225
+ </Typography>
226
+ <Grid gap={4}>
227
+ {values.selectedContentTypes.map(uid => {
228
+ const { attributes, info: { displayName } } = allContentTypes.find(item => item.uid == uid);
229
+ const stringAttributes = Object.keys(attributes).filter(_ => attributes[_].type === 'string');
230
+
231
+ return !isEmpty(stringAttributes) && (
232
+ <GridItem key={`collectionSettings-${uid}`} col={6} s={12} xs={12}>
233
+ <Card background="primary100" borderColor="primary200">
234
+ <CardBody>
235
+ <CardContent style={{ width: '100%' }}>
236
+ <Stack size={4}>
237
+ <Typography variant="epsilon" fontWeight="semibold" as="h3">{displayName}</Typography>
238
+ <Select
239
+ name={`collectionSettings-${uid}-entryLabel`}
240
+ label={getMessage('pages.settings.form.nameField.label')}
241
+ hint={getMessage('pages.settings.form.nameField.hint')}
242
+ placeholder={getMessage('pages.settings.form.nameField.placeholder')}
243
+ onClear={() => null}
244
+ value={values.nameFields[uid] || []}
245
+ onChange={(value) => setFieldValue('nameFields', prepareNameFieldFor(uid, values.nameFields, value))}
246
+ multi
247
+ withTags
248
+ disabled={isRestartRequired}
249
+ >
250
+ {stringAttributes.map(key =>
251
+ (<Option key={uid + key} value={key}>{capitalize(key.split('_').join(' '))}</Option>))}
252
+ </Select>
253
+ </Stack>
254
+ </CardContent>
255
+ </CardBody>
256
+ </Card>
257
+ </GridItem>
258
+ );
259
+ })
260
+ }
261
+ </Grid>
262
+ </Stack>
263
+ </Box>
264
+ )}
265
+ <Box
266
+ background="neutral0"
267
+ hasRadius
268
+ shadow="filterShadow"
269
+ padding={6}
270
+ >
271
+ <Stack size={4}>
272
+ <Typography variant="delta" as="h2">
273
+ {getMessage('pages.settings.restoring.title')}
274
+ </Typography>
275
+ <Grid gap={4}>
276
+ <GridItem col={12} s={12} xs={12}>
277
+ <Typography>
278
+ {getMessage('pages.settings.actions.restore.description')}
279
+ </Typography>
280
+ </GridItem>
281
+ <GridItem col={6} s={12} xs={12}>
282
+ <CheckPermissions permissions={permissions.access}>
283
+ <Button variant="danger-light" startIcon={<Refresh />} onClick={() => setIsRestorePopupOpen(true)}>
284
+ {getMessage('pages.settings.actions.restore')}
285
+ </Button>
286
+ </CheckPermissions>
287
+ <ConfirmationDialog
288
+ isVisible={isRestorePopupOpen}
289
+ header={getMessage('pages.settings.actions.restore.confirmation.header')}
290
+ labelConfirm={getMessage('pages.settings.actions.restore.confirmation.confirm')}
291
+ iconConfirm={<Refresh />}
292
+ onConfirm={() => onPopupClose(true)}
293
+ onCancel={() => onPopupClose(false)}>
294
+ {getMessage('pages.settings.actions.restore.confirmation.description')}
295
+ </ConfirmationDialog>
296
+ </GridItem>
297
+ </Grid>
298
+ </Stack>
299
+ </Box>
300
+ </Stack>
301
+ </ContentLayout>
302
+ </Form>
303
+ )}
304
+ </Formik>
305
+ </Main>
306
+ </>
307
+ );
308
+ }
309
+
310
+
311
+ export default SettingsPage;
@@ -1,5 +1,4 @@
1
1
  import React, { useEffect, useMemo, useState, useCallback } from 'react';
2
- import { useIntl } from 'react-intl';
3
2
  import { debounce, find, get, isEmpty, isEqual, isNil, isString } from 'lodash';
4
3
  import PropTypes from 'prop-types';
5
4
  import { Formik } from 'formik'
@@ -18,7 +17,8 @@ import slugify from 'slugify';
18
17
  import { extractRelatedItemLabel } from '../../utils/parsers';
19
18
  import { form as formDefinition } from './utils/form';
20
19
  import { checkFormValidity } from '../../utils/form';
21
- import { getTradId, getTrad } from '../../../../translations';
20
+ import { getTradId } from '../../../../translations';
21
+ import { getMessage } from '../../../../utils';
22
22
 
23
23
  const NavigationItemForm = ({
24
24
  isLoading,
@@ -43,7 +43,6 @@ const NavigationItemForm = ({
43
43
  const [form, setFormState] = useState({});
44
44
  const [formErrors, setFormErrorsState] = useState({});
45
45
  const { relatedType } = form;
46
- const { formatMessage } = useIntl();
47
46
 
48
47
  const relatedFieldName = `${inputsPrefix}related`;
49
48
 
@@ -397,8 +396,8 @@ const NavigationItemForm = ({
397
396
  <GridItem key={`${inputsPrefix}audience`} col={6} lg={12}>
398
397
  <Select
399
398
  id={`${inputsPrefix}audience`}
400
- placeholder={formatMessage(getTrad('popup.item.form.audience.placeholder'))}
401
- label={formatMessage(getTrad('popup.item.form.audience.label'))}
399
+ placeholder={getMessage('popup.item.form.audience.placeholder')}
400
+ label={getMessage('popup.item.form.audience.label')}
402
401
  onChange={onAudienceChange}
403
402
  value={audience}
404
403
  multi
@@ -1,25 +1,22 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { useIntl } from 'react-intl';
4
3
 
5
4
  import { Button } from '@strapi/design-system/Button';
6
5
  import { ModalFooter } from '@strapi/design-system/ModalLayout';
7
-
8
- import { getTrad } from '../../../../translations';
6
+ import { getMessage } from '../../../../utils';
9
7
 
10
8
  export const NavigationItemPopupFooter = ({ handleCancel, handleSubmit, submitDisabled, formViewId }) => {
11
- const { formatMessage } = useIntl();
12
9
 
13
10
  return (
14
11
  <ModalFooter
15
12
  startActions={
16
13
  <Button onClick={handleCancel} variant="tertiary">
17
- {formatMessage(getTrad('popup.item.form.button.cancel'))}
14
+ {getMessage('popup.item.form.button.cancel')}
18
15
  </Button>
19
16
  }
20
17
  endActions={
21
18
  <Button onClick={handleSubmit} disabled={submitDisabled}>
22
- {formatMessage(getTrad(`popup.item.form.button.save`))}
19
+ {getMessage(`popup.item.form.button.save`)}
23
20
  </Button>
24
21
  }
25
22
  />
@@ -3,15 +3,13 @@
3
3
  import React from 'react';
4
4
  import { ButtonText } from '@strapi/design-system/Text';
5
5
  import { ModalHeader } from '@strapi/design-system/ModalLayout';
6
- import { useIntl } from 'react-intl';
7
- import { getTrad } from '../../../../translations';
6
+ import { getMessage } from '../../../../utils';
8
7
 
9
8
  export const NavigationItemPopupHeader = ({isNewItem}) => {
10
- const { formatMessage } = useIntl();
11
9
  return (
12
10
  <ModalHeader>
13
11
  <ButtonText textColor="neutral800" as="h2" id="asset-dialog-title">
14
- {formatMessage(getTrad(`popup.item.header.${isNewItem ? 'new' : 'edit'}`))}
12
+ {getMessage(`popup.item.header.${isNewItem ? 'new' : 'edit'}`)}
15
13
  </ButtonText>
16
14
  </ModalHeader>
17
15
  );
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  import React from 'react';
8
- import { useIntl } from 'react-intl';
9
8
  import PropTypes from 'prop-types';
10
9
  import { find } from 'lodash';
11
10
 
@@ -15,8 +14,8 @@ import { ModalLayout } from '@strapi/design-system/ModalLayout';
15
14
  import NavigationItemForm from '../NavigationItemForm';
16
15
  import { extractRelatedItemLabel, isRelationCorrect, isRelationPublished } from '../../utils/parsers';
17
16
  import { navigationItemType } from '../../utils/enums';
18
- import { getTrad } from '../../../../translations';
19
17
  import { NavigationItemPopupHeader } from './NavigationItemPopupHeader';
18
+ import { getMessage } from '../../../../utils';
20
19
 
21
20
  const NavigationItemPopUp = ({
22
21
  isOpen,
@@ -30,7 +29,6 @@ const NavigationItemPopUp = ({
30
29
  usedContentTypesData,
31
30
  }) => {
32
31
 
33
- const { formatMessage } = useIntl();
34
32
 
35
33
  const handleOnSubmit = (payload) => {
36
34
  onSubmit(payload);
@@ -51,7 +49,7 @@ const NavigationItemPopUp = ({
51
49
  relatedRef: item,
52
50
  type: item.isSingle ? navigationItemType.INTERNAL : item.type,
53
51
  isCollection,
54
- }) ? '' : `[${formatMessage(getTrad('notification.navigation.item.relation.status.draft'))}] `.toUpperCase();
52
+ }) ? '' : `[${getMessage('notification.navigation.item.relation.status.draft')}] `.toUpperCase();
55
53
  return `${appendix}${label}`;
56
54
  };
57
55
 
@@ -18,7 +18,7 @@
18
18
  "popup.item.form.path.preview": "Preview:",
19
19
  "popup.item.form.externalPath.label": "External URL",
20
20
  "popup.item.form.externalPath.placeholder": "Link to the external source",
21
- "popup.item.form.externalPath.validation.type": "This value is not a proper url." ,
21
+ "popup.item.form.externalPath.validation.type": "This value is not a proper url.",
22
22
  "popup.item.form.menuAttached.label": "Attach to menu",
23
23
  "popup.item.form.type.label": "Internal link",
24
24
  "popup.item.form.type.internal.label": "Internal source",
@@ -43,9 +43,49 @@
43
43
  "notification.navigation.item.relation": "Entity relation does not exist!",
44
44
  "notification.navigation.item.relation.status.draft": "draft",
45
45
  "notification.navigation.item.relation.status.published": "published",
46
- "navigation.item.action.newItem": "Add nested item",
47
- "navigation.item.badge.removed": "Removed",
48
- "navigation.item.badge.draft": "{type}: Draft",
49
- "navigation.item.badge.published": "{type}: Published"
50
- }
51
-
46
+ "pages.settings.general.title": "General settings",
47
+ "pages.settings.additional.title": "Additional settings",
48
+ "pages.settings.nameField.title": "Content types settings",
49
+ "pages.settings.restoring.title": "Restoring",
50
+ "pages.settings.section.title": "Navigation Plugin",
51
+ "pages.settings.section.subtitle": "Configuration",
52
+ "pages.settings.header.title": "Navigation",
53
+ "pages.settings.header.description": "Configure the navigation plugin",
54
+ "pages.settings.actions.restart": "Restart Strapi",
55
+ "pages.settings.actions.submit": "Save configuration",
56
+ "pages.settings.actions.restore": "Restore configuration",
57
+ "pages.settings.actions.restore.confirmation.header": "Do you want to continue?",
58
+ "pages.settings.actions.restore.confirmation.confirm": "Restore",
59
+ "pages.settings.actions.restore.confirmation.description": "Plugin config will be restored from plugins.js file.",
60
+ "pages.settings.actions.restore.description": "Restoring the plugin configuration will cause it to be replaced with configuration saved inside 'plugins.js' file.",
61
+ "pages.settings.actions.restart.alert.title": "Strapi requires restart",
62
+ "pages.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.",
63
+ "pages.settings.actions.restart.alert.close": "Discard",
64
+ "pages.settings.actions.restart.alert.cancel": "Cancel",
65
+ "pages.settings.notification.fetch.error": "Failed to fetch configuration. Retrying...",
66
+ "pages.settings.notification.submit.success": "Config has been updated successfully",
67
+ "pages.settings.notification.restore.success": "Config has been restored successfully",
68
+ "pages.settings.notification.restart.success": "Application has been restarted successfully",
69
+ "pages.settings.notification.submit.error": "Config update has failed",
70
+ "pages.settings.notification.restore.error": "Config restore has failed",
71
+ "pages.settings.notification.restart.error": "Failed to restart your application. Try to do it manually.",
72
+ "pages.settings.form.contentTypes.label": "Enable for Collection(s)",
73
+ "pages.settings.form.contentTypes.placeholder": "eg. Pages, Posts",
74
+ "pages.settings.form.contentTypes.hint": "Content types that can be related with navigation items. This configuration is applicable both for REST & GraphQL",
75
+ "pages.settings.form.allowedLevels.label": "Allowed levels",
76
+ "pages.settings.form.allowedLevels.placeholder": "eg. 2",
77
+ "pages.settings.form.allowedLevels.hint": "Maximum level for which you're able to mark item as \"Menu attached\"",
78
+ "pages.settings.form.audience.label": "Audience",
79
+ "pages.settings.form.audience.hint": "Enable audience field",
80
+ "pages.settings.form.nameField.label": "Name fields",
81
+ "pages.settings.form.nameField.placeholder": "Select at least one or leave empty to apply defaults",
82
+ "pages.settings.form.nameField.hint": "If left empty name field is going to take following ordered fields: \"title\", \"subject\" and \"name\"",
83
+ "components.navigationItem.action.newItem": "Add nested item",
84
+ "components.navigationItem.badge.removed": "Removed",
85
+ "components.navigationItem.badge.draft": "{type}: Draft",
86
+ "components.navigationItem.badge.published": "{type}: Published",
87
+ "components.confirmation.dialog.button.cancel": "Cancel",
88
+ "components.confirmation.dialog.button.confirm": "Confirm",
89
+ "components.confirmation.dialog.description": "Do you want to continue?",
90
+ "components.confirmation.dialog.header": "Confirmation"
91
+ }
@@ -38,8 +38,8 @@
38
38
  "notification.navigation.item.relation": "L'entitée n'a pas de relations!",
39
39
  "notification.navigation.item.relation.status.draft": "brouillon",
40
40
  "notification.navigation.item.relation.status.published": "publié",
41
- "navigation.item.action.newItem": "Nouvel élément imbriqué",
42
- "navigation.item.badge.removed": "Supprimé",
43
- "navigation.item.badge.draft": "Brouillon",
44
- "navigation.item.badge.published": "Publié"
41
+ "components.navigationItem.action.newItem": "Nouvel élément imbriqué",
42
+ "components.navigationItem.badge.removed": "Supprimé",
43
+ "components.navigationItem.badge.draft": "Brouillon",
44
+ "components.navigationItem.badge.published": "Publié"
45
45
  }
@@ -0,0 +1,51 @@
1
+ import { request } from '@strapi/helper-plugin';
2
+ import pluginId from '../pluginId';
3
+
4
+ export const fetchNavigationConfig = async () => {
5
+ try {
6
+ const data = await request(`/${pluginId}/settings/config`, { method: 'GET' });
7
+ return data;
8
+ } catch (err) {
9
+ toggleNotification({
10
+ type: 'warning',
11
+ message: { id: 'notification.error' },
12
+ });
13
+
14
+ return { err };
15
+ }
16
+ }
17
+
18
+ export const updateNavigationConfig = async ({ body }) =>
19
+ request(`/${pluginId}/config`, { method: 'PUT', body }, true);
20
+
21
+ export const restoreNavigationConfig = async () =>
22
+ request(`/${pluginId}/config`, { method: 'DELETE' }, true);
23
+
24
+ export const fetchAllContentTypes = async () => {
25
+ try {
26
+ const { data } = await request('/content-manager/content-types');
27
+ return { ...data }
28
+ } catch (err) {
29
+ toggleNotification({
30
+ type: 'warning',
31
+ message: { id: 'notification.error' },
32
+ });
33
+
34
+ return { err };
35
+ }
36
+ }
37
+
38
+ export const restartStrapi = async (toggleNotification) => {
39
+ try {
40
+ const { data } = await request(`/${pluginId}/settings/restart`);
41
+
42
+ return data;
43
+ } catch (err) {
44
+ toggleNotification({
45
+ type: 'warning',
46
+ message: { id: 'notification.error' },
47
+ });
48
+
49
+ return { err };
50
+ }
51
+ };
@@ -0,0 +1,20 @@
1
+ import { useIntl } from 'react-intl';
2
+ import { isString } from 'lodash';
3
+
4
+ import pluginId from '../pluginId';
5
+
6
+ const getMessage = (input, defaultMessage = '', inPluginScope = true) => {
7
+ const { formatMessage } = useIntl();
8
+ let formattedId = ''
9
+ if (isString(input)) {
10
+ formattedId = input;
11
+ } else {
12
+ formattedId = input?.id;
13
+ }
14
+ return formatMessage({
15
+ id: `${inPluginScope ? pluginId : 'app.components'}.${formattedId}`,
16
+ defaultMessage,
17
+ }, input?.props || undefined)
18
+ };
19
+
20
+ export { getMessage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-navigation",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Strapi - Navigation plugin",
5
5
  "strapi": {
6
6
  "name": "navigation",
@@ -13,7 +13,7 @@
13
13
  "url": "https://github.com/VirtusLab/strapi-plugin-navigation"
14
14
  },
15
15
  "scripts": {
16
- "publish": "npm publish --tag latest",
16
+ "publish:latest": "npm publish --tag latest",
17
17
  "test:unit": "jest --verbose --coverage"
18
18
  },
19
19
  "dependencies": {
@@ -44,8 +44,8 @@
44
44
  "@strapi/strapi": "4.x"
45
45
  },
46
46
  "author": {
47
- "name": "VirtusLab // Mateusz Ziarko",
48
- "email": "mziarko@virtuslab.com",
47
+ "name": "VirtusLab",
48
+ "email": "strapi@virtuslab.com",
49
49
  "url": "https://virtuslab.com"
50
50
  },
51
51
  "maintainers": [
@@ -23,7 +23,9 @@ module.exports = async ({ strapi }) => {
23
23
  pluginName: "navigation",
24
24
  },
25
25
  ];
26
+ await strapi.admin.services.permission.actionProvider.registerMany(actions);
26
27
 
28
+ // Initialize first navigation
27
29
  const navigations = await strapi
28
30
  .query("plugin::navigation.navigation")
29
31
  .findMany();
@@ -38,5 +40,32 @@ module.exports = async ({ strapi }) => {
38
40
  }
39
41
  });
40
42
  }
41
- await strapi.admin.services.permission.actionProvider.registerMany(actions);
43
+
44
+ // Initialize configuration
45
+ const pluginStore = strapi.store({
46
+ environment: '',
47
+ type: 'plugin',
48
+ name: 'navigation',
49
+ });
50
+
51
+ const config = await pluginStore.get({ key: 'config' });
52
+ const pluginDefaultConfig = await strapi.plugin('navigation').config
53
+ const defaultConfigValue = {
54
+ additionalFields: pluginDefaultConfig('additionalFields'),
55
+ contentTypes: pluginDefaultConfig('contentTypes'),
56
+ contentTypesNameFields: pluginDefaultConfig('contentTypesNameFields'),
57
+ allowedLevels: pluginDefaultConfig('allowedLevels'),
58
+ gql: pluginDefaultConfig('gql'),
59
+ }
60
+
61
+ if (!config) {
62
+ pluginStore.set({
63
+ key: 'config', value: defaultConfigValue
64
+ });
65
+ }
66
+
67
+ if (strapi.plugin('graphql')) {
68
+ const graphqlConfiguration = require('./graphql')
69
+ await graphqlConfiguration({ strapi, config: config || defaultConfigValue });
70
+ }
42
71
  };