@strapi/content-releases 4.19.1 → 4.20.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 (29) hide show
  1. package/dist/_chunks/{App-_20W9dYa.js → App-1hHIqUoZ.js} +253 -191
  2. package/dist/_chunks/App-1hHIqUoZ.js.map +1 -0
  3. package/dist/_chunks/{App-L1jSxCiL.mjs → App-U6GbyLIE.mjs} +257 -195
  4. package/dist/_chunks/App-U6GbyLIE.mjs.map +1 -0
  5. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs +51 -0
  6. package/dist/_chunks/PurchaseContentReleases-Clm0iACO.mjs.map +1 -0
  7. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js +51 -0
  8. package/dist/_chunks/PurchaseContentReleases-YhAPgpG9.js.map +1 -0
  9. package/dist/_chunks/{en-MyLPoISH.mjs → en-GqXgfmzl.mjs} +9 -3
  10. package/dist/_chunks/en-GqXgfmzl.mjs.map +1 -0
  11. package/dist/_chunks/{en-gYDqKYFd.js → en-bDhIlw-B.js} +9 -3
  12. package/dist/_chunks/en-bDhIlw-B.js.map +1 -0
  13. package/dist/_chunks/{index-c4zRX_sg.mjs → index-gkExFBa0.mjs} +89 -26
  14. package/dist/_chunks/index-gkExFBa0.mjs.map +1 -0
  15. package/dist/_chunks/{index-KJa1Rb5F.js → index-l-FvkQlQ.js} +88 -25
  16. package/dist/_chunks/index-l-FvkQlQ.js.map +1 -0
  17. package/dist/admin/index.js +1 -1
  18. package/dist/admin/index.mjs +1 -1
  19. package/dist/server/index.js +193 -34
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +193 -34
  22. package/dist/server/index.mjs.map +1 -1
  23. package/package.json +10 -9
  24. package/dist/_chunks/App-L1jSxCiL.mjs.map +0 -1
  25. package/dist/_chunks/App-_20W9dYa.js.map +0 -1
  26. package/dist/_chunks/en-MyLPoISH.mjs.map +0 -1
  27. package/dist/_chunks/en-gYDqKYFd.js.map +0 -1
  28. package/dist/_chunks/index-KJa1Rb5F.js.map +0 -1
  29. package/dist/_chunks/index-c4zRX_sg.mjs.map +0 -1
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const helperPlugin = require("@strapi/helper-plugin");
5
5
  const reactRouterDom = require("react-router-dom");
6
- const index = require("./index-KJa1Rb5F.js");
6
+ const index = require("./index-l-FvkQlQ.js");
7
7
  const React = require("react");
8
8
  const strapiAdmin = require("@strapi/admin/strapi-admin");
9
9
  const designSystem = require("@strapi/design-system");
@@ -40,7 +40,14 @@ const React__namespace = /* @__PURE__ */ _interopNamespace(React);
40
40
  const styled__default = /* @__PURE__ */ _interopDefault(styled);
41
41
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
42
42
  const RELEASE_SCHEMA = yup__namespace.object().shape({
43
- name: yup__namespace.string().trim().required()
43
+ name: yup__namespace.string().trim().required(),
44
+ // scheduledAt is a date, but we always receive strings from the client
45
+ scheduledAt: yup__namespace.string().nullable(),
46
+ timezone: yup__namespace.string().when("scheduledAt", {
47
+ is: (scheduledAt) => !!scheduledAt,
48
+ then: yup__namespace.string().required(),
49
+ otherwise: yup__namespace.string().nullable()
50
+ })
44
51
  }).required().noUnknown();
