@strapi/admin 4.2.3 → 4.3.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.
Files changed (166) hide show
  1. package/admin/src/app.js +7 -4
  2. package/admin/src/components/LeftMenu/index.js +12 -2
  3. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +5 -4
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +0 -8
  5. package/admin/src/content-manager/components/SelectMany/index.js +2 -4
  6. package/admin/src/content-manager/components/SelectWrapper/index.js +1 -13
  7. package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +2 -2
  8. package/admin/src/content-manager/pages/ListView/FieldPicker/index.js +9 -1
  9. package/admin/src/content-manager/utils/removeKeyInObject.js +0 -4
  10. package/admin/src/hooks/useFetchMarketplaceProviders/index.js +1 -1
  11. package/admin/src/index.js +1 -1
  12. package/admin/src/pages/Admin/index.js +21 -7
  13. package/admin/src/pages/App/constants.js +1 -0
  14. package/admin/src/pages/App/index.js +21 -3
  15. package/admin/src/pages/App/reducer.js +22 -0
  16. package/admin/src/pages/InstalledPluginsPage/Plugins.js +10 -2
  17. package/admin/src/pages/ProfilePage/index.js +19 -18
  18. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/components/LogoModalStepper/FromUrlForm.js +7 -3
  19. package/admin/src/pages/SettingsPage/pages/Users/EditPage/utils/layout.js +3 -1
  20. package/admin/src/pages/SettingsPage/pages/Users/ListPage/DynamicTable/TableRows/index.js +1 -1
  21. package/admin/src/pages/SettingsPage/pages/Users/ListPage/utils/tableHeaders.js +18 -4
  22. package/admin/src/pages/SettingsPage/pages/Users/components/SelectRoles/index.js +4 -1
  23. package/admin/src/reducers.js +4 -2
  24. package/admin/src/translations/en.json +37 -0
  25. package/admin/src/translations/zh-Hans.json +55 -8
  26. package/admin/src/tsconfig.json +10 -0
  27. package/build/1669.341e10d8.chunk.js +1 -0
  28. package/build/20.9e5a98b6.chunk.js +308 -0
  29. package/build/3332.1e443103.chunk.js +102 -0
  30. package/build/413.d5986568.chunk.js +284 -0
  31. package/build/{3180.ad280cb4.chunk.js → 5520.3c6bf86a.chunk.js} +34 -34
  32. package/build/{9166.5c585d7c.chunk.js → 8655.9073e17e.chunk.js} +59 -58
  33. package/build/8773.1b2ec266.chunk.js +327 -0
  34. package/build/9730.8fbe43ee.chunk.js +12 -0
  35. package/build/9799.ce46400f.chunk.js +760 -0
  36. package/build/Admin-authenticatedApp.ea608aff.chunk.js +80 -0
  37. package/build/{6102.1482bf98.chunk.js → Admin_InternalErrorPage.25c53284.chunk.js} +1 -1
  38. package/build/{Admin_homePage.4cc54224.chunk.js → Admin_homePage.118926e0.chunk.js} +1 -1
  39. package/build/{Admin_marketplace.91a1aacd.chunk.js → Admin_marketplace.8efd3fd0.chunk.js} +2 -2
  40. package/build/Admin_pluginsPage.0992c2b5.chunk.js +1 -0
  41. package/build/Admin_profilePage.35ce8e94.chunk.js +15 -0
  42. package/build/Admin_settingsPage.5fc517d7.chunk.js +178 -0
  43. package/build/admin-app.1bd5f67e.chunk.js +112 -0
  44. package/build/admin-edit-roles-page.358d98c1.chunk.js +1 -0
  45. package/build/admin-edit-users.714863af.chunk.js +10 -0
  46. package/build/admin-users.2bd6fb37.chunk.js +11 -0
  47. package/build/{api-tokens-edit-page.d41a0165.chunk.js → api-tokens-create-page.442e3be0.chunk.js} +1 -1
  48. package/build/api-tokens-edit-page.5f34eec7.chunk.js +1 -0
  49. package/build/{api-tokens-list-page.ec7c36f0.chunk.js → api-tokens-list-page.5ea3f6ce.chunk.js} +1 -1
  50. package/build/{codemirror-css.269ff90a.chunk.js → codemirror-css.4e2bbed3.chunk.js} +1 -1
  51. package/build/{codemirror-theme.bd70dd4c.chunk.js → codemirror-theme.a82cae4e.chunk.js} +1 -1
  52. package/build/content-manager.39bc9201.chunk.js +1176 -0
  53. package/build/content-type-builder-list-view.b12687b2.chunk.js +194 -0
  54. package/build/content-type-builder-translation-en-json.201bfb78.chunk.js +1 -0
  55. package/build/content-type-builder.ec6ccb59.chunk.js +142 -0
  56. package/build/{cropper-css.f4896679.chunk.js → cropper-css.12fe038c.chunk.js} +1 -1
  57. package/build/{email-settings-page.f12299bd.chunk.js → email-settings-page.818761d5.chunk.js} +2 -2
  58. package/build/email-translation-en-json.3d74ff95.chunk.js +1 -0
  59. package/build/email-translation-zh-Hans-json.8172da08.chunk.js +1 -0
  60. package/build/en-json.6d70e9ff.chunk.js +1 -0
  61. package/build/{fontawesome-css-all.4ecf62f5.chunk.js → fontawesome-css-all.15068c6e.chunk.js} +1 -1
  62. package/build/{fontawesome-css.18f0d57b.chunk.js → fontawesome-css.418f40da.chunk.js} +1 -1
  63. package/build/{highlight.js.22f875ca.chunk.js → highlight.js.af2de364.chunk.js} +1 -1
  64. package/build/i18n-settings-page.9d426e96.chunk.js +101 -0
  65. package/build/index.html +1 -1
  66. package/build/main.b19c2ee3.js +8675 -0
  67. package/build/runtime~main.426f9375.js +2 -0
  68. package/build/{sso-settings-page.2dbec3a3.chunk.js → sso-settings-page.445184e0.chunk.js} +1 -1
  69. package/build/{upload-settings.6c0eb939.chunk.js → upload-settings.4bad0bdd.chunk.js} +1 -1
  70. package/build/upload-translation-de-json.745613c0.chunk.js +1 -0
  71. package/build/upload-translation-dk-json.cb25dcf0.chunk.js +1 -0
  72. package/build/upload-translation-en-json.bc79c867.chunk.js +1 -0
  73. package/build/upload-translation-es-json.1f344b53.chunk.js +1 -0
  74. package/build/upload-translation-fr-json.e21c0c7a.chunk.js +1 -0
  75. package/build/upload-translation-he-json.4ce77b7b.chunk.js +1 -0
  76. package/build/upload-translation-it-json.5ce11e0b.chunk.js +1 -0
  77. package/build/upload-translation-ja-json.22afae44.chunk.js +1 -0
  78. package/build/upload-translation-ko-json.9a2c21cb.chunk.js +1 -0
  79. package/build/upload-translation-ms-json.0605d6da.chunk.js +1 -0
  80. package/build/upload-translation-pl-json.c1f86b50.chunk.js +1 -0
  81. package/build/upload-translation-pt-BR-json.95686cfb.chunk.js +1 -0
  82. package/build/upload-translation-ru-json.37bd1546.chunk.js +1 -0
  83. package/build/upload-translation-sk-json.b03d4904.chunk.js +1 -0
  84. package/build/upload-translation-th-json.64dd70ce.chunk.js +1 -0
  85. package/build/upload-translation-uk-json.1328cb3e.chunk.js +1 -0
  86. package/build/upload-translation-zh-Hans-json.37a2981e.chunk.js +1 -0
  87. package/build/upload-translation-zh-json.ee8fba96.chunk.js +1 -0
  88. package/build/upload.1346f4b1.chunk.js +7 -0
  89. package/build/{users-advanced-settings-page.06330ec9.chunk.js → users-advanced-settings-page.f38654fc.chunk.js} +1 -1
  90. package/build/users-email-settings-page.824a3cdb.chunk.js +101 -0
  91. package/build/{users-providers-settings-page.f011f210.chunk.js → users-providers-settings-page.a0b0fe39.chunk.js} +1 -1
  92. package/build/{users-roles-settings-page.d756dce9.chunk.js → users-roles-settings-page.3db986a4.chunk.js} +2 -2
  93. package/build/{webhook-edit-page.181ea60a.chunk.js → webhook-edit-page.3417d93c.chunk.js} +2 -2
  94. package/build/{webhook-list-page.b6000354.chunk.js → webhook-list-page.2ab4bbf0.chunk.js} +1 -1
  95. package/build/zh-Hans-json.eac1d90a.chunk.js +1 -0
  96. package/ee/admin/pages/SettingsPage/pages/Roles/CreatePage/index.js +3 -3
  97. package/index.js +47 -239
  98. package/package.json +14 -10
  99. package/scripts/build.js +19 -3
  100. package/server/controllers/admin.js +21 -0
  101. package/server/policies/index.js +1 -0
  102. package/server/policies/isTelemetryEnabled.js +16 -0
  103. package/server/routes/admin.js +8 -0
  104. package/server/routes/serve-admin-panel.js +1 -1
  105. package/utils/create-cache-dir.js +131 -0
  106. package/utils/get-custom-app-config-file.js +28 -0
  107. package/utils/get-custom-webpack-config.js +38 -0
  108. package/utils/get-plugins-path.js +26 -0
  109. package/utils/index.js +13 -0
  110. package/utils/should-build-admin.js +52 -0
  111. package/utils/watch-admin-files.js +59 -0
  112. package/webpack.alias.js +0 -1
  113. package/webpack.config.js +32 -10
  114. package/admin/src/content-manager/components/SelectWrapper/ClearIndicator.js +0 -18
  115. package/admin/src/content-manager/components/SelectWrapper/DropdownIndicator.js +0 -24
  116. package/admin/src/content-manager/components/SelectWrapper/IconBox.js +0 -20
  117. package/admin/src/content-manager/components/SelectWrapper/IndicatorSeparator.js +0 -3
  118. package/admin/src/content-manager/components/SelectWrapper/utils/getSelectStyles.js +0 -92
  119. package/build/2912.dd031292.chunk.js +0 -253
  120. package/build/3526.849d6a28.chunk.js +0 -162
  121. package/build/4094.ff4573b6.chunk.js +0 -194
  122. package/build/4982.c57c5675.chunk.js +0 -308
  123. package/build/6925.fb35248e.chunk.js +0 -761
  124. package/build/7810.c0d5e393.chunk.js +0 -113
  125. package/build/7841.9e9cf739.chunk.js +0 -253
  126. package/build/8681.334d9893.chunk.js +0 -163
  127. package/build/9298.fbe24a6e.chunk.js +0 -334
  128. package/build/948.d64fb515.chunk.js +0 -2
  129. package/build/Admin-authenticatedApp.a13de617.chunk.js +0 -80
  130. package/build/Admin_pluginsPage.b339b9c3.chunk.js +0 -1
  131. package/build/Admin_profilePage.369a0308.chunk.js +0 -15
  132. package/build/Admin_settingsPage.9bc7a0f0.chunk.js +0 -180
  133. package/build/admin-edit-roles-page.31acda7c.chunk.js +0 -1
  134. package/build/admin-edit-users.98a32ee5.chunk.js +0 -11
  135. package/build/admin-users.ab8ba52e.chunk.js +0 -12
  136. package/build/api-tokens-create-page.a3b9c8bd.chunk.js +0 -1
  137. package/build/content-manager.02509825.chunk.js +0 -1198
  138. package/build/content-type-builder-translation-en-json.ea3c66b3.chunk.js +0 -1
  139. package/build/content-type-builder.af41a338.chunk.js +0 -142
  140. package/build/email-translation-en-json.6da7e388.chunk.js +0 -1
  141. package/build/email-translation-zh-Hans-json.b463cb25.chunk.js +0 -1
  142. package/build/en-json.4f6bd46a.chunk.js +0 -1
  143. package/build/i18n-settings-page.c1ecebbc.chunk.js +0 -101
  144. package/build/main.48e0f6dc.js +0 -8434
  145. package/build/runtime~main.e9852fed.js +0 -2
  146. package/build/upload-translation-de-json.b642da08.chunk.js +0 -1
  147. package/build/upload-translation-dk-json.fc61df13.chunk.js +0 -1
  148. package/build/upload-translation-en-json.59269508.chunk.js +0 -1
  149. package/build/upload-translation-es-json.8ec935ef.chunk.js +0 -1
  150. package/build/upload-translation-fr-json.eb9b4f84.chunk.js +0 -1
  151. package/build/upload-translation-he-json.c226f2dc.chunk.js +0 -1
  152. package/build/upload-translation-it-json.8e58456e.chunk.js +0 -1
  153. package/build/upload-translation-ja-json.1378a2e7.chunk.js +0 -1
  154. package/build/upload-translation-ko-json.5e06e112.chunk.js +0 -1
  155. package/build/upload-translation-ms-json.dc3bf0d7.chunk.js +0 -1
  156. package/build/upload-translation-pl-json.bb2aa937.chunk.js +0 -1
  157. package/build/upload-translation-pt-BR-json.7e8d9550.chunk.js +0 -1
  158. package/build/upload-translation-ru-json.da2529f3.chunk.js +0 -1
  159. package/build/upload-translation-sk-json.bfdf4f09.chunk.js +0 -1
  160. package/build/upload-translation-th-json.6a48b826.chunk.js +0 -1
  161. package/build/upload-translation-uk-json.6fb09148.chunk.js +0 -1
  162. package/build/upload-translation-zh-Hans-json.c9622577.chunk.js +0 -1
  163. package/build/upload-translation-zh-json.711f804b.chunk.js +0 -1
  164. package/build/upload.92d5c845.chunk.js +0 -105
  165. package/build/users-email-settings-page.151b35a9.chunk.js +0 -1
  166. package/build/zh-Hans-json.cbc69f3d.chunk.js +0 -1
