@strapi/content-releases 0.0.0-experimental.d954d57341a6623992a0d211daaec8e245c3517d → 0.0.0-experimental.dcd10ea61ffc127dbedf2e7ca72b7d4de4d9ebc4

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 (111) hide show
  1. package/LICENSE +17 -1
  2. package/dist/_chunks/{App-CqbuK4M6.js → App-dLXY5ei3.js} +439 -431
  3. package/dist/_chunks/App-dLXY5ei3.js.map +1 -0
  4. package/dist/_chunks/{App-Do-Rnv0A.mjs → App-jrh58sXY.mjs} +416 -409
  5. package/dist/_chunks/App-jrh58sXY.mjs.map +1 -0
  6. package/dist/_chunks/{PurchaseContentReleases-_MxP6-Dt.mjs → PurchaseContentReleases-3tRbmbY3.mjs} +7 -8
  7. package/dist/_chunks/PurchaseContentReleases-3tRbmbY3.mjs.map +1 -0
  8. package/dist/_chunks/{PurchaseContentReleases-Be3acS2L.js → PurchaseContentReleases-bpIYXOfu.js} +6 -7
  9. package/dist/_chunks/PurchaseContentReleases-bpIYXOfu.js.map +1 -0
  10. package/dist/_chunks/{en-DtFJ5ViE.js → en-HrREghh3.js} +1 -1
  11. package/dist/_chunks/en-HrREghh3.js.map +1 -0
  12. package/dist/_chunks/{en-B9Ur3VsE.mjs → en-ltT1TlKQ.mjs} +1 -1
  13. package/dist/_chunks/en-ltT1TlKQ.mjs.map +1 -0
  14. package/dist/_chunks/{index-Tedsw4GC.js → index-CVO0Rqdm.js} +504 -197
  15. package/dist/_chunks/index-CVO0Rqdm.js.map +1 -0
  16. package/dist/_chunks/{index-D_pgdqQL.mjs → index-PiOGBETy.mjs} +503 -198
  17. package/dist/_chunks/index-PiOGBETy.mjs.map +1 -0
  18. package/dist/admin/index.js +15 -1
  19. package/dist/admin/index.js.map +1 -1
  20. package/dist/admin/index.mjs +16 -2
  21. package/dist/admin/index.mjs.map +1 -1
  22. package/dist/server/index.js +86 -83
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/server/index.mjs +86 -84
  25. package/dist/server/index.mjs.map +1 -1
  26. package/package.json +37 -30
  27. package/dist/_chunks/App-CqbuK4M6.js.map +0 -1
  28. package/dist/_chunks/App-Do-Rnv0A.mjs.map +0 -1
  29. package/dist/_chunks/PurchaseContentReleases-Be3acS2L.js.map +0 -1
  30. package/dist/_chunks/PurchaseContentReleases-_MxP6-Dt.mjs.map +0 -1
  31. package/dist/_chunks/en-B9Ur3VsE.mjs.map +0 -1
  32. package/dist/_chunks/en-DtFJ5ViE.js.map +0 -1
  33. package/dist/_chunks/index-D_pgdqQL.mjs.map +0 -1
  34. package/dist/_chunks/index-Tedsw4GC.js.map +0 -1
  35. package/dist/admin/src/components/CMReleasesContainer.d.ts +0 -22
  36. package/dist/admin/src/components/RelativeTime.d.ts +0 -28
  37. package/dist/admin/src/components/ReleaseAction.d.ts +0 -3
  38. package/dist/admin/src/components/ReleaseActionMenu.d.ts +0 -26
  39. package/dist/admin/src/components/ReleaseActionOptions.d.ts +0 -9
  40. package/dist/admin/src/components/ReleaseListCell.d.ts +0 -0
  41. package/dist/admin/src/components/ReleaseModal.d.ts +0 -17
  42. package/dist/admin/src/constants.d.ts +0 -58
  43. package/dist/admin/src/index.d.ts +0 -3
  44. package/dist/admin/src/pages/App.d.ts +0 -1
  45. package/dist/admin/src/pages/PurchaseContentReleases.d.ts +0 -2
  46. package/dist/admin/src/pages/ReleaseDetailsPage.d.ts +0 -2
  47. package/dist/admin/src/pages/ReleasesPage.d.ts +0 -8
  48. package/dist/admin/src/pages/tests/mockReleaseDetailsPageData.d.ts +0 -181
  49. package/dist/admin/src/pages/tests/mockReleasesPageData.d.ts +0 -39
  50. package/dist/admin/src/pluginId.d.ts +0 -1
  51. package/dist/admin/src/services/release.d.ts +0 -105
  52. package/dist/admin/src/store/hooks.d.ts +0 -7
  53. package/dist/admin/src/utils/api.d.ts +0 -6
  54. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +0 -3
  55. package/dist/admin/src/utils/time.d.ts +0 -1
  56. package/dist/server/src/bootstrap.d.ts +0 -5
  57. package/dist/server/src/bootstrap.d.ts.map +0 -1
  58. package/dist/server/src/constants.d.ts +0 -12
  59. package/dist/server/src/constants.d.ts.map +0 -1
  60. package/dist/server/src/content-types/index.d.ts +0 -99
  61. package/dist/server/src/content-types/index.d.ts.map +0 -1
  62. package/dist/server/src/content-types/release/index.d.ts +0 -48
  63. package/dist/server/src/content-types/release/index.d.ts.map +0 -1
  64. package/dist/server/src/content-types/release/schema.d.ts +0 -47
  65. package/dist/server/src/content-types/release/schema.d.ts.map +0 -1
  66. package/dist/server/src/content-types/release-action/index.d.ts +0 -50
  67. package/dist/server/src/content-types/release-action/index.d.ts.map +0 -1
  68. package/dist/server/src/content-types/release-action/schema.d.ts +0 -49
  69. package/dist/server/src/content-types/release-action/schema.d.ts.map +0 -1
  70. package/dist/server/src/controllers/index.d.ts +0 -20
  71. package/dist/server/src/controllers/index.d.ts.map +0 -1
  72. package/dist/server/src/controllers/release-action.d.ts +0 -10
  73. package/dist/server/src/controllers/release-action.d.ts.map +0 -1
  74. package/dist/server/src/controllers/release.d.ts +0 -12
  75. package/dist/server/src/controllers/release.d.ts.map +0 -1
  76. package/dist/server/src/controllers/validation/release-action.d.ts +0 -8
  77. package/dist/server/src/controllers/validation/release-action.d.ts.map +0 -1
  78. package/dist/server/src/controllers/validation/release.d.ts +0 -2
  79. package/dist/server/src/controllers/validation/release.d.ts.map +0 -1
  80. package/dist/server/src/destroy.d.ts +0 -5
  81. package/dist/server/src/destroy.d.ts.map +0 -1
  82. package/dist/server/src/index.d.ts +0 -2096
  83. package/dist/server/src/index.d.ts.map +0 -1
  84. package/dist/server/src/migrations/index.d.ts +0 -13
  85. package/dist/server/src/migrations/index.d.ts.map +0 -1
  86. package/dist/server/src/register.d.ts +0 -5
  87. package/dist/server/src/register.d.ts.map +0 -1
  88. package/dist/server/src/routes/index.d.ts +0 -35
  89. package/dist/server/src/routes/index.d.ts.map +0 -1
  90. package/dist/server/src/routes/release-action.d.ts +0 -18
  91. package/dist/server/src/routes/release-action.d.ts.map +0 -1
  92. package/dist/server/src/routes/release.d.ts +0 -18
  93. package/dist/server/src/routes/release.d.ts.map +0 -1
  94. package/dist/server/src/services/index.d.ts +0 -1826
  95. package/dist/server/src/services/index.d.ts.map +0 -1
  96. package/dist/server/src/services/release.d.ts +0 -66
  97. package/dist/server/src/services/release.d.ts.map +0 -1
  98. package/dist/server/src/services/scheduling.d.ts +0 -18
  99. package/dist/server/src/services/scheduling.d.ts.map +0 -1
  100. package/dist/server/src/services/validation.d.ts +0 -18
  101. package/dist/server/src/services/validation.d.ts.map +0 -1
  102. package/dist/server/src/utils/index.d.ts +0 -14
  103. package/dist/server/src/utils/index.d.ts.map +0 -1
  104. package/dist/shared/contracts/release-actions.d.ts +0 -131
  105. package/dist/shared/contracts/release-actions.d.ts.map +0 -1
  106. package/dist/shared/contracts/releases.d.ts +0 -182
  107. package/dist/shared/contracts/releases.d.ts.map +0 -1
  108. package/dist/shared/types.d.ts +0 -24
  109. package/dist/shared/types.d.ts.map +0 -1
  110. package/dist/shared/validation-schemas.d.ts +0 -2
  111. package/dist/shared/validation-schemas.d.ts.map +0 -1