45
52
  const ReleaseModal = ({
46
53
  handleClose,
@@ -114,10 +121,7 @@ const ReleaseInfoWrapper = styled__default.default(designSystem.Flex)`
114
121
  border-bottom-left-radius: ${({ theme }) => theme.borderRadius};
115
122
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
116
123
  `;
117
- const StyledFlex = styled__default.default(designSystem.Flex)`
118
- align-self: stretch;
119
- cursor: ${({ disabled }) => disabled ? "not-allowed" : "pointer"};
120
-
124
+ const StyledMenuItem = styled__default.default(v2.Menu.Item)`
121
125
  svg path {
122
126
  fill: ${({ theme, disabled }) => disabled && theme.colors.neutral500};
123
127
  }
@@ -126,15 +130,15 @@ const StyledFlex = styled__default.default(designSystem.Flex)`
126
130
  }
127
131
  `;
128
132
  const PencilIcon = styled__default.default(icons.Pencil)`
129
- width: ${({ theme }) => theme.spaces[4]};
130
- height: ${({ theme }) => theme.spaces[4]};
133
+ width: ${({ theme }) => theme.spaces[3]};
134
+ height: ${({ theme }) => theme.spaces[3]};
131
135
  path {
132
136
  fill: ${({ theme }) => theme.colors.neutral600};
133
137
  }
134
138
  `;
135
139
  const TrashIcon = styled__default.default(icons.Trash)`
136
- width: ${({ theme }) => theme.spaces[4]};
137
- height: ${({ theme }) => theme.spaces[4]};
140
+ width: ${({ theme }) => theme.spaces[3]};
141
+ height: ${({ theme }) => theme.spaces[3]};
138
142
  path {
139
143
  fill: ${({ theme }) => theme.colors.danger600};
140
144
  }
@@ -142,24 +146,6 @@ const TrashIcon = styled__default.default(icons.Trash)`
142
146
  const TypographyMaxWidth = styled__default.default(designSystem.Typography)`
143
147
  max-width: 300px;
144
148
  `;
145
- const PopoverButton = ({ onClick, disabled, children }) => {
146
- return /* @__PURE__ */ jsxRuntime.jsx(
147
- StyledFlex,
148
- {
149
- paddingTop: 2,
150
- paddingBottom: 2,
151
- paddingLeft: 4,
152
- paddingRight: 4,
153
- alignItems: "center",
154
- gap: 2,
155
- as: "button",
156
- hasRadius: true,
157
- onClick,
158
- disabled,
159
- children
160
- }
161
- );
162
- };
163
149
  const EntryValidationText = ({ action, schema, components, entry }) => {
164
150
  const { formatMessage } = reactIntl.useIntl();
165
151
  const { validate } = strapiAdmin.unstable_useDocument();
@@ -210,8 +196,6 @@ const ReleaseDetailsLayout = ({
210
196
  }) => {
211
197
  const { formatMessage } = reactIntl.useIntl();
212
198
  const { releaseId } = reactRouterDom.useParams();
213
- const [isPopoverVisible, setIsPopoverVisible] = React__namespace.useState(false);
214
- const moreButtonRef = React__namespace.useRef(null);
215
199
  const {
216
200
  data,
217
201
  isLoading: isLoadingDetails,
@@ -225,14 +209,8 @@ const ReleaseDetailsLayout = ({
225
209
  allowedActions: { canUpdate, canDelete }
226
210
  } = helperPlugin.useRBAC(index.PERMISSIONS);
227
211
  const dispatch = index.useTypedDispatch();
212
+ const { trackUsage } = helperPlugin.useTracking();
228
213
  const release = data?.data;
229
- const handleTogglePopover = () => {
230
- setIsPopoverVisible((prev) => !prev);
231
- };
232
- const openReleaseModal = () => {
233
- toggleEditReleaseModal();
234
- handleTogglePopover();
235
- };
236
214
  const handlePublishRelease = async () => {
237
215
  const response = await publishRelease({ id: releaseId });
238
216
  if ("data" in response) {
@@ -243,6 +221,12 @@ const ReleaseDetailsLayout = ({
243
221
  defaultMessage: "Release was published successfully."
244
222
  })
245
223
  });
224
+ const { totalEntries: totalEntries2, totalPublishedEntries, totalUnpublishedEntries } = response.data.meta;
225
+ trackUsage("didPublishRelease", {
226
+ totalEntries: totalEntries2,
227
+ totalPublishedEntries,
228
+ totalUnpublishedEntries
229
+ });
246
230
  } else if (index.isAxiosError(response.error)) {
247
231
  toggleNotification({
248
232
  type: "warning",
@@ -255,13 +239,21 @@ const ReleaseDetailsLayout = ({
255
239
  });
256
240
  }
257
241
  };
258
- const openWarningConfirmDialog = () => {
259
- toggleWarningSubmit();
260
- handleTogglePopover();
261
- };
262
242
  const handleRefresh = () => {
263
243
  dispatch(index.releaseApi.util.invalidateTags([{ type: "ReleaseAction", id: "LIST" }]));
264
244
  };
245
+ const getCreatedByUser = () => {
246
+ if (!release?.createdBy) {
247
+ return null;
248
+ }
249
+ if (release.createdBy.username) {
250
+ return release.createdBy.username;
251
+ }
252
+ if (release.createdBy.firstname) {
253
+ return `${release.createdBy.firstname} ${release.createdBy.lastname || ""}`.trim();
254
+ }
255
+ return release.createdBy.email;
256
+ };
265
257
  if (isLoadingDetails) {
266
258
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoadingDetails, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
267
259
  }
@@ -283,7 +275,7 @@ const ReleaseDetailsLayout = ({
283
275
  );
284
276
  }
285
277
  const totalEntries = release.actions.meta.count || 0;
286
- const createdBy = release.createdBy.lastname ? `${release.createdBy.firstname} ${release.createdBy.lastname}` : `${release.createdBy.firstname}`;
278
+ const hasCreatedByUser = Boolean(getCreatedByUser());
287
279
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoadingDetails, children: [
288
280
  /* @__PURE__ */ jsxRuntime.jsx(
289
281
  designSystem.HeaderLayout,
@@ -301,72 +293,98 @@ const ReleaseDetailsLayout = ({
301
293
  defaultMessage: "Back"
302
294
  }) }),
303
295
  primaryAction: !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
304
- /* @__PURE__ */ jsxRuntime.jsx(
305
- designSystem.IconButton,
306
- {
307
- label: formatMessage({
308
- id: "content-releases.header.actions.open-release-actions",
309
- defaultMessage: "Release actions"
310
- }),
311
- ref: moreButtonRef,
312
- onClick: handleTogglePopover,
313
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {})
314
- }
315
- ),
316
- isPopoverVisible && /* @__PURE__ */ jsxRuntime.jsxs(
317
- designSystem.Popover,
318
- {
319
- source: moreButtonRef,
320
- placement: "bottom-end",
321
- onDismiss: handleTogglePopover,
322
- spacing: 4,
323
- minWidth: "242px",
324
- children: [
325
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", justifyContent: "center", direction: "column", padding: 1, children: [
326
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverButton, { disabled: !canUpdate, onClick: openReleaseModal, children: [
327
- /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
328
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
329
- id: "content-releases.header.actions.edit",
330
- defaultMessage: "Edit"
331
- }) })
332
- ] }),
333
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverButton, { disabled: !canDelete, onClick: openWarningConfirmDialog, children: [
334
- /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
335
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
336
- id: "content-releases.header.actions.delete",
337
- defaultMessage: "Delete"
338
- }) })
339
- ] })
340
- ] }),
341
- /* @__PURE__ */ jsxRuntime.jsxs(
342
- ReleaseInfoWrapper,
343
- {
344
- direction: "column",
345
- justifyContent: "center",
346
- alignItems: "flex-start",
347
- gap: 1,
348
- padding: 5,
349
- children: [
350
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
351
- id: "content-releases.header.actions.created",
352
- defaultMessage: "Created"
353
- }) }),
354
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
355
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
356
- formatMessage(
357
- {
358
- id: "content-releases.header.actions.created.description",
359
- defaultMessage: " by {createdBy}"
360
- },
361
- { createdBy }
362
- )
363
- ] })
364
- ]
365
- }
366
- )
367
- ]
368
- }
369
- ),
296
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Root, { children: [
297
+ /* @__PURE__ */ jsxRuntime.jsx(
298
+ v2.Menu.Trigger,
299
+ {
300
+ as: designSystem.IconButton,
301
+ paddingLeft: 2,
302
+ paddingRight: 2,
303
+ "aria-label": formatMessage({
304
+ id: "content-releases.header.actions.open-release-actions",
305
+ defaultMessage: "Release edit and delete menu"
306
+ }),
307
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.More, {}),
308
+ variant: "tertiary"
309
+ }
310
+ ),
311
+ /* @__PURE__ */ jsxRuntime.jsxs(v2.Menu.Content, { top: 1, popoverPlacement: "bottom-end", children: [
312
+ /* @__PURE__ */ jsxRuntime.jsxs(
313
+ designSystem.Flex,
314
+ {
315
+ alignItems: "center",
316
+ justifyContent: "center",
317
+ direction: "column",
318
+ padding: 1,
319
+ width: "100%",
320
+ children: [
321
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canUpdate, onSelect: toggleEditReleaseModal, children: /* @__PURE__ */ jsxRuntime.jsxs(
322
+ designSystem.Flex,
323
+ {
324
+ paddingTop: 2,
325
+ paddingBottom: 2,
326
+ alignItems: "center",
327
+ gap: 2,
328
+ hasRadius: true,
329
+ width: "100%",
330
+ children: [
331
+ /* @__PURE__ */ jsxRuntime.jsx(PencilIcon, {}),
332
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: formatMessage({
333
+ id: "content-releases.header.actions.edit",
334
+ defaultMessage: "Edit"
335
+ }) })
336
+ ]
337
+ }
338
+ ) }),
339
+ /* @__PURE__ */ jsxRuntime.jsx(StyledMenuItem, { disabled: !canDelete, onSelect: toggleWarningSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(
340
+ designSystem.Flex,
341
+ {
342
+ paddingTop: 2,
343
+ paddingBottom: 2,
344
+ alignItems: "center",
345
+ gap: 2,
346
+ hasRadius: true,
347
+ width: "100%",
348
+ children: [
349
+ /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {}),
350
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, textColor: "danger600", children: formatMessage({
351
+ id: "content-releases.header.actions.delete",
352
+ defaultMessage: "Delete"
353
+ }) })
354
+ ]
355
+ }
356
+ ) })
357
+ ]
358
+ }
359
+ ),
360
+ /* @__PURE__ */ jsxRuntime.jsxs(
361
+ ReleaseInfoWrapper,
362
+ {
363
+ direction: "column",
364
+ justifyContent: "center",
365
+ alignItems: "flex-start",
366
+ gap: 1,
367
+ padding: 5,
368
+ children: [
369
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: formatMessage({
370
+ id: "content-releases.header.actions.created",
371
+ defaultMessage: "Created"
372
+ }) }),
373
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", color: "neutral300", children: [
374
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.RelativeTime, { timestamp: new Date(release.createdAt) }),
375
+ formatMessage(
376
+ {
377
+ id: "content-releases.header.actions.created.description",
378
+ defaultMessage: "{hasCreatedByUser, select, true { by {createdBy}} other { by deleted user}}"
379
+ },
380
+ { createdBy: getCreatedByUser(), hasCreatedByUser }
381
+ )
382
+ ] })
383
+ ]
384
+ }
385
+ )
386
+ ] })
387
+ ] }),
370
388
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { size: "S", variant: "tertiary", onClick: handleRefresh, children: formatMessage({
371
389
  id: "content-releases.header.actions.refresh",
372
390
  defaultMessage: "Refresh"
@@ -422,6 +440,9 @@ const ReleaseDetailsBody = () => {
422
440
  isError: isReleaseError,
423
441
  error: releaseError
424
442
  } = index.useGetReleaseQuery({ id: releaseId });
443
+ const {
444
+ allowedActions: { canUpdate }
445
+ } = helperPlugin.useRBAC(index.PERMISSIONS);
425
446
  const release = releaseData?.data;
426
447
  const selectedGroupBy = query?.groupBy || "contentType";
427
448
  const {
@@ -435,7 +456,7 @@ const ReleaseDetailsBody = () => {
435
456
  releaseId
436
457
  });
437
458
  const [updateReleaseAction] = index.useUpdateReleaseActionMutation();
438
- const handleChangeType = async (e, actionId) => {
459
+ const handleChangeType = async (e, actionId, actionPath) => {
439
460
  const response = await updateReleaseAction({
440
461
  params: {
441
462
  releaseId,
@@ -443,7 +464,11 @@ const ReleaseDetailsBody = () => {
443
464
  },
444
465
  body: {
445
466
  type: e.target.value
446
- }
467
+ },
468
+ query,
469
+ // We are passing the query params to make optimistic updates
470
+ actionPath
471
+ // We are passing the action path to found the position in the cache of the action for optimistic updates
447
472
  });
448
473
  if ("error" in response) {
449
474
  if (index.isAxiosError(response.error)) {
@@ -524,7 +549,7 @@ const ReleaseDetailsBody = () => {
524
549
  designSystem.SingleSelect,
525
550
  {
526
551
  "aria-label": formatMessage({
527
- id: "content-releases.pages.ReleaseDetails.groupBy.label",
552
+ id: "content-releases.pages.ReleaseDetails.groupBy.aria-label",
528
553
  defaultMessage: "Group by"
529
554
  }),
530
555
  customizeContent: (value) => formatMessage(
@@ -542,7 +567,7 @@ const ReleaseDetailsBody = () => {
542
567
  }
543
568
  ) }),
544
569
  Object.keys(releaseActions).map((key) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
545
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
570
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { role: "separator", "aria-label": key, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: key }) }),
546
571
  /* @__PURE__ */ jsxRuntime.jsx(
547
572
  helperPlugin.Table.Root,
548
573
  {
@@ -612,56 +637,59 @@ const ReleaseDetailsBody = () => {
612
637
  )
613
638
  ] }),
614
639
  /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.LoadingBody, {}),
615
- /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(({ id, contentType, locale, type, entry }) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
616
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
617
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
618
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
619
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
620
- {
621
- id: "content-releases.page.ReleaseDetails.table.action-published",
622
- defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
623
- },
624
- {
625
- isPublish: type === "publish",
626
- b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
627
- }
628
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(
629
- index.ReleaseActionOptions,
630
- {
631
- selected: type,
632
- handleChange: (e) => handleChangeType(e, id),
633
- name: `release-action-${id}-type`
634
- }
635
- ) }),
636
- !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
637
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
638
- EntryValidationText,
640
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Table.Body, { children: releaseActions[key].map(
641
+ ({ id, contentType, locale, type, entry }, actionIndex) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
642
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "25%", maxWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, children: `${contentType.mainFieldValue || entry.id}` }) }),
643
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: `${locale?.name ? locale.name : "-"}` }) }),
644
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "10%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: contentType.displayName || "" }) }),
645
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: release.releasedAt ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
646
+ {
647
+ id: "content-releases.page.ReleaseDetails.table.action-published",
648
+ defaultMessage: "This entry was <b>{isPublish, select, true {published} other {unpublished}}</b>."
649
+ },
639
650
  {
640
- action: type,
641
- schema: contentTypes?.[contentType.uid],
642
- components,
643
- entry
651
+ isPublish: type === "publish",
652
+ b: (children) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children })
653
+ }
654
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
655
+ index.ReleaseActionOptions,
656
+ {
657
+ selected: type,
658
+ handleChange: (e) => handleChangeType(e, id, [key, actionIndex]),
659
+ name: `release-action-${id}-type`,
660
+ disabled: !canUpdate
644
661
  }
