@strapi/admin 4.12.0-beta.5 → 4.12.1

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 (162) hide show
  1. package/admin/src/components/LeftMenu/index.js +1 -1
  2. package/admin/src/components/PluginsInitializer/index.js +23 -0
  3. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +9 -14
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +1 -1
  5. package/admin/src/content-manager/components/InputUID/index.js +2 -3
  6. package/admin/src/content-manager/components/RelationInput/RelationInput.js +1 -1
  7. package/admin/src/content-manager/components/RelationInputDataManager/utils/getRelationLink.js +1 -3
  8. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +4 -6
  9. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +7 -9
  10. package/admin/src/content-manager/pages/App/utils/getContentTypeLinks.js +1 -3
  11. package/admin/src/content-manager/pages/EditSettingsView/index.js +31 -18
  12. package/admin/src/content-manager/pages/ListSettingsView/components/EditFieldForm.js +1 -3
  13. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +1 -3
  14. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +14 -32
  15. package/admin/src/content-manager/pages/ListSettingsView/index.js +50 -40
  16. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/ConfirmBulkActionDialog/index.js +2 -0
  17. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +83 -36
  18. package/admin/src/content-manager/pages/ListView/components/CellContent/RelationMultiple/index.js +2 -2
  19. package/admin/src/content-manager/pages/ListView/index.js +3 -3
  20. package/admin/src/content-manager/sharedReducers/crudReducer/reducer.js +1 -1
  21. package/admin/src/content-manager/utils/checkIfAttributeIsDisplayable.js +2 -4
  22. package/admin/src/content-manager/utils/index.js +0 -1
  23. package/admin/src/pages/AuthPage/constants.js +2 -2
  24. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +1 -1
  25. package/admin/src/translations/ar.json +9 -3
  26. package/admin/src/translations/ca.json +8 -2
  27. package/admin/src/translations/de.json +8 -2
  28. package/admin/src/translations/dk.json +8 -2
  29. package/admin/src/translations/en.json +9 -2
  30. package/admin/src/translations/es.json +9 -3
  31. package/admin/src/translations/eu.json +8 -2
  32. package/admin/src/translations/fr.json +9 -2
  33. package/admin/src/translations/gu.json +8 -2
  34. package/admin/src/translations/hi.json +9 -3
  35. package/admin/src/translations/hu.json +9 -3
  36. package/admin/src/translations/ja.json +12 -6
  37. package/admin/src/translations/ko.json +12 -6
  38. package/admin/src/translations/ml.json +8 -2
  39. package/admin/src/translations/nl.json +8 -2
  40. package/admin/src/translations/pl.json +8 -2
  41. package/admin/src/translations/pt-BR.json +8 -2
  42. package/admin/src/translations/ru.json +8 -2
  43. package/admin/src/translations/sa.json +9 -3
  44. package/admin/src/translations/sk.json +8 -2
  45. package/admin/src/translations/sv.json +7 -2
  46. package/admin/src/translations/tr.json +8 -2
  47. package/admin/src/translations/zh-Hans.json +8 -2
  48. package/admin/src/translations/zh.json +8 -2
  49. package/admin/src/utils/index.js +0 -1
  50. package/build/{1049.758a01f5.chunk.js → 1049.c3d082e9.chunk.js} +1 -1
  51. package/build/1386.879bcd90.chunk.js +7 -0
  52. package/build/{2225.15d1df72.chunk.js → 2225.0e4f8c77.chunk.js} +1 -1
  53. package/build/2379.f1641312.chunk.js +1 -0
  54. package/build/2395.46f8d0c1.chunk.js +26 -0
  55. package/build/2801.5cef5ec8.chunk.js +1 -0
  56. package/build/{3483.e2ee2547.chunk.js → 3483.03c24f96.chunk.js} +1 -1
  57. package/build/3929.5632f24d.chunk.js +114 -0
  58. package/build/4546.cfafae68.chunk.js +1 -0
  59. package/build/6691.4985ef22.chunk.js +105 -0
  60. package/build/7464.3e64a1d5.chunk.js +1 -0
  61. package/build/8276.10a3f883.chunk.js +26 -0
  62. package/build/{9806.aa25371d.chunk.js → 9806.3392505e.chunk.js} +2 -2
  63. package/build/{Admin-authenticatedApp.6b8dfa45.chunk.js → Admin-authenticatedApp.8dfbc48d.chunk.js} +3 -3
  64. package/build/{Admin_profilePage.a968035f.chunk.js → Admin_profilePage.ca82c67b.chunk.js} +1 -1
  65. package/build/{Admin_settingsPage.8c600d1a.chunk.js → Admin_settingsPage.50c867bf.chunk.js} +1 -1
  66. package/build/admin-app.041dcd81.chunk.js +36 -0
  67. package/build/{admin-edit-users.67704088.chunk.js → admin-edit-users.79eeb125.chunk.js} +1 -1
  68. package/build/{admin-users.3279ffb0.chunk.js → admin-users.123aa08e.chunk.js} +1 -1
  69. package/build/ar-json.74e40bc7.chunk.js +1 -0
  70. package/build/{ca-json.a53c10b6.chunk.js → ca-json.fc6001d3.chunk.js} +1 -1
  71. package/build/content-manager.098eb004.chunk.js +1099 -0
  72. package/build/content-type-builder.64f4d6ac.chunk.js +170 -0
  73. package/build/{de-json.b3be02c7.chunk.js → de-json.e72545cf.chunk.js} +1 -1
  74. package/build/dk-json.e77140ef.chunk.js +1 -0
  75. package/build/{en-json.4c733bd1.chunk.js → en-json.01456e61.chunk.js} +1 -1
  76. package/build/es-json.b1f2284b.chunk.js +1 -0
  77. package/build/{eu-json.633025f0.chunk.js → eu-json.63d0a898.chunk.js} +1 -1
  78. package/build/{fr-json.aa8839d2.chunk.js → fr-json.33c6428b.chunk.js} +1 -1
  79. package/build/{gu-json.5bd62812.chunk.js → gu-json.7efe8cc2.chunk.js} +1 -1
  80. package/build/{hi-json.9104eb78.chunk.js → hi-json.0d633692.chunk.js} +1 -1
  81. package/build/{hu-json.9f4aae42.chunk.js → hu-json.c74b6a1e.chunk.js} +1 -1
  82. package/build/index.html +1 -1
  83. package/build/{ja-json.91286391.chunk.js → ja-json.e1959a1c.chunk.js} +1 -1
  84. package/build/{ko-json.fcf3ec4b.chunk.js → ko-json.ce5d6d94.chunk.js} +1 -1
  85. package/build/{main.af84ad9c.js → main.1f8cc299.js} +429 -429
  86. package/build/{ml-json.557aa14c.chunk.js → ml-json.940d7ace.chunk.js} +1 -1
  87. package/build/{nl-json.b2b16eea.chunk.js → nl-json.fe38f0fb.chunk.js} +1 -1
  88. package/build/{pl-json.f094a417.chunk.js → pl-json.d55e8e78.chunk.js} +1 -1
  89. package/build/{pt-BR-json.dec7fb01.chunk.js → pt-BR-json.ae0a0d2e.chunk.js} +1 -1
  90. package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +1 -0
  91. package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +1 -0
  92. package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +56 -0
  93. package/build/{ru-json.8193d8c4.chunk.js → ru-json.1c976644.chunk.js} +1 -1
  94. package/build/{runtime~main.a65ca6fb.js → runtime~main.80a43c16.js} +2 -2
  95. package/build/{sa-json.a56836f1.chunk.js → sa-json.2c03ef4e.chunk.js} +1 -1
  96. package/build/sk-json.b41847e8.chunk.js +1 -0
  97. package/build/sso-settings-page.81152e62.chunk.js +1 -0
  98. package/build/{sv-json.fd0e86c6.chunk.js → sv-json.568cb7ae.chunk.js} +1 -1
  99. package/build/{tr-json.56c32cf6.chunk.js → tr-json.c9f22432.chunk.js} +1 -1
  100. package/build/transfer-tokens-list-page.692eee77.chunk.js +16 -0
  101. package/build/upload-settings.7f93d4c0.chunk.js +14 -0
  102. package/build/upload.77d8a64c.chunk.js +58 -0
  103. package/build/users-advanced-settings-page.f0760eb8.chunk.js +9 -0
  104. package/build/users-email-settings-page.ff4b32f3.chunk.js +9 -0
  105. package/build/users-providers-settings-page.48de0306.chunk.js +14 -0
  106. package/build/users-roles-settings-page.3f9f063e.chunk.js +30 -0
  107. package/build/{webhook-edit-page.a91f27a1.chunk.js → webhook-edit-page.6cb479ff.chunk.js} +2 -2
  108. package/build/{zh-Hans-json.36d81cdc.chunk.js → zh-Hans-json.937b395b.chunk.js} +1 -1
  109. package/build/{zh-json.1cc86ff0.chunk.js → zh-json.bfc2e036.chunk.js} +1 -1
  110. package/ee/admin/hooks/useAuthProviders/index.js +1 -3
  111. package/ee/admin/pages/AuthResponse/index.js +1 -3
  112. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +35 -32
  113. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -7
  114. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +16 -14
  115. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +33 -33
  116. package/ee/admin/pages/SettingsPage/pages/SingleSignOn/index.js +1 -2
  117. package/ee/server/bootstrap.js +2 -0
  118. package/ee/server/config/admin-actions.js +6 -6
  119. package/ee/server/services/auth.js +1 -1
  120. package/ee/server/services/index.js +1 -0
  121. package/ee/server/services/review-workflows/entity-service-decorator.js +4 -3
  122. package/ee/server/services/review-workflows/metrics/index.js +51 -0
  123. package/ee/server/services/review-workflows/metrics/weekly-metrics.js +76 -0
  124. package/ee/server/services/review-workflows/workflows/index.js +5 -0
  125. package/package.json +16 -16
  126. package/server/middlewares/rateLimit.js +6 -2
  127. package/server/services/transfer/token.js +27 -4
  128. package/server/validation/authentication/register.js +2 -2
  129. package/admin/src/content-manager/components/SingleTypeFormWrapper/utils/getRequestUrl.js +0 -5
  130. package/admin/src/content-manager/components/SingleTypeFormWrapper/utils/index.js +0 -2
  131. package/admin/src/content-manager/pages/EditSettingsView/utils/api.js +0 -16
  132. package/admin/src/content-manager/pages/ListSettingsView/init.js +0 -9
  133. package/admin/src/content-manager/utils/getRequestUrl.js +0 -4
  134. package/admin/src/utils/getRequestUrl.js +0 -3
  135. package/build/1386.762d6eb8.chunk.js +0 -7
  136. package/build/2379.0ca87a89.chunk.js +0 -1
  137. package/build/2395.df7a044a.chunk.js +0 -26
  138. package/build/2801.b1140c9b.chunk.js +0 -1
  139. package/build/4546.ff9fdf30.chunk.js +0 -1
  140. package/build/6691.f880a0b6.chunk.js +0 -105
  141. package/build/7065.ec811562.chunk.js +0 -114
  142. package/build/7464.8a6c1e6c.chunk.js +0 -1
  143. package/build/8276.6c7b8e6e.chunk.js +0 -26
  144. package/build/admin-app.c2e4e128.chunk.js +0 -36
  145. package/build/ar-json.f530bc3f.chunk.js +0 -1
  146. package/build/content-manager.8772445b.chunk.js +0 -1103
  147. package/build/content-type-builder.40534de5.chunk.js +0 -170
  148. package/build/dk-json.842aa391.chunk.js +0 -1
  149. package/build/es-json.f57b5335.chunk.js +0 -1
  150. package/build/review-workflows-settings-create-view.05758184.chunk.js +0 -1
  151. package/build/review-workflows-settings-edit-view.c33f7c58.chunk.js +0 -1
  152. package/build/review-workflows-settings-list-view.3ee9190d.chunk.js +0 -56
  153. package/build/sk-json.bf2f057a.chunk.js +0 -1
  154. package/build/sso-settings-page.7c9b2fd9.chunk.js +0 -1
  155. package/build/transfer-tokens-list-page.22147d2c.chunk.js +0 -16
  156. package/build/upload-settings.cac210a0.chunk.js +0 -14
  157. package/build/upload.cbfeefa5.chunk.js +0 -58
  158. package/build/users-advanced-settings-page.18379a56.chunk.js +0 -9
  159. package/build/users-email-settings-page.a87978e5.chunk.js +0 -9
  160. package/build/users-providers-settings-page.8876c1ee.chunk.js +0 -14
  161. package/build/users-roles-settings-page.0431f48c.chunk.js +0 -30
  162. package/ee/server/services/review-workflows/metrics.js +0 -24