@@ -1,16 +1,18 @@
1
+ import { getFetchClient, useNotification, useAPIErrorHandler, CheckPermissions, useCMEditViewDataManager, NoContent, useRBAC, SortIcon, prefixPluginTranslations } from "@strapi/helper-plugin";
1
2
  import { Cross, Pencil, More, Plus, PaperPlane } from "@strapi/icons";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import * as React from "react";
4
5
  import { skipToken } from "@reduxjs/toolkit/query";
5
- import { adminApi, useNotification, useAPIErrorHandler, useRBAC, useAuth, isFetchError, useQueryParams } from "@strapi/admin/strapi-admin";
6
- import { unstable_useDocument } from "@strapi/content-manager/strapi-admin";
7
- import { Menu, Flex, Typography, AccessibleIcon, Field, VisuallyHidden, Box, Button, Modal, SingleSelect, SingleSelectOption, EmptyStateLayout, LinkButton } from "@strapi/design-system";
8
- import { EmptyDocuments } from "@strapi/icons/symbols";
6
+ import { IconButton, Flex, Icon, Typography, Field, FieldLabel, VisuallyHidden, FieldInput, Box, Button as Button$1, ModalLayout, ModalHeader, ModalBody, SingleSelect, SingleSelectOption, ModalFooter, Popover } from "@strapi/design-system";
7
+ import { Menu, Link, LinkButton } from "@strapi/design-system/v2";
8
+ import { isAxiosError as isAxiosError$1 } from "axios";
9
9
  import { Formik, Form } from "formik";
10
10
  import { useIntl } from "react-intl";
11
- import { Link, useParams } from "react-router-dom";
11
+ import { NavLink, Link as Link$1 } from "react-router-dom";
12
12
  import * as yup from "yup";
13
- import { styled } from "styled-components";
13
+ import { createApi } from "@reduxjs/toolkit/query/react";
14
+ import styled from "styled-components";
15
+ import { useDispatch, useSelector } from "react-redux";
14
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
15
17
  const v = glob[path];
16
18
  if (v) {
@@ -92,9 +94,49 @@ const PERMISSIONS = {
92
94
  }
93
95
  ]
94
96
  };