645
662
  ) }),
646
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
647
- /* @__PURE__ */ jsxRuntime.jsx(
648
- index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
649
- {
650
- contentTypeUid: contentType.uid,
651
- entryId: entry.id,
652
- locale: locale?.code
653
- }
654
- ),
655
- /* @__PURE__ */ jsxRuntime.jsx(
656
- index.ReleaseActionMenu.DeleteReleaseActionItem,
663
+ !release.releasedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
664
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", minWidth: "200px", children: /* @__PURE__ */ jsxRuntime.jsx(
665
+ EntryValidationText,
657
666
  {
658
- releaseId: release.id,
659
- actionId: id
667
+ action: type,
668
+ schema: contentTypes?.[contentType.uid],
669
+ components,
670
+ entry
660
671
  }
661
- )
662
- ] }) }) })
663
- ] })
664
- ] }, id)) })
672
+ ) }),
673
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(index.ReleaseActionMenu.Root, { children: [
674
+ /* @__PURE__ */ jsxRuntime.jsx(
675
+ index.ReleaseActionMenu.ReleaseActionEntryLinkItem,
676
+ {
677
+ contentTypeUid: contentType.uid,
678
+ entryId: entry.id,
679
+ locale: locale?.code
680
+ }
681
+ ),
682
+ /* @__PURE__ */ jsxRuntime.jsx(
683
+ index.ReleaseActionMenu.DeleteReleaseActionItem,
684
+ {
685
+ releaseId: release.id,
686
+ actionId: id
687
+ }
688
+ )
689
+ ] }) }) })
690
+ ] })
691
+ ] }, id)
692
+ ) })
665
693
  ] })