package/admin/src/app.js CHANGED
@@ -1,6 +1,9 @@
1
+ const config = {
2
+ locales: ['fr'],
3
+ };
4
+ const bootstrap = () => {};
5
+
1
6
  export default {
2
- config: {
3
- locales: ['fr'],
4
- },
5
- bootstrap() {},
7
+ config,
8
+ bootstrap,
6
9
  };
@@ -115,7 +115,12 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
115
115
  </NavLink>
116
116
 
117
117
  {pluginsSectionLinks.length > 0 ? (
118
- <NavSection label="Plugins">
118
+ <NavSection
119
+ label={formatMessage({
120
+ id: 'app.components.LeftMenu.plugins',
121
+ defaultMessage: 'Plugins',
122
+ })}
123
+ >
119
124
  {pluginsSectionLinks.map(link => {
120
125
  const Icon = link.icon;
121
126
 
@@ -129,7 +134,12 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
129
134
  ) : null}
130
135
 
131
136
  {generalSectionLinks.length > 0 ? (
132
- <NavSection label="General">
137
+ <NavSection
138
+ label={formatMessage({
139
+ id: 'app.components.LeftMenu.general',
140
+ defaultMessage: 'General',
141
+ })}
142
+ >
133
143
  {generalSectionLinks.map(link => {
134
144
  const LinkIcon = link.icon;
135
145
 
@@ -15,12 +15,12 @@ import {
15
15
  useOverlayBlocker,
16
16
  useTracking,
17
17
  getYupInnerErrors,
18
+ getAPIInnerErrors,
18
19
  } from '@strapi/helper-plugin';
19
20
 
20
21
  import { getTrad, removeKeyInObject } from '../../utils';
21
22
  import reducer, { initialState } from './reducer';
22
23
  import { cleanData, createYupSchema } from './utils';
23
- import { getAPIInnerError } from './utils/getAPIInnerError';
24
24
 
25
25
  const EditViewDataManagerProvider = ({
26
26
  allLayoutData,
@@ -238,7 +238,8 @@ const EditViewDataManagerProvider = ({
238
238
  ['text', 'textarea', 'string', 'email', 'uid', 'select', 'select-one', 'number'].includes(
239
239
  type
240
240
  ) &&
241
- !value
241
+ !value &&
242
+ value !== 0
242
243
  ) {
243
244
  inputValue = null;
244
245
  }
@@ -310,7 +311,7 @@ const EditViewDataManagerProvider = ({
310
311
  } catch (err) {
311
312
  errors = {
312
313
  ...errors,
313
- ...getAPIInnerError(err),
314
+ ...getAPIInnerErrors(err, { getTrad }),
314
315
  };
315
316
  }
316
317
 
@@ -346,7 +347,7 @@ const EditViewDataManagerProvider = ({
346
347
  } catch (err) {
347
348
  errors = {
348
349
  ...errors,
349
- ...getAPIInnerError(err),
350
+ ...getAPIInnerErrors(err, { getTrad }),
350
351
  };
351
352
  }
352
353
 
@@ -20,14 +20,6 @@ const cleanData = (retrievedData, currentSchema, componentsSchema) => {
20
20
  case 'json':
21
21
  cleanedData = JSON.parse(value);
22
22
  break;
23
- // TODO
24
- // case 'date':
25
- // cleanedData =
26
- // value && value._isAMomentObject === true ? value.format('YYYY-MM-DD') : value;
27
- // break;
28
- // case 'datetime':
29
- // cleanedData = value && value._isAMomentObject === true ? value.toISOString() : value;
30
- // break;
31
23
  case 'time': {
32
24
  cleanedData = value;
33
25
 
@@ -2,7 +2,8 @@ import React, { memo } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
4
  import isEmpty from 'lodash/isEmpty';
5
- import Select, { createFilter } from 'react-select';
5
+ import { createFilter } from 'react-select';
6
+ import { ReactSelect as Select } from '@strapi/helper-plugin';
6
7
  import { Box } from '@strapi/design-system/Box';
7
8
  import { Stack } from '@strapi/design-system/Stack';
8
9
  import { Typography } from '@strapi/design-system/Typography';
@@ -24,7 +25,6 @@ function SelectMany({
24
25
  options,
25
26
  placeholder,
26
27
  searchToPersist,
27
- styles,
28
28
  targetModel,
29
29
  value,
30
30
  description,
@@ -72,7 +72,6 @@ function SelectMany({
72
72
  placeholder={formatMessage(
73
73
  placeholder || { id: 'global.select', defaultMessage: 'Select...' }
74
74
  )}
75
- styles={styles}
76
75
  value={[]}
77
76
  />
78
77
  <Box paddingTop={3} style={{ overflow: 'auto' }}>
@@ -138,7 +137,6 @@ SelectMany.propTypes = {
138
137
  defaultMessage: PropTypes.string.isRequired,
139
138
  }),
140
139
  searchToPersist: PropTypes.string,
141
- styles: PropTypes.object.isRequired,
142
140
  targetModel: PropTypes.string.isRequired,
143
141
  value: PropTypes.array,
144
142
  description: PropTypes.string,
@@ -2,7 +2,7 @@ import React, { useCallback, useState, useEffect, useMemo, memo } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
4
  import { useLocation } from 'react-router-dom';
5
- import { useTheme } from 'styled-components';
5
+ import { Stack } from '@strapi/design-system/Stack';
6
6
  import findIndex from 'lodash/findIndex';
7
7
  import get from 'lodash/get';
8
8
  import isArray from 'lodash/isArray';
@@ -16,18 +16,13 @@ import {
16
16
  } from '@strapi/helper-plugin';
17
17
  import { stringify } from 'qs';
18
18
  import axios from 'axios';
19
- import { Stack } from '@strapi/design-system/Stack';
20
19
  import { axiosInstance } from '../../../core/utils';
21
20
  import { getTrad } from '../../utils';
22
21
  import Label from './Label';
23
22
  import SelectOne from '../SelectOne';
24
23
  import SelectMany from '../SelectMany';
25
- import ClearIndicator from './ClearIndicator';
26
- import DropdownIndicator from './DropdownIndicator';
27
- import IndicatorSeparator from './IndicatorSeparator';
28
24
  import Option from './Option';
29
25
  import { connect, select } from './utils';
30
- import getSelectStyles from './utils/getSelectStyles';
31
26
 
32
27
  const initialPaginationState = {
33
28
  contains: '',
@@ -77,7 +72,6 @@ function SelectWrapper({
77
72
  onRemoveRelation,
78
73
  } = useCMEditViewDataManager();
79
74
  const { pathname } = useLocation();
80
- const theme = useTheme();
81
75
 
82
76
  const value = get(modifiedData, name, null);
83
77
  const [state, setState] = useState(initialPaginationState);
@@ -278,8 +272,6 @@ function SelectWrapper({
278
272
  return <NotAllowedInput intlLabel={intlLabel} labelAction={labelAction} />;
279
273
  }
280
274
 
281
- const styles = getSelectStyles(theme);
282
-
283
275
  return (
284
276
  <Stack spacing={1}>
285
277
  <Label
@@ -293,9 +285,6 @@ function SelectWrapper({
293
285
  <Component
294
286
  addRelation={handleAddRelation}
295
287
  components={{
296
- ClearIndicator,
297
- DropdownIndicator,
298
- IndicatorSeparator,
299
288
  Option,
300
289
  }}
301
290
  displayNavigationLink={shouldDisplayRelationLink}
@@ -315,7 +304,6 @@ function SelectWrapper({
315
304
  onRemove={onRemoveRelation}
316
305
  placeholder={placeholder}
317
306
  searchToPersist={searchToPersist}
318
- styles={styles}
319
307
  targetModel={targetModel}
320
308
  value={value}
321
309
  description={description}
@@ -59,8 +59,8 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
59
59
  const formType = get(attributes, [selectedField, 'type']);
60
60
 
61
61
  if (
62
- formType === 'dynamiczone' ||
63
- (formType === 'component' && !['label', 'description'].includes(meta))
62
+ ['component', 'dynamiczone'].includes(formType) &&
63
+ !['label', 'description'].includes(meta)
64
64
  ) {
65
65
  return null;
66
66
  }
@@ -8,6 +8,7 @@ import { useTracking } from '@strapi/helper-plugin';
8
8
  import { onChangeListHeaders } from '../actions';
9
9
  import { selectDisplayedHeaders } from '../selectors';
10
10
  import getAllAllowedHeaders from './utils/getAllAllowedHeader';
11
+ import getTrad from '../../../utils/getTrad';
11
12
 
12
13
  const FieldPicker = ({ layout }) => {
13
14
  const dispatch = useDispatch();
@@ -50,7 +51,14 @@ const FieldPicker = ({ layout }) => {
50
51
  aria-label="change displayed fields"
51
52
  value={values}
52
53
  onChange={handleChange}
53
- customizeContent={values => `${values.length} currently selected`}
54
+ customizeContent={values =>
55
+ formatMessage(
56
+ {
57
+ id: getTrad('select.currently.selected'),
58
+ defaultMessage: '{count} currently selected',
59
+ },
60
+ { count: values.length }
61
+ )}
54
62
  multi
55
63
  size="S"
56
64
  >
@@ -21,10 +21,6 @@ const removeKeyInObject = (obj, keyToRemove) => {
21
21
  }
22
22
 
23
23
  if (typeof value === 'object') {
24
- if (value._isAMomentObject === true) {
25
- return { ...acc, [current]: value };
26
- }
27
-
28
24
  if (Array.isArray(acc)) {
29
25
  acc[current] = removeKeyInObject(value, keyToRemove);
30
26
 
@@ -2,7 +2,7 @@ import { useQuery } from 'react-query';
2
2
  import { useNotification } from '@strapi/helper-plugin';
3
3
  import { fetchMarketplacePlugins } from './utils/api';
4
4
 
5
- const useFetchMarketplaceProviders = (notifyLoad) => {
5
+ const useFetchMarketplaceProviders = notifyLoad => {
6
6
  const toggleNotification = useNotification();
7
7
 
8
8
  return useQuery('list-marketplace-providers', () => fetchMarketplacePlugins(), {
@@ -48,7 +48,7 @@ const run = async () => {
48
48
 
49
49
  // We need to make sure to fetch the project type before importing the StrapiApp
50
50
  // otherwise the strapi-babel-plugin does not work correctly
51
- const StrapiApp = await import('./StrapiApp');
51
+ const StrapiApp = await import(/* webpackChunkName: "admin-app" */ './StrapiApp');
52
52
 
53
53
  const app = StrapiApp.default({
54
54
  appPlugins: plugins,
@@ -6,16 +6,17 @@
6
6
 
7
7
  import React, { Suspense, useEffect, useMemo, lazy } from 'react';
8
8
  import { Switch, Route } from 'react-router-dom';
9
- // Components from @strapi/helper-plugin
10
9
  import { useTracking, LoadingIndicatorPage, useStrapiApp } from '@strapi/helper-plugin';
10
+ import { useDispatch, useSelector } from 'react-redux';
11
11
  import { DndProvider } from 'react-dnd';
12
12
  import { HTML5Backend } from 'react-dnd-html5-backend';
13
+ import GuidedTourModal from '../../components/GuidedTour/Modal';
13
14
  import LeftMenu from '../../components/LeftMenu';
14
15
  import AppLayout from '../../layouts/AppLayout';
15
16
  import { useMenu } from '../../hooks';
16
- import Onboarding from './Onboarding';
17
17
  import { createRoute } from '../../utils';
18
- import GuidedTourModal from '../../components/GuidedTour/Modal';
18
+ import { SET_APP_RUNTIME_STATUS } from '../App/constants';
19
+ import Onboarding from './Onboarding';
19
20
 
20
21
  const CM = lazy(() =>
21
22
  import(/* webpackChunkName: "content-manager" */ '../../content-manager/pages/App')
@@ -27,8 +28,12 @@ const InstalledPluginsPage = lazy(() =>
27
28
  const MarketplacePage = lazy(() =>
28
29
  import(/* webpackChunkName: "Admin_marketplace" */ '../MarketplacePage')
29
30
  );
30
- const NotFoundPage = lazy(() => import('../NotFoundPage'));
31
- const InternalErrorPage = lazy(() => import('../InternalErrorPage'));
31
+ const NotFoundPage = lazy(() =>
32
+ import(/* webpackChunkName: "Admin_NotFoundPage" */ '../NotFoundPage')
33
+ );
34
+ const InternalErrorPage = lazy(() =>
35
+ import(/* webpackChunkName: "Admin_InternalErrorPage" */ '../InternalErrorPage')
36
+ );
32
37
 
33
38
  const ProfilePage = lazy(() =>
34
39
  import(/* webpackChunkName: "Admin_profilePage" */ '../ProfilePage')
@@ -40,11 +45,20 @@ const SettingsPage = lazy(() =>
40
45
  // Simple hook easier for testing
41
46
  const useTrackUsage = () => {
42
47
  const { trackUsage } = useTracking();
48
+ const dispatch = useDispatch();
49
+ const appStatus = useSelector(state => state.admin_app.status);
43
50
 
44
51
  useEffect(() => {
45
- trackUsage('didAccessAuthenticatedAdministration');
52
+ // Make sure the event is only send once after accessing the admin panel
53
+ // and not at runtime for example when regenerating the permissions with the ctb
54
+ // or with i18n
55
+ if (appStatus === 'init') {
56
+ trackUsage('didAccessAuthenticatedAdministration');
57
+
58
+ dispatch({ type: SET_APP_RUNTIME_STATUS });
59
+ }
46
60
  // eslint-disable-next-line react-hooks/exhaustive-deps
47
- }, []);
61
+ }, [appStatus]);
48
62
  };
49
63
 
50
64
  const Admin = () => {
@@ -0,0 +1 @@
1
+ export const SET_APP_RUNTIME_STATUS = 'StrapiAdmin/APP/SET_APP_RUNTIME_STATUS';
@@ -13,7 +13,9 @@ import {
13
13
  useNotification,
14
14
  TrackingContext,
15
15
  prefixFileUrlWithBackendUrl,
16
+ useAppInfos,
16
17
  } from '@strapi/helper-plugin';
18
+ import axios from 'axios';
17
19
  import { SkipToContent } from '@strapi/design-system/Main';
18
20
  import { useIntl } from 'react-intl';
19
21
  import PrivateRoute from '../../components/PrivateRoute';
@@ -34,6 +36,7 @@ function App() {
34
36
  const { updateProjectSettings } = useConfigurations();
35
37
  const { formatMessage } = useIntl();
36
38
  const [{ isLoading, hasAdmin, uuid }, setState] = useState({ isLoading: true, hasAdmin: false });
39
+ const appInfo = useAppInfos();
37
40
 
38
41
  const authRoutes = useMemo(() => {
39
42
  return makeUniqueRoutes(
@@ -41,6 +44,8 @@ function App() {
41
44
  );
42
45
  }, []);
43
46
 
47
+ const [telemetryProperties, setTelemetryProperties] = useState(null);
48
+
44
49
  useEffect(() => {
45
50
  const currentToken = auth.getToken();
46
51
 
@@ -69,12 +74,20 @@ function App() {
69
74
  const getData = async () => {
70
75
  try {
71
76
  const {
72
- data: { hasAdmin, uuid, menuLogo },
73
- } = await request('/admin/init', { method: 'GET' });
77
+ data: {
78
+ data: { hasAdmin, uuid, menuLogo },
79
+ },
80
+ } = await axios.get(`${strapi.backendURL}/admin/init`);
74
81
 
75
82
  updateProjectSettings({ menuLogo: prefixFileUrlWithBackendUrl(menuLogo) });
76
83
 
77
84
  if (uuid) {
85
+ const {
86
+ data: { data: properties },
87
+ } = await axios.get(`${strapi.backendURL}/admin/telemetry-properties`);
88
+
89
+ setTelemetryProperties(properties);
90
+
78
91
  try {
79
92
  const deviceId = await getUID();
80
93
 
@@ -84,6 +97,10 @@ function App() {
84
97
  event: 'didInitializeAdministration',
85
98
  uuid,
86
99
  deviceId,
100
+ properties: {
101
+ ...properties,
102
+ environment: appInfo.currentEnvironment,
103
+ },
87
104
  }),
88
105
  headers: {
89
106
  'Content-Type': 'application/json',
@@ -104,6 +121,7 @@ function App() {
104
121
  };
105
122
 
106
123
  getData();
124
+ // eslint-disable-next-line react-hooks/exhaustive-deps
107
125
  }, [toggleNotification, updateProjectSettings]);
108
126
 
109
127
  const setHasAdmin = hasAdmin => setState(prev => ({ ...prev, hasAdmin }));
@@ -115,7 +133,7 @@ function App() {
115
133
  return (
116
134
  <Suspense fallback={<LoadingIndicatorPage />}>
117
135
  <SkipToContent>{formatMessage({ id: 'skipToContent' })}</SkipToContent>
118
- <TrackingContext.Provider value={uuid}>
136
+ <TrackingContext.Provider value={{ uuid, telemetryProperties }}>
119
137
  <Switch>
120
138
  {authRoutes}
121
139
  <Route
@@ -0,0 +1,22 @@
1
+ import produce from 'immer';
2
+ import { SET_APP_RUNTIME_STATUS } from './constants';
3
+
4
+ const initialState = {
5
+ status: 'init',
6
+ };
7
+
8
+ const reducer = (state = initialState, action) =>
9
+ /* eslint-disable-next-line consistent-return */
10
+ produce(state, draftState => {
11
+ switch (action.type) {
12
+ case SET_APP_RUNTIME_STATUS: {
13
+ draftState.status = 'runtime';
14
+ break;
15
+ }
16
+ default:
17
+ return draftState;
18
+ }
19
+ });
20
+
21
+ export { initialState };
22
+ export default reducer;
@@ -82,11 +82,19 @@ const Plugins = () => {
82
82
  <Tr key={name}>
83
83
  <Td>
84
84
  <Typography textColor="neutral800" variant="omega" fontWeight="bold">
85
- {displayName}
85
+ {formatMessage({
86
+ id: `global.plugins.${name}`,
87
+ defaultMessage: displayName,
88
+ })}
86
89
  </Typography>
87
90
  </Td>
88
91
  <Td>
89
- <Typography textColor="neutral800">{description}</Typography>
92
+ <Typography textColor="neutral800">
93
+ {formatMessage({
94
+ id: `global.plugins.${name}.description`,
95
+ defaultMessage: description,
96
+ })}
97
+ </Typography>
90
98
  </Td>
91
99
  </Tr>
92
100
  );
@@ -357,6 +357,7 @@ const ProfilePage = () => {
357
357
  })}
358
358
  name="password"
359
359
  type={passwordShown ? 'text' : 'password'}
360
+ autoComplete="new-password"
360
361
  endAction={
361
362
  <FieldActionWrapper
362
363
  onClick={e => {
@@ -398,6 +399,7 @@ const ProfilePage = () => {
398
399
  })}
399
400
  name="confirmPassword"
400
401
  type={passwordConfirmShown ? 'text' : 'password'}
402
+ autoComplete="new-password"
401
403
  endAction={
402
404
  <FieldActionWrapper
403
405
  onClick={e => {
@@ -531,24 +533,23 @@ const ProfilePage = () => {
531
533
  });
532
534
  }}
533
535
  >
534
- {themesToDisplay.map(theme => {
535
- const label = formatMessage(
536
- {
537
- id:
538
- 'Settings.profile.form.section.experience.mode.option-label',
539
- defaultMessage: '{name} mode',
540
- },
541
- {
542
- name: upperFirst(theme),
543
- }
544
- );
545
-
546
- return (
547
- <Option value={theme} key={theme}>
548
- {label}
549
- </Option>
550
- );
551
- })}
536
+ {themesToDisplay.map(theme => (
537
+ <Option value={theme} key={theme}>
538
+ {formatMessage(
539
+ {
540
+ id:
541
+ 'Settings.profile.form.section.experience.mode.option-label',
542
+ defaultMessage: '{name} mode',
543
+ },
544
+ {
545
+ name: formatMessage({
546
+ id: theme,
547
+ defaultMessage: upperFirst(theme),
548
+ }),
549
+ }
550
+ )}
551
+ </Option>
552
+ ))}
552
553
  </Select>
553
554
  </GridItem>
554
555
  </Grid>
@@ -18,8 +18,7 @@ const FromUrlForm = ({ goTo, next, onClose, setLocalImage }) => {
18
18
  setLogoUrl(e.target.value);
19
19
  };
20
20
 
21
- const handleSubmit = async e => {
22
- e.preventDefault();
21
+ const handleSubmit = async () => {
23
22
  try {
24
23
  const file = await urlToFile(logoUrl);
25
24
  const asset = await parseFileMetadatas(file);
@@ -36,7 +35,12 @@ const FromUrlForm = ({ goTo, next, onClose, setLocalImage }) => {
36
35
  };
37
36
 
38
37
  return (
39
- <form onSubmit={handleSubmit}>
38
+ <form
39
+ onSubmit={e => {
40
+ e.preventDefault();
41
+ handleSubmit();
42
+ }}
43
+ >
40
44
  <Box paddingLeft={8} paddingRight={8} paddingTop={6} paddingBottom={6}>
41
45
  <TextInput
42
46
  label={formatMessage({
@@ -62,7 +62,7 @@ const layout = [
62
62
  id: 'Auth.form.username.placeholder',
63
63
  defaultMessage: 'e.g. Kai_Doe',
64
64
  },
65
- type: 'email',
65
+ type: 'text',
66
66
  size: {
67
67
  col: 6,
68
68
  xs: 12,
@@ -81,6 +81,7 @@ const layout = [
81
81
  col: 6,
82
82
  xs: 12,
83
83
  },
84
+ autoComplete: 'new-password',
84
85
  },
85
86
  {
86
87
  intlLabel: {
@@ -93,6 +94,7 @@ const layout = [
93
94
  col: 6,
94
95
  xs: 12,
95
96
  },
97
+ autoComplete: 'new-password',
96
98
  },
97
99
  ],
98
100
  [
@@ -63,7 +63,7 @@ const TableRows = ({
63
63
  return (
64
64
  <Td key={key}>
65
65
  {typeof cellFormatter === 'function' ? (
66
- cellFormatter(data, { key, name, ...rest })
66
+ cellFormatter(data, { key, name, formatMessage, ...rest })
67
67
  ) : (
68
68
  <Typography textColor="neutral800">{data[name] || '-'}</Typography>
69
69
  )}
@@ -24,9 +24,18 @@ const tableHeaders = [
24
24
  name: 'roles',
25
25
  metadatas: { label: 'Roles', sortable: false },
26
26
  /* eslint-disable react/prop-types */
27
- cellFormatter: ({ roles }) => {
27
+ cellFormatter: ({ roles }, { formatMessage }) => {
28
28
  return (
29
- <Typography textColor="neutral800">{roles.map(role => role.name).join(',\n')}</Typography>
29
+ <Typography textColor="neutral800">
30
+ {roles
31
+ .map(role =>
32
+ formatMessage({
33
+ id: `global.${role.code}`,
34
+ defaultMessage: role.name,
35
+ })
36
+ )
37
+ .join(',\n')}
38
+ </Typography>
30
39
  );
31
40
  },
32
41
  /* eslint-enable react/prop-types */
@@ -41,11 +50,16 @@ const tableHeaders = [
41
50
  name: 'isActive',
42
51
  metadatas: { label: 'User status', sortable: false },
43
52
  // eslint-disable-next-line react/prop-types
44
- cellFormatter: ({ isActive }) => {
53
+ cellFormatter: ({ isActive }, { formatMessage }) => {
45
54
  return (
46
55
  <Flex>
47
56
  <Status isActive={isActive} variant={isActive ? 'success' : 'danger'} />
48
- <Typography textColor="neutral800">{isActive ? 'Active' : 'Inactive'}</Typography>
57
+ <Typography textColor="neutral800">
58
+ {formatMessage({
59
+ id: isActive ? 'global.active' : 'global.inactive',
60
+ defaultMessage: isActive ? 'Active' : 'Inactive',
61
+ })}
62
+ </Typography>
49
63
  </Flex>
50
64
  );
51
65
  },
@@ -73,7 +73,10 @@ const SelectRoles = ({ disabled, error, onChange, value }) => {
73
73
  {(data || []).map(role => {
74
74
  return (
75
75
  <Option key={role.id} value={role.id}>
76
- {role.name}
76
+ {formatMessage({
77
+ id: `global.${role.code}`,
78
+ defaultMessage: role.name,
79
+ })}
77
80
  </Option>
78
81
  );
79
82
  })}
@@ -1,12 +1,13 @@
1
+ import appReducer from './pages/App/reducer';
1
2
  import rbacProviderReducer from './components/RBACProvider/reducer';
2
- import appReducer from './content-manager/pages/App/reducer';
3
+ import cmAppReducer from './content-manager/pages/App/reducer';
3
4
  import editViewLayoutManagerReducer from './content-manager/pages/EditViewLayoutManager/reducer';
4
5
  import listViewReducer from './content-manager/pages/ListView/reducer';
5
6
  import rbacManagerReducer from './content-manager/hooks/useSyncRbac/reducer';
6
7
  import editViewCrudReducer from './content-manager/sharedReducers/crudReducer/reducer';
7
8
 
8
9
  const contentManagerReducers = {
9
- 'content-manager_app': appReducer,
10
+ 'content-manager_app': cmAppReducer,
10
11
  'content-manager_listView': listViewReducer,
11
12
  'content-manager_rbacManager': rbacManagerReducer,
12
13
  'content-manager_editViewLayoutManager': editViewLayoutManagerReducer,
@@ -14,6 +15,7 @@ const contentManagerReducers = {
14
15
  };
15
16
 
16
17
  const reducers = {
18
+ admin_app: appReducer,
17
19
  rbacProvider: rbacProviderReducer,
18
20
  ...contentManagerReducers,
19
21
  };