95
- const releaseApi = adminApi.enhanceEndpoints({
96
- addTagTypes: ["Release", "ReleaseAction", "EntriesInRelease"]
97
- }).injectEndpoints({
97
+ const pluginId = "content-releases";
98
+ const axiosBaseQuery = async ({
99
+ url,
100
+ method,
101
+ data,
102
+ config
103
+ }) => {
104
+ try {
105
+ const { get, post, del, put } = getFetchClient();
106
+ if (method === "POST") {
107
+ const result2 = await post(url, data, config);
108
+ return { data: result2.data };
109
+ }
110
+ if (method === "DELETE") {
111
+ const result2 = await del(url, config);
112
+ return { data: result2.data };
113
+ }
114
+ if (method === "PUT") {
115
+ const result2 = await put(url, data, config);
116
+ return { data: result2.data };
117
+ }
118
+ const result = await get(url, config);
119
+ return { data: result.data };
120
+ } catch (error) {
121
+ const err = error;
122
+ return {
123
+ error: {
124
+ status: err.response?.status,
125
+ code: err.code,
126
+ response: {
127
+ data: err.response?.data
128
+ }
129
+ }
130
+ };
131
+ }
132
+ };
133
+ const isAxiosError = (err) => {
134
+ return typeof err === "object" && err !== null && "response" in err && typeof err.response === "object" && err.response !== null && "data" in err.response;
135
+ };
136
+ const releaseApi = createApi({
137
+ reducerPath: pluginId,
138
+ baseQuery: axiosBaseQuery,
139
+ tagTypes: ["Release", "ReleaseAction", "EntriesInRelease"],
98
140
  endpoints: (build) => {
99
141
  return {
100
142
  getReleasesForEntry: build.query({
@@ -238,17 +280,13 @@ const releaseApi = adminApi.enhanceEndpoints({
238
280
  ...query
239
281
  };
240
282
  const patchResult = dispatch(
241
- releaseApi.util.updateQueryData(
242
- "getReleaseActions",
243
- paramsWithoutActionId,
244
- (draft) => {
245
- const [key, index] = actionPath;
246
- const action = draft.data[key][index];
247
- if (action) {
248
- action.type = body.type;
249
- }
283
+ releaseApi.util.updateQueryData("getReleaseActions", paramsWithoutActionId, (draft) => {
284
+ const [key, index] = actionPath;
285
+ const action = draft.data[key][index];
286
+ if (action) {
287
+ action.type = body.type;
250
288
  }
251
- )
289
+ })
252
290
  );
253
291
  try {
254
292
  await queryFulfilled;
@@ -338,12 +376,16 @@ const getTimezoneOffset = (timezone, date) => {
338
376
  return "";
339
377
  }
340
378
  };
379
+ const useTypedDispatch = useDispatch;
380
+ const useTypedSelector = useSelector;
341
381
  const StyledMenuItem = styled(Menu.Item)`
342
382
  &:hover {
343
- background: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}100`]};
383
+ background: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}100`]};
344
384
 
345
385
  svg {
346
- fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
386
+ path {
387
+ fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
388
+ }
347
389
  }
348
390
 
349
391
  a {
@@ -352,7 +394,9 @@ const StyledMenuItem = styled(Menu.Item)`
352
394
  }
353
395
 
354
396
  svg {
355
- fill: ${({ theme, $variant = "neutral" }) => theme.colors[`${$variant}600`]};
397
+ path {
398
+ fill: ${({ theme, variant = "neutral" }) => theme.colors[`${variant}600`]};
399
+ }
356
400
  }
357
401
 
358
402
  a {
@@ -364,14 +408,15 @@ const StyledMenuItem = styled(Menu.Item)`
364
408
  width: 100%;
365
409
  }
366
410
  `;
411
+ const StyledIconButton = styled(IconButton)`
412
+ /* Setting this style inline with borderColor will not apply the style */
413
+ border: ${({ theme }) => `1px solid ${theme.colors.neutral200}`};
414
+ `;
367
415
  const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
368
416
  const { formatMessage } = useIntl();
369
- const { toggleNotification } = useNotification();
417
+ const toggleNotification = useNotification();
370
418
  const { formatAPIError } = useAPIErrorHandler();
371
419
  const [deleteReleaseAction] = useDeleteReleaseActionMutation();
372
- const {
373
- allowedActions: { canDeleteAction }
374
- } = useRBAC(PERMISSIONS);
375
420
  const handleDeleteAction = async () => {
376
421
  const response = await deleteReleaseAction({
377
422
  params: { releaseId, actionId }
@@ -387,29 +432,26 @@ const DeleteReleaseActionItem = ({ releaseId, actionId }) => {
387
432
  return;
388
433
  }
389
434
  if ("error" in response) {
390
- if (isFetchError(response.error)) {
435
+ if (isAxiosError$1(response.error)) {
391
436
  toggleNotification({
392
- type: "danger",
437
+ type: "warning",
393
438
  message: formatAPIError(response.error)
394
439
  });
395
440
  } else {
396
441
  toggleNotification({
397
- type: "danger",
442
+ type: "warning",
398
443
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
399
444
  });
400
445
  }
401
446
  }
402
447
  };
403
- if (!canDeleteAction) {
404
- return null;
405
- }
406
- return /* @__PURE__ */ jsx(StyledMenuItem, { $variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
407
- /* @__PURE__ */ jsx(Cross, { width: "1.6rem", height: "1.6rem" }),
448
+ return /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsx(StyledMenuItem, { variant: "danger", onSelect: handleDeleteAction, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
449
+ /* @__PURE__ */ jsx(Icon, { as: Cross, width: 3, height: 3 }),
408
450
  /* @__PURE__ */ jsx(Typography, { textColor: "danger600", variant: "omega", children: formatMessage({
409
451
  id: "content-releases.content-manager-edit-view.remove-from-release",
410
452
  defaultMessage: "Remove from release"
411
453
  }) })
412
- ] }) });
454
+ ] }) }) });
413
455
  };
414
456
  const ReleaseActionEntryLinkItem = ({
415
457
  contentTypeUid,
@@ -417,79 +459,77 @@ const ReleaseActionEntryLinkItem = ({
417
459
  locale
418
460
  }) => {
419
461
  const { formatMessage } = useIntl();
420
- const userPermissions = useAuth("ReleaseActionEntryLinkItem", (state) => state.permissions);
421
- const canUpdateEntryForLocale = React.useMemo(() => {
422
- const updatePermissions = userPermissions.find(
423
- (permission) => permission.subject === contentTypeUid && permission.action === "plugin::content-manager.explorer.update"
424
- );
425
- if (!updatePermissions) {
426
- return false;
427
- }
428
- return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
429
- }, [contentTypeUid, locale, userPermissions]);
430
- const {
431
- allowedActions: { canUpdate: canUpdateContentType }
432
- } = useRBAC({
433
- updateContentType: [
434
- {
435
- action: "plugin::content-manager.explorer.update",
436
- subject: contentTypeUid
437
- }
438
- ]
439
- });
440
- if (!canUpdateContentType || !canUpdateEntryForLocale) {
441
- return null;
442
- }
462
+ const collectionTypePermissions = useTypedSelector(
463
+ (state) => state.rbacProvider.collectionTypesRelatedPermissions
464
+ );
465
+ const updatePermissions = contentTypeUid ? collectionTypePermissions[contentTypeUid]?.["plugin::content-manager.explorer.update"] : [];
466
+ const canUpdateEntryForLocale = Boolean(
467
+ !locale || updatePermissions?.find(
468
+ (permission) => permission.properties?.locales?.includes(locale)
469
+ )
470
+ );
443
471
  return /* @__PURE__ */ jsx(
444
- StyledMenuItem,
472
+ CheckPermissions,
445
473
  {
446
- tag: Link,
447
- isLink: true,
448
- to: {
449
- pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
450
- search: locale && `?plugins[i18n][locale]=${locale}`
451
- },
452
- children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
453
- /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" }),
454
- /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
455
- id: "content-releases.content-manager-edit-view.edit-entry",
456
- defaultMessage: "Edit entry"
457
- }) })
458
- ] })
474
+ permissions: [
475
+ {
476
+ action: "plugin::content-manager.explorer.update",
477
+ subject: contentTypeUid
478
+ }
479
+ ],
480
+ children: canUpdateEntryForLocale && /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
481
+ Link,
482
+ {
483
+ as: NavLink,
484
+ to: {
485
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${entryId}`,
486
+ search: locale && `?plugins[i18n][locale]=${locale}`
487
+ },
488
+ startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
489
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
490
+ id: "content-releases.content-manager-edit-view.edit-entry",
491
+ defaultMessage: "Edit entry"
492
+ }) })
493
+ }
494
+ ) })
459
495
  }
460
496
  );
461
497
  };
462
498
  const EditReleaseItem = ({ releaseId }) => {
463
499
  const { formatMessage } = useIntl();
464
- return (
465
- /* @ts-expect-error inference isn't working in DS */
466
- /* @__PURE__ */ jsx(StyledMenuItem, { tag: Link, isLink: true, to: `/plugins/content-releases/${releaseId}`, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
467
- /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" }),
468
- /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
500
+ return /* @__PURE__ */ jsx(StyledMenuItem, { children: /* @__PURE__ */ jsx(
501
+ Link,
502
+ {
503
+ href: `/admin/plugins/content-releases/${releaseId}`,
504
+ startIcon: /* @__PURE__ */ jsx(Icon, { as: Pencil, width: 3, height: 3 }),
505
+ isExternal: false,
506
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
469
507
  id: "content-releases.content-manager-edit-view.edit-release",
470
508
  defaultMessage: "Edit release"
471
509
  }) })
472
- ] }) })
473
- );
510
+ }
511
+ ) });
474
512
  };
475
- const Root = ({ children }) => {
513
+ const Root = ({ children, hasTriggerBorder = false }) => {
476
514
  const { formatMessage } = useIntl();
477
- const { allowedActions } = useRBAC(PERMISSIONS);
478
515
  return (
479
516
  // A user can access the dropdown if they have permissions to delete a release-action OR update a release
480
- allowedActions.canDeleteAction || allowedActions.canUpdate ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
481
- /* @__PURE__ */ jsx(Menu.Trigger, { paddingLeft: 2, paddingRight: 2, children: /* @__PURE__ */ jsx(
482
- AccessibleIcon,
517
+ /* @__PURE__ */ jsx(CheckPermissions, { permissions: [...PERMISSIONS.deleteAction, ...PERMISSIONS.update], children: /* @__PURE__ */ jsxs(Menu.Root, { children: [
518
+ /* @__PURE__ */ jsx(
519
+ Menu.Trigger,
483
520
  {
484
- label: formatMessage({
521
+ as: hasTriggerBorder ? StyledIconButton : IconButton,
522
+ paddingLeft: 2,
523
+ paddingRight: 2,
524
+ "aria-label": formatMessage({
485
525
  id: "content-releases.content-manager-edit-view.release-action-menu",
486
526
  defaultMessage: "Release action options"
487
527
  }),
488
- children: /* @__PURE__ */ jsx(More, {})
528
+ icon: /* @__PURE__ */ jsx(More, {})
489
529
  }
490
- ) }),
530
+ ),
491
531
  /* @__PURE__ */ jsx(Menu.Content, { top: 1, popoverPlacement: "bottom-end", children })
492
- ] }) : null
532
+ ] }) })
493
533
  );
494
534
  };
495
535
  const ReleaseActionMenu = {
@@ -504,11 +544,11 @@ const getBorderLeftRadiusValue = (actionType) => {
504
544
  const getBorderRightRadiusValue = (actionType) => {
505
545
  return actionType === "publish" ? 0 : 1;
506
546
  };
507
- const FieldWrapper = styled(Field.Root)`
508
- border-top-left-radius: ${({ $actionType, theme }) => theme.spaces[getBorderLeftRadiusValue($actionType)]};
509
- border-bottom-left-radius: ${({ $actionType, theme }) => theme.spaces[getBorderLeftRadiusValue($actionType)]};
510
- border-top-right-radius: ${({ $actionType, theme }) => theme.spaces[getBorderRightRadiusValue($actionType)]};
511
- border-bottom-right-radius: ${({ $actionType, theme }) => theme.spaces[getBorderRightRadiusValue($actionType)]};
547
+ const FieldWrapper = styled(Field)`
548
+ border-top-left-radius: ${({ actionType, theme }) => theme.spaces[getBorderLeftRadiusValue(actionType)]};
549
+ border-bottom-left-radius: ${({ actionType, theme }) => theme.spaces[getBorderLeftRadiusValue(actionType)]};
550
+ border-top-right-radius: ${({ actionType, theme }) => theme.spaces[getBorderRightRadiusValue(actionType)]};
551
+ border-bottom-right-radius: ${({ actionType, theme }) => theme.spaces[getBorderRightRadiusValue(actionType)]};
512
552
 
513
553
  > label {
514
554
  color: inherit;
@@ -519,14 +559,14 @@ const FieldWrapper = styled(Field.Root)`
519
559
  }
520
560
 
521
561
  &[data-checked='true'] {
522
- color: ${({ theme, $actionType }) => $actionType === "publish" ? theme.colors.primary700 : theme.colors.danger600};
523
- background-color: ${({ theme, $actionType }) => $actionType === "publish" ? theme.colors.primary100 : theme.colors.danger100};
524
- border-color: ${({ theme, $actionType }) => $actionType === "publish" ? theme.colors.primary700 : theme.colors.danger600};
562
+ color: ${({ theme, actionType }) => actionType === "publish" ? theme.colors.primary700 : theme.colors.danger600};
563
+ background-color: ${({ theme, actionType }) => actionType === "publish" ? theme.colors.primary100 : theme.colors.danger100};
564
+ border-color: ${({ theme, actionType }) => actionType === "publish" ? theme.colors.primary700 : theme.colors.danger600};
525
565
  }
526
566
 
527
567
  &[data-checked='false'] {
528
- border-left: ${({ $actionType }) => $actionType === "unpublish" && "none"};
529
- border-right: ${({ $actionType }) => $actionType === "publish" && "none"};
568
+ border-left: ${({ actionType }) => actionType === "unpublish" && "none"};
569
+ border-right: ${({ actionType }) => actionType === "publish" && "none"};
530
570
  }
531
571
 
532
572
  &[data-checked='false'][data-disabled='false']:hover {
@@ -555,7 +595,7 @@ const ActionOption = ({
555
595
  return /* @__PURE__ */ jsx(
556
596
  FieldWrapper,
557
597
  {
558
- $actionType: actionType,
598
+ actionType,
559
599
  background: "primary0",
560
600
  borderColor: "neutral200",
561
601
  color: selected === actionType ? "primary600" : "neutral600",
@@ -563,11 +603,12 @@ const ActionOption = ({
563
603
  cursor: "pointer",
564
604
  "data-checked": selected === actionType,
565
605
  "data-disabled": disabled && selected !== actionType,
566
- children: /* @__PURE__ */ jsxs(Field.Label, { children: [
606
+ children: /* @__PURE__ */ jsxs(FieldLabel, { htmlFor: `${name}-${actionType}`, children: [
567
607
  /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(
568
- Field.Input,
608
+ FieldInput,
569
609
  {
570
610
  type: "radio",
611
+ id: `${name}-${actionType}`,
571
612
  name,
572
613
  checked: selected === actionType,
573
614
  onChange: handleChange,
@@ -620,20 +661,19 @@ const INITIAL_VALUES = {
620
661
  const NoReleases = () => {
621
662
  const { formatMessage } = useIntl();
622
663
  return /* @__PURE__ */ jsx(
623
- EmptyStateLayout,
664
+ NoContent,
624
665
  {
625
- icon: /* @__PURE__ */ jsx(EmptyDocuments, { width: "16rem" }),
626
- content: formatMessage({
666
+ content: {
627
667
  id: "content-releases.content-manager-edit-view.add-to-release.no-releases-message",
628
668
  defaultMessage: "No available releases. Open the list of releases and create a new one from there."
629
- }),
669
+ },
630
670
  action: /* @__PURE__ */ jsx(
631
671
  LinkButton,
632
672
  {
633
673
  to: {
634
674
  pathname: "/plugins/content-releases"
635
675
  },
636
- tag: Link,
676
+ as: Link$1,
637
677
  variant: "secondary",
638
678
  children: formatMessage({
639
679
  id: "content-releases.content-manager-edit-view.add-to-release.redirect-button",
@@ -645,16 +685,15 @@ const NoReleases = () => {
645
685
  );
646
686
  };
647
687
  const AddActionToReleaseModal = ({
648
- open,
649
- onOpenChange,
688
+ handleClose,
650
689
  contentTypeUid,
651
690
  entryId
652
691
  }) => {
692
+ const releaseHeaderId = React.useId();
653
693
  const { formatMessage } = useIntl();
654
- const { toggleNotification } = useNotification();
694
+ const toggleNotification = useNotification();
655
695
  const { formatAPIError } = useAPIErrorHandler();
656
- const [{ query }] = useQueryParams();
657
- const locale = query.plugins?.i18n?.locale;
696
+ const { modifiedData } = useCMEditViewDataManager();
658
697
  const response = useGetReleasesForEntryQuery({
659
698
  contentTypeUid,
660
699
  entryId,
@@ -663,6 +702,7 @@ const AddActionToReleaseModal = ({
663
702
  const releases = response.data?.data;
664
703
  const [createReleaseAction, { isLoading }] = useCreateReleaseActionMutation();
665
704
  const handleSubmit = async (values) => {
705
+ const locale = modifiedData.locale;
666
706
  const releaseActionEntry = {
667
707
  contentType: contentTypeUid,
668
708
  id: entryId,
@@ -680,25 +720,25 @@ const AddActionToReleaseModal = ({
680
720
  defaultMessage: "Entry added to release"
681
721
  })
682
722
  });
683
- onOpenChange();
723
+ handleClose();
684
724
  return;
685
725
  }
686
726
  if ("error" in response2) {
687
- if (isFetchError(response2.error)) {
727
+ if (isAxiosError$1(response2.error)) {
688
728
  toggleNotification({
689
- type: "danger",
729
+ type: "warning",
690
730
  message: formatAPIError(response2.error)
691
731
  });
692
732
  } else {
693
733
  toggleNotification({
694
- type: "danger",
734
+ type: "warning",
695
735
  message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
696
736
  });
697
737
  }
698
738
  }
699
739
  };
700
- return /* @__PURE__ */ jsx(Modal.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
701
- /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { fontWeight: "bold", children: formatMessage({
740
+ return /* @__PURE__ */ jsxs(ModalLayout, { onClose: handleClose, labelledBy: releaseHeaderId, children: [
741
+ /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { id: releaseHeaderId, fontWeight: "bold", textColor: "neutral800", children: formatMessage({
702
742
  id: "content-releases.content-manager-edit-view.add-to-release",
703
743
  defaultMessage: "Add to release"
704
744
  }) }) }),
@@ -710,26 +750,25 @@ const AddActionToReleaseModal = ({
710
750
  initialValues: INITIAL_VALUES,
711
751
  children: ({ values, setFieldValue }) => {
712
752
  return /* @__PURE__ */ jsxs(Form, { children: [
713
- releases?.length === 0 ? /* @__PURE__ */ jsx(NoReleases, {}) : /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
714
- /* @__PURE__ */ jsx(Box, { paddingBottom: 6, children: /* @__PURE__ */ jsxs(Field.Root, { required: true, children: [
715
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
716
- id: "content-releases.content-manager-edit-view.add-to-release.select-label",
717
- defaultMessage: "Select a release"
718
- }) }),
719
- /* @__PURE__ */ jsx(
720
- SingleSelect,
721
- {
722
- placeholder: formatMessage({
723
- id: "content-releases.content-manager-edit-view.add-to-release.select-placeholder",
724
- defaultMessage: "Select"
725
- }),
726
- onChange: (value) => setFieldValue("releaseId", value),
727
- value: values.releaseId,
728
- children: releases?.map((release) => /* @__PURE__ */ jsx(SingleSelectOption, { value: release.id, children: release.name }, release.id))
729
- }
730
- )
731
- ] }) }),
732
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
753
+ releases?.length === 0 ? /* @__PURE__ */ jsx(NoReleases, {}) : /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
754
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 6, children: /* @__PURE__ */ jsx(
755
+ SingleSelect,
756
+ {
757
+ required: true,
758
+ label: formatMessage({
759
+ id: "content-releases.content-manager-edit-view.add-to-release.select-label",
760
+ defaultMessage: "Select a release"
761
+ }),
762
+ placeholder: formatMessage({
763
+ id: "content-releases.content-manager-edit-view.add-to-release.select-placeholder",
764
+ defaultMessage: "Select"
765
+ }),
766
+ onChange: (value) => setFieldValue("releaseId", value),
767
+ value: values.releaseId,
768
+ children: releases?.map((release) => /* @__PURE__ */ jsx(SingleSelectOption, { value: release.id, children: release.name }, release.id))
769
+ }
770
+ ) }),
771
+ /* @__PURE__ */ jsx(FieldLabel, { children: formatMessage({
733
772
  id: "content-releases.content-manager-edit-view.add-to-release.action-type-label",
734
773
  defaultMessage: "What do you want to do with this entry?"
735
774
  }) }),
@@ -742,37 +781,42 @@ const AddActionToReleaseModal = ({
742
781
  }
743
782
  )
744
783
  ] }) }),
745
- /* @__PURE__ */ jsxs(Modal.Footer, { children: [
746
- /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", name: "cancel", children: formatMessage({
747
- id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
748
- defaultMessage: "Cancel"
749
- }) }) }),
750
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
751
- id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
752
- defaultMessage: "Continue"
753
- }) })
754
- ] })
784
+ /* @__PURE__ */ jsx(
785
+ ModalFooter,
786
+ {
787
+ startActions: /* @__PURE__ */ jsx(Button$1, { onClick: handleClose, variant: "tertiary", name: "cancel", children: formatMessage({
788
+ id: "content-releases.content-manager-edit-view.add-to-release.cancel-button",
789
+ defaultMessage: "Cancel"
790
+ }) }),
791
+ endActions: (
792
+ /**
793
+ * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
794
+ * for yup.string().required(), even when the value is falsy (including empty string)
795
+ */
796
+ /* @__PURE__ */ jsx(Button$1, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
797
+ id: "content-releases.content-manager-edit-view.add-to-release.continue-button",
798
+ defaultMessage: "Continue"
799
+ }) })
800
+ )
801
+ }
802
+ )
755
803
  ] });
756
804
  }
757
805
  }
758
806
  )
759
- ] }) });
807
+ ] });
760
808
  };