666
694
  }
667
695
  )
@@ -786,37 +814,6 @@ const ReleaseDetailsPage = () => {
786
814
  }
787
815
  );
788
816
  };
789
- const ReleasesLayout = ({
790
- isLoading,
791
- totalReleases,
792
- onClickAddRelease,
793
- children
794
- }) => {
795
- const { formatMessage } = reactIntl.useIntl();
796
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
797
- /* @__PURE__ */ jsxRuntime.jsx(
798
- designSystem.HeaderLayout,
799
- {
800
- title: formatMessage({
801
- id: "content-releases.pages.Releases.title",
802
- defaultMessage: "Releases"
803
- }),
804
- subtitle: !isLoading && formatMessage(
805
- {
806
- id: "content-releases.pages.Releases.header-subtitle",
807
- defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
808
- },
809
- { number: totalReleases }
810
- ),
811
- primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: onClickAddRelease, children: formatMessage({
812
- id: "content-releases.header.actions.add-release",
813
- defaultMessage: "New release"
814
- }) }) })
815
- }
816
- ),
817
- children
818
- ] });
819
- };
820
817
  const LinkCard = styled__default.default(v2.Link)`
821
818
  display: block;
822
819
  `;
@@ -868,6 +865,14 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }) => {
868
865
  }