@@ -169,43 +169,43 @@ export function ReviewWorkflowsListView() {
169
169
  <>
170
170
  <Layout.Header
171
171
  primaryAction={
172
- <LinkButton
173
- disabled={!canCreate}
174
- startIcon={<Plus />}
175
- size="S"
176
- to="/settings/review-workflows/create"
177
- onClick={(event) => {
178
- /**
179
- * If the current license has a workflow limit:
180
- * check if the total count of workflows exceeds that limit. If so,
181
- * prevent the navigation and show the limits overlay.
182
- *
183
- * If the current license does not have a limit (e.g. offline license):
184
- * allow the user to navigate to the create-view. In case they exceed the
185
- * current hard-limit of 200 they will see an error thrown by the API.
186
- */
172
+ canCreate && (
173
+ <LinkButton
174
+ startIcon={<Plus />}
175
+ size="S"
176
+ to="/settings/review-workflows/create"
177
+ onClick={(event) => {
178
+ /**
179
+ * If the current license has a workflow limit:
180
+ * check if the total count of workflows exceeds that limit. If so,
181
+ * prevent the navigation and show the limits overlay.
182
+ *
183
+ * If the current license does not have a limit (e.g. offline license):
184
+ * allow the user to navigate to the create-view. In case they exceed the
185
+ * current hard-limit of 200 they will see an error thrown by the API.
186
+ */
187
187
 
188
- if (
189
- limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] &&
190
- meta?.workflowCount >= parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10)
191
- ) {
192
- event.preventDefault();
193
- setShowLimitModal(true);
194
- } else {
195
- trackUsage('willCreateWorkflow');
196
- }
197
- }}
198
- >
199
- {formatMessage({
200
- id: 'Settings.review-workflows.list.page.create',
201
- defaultMessage: 'Create new workflow',
202
- })}
203
- </LinkButton>
188
+ if (
189
+ limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] &&
190
+ meta?.workflowCount >= parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10)
191
+ ) {
192
+ event.preventDefault();
193
+ setShowLimitModal(true);
194
+ } else {
195
+ trackUsage('willCreateWorkflow');
196
+ }
197
+ }}
198
+ >
199
+ {formatMessage({
200
+ id: 'Settings.review-workflows.list.page.create',
201
+ defaultMessage: 'Create new workflow',
202
+ })}
203
+ </LinkButton>
204
+ )
204
205
  }