761
809
  const CMReleasesContainer = () => {
762
810
  const [isModalOpen, setIsModalOpen] = React.useState(false);
763
811
  const { formatMessage, formatDate, formatTime } = useIntl();
764
- const { id, slug, collectionType } = useParams();
765
- const isCreatingEntry = id === "create";
766
- const entryId = parseInt(id, 10);
767
- const { allowedActions } = useRBAC(PERMISSIONS);
768
- const { canCreateAction, canRead: canMain, canDeleteAction } = allowedActions;
769
- const { schema } = unstable_useDocument({
770
- collectionType,
771
- model: slug
772
- });
773
- const hasDraftAndPublish = schema?.options?.draftAndPublish;
812
+ const {
813
+ isCreatingEntry,
814
+ hasDraftAndPublish,
815
+ initialData: { id: entryId },
816
+ slug
817
+ } = useCMEditViewDataManager();
774
818
  const contentTypeUid = slug;
775
- const canFetch = id != null && contentTypeUid != null;
819
+ const canFetch = entryId != null && contentTypeUid != null;
776
820
  const fetchParams = canFetch ? {
777
821
  contentTypeUid,
778
822
  entryId,
@@ -793,13 +837,10 @@ const CMReleasesContainer = () => {
793
837
  }
794
838
  return `success${shade}`;
795
839
  };
796
- if (!canMain) {
797
- return null;
798
- }
799
- return /* @__PURE__ */ jsxs(
840
+ return /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.main, children: /* @__PURE__ */ jsxs(
800
841
  Box,
801
842
  {
802
- tag: "aside",
843
+ as: "aside",
803
844
  "aria-label": formatMessage({
804
845
  id: "content-releases.plugin.name",
805
846
  defaultMessage: "Releases"
@@ -853,7 +894,7 @@ const CMReleasesContainer = () => {
853
894
  )
854
895
  }
855
896
  ),
856
- /* @__PURE__ */ jsx(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
897
+ /* @__PURE__ */ jsxs(Flex, { padding: 4, direction: "column", gap: 2, width: "100%", alignItems: "flex-start", children: [
857
898
  /* @__PURE__ */ jsx(Typography, { fontSize: 2, fontWeight: "bold", variant: "omega", textColor: "neutral700", children: release.name }),
858
899
  release.scheduledAt && release.timezone && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: formatMessage(
859
900
  {
@@ -877,7 +918,7 @@ const CMReleasesContainer = () => {
877
918
  )
878
919
  }
879
920
  ) }),
880
- canDeleteAction ? /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
921
+ /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.deleteAction, children: /* @__PURE__ */ jsxs(ReleaseActionMenu.Root, { hasTriggerBorder: true, children: [
881
922
  /* @__PURE__ */ jsx(ReleaseActionMenu.EditReleaseItem, { releaseId: release.id }),
882
923
  /* @__PURE__ */ jsx(
883
924
  ReleaseActionMenu.DeleteReleaseActionItem,
@@ -886,15 +927,15 @@ const CMReleasesContainer = () => {
886
927
  actionId: release.actions[0].id
887
928
  }
888
929
  )
889
- ] }) : null
890
- ] }) })
930
+ ] }) })
931
+ ] })
891
932
  ]
