@strapi/content-releases 5.9.0 → 5.10.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 (69) hide show
  1. package/dist/admin/chunks/App-B9yCdSLJ.js +1866 -0
  2. package/dist/admin/chunks/App-B9yCdSLJ.js.map +1 -0
  3. package/dist/admin/chunks/App-CuOosufQ.mjs +1845 -0
  4. package/dist/admin/chunks/App-CuOosufQ.mjs.map +1 -0
  5. package/dist/admin/chunks/PurchaseContentReleases-BCME5SQU.js +55 -0
  6. package/dist/admin/chunks/PurchaseContentReleases-BCME5SQU.js.map +1 -0
  7. package/dist/admin/chunks/PurchaseContentReleases-S1ccDSwp.mjs +53 -0
  8. package/dist/admin/chunks/PurchaseContentReleases-S1ccDSwp.mjs.map +1 -0
  9. package/dist/admin/chunks/ReleasesSettingsPage-BzdLEfxa.mjs +206 -0
  10. package/dist/admin/chunks/ReleasesSettingsPage-BzdLEfxa.mjs.map +1 -0
  11. package/dist/admin/chunks/ReleasesSettingsPage-DFVGppsl.js +208 -0
  12. package/dist/admin/chunks/ReleasesSettingsPage-DFVGppsl.js.map +1 -0
  13. package/dist/admin/chunks/en-B2EeDoOz.mjs +101 -0
  14. package/dist/{_chunks/en-D9Q4YW03.mjs.map → admin/chunks/en-B2EeDoOz.mjs.map} +1 -1
  15. package/dist/admin/chunks/en-BzpFfVeO.js +103 -0
  16. package/dist/{_chunks/en-BWPPsSH-.js.map → admin/chunks/en-BzpFfVeO.js.map} +1 -1
  17. package/dist/admin/chunks/index-1nn-zHX-.js +1657 -0
  18. package/dist/admin/chunks/index-1nn-zHX-.js.map +1 -0
  19. package/dist/admin/chunks/index-CmAFGQWf.mjs +1618 -0
  20. package/dist/admin/chunks/index-CmAFGQWf.mjs.map +1 -0
  21. package/dist/admin/chunks/schemas-DMt8h1z-.mjs +43 -0
  22. package/dist/admin/chunks/schemas-DMt8h1z-.mjs.map +1 -0
  23. package/dist/admin/chunks/schemas-DS7NeFDN.js +65 -0
  24. package/dist/admin/chunks/schemas-DS7NeFDN.js.map +1 -0
  25. package/dist/admin/index.js +18 -3
  26. package/dist/admin/index.js.map +1 -1
  27. package/dist/admin/index.mjs +13 -5
  28. package/dist/admin/index.mjs.map +1 -1
  29. package/dist/admin/src/components/ReleaseListCell.d.ts +1 -1
  30. package/dist/server/index.js +2166 -1870
  31. package/dist/server/index.js.map +1 -1
  32. package/dist/server/index.mjs +2156 -1861
  33. package/dist/server/index.mjs.map +1 -1
  34. package/dist/server/src/destroy.d.ts +1 -1
  35. package/dist/server/src/destroy.d.ts.map +1 -1
  36. package/dist/server/src/middlewares/documents.d.ts +1 -1
  37. package/dist/server/src/middlewares/documents.d.ts.map +1 -1
  38. package/dist/server/src/services/scheduling.d.ts +1 -1
  39. package/dist/server/src/services/scheduling.d.ts.map +1 -1
  40. package/dist/server/src/services/validation.d.ts +1 -1
  41. package/dist/server/src/services/validation.d.ts.map +1 -1
  42. package/dist/shared/contracts/release-actions.d.ts +0 -1
  43. package/dist/shared/contracts/releases.d.ts +0 -1
  44. package/dist/shared/contracts/settings.d.ts +1 -2
  45. package/dist/shared/contracts/settings.d.ts.map +1 -1
  46. package/dist/shared/types.d.ts +0 -1
  47. package/package.json +16 -13
  48. package/dist/_chunks/App-CiZCkScI.mjs +0 -1558
  49. package/dist/_chunks/App-CiZCkScI.mjs.map +0 -1
  50. package/dist/_chunks/App-SGjO5UPV.js +0 -1578
  51. package/dist/_chunks/App-SGjO5UPV.js.map +0 -1
  52. package/dist/_chunks/PurchaseContentReleases--qQepXpP.js +0 -52
  53. package/dist/_chunks/PurchaseContentReleases--qQepXpP.js.map +0 -1
  54. package/dist/_chunks/PurchaseContentReleases-D-n-w-st.mjs +0 -52
  55. package/dist/_chunks/PurchaseContentReleases-D-n-w-st.mjs.map +0 -1
  56. package/dist/_chunks/ReleasesSettingsPage-Cto_NLUd.js +0 -178
  57. package/dist/_chunks/ReleasesSettingsPage-Cto_NLUd.js.map +0 -1
  58. package/dist/_chunks/ReleasesSettingsPage-DQT8N3A-.mjs +0 -178
  59. package/dist/_chunks/ReleasesSettingsPage-DQT8N3A-.mjs.map +0 -1
  60. package/dist/_chunks/en-BWPPsSH-.js +0 -102
  61. package/dist/_chunks/en-D9Q4YW03.mjs +0 -102
  62. package/dist/_chunks/index-BjvFfTtA.mjs +0 -1386
  63. package/dist/_chunks/index-BjvFfTtA.mjs.map +0 -1
  64. package/dist/_chunks/index-CyU534vL.js +0 -1404
  65. package/dist/_chunks/index-CyU534vL.js.map +0 -1
  66. package/dist/_chunks/schemas-DBYv9gK8.js +0 -61
  67. package/dist/_chunks/schemas-DBYv9gK8.js.map +0 -1
  68. package/dist/_chunks/schemas-DdA2ic2U.mjs +0 -44
  69. package/dist/_chunks/schemas-DdA2ic2U.mjs.map +0 -1