869
866
  ) }) }, id)) });
870
867
  };
868
+ const StyledAlert = styled__default.default(designSystem.Alert)`
869
+ button {
870
+ display: none;
871
+ }
872
+ p + div {
873
+ margin-left: auto;
874
+ }
875
+ `;
871
876
  const INITIAL_FORM_VALUES = {
872
877
  name: ""
873
878
  };
@@ -882,6 +887,9 @@ const ReleasesPage = () => {
882
887
  const [{ query }, setQuery] = helperPlugin.useQueryParams();
883
888
  const response = index.useGetReleasesQuery(query);
884
889
  const [createRelease, { isLoading: isSubmittingForm }] = index.useCreateReleaseMutation();
890
+ const { getFeature } = strapiAdmin.useLicenseLimits();
891
+ const { maximumReleases = 3 } = getFeature("cms-content-releases");
892
+ const { trackUsage } = helperPlugin.useTracking();
885
893
  const { isLoading, isSuccess, isError } = response;
886
894
  const activeTab = response?.currentData?.meta?.activeTab || "pending";
887
895
  const activeTabIndex = ["pending", "done"].indexOf(activeTab);
@@ -910,9 +918,10 @@ const ReleasesPage = () => {
910
918
  setReleaseModalShown((prev) => !prev);
911
919
  };
912
920
  if (isLoading) {
913
- return /* @__PURE__ */ jsxRuntime.jsx(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, isLoading: true, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) }) });
921
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Main, { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}) });
914
922
  }