892
933
  },
893
934
  release.id
894
935
  );
895
936
  }),
896
- canCreateAction ? /* @__PURE__ */ jsx(
897
- Button,
937
+ /* @__PURE__ */ jsx(CheckPermissions, { permissions: PERMISSIONS.createAction, children: /* @__PURE__ */ jsx(
938
+ Button$1,
898
939
  {
899
940
  justifyContent: "center",
900
941
  paddingLeft: 4,
@@ -908,30 +949,281 @@ const CMReleasesContainer = () => {
908
949
  defaultMessage: "Add to release"
909
950
  })
910
951
  }
911
- ) : null
952
+ ) })
912
953
  ] }),
913
- /* @__PURE__ */ jsx(
954
+ isModalOpen && /* @__PURE__ */ jsx(
914
955
  AddActionToReleaseModal,
915
956
  {
916
- open: isModalOpen,
917
- onOpenChange: toggleModal,
957
+ handleClose: toggleModal,
918
958
  contentTypeUid,
919
959
  entryId
920
960
  }
921
961
  )
922
962
  ]
923
963
  }
964
+ ) });
965
+ };
966
+ const getContentPermissions = (subject) => {
967
+ const permissions = {
968
+ publish: [
969
+ {
970
+ action: "plugin::content-manager.explorer.publish",
971
+ subject,
972
+ id: "",
973
+ actionParameters: {},
974
+ properties: {},
975
+ conditions: []
976
+ }
977
+ ]
978
+ };
979
+ return permissions;
980
+ };
981
+ const ReleaseAction = ({ ids, model }) => {
982
+ const { formatMessage } = useIntl();
983
+ const toggleNotification = useNotification();
984
+ const { formatAPIError } = useAPIErrorHandler();
985
+ const { modifiedData } = useCMEditViewDataManager();
986
+ const contentPermissions = getContentPermissions(model);
987
+ const {
988
+ allowedActions: { canPublish }
989
+ } = useRBAC(contentPermissions);
990
+ const {
991
+ allowedActions: { canCreate }
992
+ } = useRBAC(PERMISSIONS);
993
+ const response = useGetReleasesQuery();
994
+ const releases = response.data?.data;
995
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
996
+ const handleSubmit = async (values) => {
997
+ const locale = modifiedData.locale;
998
+ const releaseActionEntries = ids.map((id) => ({
999
+ type: values.type,
1000
+ entry: {
1001
+ contentType: model,
1002
+ id,
1003
+ locale
1004
+ }
1005
+ }));
1006
+ const response2 = await createManyReleaseActions({
1007
+ body: releaseActionEntries,
1008
+ params: { releaseId: values.releaseId }
1009
+ });
1010
+ if ("data" in response2) {
1011
+ const notificationMessage = formatMessage(
1012
+ {
1013
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.message",
1014
+ defaultMessage: "{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release."
1015
+ },
1016
+ {
1017
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1018
+ totalEntries: response2.data.meta.totalEntries
1019
+ }
1020
+ );
1021
+ const notification = {
1022
+ type: "success",
1023
+ title: formatMessage(
1024
+ {
1025
+ id: "content-releases.content-manager-list-view.add-to-release.notification.success.title",
1026
+ defaultMessage: "Successfully added to release."
1027
+ },
1028
+ {
1029
+ entriesAlreadyInRelease: response2.data.meta.entriesAlreadyInRelease,
1030
+ totalEntries: response2.data.meta.totalEntries
1031
+ }
1032
+ ),
1033
+ message: response2.data.meta.entriesAlreadyInRelease ? notificationMessage : ""
1034
+ };
1035
+ toggleNotification(notification);
1036
+ return true;
1037
+ }
1038
+ if ("error" in response2) {
1039
+ if (isAxiosError$1(response2.error)) {
1040
+ toggleNotification({
1041
+ type: "warning",
1042
+ message: formatAPIError(response2.error)
1043
+ });
1044
+ } else {
1045
+ toggleNotification({
1046
+ type: "warning",
1047
+ message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" })
1048
+ });
1049
+ }
1050
+ }
1051
+ };
1052
+ if (!canCreate || !canPublish)
1053
+ return null;
1054
+ return {
1055
+ actionType: "release",
1056
+ variant: "tertiary",
1057
+ label: formatMessage({
1058
+ id: "content-manager-list-view.add-to-release",
1059
+ defaultMessage: "Add to Release"
1060
+ }),
1061
+ dialog: {
1062
+ type: "modal",
1063
+ title: formatMessage({
1064
+ id: "content-manager-list-view.add-to-release",
1065
+ defaultMessage: "Add to Release"
1066
+ }),
1067
+ content: ({ onClose }) => {
1068
+ return /* @__PURE__ */ jsx(
1069
+ Formik,
1070
+ {
1071
+ onSubmit: async (values) => {
1072
+ const data = await handleSubmit(values);
1073
+ if (data) {
1074
+ return onClose();
1075
+ }
1076
+ },
1077
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
1078
+ initialValues: INITIAL_VALUES,
1079
+ children: ({ values, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { children: [
1080
+ releases?.length === 0 ? /* @__PURE__ */ jsx(NoReleases, {}) : /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1081
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 6, children: /* @__PURE__ */ jsx(
1082
+ SingleSelect,
1083
+ {
1084
+ required: true,
1085
+ label: formatMessage({
1086
+ id: "content-releases.content-manager-list-view.add-to-release.select-label",
1087
+ defaultMessage: "Select a release"
1088
+ }),
1089
+ placeholder: formatMessage({
1090
+ id: "content-releases.content-manager-list-view.add-to-release.select-placeholder",
1091
+ defaultMessage: "Select"
1092
+ }),
1093
+ onChange: (value) => setFieldValue("releaseId", value),
1094
+ value: values.releaseId,
1095
+ children: releases?.map((release) => /* @__PURE__ */ jsx(SingleSelectOption, { value: release.id, children: release.name }, release.id))
1096
+ }
1097
+ ) }),
1098
+ /* @__PURE__ */ jsx(FieldLabel, { children: formatMessage({
1099
+ id: "content-releases.content-manager-list-view.add-to-release.action-type-label",
1100
+ defaultMessage: "What do you want to do with these entries?"
1101
+ }) }),
1102
+ /* @__PURE__ */ jsx(
1103
+ ReleaseActionOptions,
1104
+ {
1105
+ selected: values.type,
1106
+ handleChange: (e) => setFieldValue("type", e.target.value),
1107
+ name: "type"
1108
+ }
1109
+ )
1110
+ ] }) }),
1111
+ /* @__PURE__ */ jsx(
1112
+ ModalFooter,
1113
+ {
1114
+ startActions: /* @__PURE__ */ jsx(Button$1, { onClick: onClose, variant: "tertiary", name: "cancel", children: formatMessage({
1115
+ id: "content-releases.content-manager-list-view.add-to-release.cancel-button",
1116
+ defaultMessage: "Cancel"
1117
+ }) }),
1118
+ endActions: (
1119
+ /**
1120
+ * TODO: Ideally we would use isValid from Formik to disable the button, however currently it always returns true
1121
+ * for yup.string().required(), even when the value is falsy (including empty string)
1122
+ */
1123
+ /* @__PURE__ */ jsx(Button$1, { type: "submit", disabled: !values.releaseId, loading: isLoading, children: formatMessage({
1124
+ id: "content-releases.content-manager-list-view.add-to-release.continue-button",
1125
+ defaultMessage: "Continue"
1126
+ }) })
1127
+ )
1128
+ }
1129
+ )
1130
+ ] })
1131
+ }
1132
+ );
1133
+ }
1134
+ }
1135
+ };
1136
+ };
1137
+ const Button = styled.button`
1138
+ svg {
1139
+ > g,
1140
+ path {
1141
+ fill: ${({ theme }) => theme.colors.neutral500};
1142
+ }
1143
+ }
1144
+ &:hover {
1145
+ svg {
1146
+ > g,
1147
+ path {
1148
+ fill: ${({ theme }) => theme.colors.neutral600};
1149
+ }
1150
+ }
1151
+ }
1152
+ &:active {
1153
+ svg {
1154
+ > g,
1155
+ path {
1156
+ fill: ${({ theme }) => theme.colors.neutral400};
1157
+ }
1158
+ }
1159
+ }
1160
+ `;
1161
+ const ActionWrapper = styled(Flex)`
1162
+ svg {
1163
+ height: ${4 / 16}rem;
1164
+ }
1165
+ `;
1166
+ const useReleasesList = (entryId) => {
1167
+ const { uid: contentTypeUid } = useTypedSelector(
1168
+ (state) => state["content-manager_listView"].contentType
1169
+ );
1170
+ const listViewData = useTypedSelector((state) => state["content-manager_listView"].data);
1171
+ const entriesIds = listViewData.map((entry) => entry.id);
1172
+ const response = useGetMappedEntriesInReleasesQuery(
1173
+ { contentTypeUid, entriesIds },
1174
+ { skip: !entriesIds || !contentTypeUid || entriesIds.length === 0 }
924
1175
  );
1176
+ const mappedEntriesInReleases = response.data || {};
1177
+ return mappedEntriesInReleases?.[entryId] || [];
925
1178
  };