@@ -0,0 +1,1657 @@
1
+ 'use strict';
2
+
3
+ var icons = require('@strapi/icons');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var React = require('react');
6
+ var strapiAdmin = require('@strapi/admin/strapi-admin');
7
+ var designSystem = require('@strapi/design-system');
8
+ var formik = require('formik');
9
+ var reactIntl = require('react-intl');
10
+ var strapiAdmin$1 = require('@strapi/content-manager/strapi-admin');
11
+ var symbols = require('@strapi/icons/symbols');
12
+ var reactRouterDom = require('react-router-dom');
13
+ var yup = require('yup');
14
+ var styledComponents = require('styled-components');
15
+
16
+ function _interopNamespaceDefault(e) {
17
+ var n = Object.create(null);
18
+ if (e) {
19
+ Object.keys(e).forEach(function (k) {
20
+ if (k !== 'default') {
21
+ var d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: function () { return e[k]; }
25
+ });
26
+ }
27
+ });
28
+ }
29
+ n.default = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
34
+ var yup__namespace = /*#__PURE__*/_interopNamespaceDefault(yup);
35
+
36
+ const PERMISSIONS = {
37
+ main: [
38
+ {
39
+ action: 'plugin::content-releases.read',
40
+ subject: null,
41
+ id: '',
42
+ actionParameters: {},
43
+ properties: {},
44
+ conditions: []
45
+ }
46
+ ],
47
+ create: [
48
+ {
49
+ action: 'plugin::content-releases.create',
50
+ subject: null,
51
+ id: '',
52
+ actionParameters: {},
53
+ properties: {},
54
+ conditions: []
55
+ }
56
+ ],
57
+ update: [
58
+ {
59
+ action: 'plugin::content-releases.update',
60
+ subject: null,
61
+ id: '',
62
+ actionParameters: {},
63
+ properties: {},
64
+ conditions: []
65
+ }
66
+ ],
67
+ delete: [
68
+ {
69
+ action: 'plugin::content-releases.delete',
70
+ subject: null,
71
+ id: '',
72
+ actionParameters: {},
73
+ properties: {},
74
+ conditions: []
75
+ }
76
+ ],
77
+ createAction: [
78
+ {
79
+ action: 'plugin::content-releases.create-action',
80
+ subject: null,
81
+ id: '',
82
+ actionParameters: {},
83
+ properties: {},
84
+ conditions: []
85
+ }
86
+ ],
87
+ deleteAction: [
88
+ {
89
+ action: 'plugin::content-releases.delete-action',
90
+ subject: null,
91
+ id: '',
92
+ actionParameters: {},
93
+ properties: {},
94
+ conditions: []
95
+ }
96
+ ],
97
+ publish: [
98
+ {
99
+ action: 'plugin::content-releases.publish',
100
+ subject: null,
101
+ id: '',
102
+ actionParameters: {},
103
+ properties: {},
104
+ conditions: []
105
+ }
106
+ ]
107
+ };
108
+
109
+ // TODO: move this into the admin code & expose an improved version of enhanceEndpoints or a new function
110
+ const extendInvalidatesTags = (endpoint, extraTags)=>{
111
+ if (!endpoint) {
112
+ return;
113
+ }
114
+ const originalInvalidatesTags = endpoint.invalidatesTags;
115
+ const newInvalidatesTags = (result, err, args, meta)=>{
116
+ const originalTags = typeof originalInvalidatesTags === 'function' ? originalInvalidatesTags(result, err, args, meta) : originalInvalidatesTags;
117
+ return [
118
+ ...originalTags ?? [],
119
+ ...extraTags
120
+ ];
121
+ };
122
+ Object.assign(endpoint, {
123
+ invalidatesTags: newInvalidatesTags
124
+ });
125
+ };
126
+ const releaseApi = strapiAdmin.adminApi.enhanceEndpoints({
127
+ addTagTypes: [
128
+ 'Release',
129
+ 'ReleaseAction',
130
+ 'EntriesInRelease',
131
+ 'ReleaseSettings',
132
+ 'Document'
133
+ ],
134
+ endpoints: {
135
+ updateDocument (endpoint) {
136
+ extendInvalidatesTags(endpoint, [
137
+ {
138
+ type: 'Release',
139
+ id: 'LIST'
140
+ },
141
+ {
142
+ type: 'ReleaseAction',
143
+ id: 'LIST'
144
+ }
145
+ ]);
146
+ },
147
+ deleteDocument (endpoint) {
148
+ extendInvalidatesTags(endpoint, [
149
+ {
150
+ type: 'Release',
151
+ id: 'LIST'
152
+ },
153
+ {
154
+ type: 'ReleaseAction',
155
+ id: 'LIST'
156
+ }
157
+ ]);
158
+ },
159
+ deleteManyDocuments (endpoint) {
160
+ extendInvalidatesTags(endpoint, [
161
+ {
162
+ type: 'Release',
163
+ id: 'LIST'
164
+ },
165
+ {
166
+ type: 'ReleaseAction',
167
+ id: 'LIST'
168
+ }
169
+ ]);
170
+ },
171
+ discardDocument (endpoint) {
172
+ extendInvalidatesTags(endpoint, [
173
+ {
174
+ type: 'Release',
175
+ id: 'LIST'
176
+ },
177
+ {
178
+ type: 'ReleaseAction',
179
+ id: 'LIST'
180
+ }
181
+ ]);
182
+ },
183
+ createWorkflow (endpoint) {
184
+ extendInvalidatesTags(endpoint, [
185
+ {
186
+ type: 'Release',
187
+ id: 'LIST'
188
+ },
189
+ {
190
+ type: 'ReleaseAction',
191
+ id: 'LIST'
192
+ }
193
+ ]);
194
+ },
195
+ updateWorkflow (endpoint) {
196
+ extendInvalidatesTags(endpoint, [
197
+ {
198
+ type: 'Release',
199
+ id: 'LIST'
200
+ },
201
+ {
202
+ type: 'ReleaseAction',
203
+ id: 'LIST'
204
+ }
205
+ ]);
206
+ },
207
+ deleteWorkflow (endpoint) {
208
+ extendInvalidatesTags(endpoint, [
209
+ {
210
+ type: 'Release',
211
+ id: 'LIST'
212
+ },
213
+ {
214
+ type: 'ReleaseAction',
215
+ id: 'LIST'
216
+ }
217
+ ]);
218
+ }
219
+ }
220
+ }).injectEndpoints({
221
+ endpoints: (build)=>{
222
+ return {
223
+ getReleasesForEntry: build.query({
224
+ query (params) {
225
+ return {
226
+ url: '/content-releases/getByDocumentAttached',
227
+ method: 'GET',
228
+ config: {
229
+ params
230
+ }
231
+ };
232
+ },
233
+ providesTags: (result)=>result ? [
234
+ ...result.data.map(({ id })=>({
235
+ type: 'Release',
236
+ id
237
+ })),
238
+ {
239
+ type: 'Release',
240
+ id: 'LIST'
241
+ }
242
+ ] : []
243
+ }),
244
+ getReleases: build.query({
245
+ query ({ page, pageSize, filters } = {
246
+ page: 1,
247
+ pageSize: 16,
248
+ filters: {
249
+ releasedAt: {
250
+ $notNull: false
251
+ }
252
+ }
253
+ }) {
254
+ return {
255
+ url: '/content-releases',
256
+ method: 'GET',
257
+ config: {
258
+ params: {
259
+ page: page || 1,
260
+ pageSize: pageSize || 16,
261
+ filters: filters || {
262
+ releasedAt: {
263
+ $notNull: false
264
+ }
265
+ }
266
+ }
267
+ }
268
+ };
269
+ },
270
+ transformResponse (response, meta, arg) {
271
+ const releasedAtValue = arg?.filters?.releasedAt?.$notNull;
272
+ const isActiveDoneTab = releasedAtValue === 'true';
273
+ const newResponse = {
274
+ ...response,
275
+ meta: {
276
+ ...response.meta,
277
+ activeTab: isActiveDoneTab ? 'done' : 'pending'
278
+ }
279
+ };
280
+ return newResponse;
281
+ },
282
+ providesTags: (result)=>result ? [
283
+ ...result.data.map(({ id })=>({
284
+ type: 'Release',
285
+ id
286
+ })),
287
+ {
288
+ type: 'Release',
289
+ id: 'LIST'
290
+ }
291
+ ] : [
292
+ {
293
+ type: 'Release',
294
+ id: 'LIST'
295
+ }
296
+ ]
297
+ }),
298
+ getRelease: build.query({
299
+ query ({ id }) {
300
+ return {
301
+ url: `/content-releases/${id}`,
302
+ method: 'GET'
303
+ };
304
+ },
305
+ providesTags: (result, error, arg)=>[
306
+ {
307
+ type: 'Release',
308
+ id: 'LIST'
309
+ },
310
+ {
311
+ type: 'Release',
312
+ id: arg.id
313
+ }
314
+ ]
315
+ }),
316
+ getReleaseActions: build.query({
317
+ query ({ releaseId, ...params }) {
318
+ return {
319
+ url: `/content-releases/${releaseId}/actions`,
320
+ method: 'GET',
321
+ config: {
322
+ params
323
+ }
324
+ };
325
+ },
326
+ providesTags: [
327
+ {
328
+ type: 'ReleaseAction',
329
+ id: 'LIST'
330
+ }
331
+ ]
332
+ }),
333
+ createRelease: build.mutation({
334
+ query (data) {
335
+ return {
336
+ url: '/content-releases',
337
+ method: 'POST',
338
+ data
339
+ };
340
+ },
341
+ invalidatesTags: [
342
+ {
343
+ type: 'Release',
344
+ id: 'LIST'
345
+ }
346
+ ]
347
+ }),
348
+ updateRelease: build.mutation({
349
+ query ({ id, ...data }) {
350
+ return {
351
+ url: `/content-releases/${id}`,
352
+ method: 'PUT',
353
+ data
354
+ };
355
+ },
356
+ invalidatesTags: (result, error, arg)=>[
357
+ {
358
+ type: 'Release',
359
+ id: arg.id
360
+ }
361
+ ]
362
+ }),
363
+ createReleaseAction: build.mutation({
364
+ query ({ body, params }) {
365
+ return {
366
+ url: `/content-releases/${params.releaseId}/actions`,
367
+ method: 'POST',
368
+ data: body
369
+ };
370
+ },
371
+ invalidatesTags: [
372
+ {
373
+ type: 'Release',
374
+ id: 'LIST'
375
+ },
376
+ {
377
+ type: 'ReleaseAction',
378
+ id: 'LIST'
379
+ }
380
+ ]
381
+ }),
382
+ createManyReleaseActions: build.mutation({
383
+ query ({ body, params }) {
384
+ return {
385
+ url: `/content-releases/${params.releaseId}/actions/bulk`,
386
+ method: 'POST',
387
+ data: body
388
+ };
389
+ },
390
+ invalidatesTags: [
391
+ {
392
+ type: 'Release',
393
+ id: 'LIST'
394
+ },
395
+ {
396
+ type: 'ReleaseAction',
397
+ id: 'LIST'
398
+ },
399
+ {
400
+ type: 'EntriesInRelease'
401
+ }
402
+ ]
403
+ }),
404
+ updateReleaseAction: build.mutation({
405
+ query ({ body, params }) {
406
+ return {
407
+ url: `/content-releases/${params.releaseId}/actions/${params.actionId}`,
408
+ method: 'PUT',
409
+ data: body
410
+ };
411
+ },
412
+ invalidatesTags: (res, error, arg)=>[
413
+ {
414
+ type: 'ReleaseAction',
415
+ id: 'LIST'
416
+ },
417
+ {
418
+ type: 'Release',
419
+ id: 'LIST'
420
+ },
421
+ {
422
+ type: 'Release',
423
+ id: arg.params.releaseId
424
+ }
425
+ ],
426
+ async onQueryStarted ({ body, params, query, actionPath }, { dispatch, queryFulfilled }) {
427
+ // We need to mimic the same params received by the getReleaseActions query
428
+ const paramsWithoutActionId = {
429
+ releaseId: params.releaseId,
430
+ ...query
431
+ };
432
+ const patchResult = dispatch(releaseApi.util.updateQueryData('getReleaseActions', paramsWithoutActionId, (draft)=>{
433
+ const [key, index] = actionPath;
434
+ const action = draft.data[key][index];
435
+ if (action) {
436
+ action.type = body.type;
437
+ }
438
+ }));
439
+ try {
440
+ await queryFulfilled;
441
+ } catch {
442
+ patchResult.undo();
443
+ }
444
+ }
445
+ }),
446
+ deleteReleaseAction: build.mutation({
447
+ query ({ params }) {
448
+ return {
449
+ url: `/content-releases/${params.releaseId}/actions/${params.actionId}`,
450
+ method: 'DELETE'
451
+ };
452
+ },
453
+ invalidatesTags: (result, error, arg)=>[
454
+ {
455
+ type: 'Release',
456
+ id: 'LIST'
457
+ },
458
+ {
459
+ type: 'Release',
460
+ id: arg.params.releaseId
461
+ },
462
+ {
463
+ type: 'ReleaseAction',
464
+ id: 'LIST'
465
+ },
466
+ {
467
+ type: 'EntriesInRelease'
468
+ }
469
+ ]
470
+ }),
471
+ publishRelease: build.mutation({
472
+ query ({ id }) {
473
+ return {
474
+ url: `/content-releases/${id}/publish`,
475
+ method: 'POST'
476
+ };
477
+ },
478
+ invalidatesTags: (result, error, arg)=>[
479
+ {
480
+ type: 'Release',
481
+ id: arg.id
482
+ },
483
+ {
484
+ type: 'Document',
485
+ id: `ALL_LIST`
486
+ }
487
+ ]
488
+ }),
489
+ deleteRelease: build.mutation({
490
+ query ({ id }) {
491
+ return {
492
+ url: `/content-releases/${id}`,
493
+ method: 'DELETE'
494
+ };
495
+ },
496
+ invalidatesTags: ()=>[
497
+ {
498
+ type: 'Release',
499
+ id: 'LIST'
500
+ },
501
+ {
502
+ type: 'EntriesInRelease'
503
+ }
504
+ ]
505
+ }),
506
+ getMappedEntriesInReleases: build.query({
507
+ query (params) {
508
+ return {
509
+ url: '/content-releases/mapEntriesToReleases',
510
+ method: 'GET',
511
+ config: {
512
+ params
513
+ }
514
+ };
515
+ },
516
+ transformResponse (response) {
517
+ return response.data;
518
+ },
519
+ providesTags: [
520
+ {
521
+ type: 'EntriesInRelease'
522
+ }
523
+ ]
524
+ }),
525
+ getReleaseSettings: build.query({
526
+ query: ()=>'/content-releases/settings',
527
+ providesTags: [
528
+ {
529
+ type: 'ReleaseSettings'
530
+ }
531
+ ]
532
+ }),
533
+ updateReleaseSettings: build.mutation({
534
+ query (data) {
535
+ return {
536
+ url: '/content-releases/settings',
537
+ method: 'PUT',
538
+ data
539
+ };
540
+ },
541
+ invalidatesTags: [
542
+ {
543
+ type: 'ReleaseSettings'
544
+ }
545
+ ]
546
+ })
547
+ };
548
+ }
549
+ });
550
+ const { useGetReleasesQuery, useGetReleasesForEntryQuery, useGetReleaseQuery, useGetReleaseActionsQuery, useCreateReleaseMutation, useCreateReleaseActionMutation, useCreateManyReleaseActionsMutation, useUpdateReleaseMutation, useUpdateReleaseActionMutation, usePublishReleaseMutation, useDeleteReleaseActionMutation, useDeleteReleaseMutation, useGetMappedEntriesInReleasesQuery, useGetReleaseSettingsQuery, useUpdateReleaseSettingsMutation } = releaseApi;
551
+
552
+ const getBorderLeftRadiusValue = (actionType)=>{
553
+ return actionType === 'publish' ? 1 : 0;
554
+ };
555
+ const getBorderRightRadiusValue = (actionType)=>{
556
+ return actionType === 'publish' ? 0 : 1;
557
+ };
558
+ const FieldWrapper = styledComponents.styled(designSystem.Field.Root)`
559
+ border-top-left-radius: ${({ $actionType, theme })=>theme.spaces[getBorderLeftRadiusValue($actionType)]};
560
+ border-bottom-left-radius: ${({ $actionType, theme })=>theme.spaces[getBorderLeftRadiusValue($actionType)]};
561
+ border-top-right-radius: ${({ $actionType, theme })=>theme.spaces[getBorderRightRadiusValue($actionType)]};
562
+ border-bottom-right-radius: ${({ $actionType, theme })=>theme.spaces[getBorderRightRadiusValue($actionType)]};
563
+
564
+ > label {
565
+ color: inherit;
566
+ padding: ${({ theme })=>`${theme.spaces[2]} ${theme.spaces[3]}`};
567
+ text-align: center;
568
+ vertical-align: middle;
569
+ text-transform: capitalize;
570
+ }
571
+
572
+ &[data-checked='true'] {
573
+ color: ${({ theme, $actionType })=>$actionType === 'publish' ? theme.colors.primary700 : theme.colors.danger600};
574
+ background-color: ${({ theme, $actionType })=>$actionType === 'publish' ? theme.colors.primary100 : theme.colors.danger100};
575
+ border-color: ${({ theme, $actionType })=>$actionType === 'publish' ? theme.colors.primary700 : theme.colors.danger600};
576
+ }
577
+
578
+ &[data-checked='false'] {
579
+ border-left: ${({ $actionType })=>$actionType === 'unpublish' && 'none'};
580
+ border-right: ${({ $actionType })=>$actionType === 'publish' && 'none'};
581
+ }
582
+
583
+ &[data-checked='false'][data-disabled='false']:hover {
584
+ color: ${({ theme })=>theme.colors.neutral700};
585
+ background-color: ${({ theme })=>theme.colors.neutral100};
586
+ border-color: ${({ theme })=>theme.colors.neutral200};
587
+
588
+ & > label {
589
+ cursor: pointer;
590
+ }
591
+ }
592
+
593
+ &[data-disabled='true'] {
594
+ color: ${({ theme })=>theme.colors.neutral600};
595
+ background-color: ${({ theme })=>theme.colors.neutral150};
596
+ border-color: ${({ theme })=>theme.colors.neutral300};
597
+ }
598
+ `;
599
+ const ActionOption = ({ selected, actionType, handleChange, name, disabled = false })=>{
600
+ return /*#__PURE__*/ jsxRuntime.jsx(FieldWrapper, {
601
+ $actionType: actionType,
602
+ background: "primary0",
603
+ borderColor: "neutral200",
604
+ color: selected === actionType ? 'primary600' : 'neutral600',
605
+ position: "relative",
606
+ cursor: "pointer",
607
+ "data-checked": selected === actionType,
608
+ "data-disabled": disabled && selected !== actionType,
609
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Label, {
610
+ children: [
611
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.VisuallyHidden, {
612
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Input, {
613
+ type: "radio",
614
+ name: name,
615
+ checked: selected === actionType,
616
+ onChange: handleChange,
617
+ value: actionType,
618
+ disabled: disabled
619
+ })
620
+ }),
621
+ actionType
622
+ ]
623
+ })
624
+ });
625
+ };
626
+ const ReleaseActionOptions = ({ selected, handleChange, name, disabled = false })=>{
627
+ return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
628
+ children: [
629
+ /*#__PURE__*/ jsxRuntime.jsx(ActionOption, {
630
+ actionType: "publish",
631
+ selected: selected,
632
+ handleChange: handleChange,
633
+ name: name,
634
+ disabled: disabled
635
+ }),
636
+ /*#__PURE__*/ jsxRuntime.jsx(ActionOption, {
637
+ actionType: "unpublish",
638
+ selected: selected,
639
+ handleChange: handleChange,
640
+ name: name,
641
+ disabled: disabled
642
+ })
643
+ ]
644
+ });
645
+ };
646
+
647
+ /* -------------------------------------------------------------------------------------------------
648
+ * AddActionToReleaseModal
649
+ * -----------------------------------------------------------------------------------------------*/ const RELEASE_ACTION_FORM_SCHEMA = yup__namespace.object().shape({
650
+ type: yup__namespace.string().oneOf([
651
+ 'publish',
652
+ 'unpublish'
653
+ ]).required(),
654
+ releaseId: yup__namespace.string().required()
655
+ });
656
+ const INITIAL_VALUES = {
657
+ type: 'publish',
658
+ releaseId: ''
659
+ };
660
+ const NoReleases = ()=>{
661
+ const { formatMessage } = reactIntl.useIntl();
662
+ return /*#__PURE__*/ jsxRuntime.jsx(designSystem.EmptyStateLayout, {
663
+ icon: /*#__PURE__*/ jsxRuntime.jsx(symbols.EmptyDocuments, {
664
+ width: "16rem"
665
+ }),
666
+ content: formatMessage({
667
+ id: 'content-releases.content-manager-edit-view.add-to-release.no-releases-message',
668
+ defaultMessage: 'No available releases. Open the list of releases and create a new one from there.'
669
+ }),
670
+ action: /*#__PURE__*/ jsxRuntime.jsx(designSystem.LinkButton, {
671
+ to: {
672
+ pathname: '/plugins/content-releases'
673
+ },
674
+ tag: reactRouterDom.Link,
675
+ variant: "secondary",
676
+ children: formatMessage({
677
+ id: 'content-releases.content-manager-edit-view.add-to-release.redirect-button',
678
+ defaultMessage: 'Open the list of releases'
679
+ })
680
+ }),
681
+ shadow: "none"
682
+ });
683
+ };
684
+ const AddActionToReleaseModal = ({ contentType, documentId, onInputChange, values })=>{
685
+ const { formatMessage } = reactIntl.useIntl();
686
+ const [{ query }] = strapiAdmin.useQueryParams();
687
+ const locale = query.plugins?.i18n?.locale;
688
+ // Get all 'pending' releases that do not have the entry attached
689
+ const response = useGetReleasesForEntryQuery({
690
+ contentType,
691
+ entryDocumentId: documentId,
692
+ hasEntryAttached: false,
693
+ locale
694
+ });
695
+ const releases = response.data?.data;
696
+ if (releases?.length === 0) {
697
+ return /*#__PURE__*/ jsxRuntime.jsx(NoReleases, {});
698
+ }
699
+ return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
700
+ direction: "column",
701
+ alignItems: "stretch",
702
+ gap: 2,
703
+ children: [
704
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
705
+ paddingBottom: 6,
706
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
707
+ required: true,
708
+ children: [
709
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
710
+ children: formatMessage({
711
+ id: 'content-releases.content-manager-edit-view.add-to-release.select-label',
712
+ defaultMessage: 'Select a release'
713
+ })
714
+ }),
715
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelect, {
716
+ required: true,
717
+ placeholder: formatMessage({
718
+ id: 'content-releases.content-manager-edit-view.add-to-release.select-placeholder',
719
+ defaultMessage: 'Select'
720
+ }),
721
+ name: "releaseId",
722
+ onChange: (value)=>onInputChange('releaseId', value),
723
+ value: values.releaseId,
724
+ children: releases?.map((release)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
725
+ value: release.id,
726
+ children: release.name
727
+ }, release.id))
728
+ })
729
+ ]
730
+ })
731
+ }),
732
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
733
+ children: formatMessage({
734
+ id: 'content-releases.content-manager-edit-view.add-to-release.action-type-label',
735
+ defaultMessage: 'What do you want to do with this entry?'
736
+ })
737
+ }),
738
+ /*#__PURE__*/ jsxRuntime.jsx(ReleaseActionOptions, {
739
+ selected: values.type,
740
+ handleChange: (e)=>onInputChange('type', e.target.value),
741
+ name: "type"
742
+ })
743
+ ]
744
+ });
745
+ };
746
+ /* -------------------------------------------------------------------------------------------------
747
+ * ReleaseActionModalForm
748
+ * -----------------------------------------------------------------------------------------------*/ const ReleaseActionModalForm = ({ documentId, document, model, collectionType })=>{
749
+ const { formatMessage } = reactIntl.useIntl();
750
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
751
+ const { canCreateAction } = allowedActions;
752
+ const [createReleaseAction, { isLoading }] = useCreateReleaseActionMutation();
753
+ const { toggleNotification } = strapiAdmin.useNotification();
754
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
755
+ const [{ query }] = strapiAdmin.useQueryParams();
756
+ const locale = query.plugins?.i18n?.locale;
757
+ const handleSubmit = async (e, onClose)=>{
758
+ try {
759
+ await formik$1.handleSubmit(e);
760
+ onClose();
761
+ } catch (error) {
762
+ if (strapiAdmin.isFetchError(error)) {
763
+ // Handle axios error
764
+ toggleNotification({
765
+ type: 'danger',
766
+ message: formatAPIError(error)
767
+ });
768
+ } else {
769
+ // Handle generic error
770
+ toggleNotification({
771
+ type: 'danger',
772
+ message: formatMessage({
773
+ id: 'notification.error',
774
+ defaultMessage: 'An error occurred'
775
+ })
776
+ });
777
+ }
778
+ }
779
+ };
780
+ const formik$1 = formik.useFormik({
781
+ initialValues: INITIAL_VALUES,
782
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
783
+ onSubmit: async (values)=>{
784
+ if (collectionType === 'collection-types' && !documentId) {
785
+ throw new Error('Document id is required');
786
+ }
787
+ const response = await createReleaseAction({
788
+ body: {
789
+ type: values.type,
790
+ contentType: model,
791
+ entryDocumentId: documentId,
792
+ locale
793
+ },
794
+ params: {
795
+ releaseId: values.releaseId
796
+ }
797
+ });
798
+ if ('data' in response) {
799
+ // Handle success
800
+ toggleNotification({
801
+ type: 'success',
802
+ message: formatMessage({
803
+ id: 'content-releases.content-manager-edit-view.add-to-release.notification.success',
804
+ defaultMessage: 'Entry added to release'
805
+ })
806
+ });
807
+ return;
808
+ }
809
+ if ('error' in response) {
810
+ throw response.error;
811
+ }
812
+ }
813
+ });
814
+ const { edit: { options } } = strapiAdmin$1.unstable_useDocumentLayout(model);
815
+ // Project is not EE or contentType does not have draftAndPublish enabled
816
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canCreateAction) {
817
+ return null;
818
+ }
819
+ if (collectionType === 'collection-types' && (!documentId || documentId === 'create')) {
820
+ return null;
821
+ }
822
+ return {
823
+ label: formatMessage({
824
+ id: 'content-releases.content-manager-edit-view.add-to-release',
825
+ defaultMessage: 'Add to release'
826
+ }),
827
+ icon: /*#__PURE__*/ jsxRuntime.jsx(icons.PaperPlane, {}),
828
+ // Entry is creating so we don't want to allow adding it to a release
829
+ disabled: !document,
830
+ position: [
831
+ 'panel',
832
+ 'table-row'
833
+ ],
834
+ dialog: {
835
+ type: 'modal',
836
+ title: formatMessage({
837
+ id: 'content-releases.content-manager-edit-view.add-to-release',
838
+ defaultMessage: 'Add to release'
839
+ }),
840
+ content: /*#__PURE__*/ jsxRuntime.jsx(AddActionToReleaseModal, {
841
+ contentType: model,
842
+ documentId: documentId,
843
+ onInputChange: formik$1.setFieldValue,
844
+ values: formik$1.values
845
+ }),
846
+ footer: ({ onClose })=>/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Modal.Footer, {
847
+ children: [
848
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
849
+ onClick: onClose,
850
+ variant: "tertiary",
851
+ name: "cancel",
852
+ children: formatMessage({
853
+ id: 'content-releases.content-manager-edit-view.add-to-release.cancel-button',
854
+ defaultMessage: 'Cancel'
855
+ })
856
+ }),
857
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
858
+ type: "submit",
859
+ // @ts-expect-error - formik ReactEvent types don't match button onClick types as they expect a MouseEvent
860
+ onClick: (e)=>handleSubmit(e, onClose),
861
+ disabled: !formik$1.values.releaseId,
862
+ loading: isLoading,
863
+ children: formatMessage({
864
+ id: 'content-releases.content-manager-edit-view.add-to-release.continue-button',
865
+ defaultMessage: 'Continue'
866
+ })
867
+ })
868
+ ]
869
+ })
870
+ }
871
+ };
872
+ };
873
+
874
+ const getContentPermissions = (subject)=>{
875
+ const permissions = {
876
+ publish: [
877
+ {
878
+ action: 'plugin::content-manager.explorer.publish',
879
+ subject,
880
+ id: '',
881
+ actionParameters: {},
882
+ properties: {},
883
+ conditions: []
884
+ }
885
+ ]
886
+ };
887
+ return permissions;
888
+ };
889
+ const ReleaseAction = ({ documents, model })=>{
890
+ const { formatMessage } = reactIntl.useIntl();
891
+ const { toggleNotification } = strapiAdmin.useNotification();
892
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
893
+ const [{ query }] = strapiAdmin.useQueryParams();
894
+ const contentPermissions = getContentPermissions(model);
895
+ const { allowedActions: { canPublish } } = strapiAdmin.useRBAC(contentPermissions);
896
+ const { allowedActions: { canCreate } } = strapiAdmin.useRBAC(PERMISSIONS);
897
+ // Get all the releases not published
898
+ const response = useGetReleasesQuery();
899
+ const releases = response.data?.data;
900
+ const [createManyReleaseActions, { isLoading }] = useCreateManyReleaseActionsMutation();
901
+ const documentIds = documents.map((doc)=>doc.documentId);
902
+ const handleSubmit = async (values)=>{
903
+ const locale = query.plugins?.i18n?.locale;
904
+ const releaseActionEntries = documentIds.map((entryDocumentId)=>({
905
+ type: values.type,
906
+ contentType: model,
907
+ entryDocumentId,
908
+ locale
909
+ }));
910
+ const response = await createManyReleaseActions({
911
+ body: releaseActionEntries,
912
+ params: {
913
+ releaseId: values.releaseId
914
+ }
915
+ });
916
+ if ('data' in response) {
917
+ // Handle success
918
+ const notificationMessage = formatMessage({
919
+ id: 'content-releases.content-manager-list-view.add-to-release.notification.success.message',
920
+ defaultMessage: '{entriesAlreadyInRelease} out of {totalEntries} entries were already in the release.'
921
+ }, {
922
+ entriesAlreadyInRelease: response.data.meta.entriesAlreadyInRelease,
923
+ totalEntries: response.data.meta.totalEntries
924
+ });
925
+ const notification = {
926
+ type: 'success',
927
+ title: formatMessage({
928
+ id: 'content-releases.content-manager-list-view.add-to-release.notification.success.title',
929
+ defaultMessage: 'Successfully added to release.'
930
+ }, {
931
+ entriesAlreadyInRelease: response.data.meta.entriesAlreadyInRelease,
932
+ totalEntries: response.data.meta.totalEntries
933
+ }),
934
+ message: response.data.meta.entriesAlreadyInRelease ? notificationMessage : ''
935
+ };
936
+ toggleNotification(notification);
937
+ return true;
938
+ }
939
+ if ('error' in response) {
940
+ if (strapiAdmin.isFetchError(response.error)) {
941
+ // Handle fetch error
942
+ toggleNotification({
943
+ type: 'warning',
944
+ message: formatAPIError(response.error)
945
+ });
946
+ } else {
947
+ // Handle generic error
948
+ toggleNotification({
949
+ type: 'warning',
950
+ message: formatMessage({
951
+ id: 'notification.error',
952
+ defaultMessage: 'An error occurred'
953
+ })
954
+ });
955
+ }
956
+ }
957
+ };
958
+ if (!canCreate || !canPublish) return null;
959
+ return {
960
+ actionType: 'release',
961
+ variant: 'tertiary',
962
+ label: formatMessage({
963
+ id: 'content-manager-list-view.add-to-release',
964
+ defaultMessage: 'Add to Release'
965
+ }),
966
+ dialog: {
967
+ type: 'modal',
968
+ title: formatMessage({
969
+ id: 'content-manager-list-view.add-to-release',
970
+ defaultMessage: 'Add to Release'
971
+ }),
972
+ content: ({ onClose })=>{
973
+ return /*#__PURE__*/ jsxRuntime.jsx(formik.Formik, {
974
+ onSubmit: async (values)=>{
975
+ const data = await handleSubmit(values);
976
+ if (data) {
977
+ return onClose();
978
+ }
979
+ },
980
+ validationSchema: RELEASE_ACTION_FORM_SCHEMA,
981
+ initialValues: INITIAL_VALUES,
982
+ children: ({ values, setFieldValue })=>/*#__PURE__*/ jsxRuntime.jsxs(formik.Form, {
983
+ children: [
984
+ releases?.length === 0 ? /*#__PURE__*/ jsxRuntime.jsx(NoReleases, {}) : /*#__PURE__*/ jsxRuntime.jsx(designSystem.Modal.Body, {
985
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
986
+ direction: "column",
987
+ alignItems: "stretch",
988
+ gap: 2,
989
+ children: [
990
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
991
+ paddingBottom: 6,
992
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Field.Root, {
993
+ required: true,
994
+ children: [
995
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
996
+ children: formatMessage({
997
+ id: 'content-releases.content-manager-list-view.add-to-release.select-label',
998
+ defaultMessage: 'Select a release'
999
+ })
1000
+ }),
1001
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelect, {
1002
+ placeholder: formatMessage({
1003
+ id: 'content-releases.content-manager-list-view.add-to-release.select-placeholder',
1004
+ defaultMessage: 'Select'
1005
+ }),
1006
+ onChange: (value)=>setFieldValue('releaseId', value),
1007
+ value: values.releaseId,
1008
+ children: releases?.map((release)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
1009
+ value: release.id,
1010
+ children: release.name
1011
+ }, release.id))
1012
+ })
1013
+ ]
1014
+ })
1015
+ }),
1016
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Field.Label, {
1017
+ children: formatMessage({
1018
+ id: 'content-releases.content-manager-list-view.add-to-release.action-type-label',
1019
+ defaultMessage: 'What do you want to do with these entries?'
1020
+ })
1021
+ }),
1022
+ /*#__PURE__*/ jsxRuntime.jsx(ReleaseActionOptions, {
1023
+ selected: values.type,
1024
+ handleChange: (e)=>setFieldValue('type', e.target.value),
1025
+ name: "type"
1026
+ })
1027
+ ]
1028
+ })
1029
+ }),
1030
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Modal.Footer, {
1031
+ children: [
1032
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
1033
+ onClick: onClose,
1034
+ variant: "tertiary",
1035
+ name: "cancel",
1036
+ children: formatMessage({
1037
+ id: 'content-releases.content-manager-list-view.add-to-release.cancel-button',
1038
+ defaultMessage: 'Cancel'
1039
+ })
1040
+ }),
1041
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
1042
+ type: "submit",
1043
+ disabled: !values.releaseId,
1044
+ loading: isLoading,
1045
+ children: formatMessage({
1046
+ id: 'content-releases.content-manager-list-view.add-to-release.continue-button',
1047
+ defaultMessage: 'Continue'
1048
+ })
1049
+ })
1050
+ ]
1051
+ })
1052
+ ]
1053
+ })
1054
+ });
1055
+ }
1056
+ }
1057
+ };
1058
+ };
1059
+
1060
+ const useReleasesList = (contentTypeUid, documentId)=>{
1061
+ const listViewData = strapiAdmin.useTable('ListView', (state)=>state.rows);
1062
+ const documentIds = listViewData.map((entry)=>entry.documentId);
1063
+ const [{ query }] = strapiAdmin.useQueryParams();
1064
+ const locale = query?.plugins?.i18n?.locale || undefined;
1065
+ const response = useGetMappedEntriesInReleasesQuery({
1066
+ contentTypeUid,
1067
+ documentIds,
1068
+ locale
1069
+ }, {
1070
+ skip: !documentIds || !contentTypeUid || documentIds.length === 0
1071
+ });
1072
+ const mappedEntriesInReleases = response.data || {};
1073
+ return mappedEntriesInReleases?.[documentId] || [];
1074
+ };
1075
+ const addColumnToTableHook = ({ displayedHeaders, layout })=>{
1076
+ const { options } = layout;
1077
+ if (!options?.draftAndPublish) {
1078
+ return {
1079
+ displayedHeaders,
1080
+ layout
1081
+ };
1082
+ }
1083
+ return {
1084
+ displayedHeaders: [
1085
+ ...displayedHeaders,
1086
+ {
1087
+ searchable: false,
1088
+ sortable: false,
1089
+ name: 'releases',
1090
+ label: {
1091
+ id: 'content-releases.content-manager.list-view.releases.header',
1092
+ defaultMessage: 'To be released in'
1093
+ },
1094
+ cellFormatter: (props, _, { model })=>/*#__PURE__*/ jsxRuntime.jsx(ReleaseListCell, {
1095
+ ...props,
1096
+ model: model
1097
+ })
1098
+ }
1099
+ ],
1100
+ layout
1101
+ };
1102
+ };
1103
+ const ReleaseListCell = ({ documentId, model })=>{
1104
+ const releases = useReleasesList(model, documentId);
1105
+ const { formatMessage } = reactIntl.useIntl();
1106
+ return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Popover.Root, {
1107
+ children: [
1108
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Popover.Trigger, {
1109
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
1110
+ variant: "ghost",
1111
+ onClick: (e)=>e.stopPropagation(),
1112
+ // TODO: find a way in the DS to define the widht and height of the icon
1113
+ endIcon: releases.length > 0 ? /*#__PURE__*/ jsxRuntime.jsx(icons.CaretDown, {
1114
+ width: "1.2rem",
1115
+ height: "1.2rem"
1116
+ }) : null,
1117
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1118
+ style: {
1119
+ maxWidth: '252px',
1120
+ cursor: 'pointer'
1121
+ },
1122
+ textColor: "neutral800",
1123
+ fontWeight: "regular",
1124
+ children: releases.length > 0 ? formatMessage({
1125
+ id: 'content-releases.content-manager.list-view.releases-number',
1126
+ defaultMessage: '{number} {number, plural, one {release} other {releases}}'
1127
+ }, {
1128
+ number: releases.length
1129
+ }) : '-'
1130
+ })
1131
+ })
1132
+ }),
1133
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Popover.Content, {
1134
+ children: /*#__PURE__*/ jsxRuntime.jsx("ul", {
1135
+ children: releases.map(({ id, name })=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
1136
+ padding: 3,
1137
+ tag: "li",
1138
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Link, {
1139
+ href: `/admin/plugins/content-releases/${id}`,
1140
+ isExternal: false,
1141
+ children: name
1142
+ })
1143
+ }, id))
1144
+ })
1145
+ })
1146
+ ]
1147
+ });
1148
+ };
1149
+
1150
+ const getTimezoneOffset = (timezone, date)=>{
1151
+ try {
1152
+ const offsetPart = new Intl.DateTimeFormat('en', {
1153
+ timeZone: timezone,
1154
+ timeZoneName: 'longOffset'
1155
+ }).formatToParts(date).find((part)=>part.type === 'timeZoneName');
1156
+ const offset = offsetPart ? offsetPart.value : '';
1157
+ // We want to show time based on UTC, not GMT so we swap that.
1158
+ let utcOffset = offset.replace('GMT', 'UTC');
1159
+ // For perfect UTC (UTC+0:00) we only get the string UTC, So we need to append the 0's.
1160
+ if (!utcOffset.includes('+') && !utcOffset.includes('-')) {
1161
+ utcOffset = `${utcOffset}+00:00`;
1162
+ }
1163
+ return utcOffset;
1164
+ } catch (error) {
1165
+ // When timezone is invalid we catch the error and return empty to don't break the app
1166
+ return '';
1167
+ }
1168
+ };
1169
+ const getTimezones = (selectedDate)=>{
1170
+ const timezoneList = Intl.supportedValuesOf('timeZone').map((timezone)=>{
1171
+ // Timezone will be in the format GMT${OFFSET} where offset could be nothing,
1172
+ // a four digit string e.g. +05:00 or -08:00
1173
+ const utcOffset = getTimezoneOffset(timezone, selectedDate);
1174
+ // Offset and timezone are concatenated with '&', so to split and save the required timezone in DB
1175
+ return {
1176
+ offset: utcOffset,
1177
+ value: `${utcOffset}&${timezone}`
1178
+ };
1179
+ });
1180
+ const systemTimezone = timezoneList.find((timezone)=>timezone.value.split('&')[1] === Intl.DateTimeFormat().resolvedOptions().timeZone);
1181
+ return {
1182
+ timezoneList,
1183
+ systemTimezone
1184
+ };
1185
+ };
1186
+
1187
+ const StyledMenuItem = styledComponents.styled(designSystem.Menu.Item)`
1188
+ &:hover {
1189
+ background: ${({ theme, $variant = 'neutral' })=>theme.colors[`${$variant}100`]};
1190
+
1191
+ svg {
1192
+ fill: ${({ theme, $variant = 'neutral' })=>theme.colors[`${$variant}600`]};
1193
+ }
1194
+
1195
+ a {
1196
+ color: ${({ theme })=>theme.colors.neutral800};
1197
+ }
1198
+ }
1199
+
1200
+ svg {
1201
+ color: ${({ theme, $variant = 'neutral' })=>theme.colors[`${$variant}500`]};
1202
+ }
1203
+
1204
+ span {
1205
+ color: ${({ theme, $variant = 'neutral' })=>theme.colors[`${$variant}800`]};
1206
+ }
1207
+
1208
+ span,
1209
+ a {
1210
+ width: 100%;
1211
+ }
1212
+ `;
1213
+ const DeleteReleaseActionItem = ({ releaseId, actionId })=>{
1214
+ const { formatMessage } = reactIntl.useIntl();
1215
+ const { toggleNotification } = strapiAdmin.useNotification();
1216
+ const { formatAPIError } = strapiAdmin.useAPIErrorHandler();
1217
+ const [deleteReleaseAction] = useDeleteReleaseActionMutation();
1218
+ const { allowedActions: { canDeleteAction } } = strapiAdmin.useRBAC(PERMISSIONS);
1219
+ const handleDeleteAction = async ()=>{
1220
+ const response = await deleteReleaseAction({
1221
+ params: {
1222
+ releaseId,
1223
+ actionId
1224
+ }
1225
+ });
1226
+ if ('data' in response) {
1227
+ // Handle success
1228
+ toggleNotification({
1229
+ type: 'success',
1230
+ message: formatMessage({
1231
+ id: 'content-releases.content-manager-edit-view.remove-from-release.notification.success',
1232
+ defaultMessage: 'Entry removed from release'
1233
+ })
1234
+ });
1235
+ return;
1236
+ }
1237
+ if ('error' in response) {
1238
+ if (strapiAdmin.isFetchError(response.error)) {
1239
+ // Handle fetch error
1240
+ toggleNotification({
1241
+ type: 'danger',
1242
+ message: formatAPIError(response.error)
1243
+ });
1244
+ } else {
1245
+ // Handle generic error
1246
+ toggleNotification({
1247
+ type: 'danger',
1248
+ message: formatMessage({
1249
+ id: 'notification.error',
1250
+ defaultMessage: 'An error occurred'
1251
+ })
1252
+ });
1253
+ }
1254
+ }
1255
+ };
1256
+ if (!canDeleteAction) {
1257
+ return null;
1258
+ }
1259
+ return /*#__PURE__*/ jsxRuntime.jsx(StyledMenuItem, {
1260
+ $variant: "danger",
1261
+ onSelect: handleDeleteAction,
1262
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
1263
+ gap: 2,
1264
+ children: [
1265
+ /*#__PURE__*/ jsxRuntime.jsx(icons.Cross, {
1266
+ width: "1.6rem",
1267
+ height: "1.6rem"
1268
+ }),
1269
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1270
+ textColor: "danger600",
1271
+ variant: "omega",
1272
+ children: formatMessage({
1273
+ id: 'content-releases.content-manager-edit-view.remove-from-release',
1274
+ defaultMessage: 'Remove from release'
1275
+ })
1276
+ })
1277
+ ]
1278
+ })
1279
+ });
1280
+ };
1281
+ const ReleaseActionEntryLinkItem = ({ contentTypeUid, documentId, locale })=>{
1282
+ const { formatMessage } = reactIntl.useIntl();
1283
+ const userPermissions = strapiAdmin.useAuth('ReleaseActionEntryLinkItem', (state)=>state.permissions);
1284
+ // Confirm user has permissions to access the entry for the given locale
1285
+ const canUpdateEntryForLocale = React__namespace.useMemo(()=>{
1286
+ const updatePermissions = userPermissions.find((permission)=>permission.subject === contentTypeUid && permission.action === 'plugin::content-manager.explorer.update');
1287
+ if (!updatePermissions) {
1288
+ return false;
1289
+ }
1290
+ return Boolean(!locale || updatePermissions.properties?.locales?.includes(locale));
1291
+ }, [
1292
+ contentTypeUid,
1293
+ locale,
1294
+ userPermissions
1295
+ ]);
1296
+ const { allowedActions: { canUpdate: canUpdateContentType } } = strapiAdmin.useRBAC({
1297
+ updateContentType: [
1298
+ {
1299
+ action: 'plugin::content-manager.explorer.update',
1300
+ subject: contentTypeUid
1301
+ }
1302
+ ]
1303
+ });
1304
+ if (!canUpdateContentType || !canUpdateEntryForLocale) {
1305
+ return null;
1306
+ }
1307
+ return /*#__PURE__*/ jsxRuntime.jsx(StyledMenuItem, {
1308
+ /* @ts-expect-error inference isn't working in DS */ tag: reactRouterDom.NavLink,
1309
+ isLink: true,
1310
+ to: {
1311
+ pathname: `/content-manager/collection-types/${contentTypeUid}/${documentId}`,
1312
+ search: locale && `?plugins[i18n][locale]=${locale}`
1313
+ },
1314
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
1315
+ gap: 2,
1316
+ children: [
1317
+ /*#__PURE__*/ jsxRuntime.jsx(icons.Pencil, {
1318
+ width: "1.6rem",
1319
+ height: "1.6rem"
1320
+ }),
1321
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1322
+ variant: "omega",
1323
+ children: formatMessage({
1324
+ id: 'content-releases.content-manager-edit-view.edit-entry',
1325
+ defaultMessage: 'Edit entry'
1326
+ })
1327
+ })
1328
+ ]
1329
+ })
1330
+ });
1331
+ };
1332
+ const EditReleaseItem = ({ releaseId })=>{
1333
+ const { formatMessage } = reactIntl.useIntl();
1334
+ return /* @ts-expect-error inference isn't working in DS */ /*#__PURE__*/ jsxRuntime.jsx(StyledMenuItem, {
1335
+ tag: reactRouterDom.NavLink,
1336
+ isLink: true,
1337
+ to: `/plugins/content-releases/${releaseId}`,
1338
+ children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
1339
+ gap: 2,
1340
+ children: [
1341
+ /*#__PURE__*/ jsxRuntime.jsx(icons.Pencil, {
1342
+ width: "1.6rem",
1343
+ height: "1.6rem"
1344
+ }),
1345
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1346
+ textColor: "neutral800",
1347
+ variant: "omega",
1348
+ children: formatMessage({
1349
+ id: 'content-releases.content-manager-edit-view.edit-release',
1350
+ defaultMessage: 'Edit release'
1351
+ })
1352
+ })
1353
+ ]
1354
+ })
1355
+ });
1356
+ };
1357
+ const Root = ({ children })=>{
1358
+ const { formatMessage } = reactIntl.useIntl();
1359
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1360
+ return(// A user can access the dropdown if they have permissions to delete a release-action OR update a release
1361
+ allowedActions.canDeleteAction || allowedActions.canUpdate ? /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Menu.Root, {
1362
+ children: [
1363
+ /*#__PURE__*/ jsxRuntime.jsx(StyledMoreButton, {
1364
+ variant: "tertiary",
1365
+ endIcon: null,
1366
+ paddingLeft: "7px",
1367
+ paddingRight: "7px",
1368
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.AccessibleIcon, {
1369
+ label: formatMessage({
1370
+ id: 'content-releases.content-manager-edit-view.release-action-menu',
1371
+ defaultMessage: 'Release action options'
1372
+ }),
1373
+ children: /*#__PURE__*/ jsxRuntime.jsx(icons.More, {})
1374
+ })
1375
+ }),
1376
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Menu.Content, {
1377
+ top: 1,
1378
+ popoverPlacement: "bottom-end",
1379
+ children: children
1380
+ })
1381
+ ]
1382
+ }) : null);
1383
+ };
1384
+ const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
1385
+ & > span {
1386
+ display: flex;
1387
+ }
1388
+ `;
1389
+ const ReleaseActionMenu = {
1390
+ Root,
1391
+ EditReleaseItem,
1392
+ DeleteReleaseActionItem,
1393
+ ReleaseActionEntryLinkItem
1394
+ };
1395
+
1396
+ const Panel = ({ model, document, documentId, collectionType })=>{
1397
+ const [{ query }] = strapiAdmin.useQueryParams();
1398
+ const locale = query.plugins?.i18n?.locale;
1399
+ const { edit: { options } } = strapiAdmin$1.unstable_useDocumentLayout(model);
1400
+ const { formatMessage, formatDate, formatTime } = reactIntl.useIntl();
1401
+ const { allowedActions } = strapiAdmin.useRBAC(PERMISSIONS);
1402
+ const { canRead, canDeleteAction } = allowedActions;
1403
+ const response = useGetReleasesForEntryQuery({
1404
+ contentType: model,
1405
+ entryDocumentId: documentId,
1406
+ locale,
1407
+ hasEntryAttached: true
1408
+ }, {
1409
+ skip: !document
1410
+ });
1411
+ const releases = response.data?.data;
1412
+ const getReleaseColorVariant = (actionType, shade)=>{
1413
+ if (actionType === 'unpublish') {
1414
+ return `secondary${shade}`;
1415
+ }
1416
+ return `success${shade}`;
1417
+ };
1418
+ // Project is not EE or contentType does not have draftAndPublish enabled
1419
+ if (!window.strapi.isEE || !options?.draftAndPublish || !canRead) {
1420
+ return null;
1421
+ }
1422
+ if (collectionType === 'collection-types' && (!documentId || documentId === 'create')) {
1423
+ return null;
1424
+ }
1425
+ if (!releases || releases.length === 0) {
1426
+ return null;
1427
+ }
1428
+ return {
1429
+ title: formatMessage({
1430
+ id: 'content-releases.plugin.name',
1431
+ defaultMessage: 'Releases'
1432
+ }),
1433
+ content: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Flex, {
1434
+ direction: "column",
1435
+ alignItems: "stretch",
1436
+ gap: 3,
1437
+ width: "100%",
1438
+ children: releases?.map((release)=>/*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
1439
+ direction: "column",
1440
+ alignItems: "start",
1441
+ borderWidth: "1px",
1442
+ borderStyle: "solid",
1443
+ borderColor: getReleaseColorVariant(release.actions[0].type, '200'),
1444
+ overflow: "hidden",
1445
+ hasRadius: true,
1446
+ children: [
1447
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
1448
+ paddingTop: 3,
1449
+ paddingBottom: 3,
1450
+ paddingLeft: 4,
1451
+ paddingRight: 4,
1452
+ background: getReleaseColorVariant(release.actions[0].type, '100'),
1453
+ width: "100%",
1454
+ children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1455
+ fontSize: 1,
1456
+ variant: "pi",
1457
+ textColor: getReleaseColorVariant(release.actions[0].type, '600'),
1458
+ children: formatMessage({
1459
+ id: 'content-releases.content-manager-edit-view.list-releases.title',
1460
+ defaultMessage: '{isPublish, select, true {Will be published in} other {Will be unpublished in}}'
1461
+ }, {
1462
+ isPublish: release.actions[0].type === 'publish'
1463
+ })
1464
+ })
1465
+ }),
1466
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
1467
+ padding: 4,
1468
+ direction: "column",
1469
+ gap: 2,
1470
+ width: "100%",
1471
+ alignItems: "flex-start",
1472
+ children: [
1473
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1474
+ fontSize: 2,
1475
+ fontWeight: "bold",
1476
+ variant: "omega",
1477
+ textColor: "neutral700",
1478
+ children: release.name
1479
+ }),
1480
+ release.scheduledAt && release.timezone && /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
1481
+ variant: "pi",
1482
+ textColor: "neutral600",
1483
+ children: formatMessage({
1484
+ id: 'content-releases.content-manager-edit-view.scheduled.date',
1485
+ defaultMessage: '{date} at {time} ({offset})'
1486
+ }, {
1487
+ date: formatDate(new Date(release.scheduledAt), {
1488
+ day: '2-digit',
1489
+ month: '2-digit',
1490
+ year: 'numeric',
1491
+ timeZone: release.timezone
1492
+ }),
1493
+ time: formatTime(new Date(release.scheduledAt), {
1494
+ hourCycle: 'h23',
1495
+ timeZone: release.timezone
1496
+ }),
1497
+ offset: getTimezoneOffset(release.timezone, new Date(release.scheduledAt))
1498
+ })
1499
+ }),
1500
+ canDeleteAction ? /*#__PURE__*/ jsxRuntime.jsxs(ReleaseActionMenu.Root, {
1501
+ hasTriggerBorder: true,
1502
+ children: [
1503
+ /*#__PURE__*/ jsxRuntime.jsx(ReleaseActionMenu.EditReleaseItem, {
1504
+ releaseId: release.id
1505
+ }),
1506
+ /*#__PURE__*/ jsxRuntime.jsx(ReleaseActionMenu.DeleteReleaseActionItem, {
1507
+ releaseId: release.id,
1508
+ actionId: release.actions[0].id
1509
+ })
1510
+ ]
1511
+ }) : null
1512
+ ]
1513
+ })
1514
+ ]
1515
+ }, release.id))
1516
+ })
1517
+ };
1518
+ };
1519
+
1520
+ const pluginId = 'content-releases';
1521
+
1522
+ const prefixPluginTranslations = (trad, pluginId)=>{
1523
+ return Object.keys(trad).reduce((acc, current)=>{
1524
+ acc[`${pluginId}.${current}`] = trad[current];
1525
+ return acc;
1526
+ }, {});
1527
+ };
1528
+
1529
+ function __variableDynamicImportRuntime3__(path) {
1530
+ switch (path) {
1531
+ case './translations/en.json': return Promise.resolve().then(function () { return require('./en-BzpFfVeO.js'); });
1532
+ default: return new Promise(function(resolve, reject) {
1533
+ (typeof queueMicrotask === 'function' ? queueMicrotask : setTimeout)(
1534
+ reject.bind(null, new Error("Unknown variable dynamic import: " + path))
1535
+ );
1536
+ })
1537
+ }
1538
+ }
1539
+ // eslint-disable-next-line import/no-default-export
1540
+ const admin = {
1541
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1542
+ register (app) {
1543
+ /**
1544
+ * Hook that adds the locale column in the Release Details table
1545
+ * @constant
1546
+ * @type {string}
1547
+ */ app.createHook('ContentReleases/pages/ReleaseDetails/add-locale-in-releases');
1548
+ if (window.strapi.features.isEnabled('cms-content-releases')) {
1549
+ app.addMenuLink({
1550
+ to: `plugins/${pluginId}`,
1551
+ icon: icons.PaperPlane,
1552
+ intlLabel: {
1553
+ id: `${pluginId}.plugin.name`,
1554
+ defaultMessage: 'Releases'
1555
+ },
1556
+ Component: ()=>Promise.resolve().then(function () { return require('./App-B9yCdSLJ.js'); }).then((mod)=>({
1557
+ default: mod.App
1558
+ })),
1559
+ permissions: PERMISSIONS.main,
1560
+ position: 2
1561
+ });
1562
+ // Insert the releases container into the CM's sidebar on the Edit View
1563
+ const contentManagerPluginApis = app.getPlugin('content-manager').apis;
1564
+ if ('addEditViewSidePanel' in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === 'function') {
1565
+ contentManagerPluginApis.addEditViewSidePanel([
1566
+ Panel
1567
+ ]);
1568
+ }
1569
+ // Insert the "add to release" action into the CM's Edit View
1570
+ if ('addDocumentAction' in contentManagerPluginApis && typeof contentManagerPluginApis.addDocumentAction === 'function') {
1571
+ contentManagerPluginApis.addDocumentAction((actions)=>{
1572
+ const indexOfDeleteAction = actions.findIndex((action)=>action.type === 'unpublish');
1573
+ actions.splice(indexOfDeleteAction, 0, ReleaseActionModalForm);
1574
+ return actions;
1575
+ });
1576
+ }
1577
+ app.addSettingsLink('global', {
1578
+ id: pluginId,
1579
+ to: 'releases',
1580
+ intlLabel: {
1581
+ id: `${pluginId}.plugin.name`,
1582
+ defaultMessage: 'Releases'
1583
+ },
1584
+ permissions: [],
1585
+ async Component () {
1586
+ const { ProtectedReleasesSettingsPage } = await Promise.resolve().then(function () { return require('./ReleasesSettingsPage-DFVGppsl.js'); });
1587
+ return {
1588
+ default: ProtectedReleasesSettingsPage
1589
+ };
1590
+ }
1591
+ });
1592
+ if ('addBulkAction' in contentManagerPluginApis && typeof contentManagerPluginApis.addBulkAction === 'function') {
1593
+ contentManagerPluginApis.addBulkAction((actions)=>{
1594
+ // We want to add this action to just before the delete action all the time
1595
+ const deleteActionIndex = actions.findIndex((action)=>action.type === 'delete');
1596
+ actions.splice(deleteActionIndex, 0, ReleaseAction);
1597
+ return actions;
1598
+ });
1599
+ }
1600
+ // Hook that adds a column into the CM's LV table
1601
+ app.registerHook('Admin/CM/pages/ListView/inject-column-in-table', addColumnToTableHook);
1602
+ } else if (!window.strapi.features.isEnabled('cms-content-releases') && window.strapi?.flags?.promoteEE) {
1603
+ app.addSettingsLink('global', {
1604
+ id: pluginId,
1605
+ to: '/plugins/purchase-content-releases',
1606
+ intlLabel: {
1607
+ id: `${pluginId}.plugin.name`,
1608
+ defaultMessage: 'Releases'
1609
+ },
1610
+ permissions: [],
1611
+ async Component () {
1612
+ const { PurchaseContentReleases } = await Promise.resolve().then(function () { return require('./PurchaseContentReleases-BCME5SQU.js'); });
1613
+ return {
1614
+ default: PurchaseContentReleases
1615
+ };
1616
+ },
1617
+ licenseOnly: true
1618
+ });
1619
+ }
1620
+ },
1621
+ async registerTrads ({ locales }) {
1622
+ const importedTrads = await Promise.all(locales.map((locale)=>{
1623
+ return __variableDynamicImportRuntime3__(`./translations/${locale}.json`).then(({ default: data })=>{
1624
+ return {
1625
+ data: prefixPluginTranslations(data, 'content-releases'),
1626
+ locale
1627
+ };
1628
+ }).catch(()=>{
1629
+ return {
1630
+ data: {},
1631
+ locale
1632
+ };
1633
+ });
1634
+ }));
1635
+ return Promise.resolve(importedTrads);
1636
+ }
1637
+ };
1638
+
1639
+ exports.PERMISSIONS = PERMISSIONS;
1640
+ exports.ReleaseActionMenu = ReleaseActionMenu;
1641
+ exports.ReleaseActionOptions = ReleaseActionOptions;
1642
+ exports.admin = admin;
1643
+ exports.getTimezoneOffset = getTimezoneOffset;
1644
+ exports.getTimezones = getTimezones;
1645
+ exports.pluginId = pluginId;
1646
+ exports.releaseApi = releaseApi;
1647
+ exports.useCreateReleaseMutation = useCreateReleaseMutation;
1648
+ exports.useDeleteReleaseMutation = useDeleteReleaseMutation;
1649
+ exports.useGetReleaseActionsQuery = useGetReleaseActionsQuery;
1650
+ exports.useGetReleaseQuery = useGetReleaseQuery;
1651
+ exports.useGetReleaseSettingsQuery = useGetReleaseSettingsQuery;
1652
+ exports.useGetReleasesQuery = useGetReleasesQuery;
1653
+ exports.usePublishReleaseMutation = usePublishReleaseMutation;
1654
+ exports.useUpdateReleaseActionMutation = useUpdateReleaseActionMutation;
1655
+ exports.useUpdateReleaseMutation = useUpdateReleaseMutation;
1656
+ exports.useUpdateReleaseSettingsMutation = useUpdateReleaseSettingsMutation;
1657
+ //# sourceMappingURL=index-1nn-zHX-.js.map