915
923
  const totalReleases = isSuccess && response.currentData?.meta?.pagination?.total || 0;
924
+ const hasReachedMaximumPendingReleases = totalReleases >= maximumReleases;
916
925
  const handleTabChange = (index2) => {
917
926
  setQuery({
918
927
  ...query,
@@ -937,6 +946,7 @@ const ReleasesPage = () => {
937
946
  defaultMessage: "Release created."
938
947
  })
939
948
  });
949
+ trackUsage("didCreateRelease");
940
950
  push(`/plugins/content-releases/${response2.data.data.id}`);
941
951
  } else if (index.isAxiosError(response2.error)) {
942
952
  toggleNotification({
@@ -950,8 +960,60 @@ const ReleasesPage = () => {
950
960
  });
951
961
  }
952
962
  };
953
- return /* @__PURE__ */ jsxRuntime.jsxs(ReleasesLayout, { onClickAddRelease: toggleAddReleaseModal, totalReleases, children: [
963
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
964
+ /* @__PURE__ */ jsxRuntime.jsx(
965
+ designSystem.HeaderLayout,
966
+ {
967
+ title: formatMessage({
968
+ id: "content-releases.pages.Releases.title",
969
+ defaultMessage: "Releases"
970
+ }),
971
+ subtitle: formatMessage(
972
+ {
973
+ id: "content-releases.pages.Releases.header-subtitle",
974
+ defaultMessage: "{number, plural, =0 {No releases} one {# release} other {# releases}}"
975
+ },
976
+ { number: totalReleases }
977
+ ),
978
+ primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.create, children: /* @__PURE__ */ jsxRuntime.jsx(
979
+ designSystem.Button,
980
+ {
981
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
982
+ onClick: toggleAddReleaseModal,
983
+ disabled: hasReachedMaximumPendingReleases,
984
+ children: formatMessage({
985
+ id: "content-releases.header.actions.add-release",
986
+ defaultMessage: "New release"
987
+ })
988
+ }
989
+ ) })
990
+ }
991
+ ),
954
992
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
993
+ activeTab === "pending" && hasReachedMaximumPendingReleases && /* @__PURE__ */ jsxRuntime.jsx(
994
+ StyledAlert,
995
+ {
996
+ marginBottom: 6,
997
+ action: /* @__PURE__ */ jsxRuntime.jsx(v2.Link, { href: "https://strapi.io/pricing-cloud", isExternal: true, children: formatMessage({
998
+ id: "content-releases.pages.Releases.max-limit-reached.action",
999
+ defaultMessage: "Explore plans"
1000
+ }) }),
1001
+ title: formatMessage(
1002
+ {
1003
+ id: "content-releases.pages.Releases.max-limit-reached.title",
1004
+ defaultMessage: "You have reached the {number} pending {number, plural, one {release} other {releases}} limit."
1005
+ },
1006
+ { number: maximumReleases }
1007
+ ),
1008
+ onClose: () => {
1009
+ },
1010
+ closeLabel: "",
1011
+ children: formatMessage({
1012
+ id: "content-releases.pages.Releases.max-limit-reached.message",
1013
+ defaultMessage: "Upgrade to manage an unlimited number of releases."
1014
+ })
1015
+ }
1016
+ ),
955
1017
  /* @__PURE__ */ jsxRuntime.jsxs(
956
1018
  designSystem.TabGroup,
957
1019
  {
@@ -1034,4 +1096,4 @@ const App = () => {
1034
1096
  ] }) });
1035
1097
  };
1036
1098
  exports.App = App;
1037
- //# sourceMappingURL=App-_20W9dYa.js.map
1099
+ //# sourceMappingURL=App-1hHIqUoZ.js.map