205
206
  subtitle={formatMessage({
206
207
  id: 'Settings.review-workflows.list.page.subtitle',
207
- defaultMessage:
208
- 'Manage content review stages and collaborate during content creation from draft to publication',
208
+ defaultMessage: 'Manage your content review process',
209
209
  })}
210
210
  title={formatMessage({
211
211
  id: 'Settings.review-workflows.list.page.title',
@@ -30,7 +30,6 @@ import { useSelector } from 'react-redux';
30
30
 
31
31
  import { useRolesList, useSettingsForm } from '../../../../../../admin/src/hooks';
32
32
  import { selectAdminPermissions } from '../../../../../../admin/src/pages/App/selectors';
33
- import { getRequestUrl } from '../../../../../../admin/src/utils';
34
33
 
35
34
  import schema from './utils/schema';
36
35
 
@@ -51,7 +50,7 @@ export const SingleSignOn = () => {
51
50
  // eslint-disable-next-line no-unused-vars
52
51
  dispatch,
53
52
  { handleChange, handleSubmit },
54
- ] = useSettingsForm(getRequestUrl('providers/options'), schema, () => {}, [
53
+ ] = useSettingsForm('/admin/providers/options', schema, () => {}, [
55
54
  'autoRegister',
56
55
  'defaultRole',
57
56
  'ssoLockedRoles',
@@ -31,6 +31,8 @@ module.exports = async () => {
31
31
  // Decorate the entity service with review workflow logic
32
32
  const { decorator } = getService('review-workflows-decorator');
33
33
  strapi.entityService.decorate(decorator);
34
+
35
+ await getService('review-workflows-weekly-metrics').registerCron();
34
36
  }
35
37
 
36
38
  await getService('seat-enforcement').seatEnforcementWorkflow();
@@ -39,24 +39,24 @@ module.exports = {
39
39
  subCategory: 'options',
40
40
  },
41
41
  {
42
- uid: 'review-workflows.update',
43
- displayName: 'Update',
42
+ uid: 'review-workflows.read',
43
+ displayName: 'Read',
44
44
  pluginName: 'admin',
45
45
  section: 'settings',
46
46
  category: 'review workflows',
47
47
  subCategory: 'options',
48
48
  },
49
49
  {
50
- uid: 'review-workflows.delete',
51
- displayName: 'Delete',
50
+ uid: 'review-workflows.update',
51
+ displayName: 'Update',
52
52
  pluginName: 'admin',
53
53
  section: 'settings',
54
54
  category: 'review workflows',
55
55
  subCategory: 'options',
56
56
  },
57
57
  {
58
- uid: 'review-workflows.read',
59
- displayName: 'Read',
58
+ uid: 'review-workflows.delete',
59
+ displayName: 'Delete',
60
60
  pluginName: 'admin',
61
61
  section: 'settings',
62
62
  category: 'review workflows',
@@ -59,7 +59,7 @@ const resetPassword = async ({ resetPasswordToken, password } = {}) => {
59
59
  .query('admin::user')
60
60
  .findOne({ where: { resetPasswordToken, isActive: true } });
61
61
 
62
- if (!matchingUser || isSsoLocked(matchingUser)) {
62
+ if (!matchingUser || (await isSsoLocked(matchingUser))) {
63
63
  throw new ApplicationError();
64
64
  }
65
65
 
@@ -12,4 +12,5 @@ module.exports = {
12
12
  'review-workflows-validation': require('./review-workflows/validation'),
13
13
  'review-workflows-decorator': require('./review-workflows/entity-service-decorator'),
14
14
  'review-workflows-metrics': require('./review-workflows/metrics'),
15
+ 'review-workflows-weekly-metrics': require('./review-workflows/metrics/weekly-metrics'),
15
16
  };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { isNil, isNull } = require('lodash/fp');
3
+ const { isNil } = require('lodash/fp');
4
4
  const { ENTITY_STAGE_ATTRIBUTE } = require('../../constants/workflows');
5
5
  const { WORKFLOW_UPDATE_STAGE } = require('../../constants/webhookEvents');
6
6
  const { getService } = require('../../utils');
@@ -56,7 +56,7 @@ const decorator = (service) => ({
56
56
  async update(uid, entityId, opts = {}) {
57
57
  // Prevents the stage from being set to null
58
58
  const data = { ...opts.data };
59
- if (isNull(data[ENTITY_STAGE_ATTRIBUTE])) {
59
+ if (isNil(data[ENTITY_STAGE_ATTRIBUTE])) {
60
60
  delete data[ENTITY_STAGE_ATTRIBUTE];
61
61
  return service.update.call(this, uid, entityId, { ...opts, data });
62
62
  }
@@ -66,7 +66,8 @@ const decorator = (service) => ({
66
66
  const updatedEntity = await service.update.call(this, uid, entityId, { ...opts, data });
67
67
  const updatedStage = updatedEntity[ENTITY_STAGE_ATTRIBUTE];
68
68
 
69
- if (previousStage?.id && previousStage.id !== updatedStage.id) {
69
+ // Stage might be null if field is not populated
70
+ if (updatedStage && previousStage?.id && previousStage.id !== updatedStage.id) {
70
71
  const model = strapi.getModel(uid);
71
72
 
72
73
  strapi.eventHub.emit(WORKFLOW_UPDATE_STAGE, {
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ const sendDidCreateStage = async () => {
4
+ strapi.telemetry.send('didCreateStage', {});
5
+ };
6
+
7
+ const sendDidEditStage = async () => {
8
+ strapi.telemetry.send('didEditStage', {});
9
+ };
10
+
11
+ const sendDidDeleteStage = async () => {
12
+ strapi.telemetry.send('didDeleteStage', {});
13
+ };
14
+
15
+ const sendDidChangeEntryStage = async () => {
16
+ strapi.telemetry.send('didChangeEntryStage', {});
17
+ };
18
+
19
+ const sendDidCreateWorkflow = async () => {
20
+ strapi.telemetry.send('didCreateWorkflow', {});
21
+ };
22
+
23
+ const sendDidEditWorkflow = async () => {
24
+ strapi.telemetry.send('didEditWorkflow', {});
25
+ };
26
+
27
+ const sendDidSendReviewWorkflowPropertiesOnceAWeek = async (
28
+ numberOfActiveWorkflows,
29
+ avgStagesCount,
30
+ maxStagesCount,
31
+ activatedContentTypes
32
+ ) => {
33
+ strapi.telemetry.send('didSendReviewWorkflowPropertiesOnceAWeek', {
34
+ groupProperties: {
35
+ numberOfActiveWorkflows,
36
+ avgStagesCount,
37
+ maxStagesCount,
38
+ activatedContentTypes,
39
+ },
40
+ });
41
+ };
42
+
43
+ module.exports = {
44
+ sendDidCreateStage,
45
+ sendDidEditStage,
46
+ sendDidDeleteStage,
47
+ sendDidChangeEntryStage,
48
+ sendDidCreateWorkflow,
49
+ sendDidEditWorkflow,
50
+ sendDidSendReviewWorkflowPropertiesOnceAWeek,
51
+ };
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ const { flow, map, sum, size, mean, max, defaultTo } = require('lodash/fp');
4
+ const { add } = require('date-fns');
5
+ const { getService } = require('../../../../../server/utils');
6
+
7
+ const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
8
+
9
+ const getWeeklyCronScheduleAt = (date) =>
10
+ `${date.getSeconds()} ${date.getMinutes()} ${date.getHours()} * * ${date.getDay()}`;
11
+
12
+ const getMetricsStoreValue = async () => {
13
+ const value = await strapi.store.get({ type: 'plugin', name: 'ee', key: 'metrics' });
14
+ return defaultTo({}, value);
15
+ };
16
+
17
+ const setMetricsStoreValue = (value) =>
18
+ strapi.store.set({ type: 'plugin', name: 'ee', key: 'metrics', value });
19
+
20
+ module.exports = ({ strapi }) => {
21
+ const metrics = getService('review-workflows-metrics', { strapi });
22
+ const workflowsService = getService('workflows', { strapi });
23
+
24
+ return {
25
+ async computeMetrics() {
26
+ // There will never be more than 200 workflow, so we can safely fetch them all
27
+ const workflows = await workflowsService.find({ populate: 'stages' });
28
+
29
+ const stagesCount = flow(
30
+ map('stages'), // Number of stages per workflow
31
+ map(size)
32
+ )(workflows);
33
+
34
+ const contentTypesCount = flow(
35
+ map('contentTypes'), // Number of content types per workflow
36
+ map(size)
37
+ )(workflows);
38
+
39
+ return {
40
+ numberOfActiveWorkflows: size(workflows),
41
+ avgStagesCount: mean(stagesCount),
42
+ maxStagesCount: max(stagesCount),
43
+ activatedContentTypes: sum(contentTypesCount),
44
+ };
45
+ },
46
+
47
+ async sendMetrics() {
48
+ const computedMetrics = await this.computeMetrics();
49
+ metrics.sendDidSendReviewWorkflowPropertiesOnceAWeek(computedMetrics);
50
+
51
+ const metricsInfoStored = await getMetricsStoreValue();
52
+ await setMetricsStoreValue({ ...metricsInfoStored, lastWeeklyUpdate: new Date().getTime() });
53
+ },
54
+
55
+ async ensureWeeklyStoredCronSchedule() {
56
+ const metricsInfoStored = await getMetricsStoreValue();
57
+ const { weeklySchedule: currentSchedule, lastWeeklyUpdate } = metricsInfoStored;
58
+
59
+ const now = new Date();
60
+ let weeklySchedule = currentSchedule;
61
+
62
+ if (!currentSchedule || !lastWeeklyUpdate || lastWeeklyUpdate + ONE_WEEK < now.getTime()) {
63
+ weeklySchedule = getWeeklyCronScheduleAt(add(now, { seconds: 10 }));
64
+ await setMetricsStoreValue({ ...metricsInfoStored, weeklySchedule });
65
+ }
66
+
67
+ return weeklySchedule;
68
+ },
69
+
70
+ async registerCron() {
71
+ const weeklySchedule = await this.ensureWeeklyStoredCronSchedule();
72
+
73
+ strapi.cron.add({ [weeklySchedule]: this.sendMetrics.bind(this) });
74
+ },
75
+ };
76
+ };
@@ -20,6 +20,7 @@ const processFilters = ({ strapi }, filters = {}) => {
20
20
  module.exports = ({ strapi }) => {
21
21
  const workflowsContentTypes = workflowsContentTypesFactory({ strapi });
22
22
  const workflowsValidationService = getService('review-workflows-validation', { strapi });
23
+ const metrics = getService('review-workflows-metrics', { strapi });
23
24
 
24
25
  return {
25
26
  /**
@@ -70,6 +71,8 @@ module.exports = ({ strapi }) => {
70
71
  });
71
72
  }
72
73
 
74
+ metrics.sendDidCreateWorkflow();
75
+
73
76
  // Create Workflow
74
77
  return strapi.entityService.create(WORKFLOW_MODEL_UID, createOpts);
75
78
  });
@@ -113,6 +116,8 @@ module.exports = ({ strapi }) => {
113
116
  });
114
117
  }
115
118
 
119
+ metrics.sendDidEditWorkflow();
120
+
116
121
  // Update Workflow
117
122
  return strapi.entityService.update(WORKFLOW_MODEL_UID, workflow.id, updateOpts);
118
123
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/admin",
3
- "version": "4.12.0-beta.5",
3
+ "version": "4.12.1",
4
4
  "description": "Strapi Admin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,31 +42,31 @@
42
42
  "dependencies": {
43
43
  "@casl/ability": "^5.4.3",
44
44
  "@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
45
- "@strapi/data-transfer": "4.12.0-beta.5",
45
+ "@strapi/data-transfer": "4.12.1",
46
46
  "@strapi/design-system": "1.8.2",
47
- "@strapi/helper-plugin": "4.12.0-beta.5",
47
+ "@strapi/helper-plugin": "4.12.1",
48
48
  "@strapi/icons": "1.8.2",
49
- "@strapi/permissions": "4.12.0-beta.5",
50
- "@strapi/provider-audit-logs-local": "4.12.0-beta.5",
51
- "@strapi/typescript-utils": "4.12.0-beta.5",
52
- "@strapi/utils": "4.12.0-beta.5",
49
+ "@strapi/permissions": "4.12.1",
50
+ "@strapi/provider-audit-logs-local": "4.12.1",
51
+ "@strapi/typescript-utils": "4.12.1",
52
+ "@strapi/utils": "4.12.1",
53
53
  "axios": "1.4.0",
54
54
  "bcryptjs": "2.4.3",
55
55
  "browserslist": "^4.17.3",
56
56
  "browserslist-to-esbuild": "1.2.0",
57
57
  "chalk": "^4.1.2",
58
- "chokidar": "^3.5.1",
58
+ "chokidar": "3.5.3",
59
59
  "codemirror5": "npm:codemirror@^5.65.11",
60
60
  "cross-env": "^7.0.3",
61
61
  "css-loader": "^6.8.1",
62
62
  "date-fns": "2.30.0",
63
- "dotenv": "8.5.1",
63
+ "dotenv": "14.2.0",
64
64
  "esbuild-loader": "^2.21.0",
65
- "execa": "^1.0.0",
65
+ "execa": "5.1.1",
66
66
  "fast-deep-equal": "3.1.3",
67
67
  "find-root": "1.1.0",
68
68
  "fork-ts-checker-webpack-plugin": "7.3.0",
69
- "formik": "^2.4.0",
69
+ "formik": "2.4.0",
70
70
  "fractional-indexing": "3.2.0",
71
71
  "fs-extra": "10.0.0",
72
72
  "highlight.js": "^10.4.1",
@@ -114,10 +114,10 @@
114
114
  "react-select": "5.7.0",
115
115
  "react-window": "1.8.8",
116
116
  "redux": "^4.2.1",
117
- "reselect": "^4.1.7",
117
+ "reselect": "4.1.7",
118
118
  "rimraf": "3.0.2",
119
119
  "sanitize-html": "2.11.0",
120
- "semver": "7.5.2",
120
+ "semver": "7.5.4",
121
121
  "sift": "16.0.1",
122
122
  "style-loader": "3.3.1",
123
123
  "styled-components": "5.3.3",
@@ -126,7 +126,7 @@
126
126
  "webpack-cli": "^5.1.0",
127
127
  "webpack-dev-server": "^4.15.0",
128
128
  "webpackbar": "^5.0.2",
129
- "yup": "^0.32.9"
129
+ "yup": "0.32.9"
130
130
  },
131
131
  "devDependencies": {
132
132
  "@testing-library/dom": "9.2.0",
@@ -142,7 +142,7 @@
142
142
  "@strapi/strapi": "^4.3.4"
143
143
  },
144
144
  "engines": {
145
- "node": ">=14.19.1 <=18.x.x",
145
+ "node": ">=16.0.0 <=20.x.x",
146
146
  "npm": ">=6.0.0"
147
147
  },
148
148
  "nx": {
@@ -154,5 +154,5 @@
154
154
  }
155
155
  }
156
156
  },
157
- "gitHead": "690c85458416da815f0e944fa8fc6dbe0fb2d001"
157
+ "gitHead": "be8985fa20cb357981bca97bc65ee5c1b843f801"
158
158
  }
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ const path = require('path');
3
4
  const utils = require('@strapi/utils');
4
- const { has, toLower } = require('lodash/fp');
5
+ const { isString, has, toLower } = require('lodash/fp');
5
6
 
6
7
  const { RateLimitError } = utils.errors;
7
8
 
@@ -24,11 +25,14 @@ module.exports =
24
25
  const rateLimit = require('koa2-ratelimit').RateLimit;
25
26
 
26
27
  const userEmail = toLower(ctx.request.body.email) || 'unknownEmail';
28
+ const requestPath = isString(ctx.request.path)
29
+ ? toLower(path.normalize(ctx.request.path)).replace(/\/$/, '')
30
+ : 'invalidPath';
27
31
 
28
32
  const loadConfig = {
29
33
  interval: { min: 5 },
30
34
  max: 5,
31
- prefixKey: `${userEmail}:${ctx.request.path}:${ctx.request.ip}`,
35
+ prefixKey: `${userEmail}:${requestPath}:${ctx.request.ip}`,
32
36
  handler() {
33
37
  throw new RateLimitError();
34
38
  },
@@ -1,7 +1,8 @@
1
1
  'use strict';
2
2
 
3
- const { map, isArray, omit, uniq, isNil, difference, isEmpty } = require('lodash/fp');
4
3
  const crypto = require('crypto');
4
+ const assert = require('assert');
5
+ const { map, isArray, omit, uniq, isNil, difference, isEmpty } = require('lodash/fp');
5
6
 
6
7
  const {
7
8
  errors: { ValidationError, NotFoundError },
@@ -65,6 +66,24 @@ const list = async () => {
65
66
  return tokens.map((token) => flattenTokenPermissions(token));
66
67
  };
67
68
 
69
+ /**
70
+ * Create a random token's access key
71
+ * @returns {string}
72
+ */
73
+ const generateRandomAccessKey = () => crypto.randomBytes(128).toString('hex');
74
+
75
+ /**
76
+ * Validate the given access key's format and returns it if valid
77
+ * @param {string} accessKey
78
+ * @return {string}
79
+ */
80
+ const validateAccessKey = (accessKey) => {
81
+ assert(typeof accessKey === 'string', 'Access key needs to be a string');
82
+ assert(accessKey.length >= 15, 'Access key needs to have at least 15 characters');
83
+
84
+ return accessKey;
85
+ };
86
+
68
87
  /**
69
88
  * Create a token and its permissions
70
89
  *
@@ -73,11 +92,16 @@ const list = async () => {
73
92
  * @param {string} attributes.description
74
93
  * @param {number} attributes.lifespan
75
94
  * @param {string[]} attributes.permissions
95
+ * @param {string} [attributes.accessKey]
76
96
  *
77
97
  * @returns {Promise<TransferToken>}
78
98
  */
79
99
  const create = async (attributes) => {
80
- const accessKey = crypto.randomBytes(128).toString('hex');
100
+ const accessKey =
101
+ 'accessKey' in attributes ? validateAccessKey(attributes.accessKey) : generateRandomAccessKey();
102
+
103
+ // Make sure the access key isn't picked up directly from the attributes for the next steps
104
+ delete attributes.accessKey;
81
105
 
82
106
  assertTokenPermissionsValidity(attributes);
83
107
  assertValidLifespan(attributes);
@@ -380,8 +404,7 @@ const flattenTokenPermissions = (token) => {
380
404
 
381
405
  /**
382
406
  * Assert that a token's permissions are valid
383
- *
384
- * @param {TransferToken} token
407
+ * @param {object} attributes
385
408
  */
386
409
  const assertTokenPermissionsValidity = (attributes) => {
387
410
  const permissionService = strapi.admin.services.transfer.permission;
@@ -11,7 +11,7 @@ const registrationSchema = yup
11
11
  .object()
12
12
  .shape({
13
13
  firstname: validators.firstname.required(),
14
- lastname: validators.lastname,
14
+ lastname: validators.lastname.nullable(),
15
15
  password: validators.password.required(),
16
16
  })
17
17
  .required()
@@ -32,7 +32,7 @@ const adminRegistrationSchema = yup
32
32
  .shape({
33
33
  email: validators.email.required(),
34
34
  firstname: validators.firstname.required(),
35
- lastname: validators.lastname,
35
+ lastname: validators.lastname.nullable(),
36
36
  password: validators.password.required(),
37
37
  })
38
38
  .required()
@@ -1,5 +0,0 @@
1
- import { getRequestUrl } from '../../../utils';
2
-
3
- const requestURL = (path) => getRequestUrl(`single-types/${path}`);
4
-
5
- export default requestURL;
@@ -1,2 +0,0 @@
1
- // eslint-disable-next-line import/prefer-default-export
2
- export { default as getRequestUrl } from './getRequestUrl';
@@ -1,16 +0,0 @@
1
- import { getFetchClient } from '@strapi/helper-plugin';
2
-
3
- import { getRequestUrl } from '../../../utils';
4
-
5
- const putCMSettingsEV = (body, slug, isContentTypeView) => {
6
- const { put } = getFetchClient();
7
-
8
- return put(
9
- getRequestUrl(
10
- isContentTypeView ? `content-types/${slug}/configuration` : `components/${slug}/configuration`
11
- ),
12
- body
13
- );
14
- };
15
-
16
- export default putCMSettingsEV;
@@ -1,9 +0,0 @@
1
- const init = (initialState, layout) => {
2
- return {
3
- ...initialState,
4
- initialData: layout,
5
- modifiedData: layout,
6
- };
7
- };
8
-
9
- export default init;
@@ -1,4 +0,0 @@
1
- // FIXME when back-end ready
2
- const getRequestUrl = (path) => `/content-manager/${path}`;
3
-
4
- export default getRequestUrl;
@@ -1,3 +0,0 @@
1
- const getRequestUrl = (path) => `/admin/${path}`;
2
-
3
- export default getRequestUrl;
@@ -1,7 +0,0 @@
1
- (self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[1386],{31386:function(R,m,c){"use strict";c.r(m),c.d(m,{ROUTES_EE:function(){return t}});var u=c(32735),a=c(19565),l=c(49189),d=c.n(l),h=c(67879),n=c(53038),r=c(86209);const g=()=>{const{params:{authResponse:o}}=(0,n.$B)("/auth/login/:authResponse"),{formatMessage:e}=(0,h.Z)(),{push:f}=(0,n.k6)(),p=(0,u.useRef)(e);let i=(0,u.useCallback)(()=>{f(`/auth/oops?info=${encodeURIComponent(p.current({id:"Auth.form.button.login.providers.error",defaultMessage:"We cannot connect you through the selected provider."}))}`)},[f]);const{get:s}=(0,a.kY)(),v=(0,u.useCallback)(async()=>{try{const E=d().get("jwtToken");if(a.I8.clearAppStorage(),E){a.I8.setToken(E,!0);const I=(0,r.IF)("users/me"),{data:{data:A}}=await s(I);a.I8.setUserInfo(A,!0),d().remove("jwtToken"),f("/auth/login")}}catch{i()}},[s,f,i]);return(0,u.useEffect)(()=>{o==="error"&&i(),o==="success"&&v()},[o,v,i]),u.createElement(a.dO,null)};var C=null;const t=[{Component:()=>({default:g}),to:"/auth/login/:authResponse",exact:!0}]},49189:function(R,m,c){var u,a;/*!
2
- * JavaScript Cookie v2.2.1
3
- * https://github.com/js-cookie/js-cookie
4
- *
5
- * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
6
- * Released under the MIT license
7
- */(function(l){var d;if(u=l,a=typeof u=="function"?u.call(m,c,m,R):u,a!==void 0&&(R.exports=a),d=!0,R.exports=l(),d=!0,!d){var h=window.Cookies,n=window.Cookies=l();n.noConflict=function(){return window.Cookies=h,n}}})(function(){function l(){for(var n=0,r={};n<arguments.length;n++){var g=arguments[n];for(var C in g)r[C]=g[C]}return r}function d(n){return n.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent)}function h(n){function r(){}function g(t,o,e){if(!(typeof document>"u")){e=l({path:"/"},r.defaults,e),typeof e.expires=="number"&&(e.expires=new Date(new Date*1+e.expires*864e5)),e.expires=e.expires?e.expires.toUTCString():"";try{var f=JSON.stringify(o);/^[\{\[]/.test(f)&&(o=f)}catch{}o=n.write?n.write(o,t):encodeURIComponent(String(o)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),t=encodeURIComponent(String(t)).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/[\(\)]/g,escape);var p="";for(var i in e)e[i]&&(p+="; "+i,e[i]!==!0&&(p+="="+e[i].split(";")[0]));return document.cookie=t+"="+o+p}}function C(t,o){if(!(typeof document>"u")){for(var e={},f=document.cookie?document.cookie.split("; "):[],p=0;p<f.length;p++){var i=f[p].split("="),s=i.slice(1).join("=");!o&&s.charAt(0)==='"'&&(s=s.slice(1,-1));try{var v=d(i[0]);if(s=(n.read||n)(s,v)||d(s),o)try{s=JSON.parse(s)}catch{}if(e[v]=s,t===v)break}catch{}}return t?e[t]:e}}return r.set=g,r.get=function(t){return C(t,!1)},r.getJSON=function(t){return C(t,!0)},r.remove=function(t,o){g(t,"",l(o,{expires:-1}))},r.defaults={},r.withConverter=h,r}return h(function(){})})}}]);
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[2379],{50337:function(U,c,t){t.d(c,{pl:function(){return g},aY:function(){return R},q5:function(){return r.q}});var e=t(32735),n=t(19565),E=t(86209),f=t(97889);const m={data:[],isLoading:!0};var L=(s,l)=>(0,f.ZP)(s,i=>{switch(l.type){case"GET_DATA_SUCCEEDED":{i.data=l.data,i.isLoading=!1;break}case"GET_DATA_ERROR":{i.isLoading=!1;break}default:return i}}),g=({ssoEnabled:s})=>{const[l,i]=(0,e.useReducer)(L,m),D=(0,n.lm)(),{get:T}=(0,n.kY)();return(0,e.useEffect)(()=>{(async()=>{try{if(!s){i({type:"GET_DATA_SUCCEEDED",data:[]});return}const{data:u}=await T((0,E.IF)("providers"));i({type:"GET_DATA_SUCCEEDED",data:u})}catch(u){console.error(u),i({type:"GET_DATA_ERROR"}),D({type:"warning",message:{id:"notification.error"}})}})()},[T,s,D]),l},a=t(36866),A=t.n(a),o=t(67879),O=t(53038),r=t(53104);const I="strapi-notification-seat-limit",P="https://cloud.strapi.io/profile/billing",C="https://strapi.io/billing/request-seats";var R=()=>{const{formatMessage:s}=(0,o.Z)();let{license:l,isError:i,isLoading:D}=(0,r.q)();const T=(0,n.lm)(),{pathname:p}=(0,O.TH)(),{enforcementUserCount:u,permittedSeats:_,licenseLimitStatus:d,isHostedOnStrapiCloud:S}=l;(0,e.useEffect)(()=>{if(i||D)return;const B=!A()(_)&&!window.sessionStorage.getItem(`${I}-${p}`)&&(d==="AT_LIMIT"||d==="OVER_LIMIT");let y;d==="OVER_LIMIT"?y="warning":d==="AT_LIMIT"&&(y="softWarning"),B&&T({type:y,message:s({id:"notification.ee.warning.over-.message",defaultMessage:"Add seats to {licenseLimitStatus, select, OVER_LIMIT {invite} other {re-enable}} Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app."},{licenseLimitStatus:d}),title:s({id:"notification.ee.warning.at-seat-limit.title",defaultMessage:"{licenseLimitStatus, select, OVER_LIMIT {Over} other {At}} seat limit ({enforcementUserCount}/{permittedSeats})"},{licenseLimitStatus:d,enforcementUserCount:u,permittedSeats:_}),link:{url:S?P:C,label:s({id:"notification.ee.warning.seat-limit.link",defaultMessage:"{isHostedOnStrapiCloud, select, true {ADD SEATS} other {CONTACT SALES}}"},{isHostedOnStrapiCloud:S})},blockTransition:!0,onClose(){window.sessionStorage.setItem(`${I}-${p}`,!0)}})},[T,l,p,s,D,_,d,u,S,i])}},53104:function(U,c,t){t.d(c,{q:function(){return f}});var e=t(32735),n=t(19565),E=t(20108);function f({enabled:m}={enabled:!0}){const{get:v}=(0,n.kY)(),{data:L,isError:M,isLoading:g}=(0,E.useQuery)(["ee","license-limit-info"],async()=>{const{data:{data:o}}=await v("/admin/license-limit-information");return o},{enabled:m}),a=L??{},A=e.useCallback(o=>(a?.features??[]).find(r=>r.name===o)?.options??{},[a?.features]);return{license:a,getFeature:A,isError:M,isLoading:g}}},42379:function(U,c,t){t.r(c),t.d(c,{CreateActionEE:function(){return r}});var e=t(32735),n=t(87933),E=t(63919),f=t(99140),m=t(41415),v=t(69932),L=t(7961),M=t(36866),g=t.n(M),a=t(60216),A=t.n(a),o=t(67879),O=t(50337);const r=({onClick:I})=>{const{formatMessage:P}=(0,o.Z)(),{license:{permittedSeats:C,shouldStopCreate:h},isError:R,isLoading:s}=(0,O.q5)();return R||s?null:e.createElement(n.k,{gap:2},!g()(C)&&h&&e.createElement(E.u,{description:P({id:"Settings.application.admin-seats.at-limit-tooltip",defaultMessage:"At limit: add seats to invite more users"}),position:"left"},e.createElement(f.J,{width:`${14/16}rem`,height:`${14/16}rem`,color:"danger500",as:v.Z})),e.createElement(m.z,{"data-testid":"create-user-button",onClick:I,startIcon:e.createElement(L.Z,null),size:"S",disabled:h},P({id:"Settings.permissions.users.create",defaultMessage:"Invite new user"})))};r.propTypes={onClick:A().func.isRequired}}}]);
@@ -1,26 +0,0 @@
1
- "use strict";(self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[2395],{50337:function(I,f,t){t.d(f,{pl:function(){return D},aY:function(){return n},q5:function(){return a.q}});var e=t(32735),u=t(19565),m=t(86209),g=t(97889);const P={data:[],isLoading:!0};var r=(o,p)=>(0,g.ZP)(o,l=>{switch(p.type){case"GET_DATA_SUCCEEDED":{l.data=p.data,l.isLoading=!1;break}case"GET_DATA_ERROR":{l.isLoading=!1;break}default:return l}}),D=({ssoEnabled:o})=>{const[p,l]=(0,e.useReducer)(r,P),A=(0,u.lm)(),{get:h}=(0,u.kY)();return(0,e.useEffect)(()=>{(async()=>{try{if(!o){l({type:"GET_DATA_SUCCEEDED",data:[]});return}const{data:v}=await h((0,m.IF)("providers"));l({type:"GET_DATA_SUCCEEDED",data:v})}catch(v){console.error(v),l({type:"GET_DATA_ERROR"}),A({type:"warning",message:{id:"notification.error"}})}})()},[h,o,A]),p},d=t(36866),_=t.n(d),c=t(67879),T=t(53038),a=t(53104);const E="strapi-notification-seat-limit",s="https://cloud.strapi.io/profile/billing",L="https://strapi.io/billing/request-seats";var n=()=>{const{formatMessage:o}=(0,c.Z)();let{license:p,isError:l,isLoading:A}=(0,a.q)();const h=(0,u.lm)(),{pathname:y}=(0,T.TH)(),{enforcementUserCount:v,permittedSeats:C,licenseLimitStatus:M,isHostedOnStrapiCloud:U}=p;(0,e.useEffect)(()=>{if(l||A)return;const B=!_()(C)&&!window.sessionStorage.getItem(`${E}-${y}`)&&(M==="AT_LIMIT"||M==="OVER_LIMIT");let S;M==="OVER_LIMIT"?S="warning":M==="AT_LIMIT"&&(S="softWarning"),B&&h({type:S,message:o({id:"notification.ee.warning.over-.message",defaultMessage:"Add seats to {licenseLimitStatus, select, OVER_LIMIT {invite} other {re-enable}} Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app."},{licenseLimitStatus:M}),title:o({id:"notification.ee.warning.at-seat-limit.title",defaultMessage:"{licenseLimitStatus, select, OVER_LIMIT {Over} other {At}} seat limit ({enforcementUserCount}/{permittedSeats})"},{licenseLimitStatus:M,enforcementUserCount:v,permittedSeats:C}),link:{url:U?s:L,label:o({id:"notification.ee.warning.seat-limit.link",defaultMessage:"{isHostedOnStrapiCloud, select, true {ADD SEATS} other {CONTACT SALES}}"},{isHostedOnStrapiCloud:U})},blockTransition:!0,onClose(){window.sessionStorage.setItem(`${E}-${y}`,!0)}})},[h,p,y,o,A,C,M,v,U,l])}},53104:function(I,f,t){t.d(f,{q:function(){return g}});var e=t(32735),u=t(19565),m=t(20108);function g({enabled:P}={enabled:!0}){const{get:O}=(0,u.kY)(),{data:r,isError:i,isLoading:D}=(0,m.useQuery)(["ee","license-limit-info"],async()=>{const{data:{data:c}}=await O("/admin/license-limit-information");return c},{enabled:P}),d=r??{},_=e.useCallback(c=>(d?.features??[]).find(a=>a.name===c)?.options??{},[d?.features]);return{license:d,getFeature:_,isError:i,isLoading:D}}},82395:function(I,f,t){t.r(f),t.d(f,{LoginEE:function(){return E}});var e=t(32735),u=t(9026),m=t(72850),g=t(87933),P=t(49372),O=t(60216),r=t.n(O),i=t(67879),D=t(8471),d=t(11060),_=t(24436),c=t(50337),T=t(68726);const a=(0,D.ZP)(u.i)`
2
- flex: 1;
3
- `,E=s=>{const L=window.strapi.features.isEnabled(window.strapi.features.SSO),{isLoading:R,data:n}=(0,c.pl)({ssoEnabled:L}),{formatMessage:o}=(0,i.Z)();return!L||!R&&n.length===0?e.createElement(d.ZP,null,e.createElement(_.Z,{...s})):e.createElement(d.ZP,null,e.createElement(_.Z,{...s},e.createElement(m.x,{paddingTop:7},e.createElement(g.k,{direction:"column",alignItems:"stretch",gap:7},e.createElement(g.k,null,e.createElement(a,null),e.createElement(m.x,{paddingLeft:3,paddingRight:3},e.createElement(P.Z,{variant:"sigma",textColor:"neutral600"},o({id:"Auth.login.sso.divider"}))),e.createElement(a,null)),e.createElement(T.Z,{providers:n,displayAllProviders:!1})))))};E.defaultProps={onSubmit:s=>s.preventDefault(),requestError:null},E.propTypes={formErrors:r().object.isRequired,modifiedData:r().object.isRequired,onChange:r().func.isRequired,onSubmit:r().func,requestError:r().object}},68726:function(I,f,t){var e=t(32735),u=t(87933),m=t(63919),g=t(49372),P=t(15335),O=t(5803),r=t(60216),i=t.n(r),D=t(67879),d=t(14911),_=t(8471);const c=_.ZP.a`
4
- width: ${136/16}rem;
5
- display: flex;
6
- justify-content: center;
7
- align-items: center;
8
- height: ${48/16}rem;
9
- border: 1px solid ${({theme:s})=>s.colors.neutral150};
10
- border-radius: ${({theme:s})=>s.borderRadius};
11
- text-decoration: inherit;
12
- &:link {
13
- text-decoration: none;
14
- }
15
- color: ${({theme:s})=>s.colors.neutral600};
16
- `,T=(0,_.ZP)(u.k)`
17
- & a:not(:first-child):not(:last-child) {
18
- margin: 0 ${({theme:s})=>s.spaces[2]};
19
- }
20
- & a:first-child {
21
- margin-right: ${({theme:s})=>s.spaces[2]};
22
- }
23
- & a:last-child {
24
- margin-left: ${({theme:s})=>s.spaces[2]};
25
- }
26
- `,a=({provider:s})=>e.createElement(m.u,{label:s.displayName},e.createElement(c,{href:`${window.strapi.backendURL}/admin/connect/${s.uid}`},s.icon?e.createElement("img",{src:s.icon,"aria-hidden":!0,alt:"",height:"32px"}):e.createElement(g.Z,null,s.displayName)));a.propTypes={provider:i().shape({icon:i().string,displayName:i().string.isRequired,uid:i().string.isRequired}).isRequired};const E=({providers:s,displayAllProviders:L})=>{const{formatMessage:R}=(0,D.Z)();return L?e.createElement(P.r,{gap:4},s.map(n=>e.createElement(O.P,{key:n.uid,col:4},e.createElement(a,{provider:n})))):s.length>2&&!L?e.createElement(P.r,{gap:4},s.slice(0,2).map(n=>e.createElement(O.P,{key:n.uid,col:4},e.createElement(a,{provider:n}))),e.createElement(O.P,{col:4},e.createElement(m.u,{label:R({id:"global.see-more"})},e.createElement(c,{as:d.rU,to:"/auth/providers"},e.createElement("span",{"aria-hidden":!0},"\u2022\u2022\u2022"))))):e.createElement(T,{justifyContent:"center"},s.map(n=>e.createElement(a,{key:n.uid,provider:n})))};E.defaultProps={displayAllProviders:!0},E.propTypes={providers:i().arrayOf(i().object).isRequired,displayAllProviders:i().bool},f.Z=E}}]);