926
- const pluginId = "content-releases";
927
- const prefixPluginTranslations = (trad, pluginId2) => {
928
- if (!pluginId2) {
929
- throw new TypeError("pluginId can't be empty");
1179
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1180
+ const { contentType } = layout;
1181
+ if (!contentType.options?.draftAndPublish) {
1182
+ return { displayedHeaders, layout };
930
1183
  }
931
- return Object.keys(trad).reduce((acc, current) => {
932
- acc[`${pluginId2}.${current}`] = trad[current];
933
- return acc;
934
- }, {});
1184
+ return {
1185
+ displayedHeaders: [
1186
+ ...displayedHeaders,
1187
+ {
1188
+ key: "__release_key__",
1189
+ fieldSchema: { type: "string" },
1190
+ metadatas: { label: "To be released in", searchable: true, sortable: false },
1191
+ name: "releasedAt",
1192
+ cellFormatter: (props) => /* @__PURE__ */ jsx(ReleaseListCell, { ...props })
1193
+ }
1194
+ ],
1195
+ layout
1196
+ };
1197
+ };
1198
+ const ReleaseListCell = ({ id }) => {
1199
+ const releases = useReleasesList(id);
1200
+ const [visible, setVisible] = React.useState(false);
1201
+ const buttonRef = React.useRef(null);
1202
+ const { formatMessage } = useIntl();
1203
+ const handleTogglePopover = () => setVisible((prev) => !prev);
1204
+ return /* @__PURE__ */ jsx(Flex, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(Button, { type: "button", onClick: handleTogglePopover, ref: buttonRef, children: /* @__PURE__ */ jsxs(ActionWrapper, { height: "2rem", width: "2rem", children: [
1205
+ /* @__PURE__ */ jsx(Typography, { style: { maxWidth: "252px", cursor: "pointer" }, textColor: "neutral800", children: releases.length > 0 ? formatMessage(
1206
+ {
1207
+ id: "content-releases.content-manager.list-view.releases-number",
1208
+ defaultMessage: "{number} {number, plural, one {release} other {releases}}"
1209
+ },
1210
+ {
1211
+ number: releases.length
1212
+ }
1213
+ ) : "-" }),
1214
+ /* @__PURE__ */ jsxs(Flex, { children: [
1215
+ releases.length > 0 && /* @__PURE__ */ jsx(SortIcon, {}),
1216
+ visible && /* @__PURE__ */ jsx(
1217
+ Popover,
1218
+ {
1219
+ onDismiss: handleTogglePopover,
1220
+ source: buttonRef,
1221
+ spacing: 16,
1222
+ children: /* @__PURE__ */ jsx("ul", { children: releases.map(({ id: id2, name }) => /* @__PURE__ */ jsx(Box, { padding: 3, as: "li", children: /* @__PURE__ */ jsx(Link, { href: `/admin/plugins/content-releases/${id2}`, isExternal: false, children: name }) }, id2)) })
1223
+ }
1224
+ )
1225
+ ] })
1226
+ ] }) }) });
935
1227
  };
936
1228
  const admin = {
937
1229
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -939,20 +1231,32 @@ const admin = {
939
1231
  app.createHook("ContentReleases/pages/ReleaseDetails/add-locale-in-releases");
940
1232
  if (window.strapi.features.isEnabled("cms-content-releases")) {
941
1233
  app.addMenuLink({
942
- to: `plugins/${pluginId}`,
1234
+ to: `/plugins/${pluginId}`,
943
1235
  icon: PaperPlane,
944
1236
  intlLabel: {
945
1237
  id: `${pluginId}.plugin.name`,
946
1238
  defaultMessage: "Releases"
947
1239
  },
948
- Component: () => import("./App-Do-Rnv0A.mjs").then((mod) => ({ default: mod.App })),
949
- permissions: PERMISSIONS.main,
950
- position: 2
1240
+ async Component() {
1241
+ const { App } = await import("./App-jrh58sXY.mjs");
1242
+ return App;
1243
+ },
1244
+ permissions: PERMISSIONS.main
951
1245
  });
952
- app.getPlugin("content-manager").injectComponent("editView", "right-links", {
1246
+ app.addMiddlewares([() => releaseApi.middleware]);
1247
+ app.addReducers({
1248
+ [releaseApi.reducerPath]: releaseApi.reducer
1249
+ });
1250
+ app.injectContentManagerComponent("editView", "right-links", {
953
1251
  name: `${pluginId}-link`,
954
1252
  Component: CMReleasesContainer
955
1253
  });
1254
+ app.plugins["content-manager"].apis.addBulkAction((actions) => {
1255
+ const deleteActionIndex = actions.findIndex((action) => action.name === "DeleteAction");
1256
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1257
+ return actions;
1258
+ });
1259
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
956
1260
  } else if (!window.strapi.features.isEnabled("cms-content-releases") && window.strapi?.flags?.promoteEE) {
957
1261
  app.addMenuLink({
958
1262
  to: `/plugins/purchase-content-releases`,
@@ -961,20 +1265,19 @@ const admin = {
961
1265
  id: `${pluginId}.plugin.name`,
962
1266
  defaultMessage: "Releases"
963
1267
  },
964
- permissions: [],
965
1268
  async Component() {
966
- const { PurchaseContentReleases } = await import("./PurchaseContentReleases-_MxP6-Dt.mjs");
967
- return { default: PurchaseContentReleases };
1269
+ const { PurchaseContentReleases } = await import("./PurchaseContentReleases-3tRbmbY3.mjs");
1270
+ return PurchaseContentReleases;
968
1271
  },
969
- lockIcon: true,
970
- position: 2
1272
+ lockIcon: true
1273
+ // TODO: to replace with another name in v5
971
1274
  });
972
1275
  }
973
1276
  },
974
1277
  async registerTrads({ locales }) {
975
1278
  const importedTrads = await Promise.all(
976
1279
  locales.map((locale) => {
977
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-B9Ur3VsE.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1280
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-ltT1TlKQ.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
978
1281
  return {
979
1282
  data: prefixPluginTranslations(data, "content-releases"),
980
1283
  locale
@@ -998,13 +1301,15 @@ export {
998
1301
  useUpdateReleaseMutation as c,
999
1302
  useDeleteReleaseMutation as d,
1000
1303
  usePublishReleaseMutation as e,
1001
- useGetReleaseActionsQuery as f,
1304
+ useTypedDispatch as f,
1002
1305
  getTimezoneOffset as g,
1003
- useUpdateReleaseActionMutation as h,
1004
- ReleaseActionMenu as i,
1005
- admin as j,
1306
+ useGetReleaseActionsQuery as h,
1307
+ isAxiosError as i,
1308
+ useUpdateReleaseActionMutation as j,
1309
+ ReleaseActionMenu as k,
1310
+ admin as l,
1006
1311
  pluginId as p,
1007
1312
  releaseApi as r,
1008
1313
  useGetReleasesQuery as u
1009
1314
  };
1010
- //# sourceMappingURL=index-D_pgdqQL.mjs.map
1315
+ //# sourceMappingURL=index-PiOGBETy.mjs.map