@blokkli/editor 2.0.0-alpha.17 → 2.0.0-alpha.18

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 (139) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +380 -59
  3. package/dist/modules/drupal/graphql/base/fragment.paragraphsFieldItem.graphql +3 -1
  4. package/dist/modules/drupal/graphql/base/query.pbConfig.graphql +1 -10
  5. package/dist/modules/drupal/graphql/mutations/set_paragraph_schedule.graphql +15 -0
  6. package/dist/modules/drupal/index.mjs +33 -0
  7. package/dist/modules/drupal/runtime/adapter/index.js +10 -2
  8. package/dist/runtime/adapter/index.d.ts +21 -0
  9. package/dist/runtime/blokkliPlugins/ContextMenu/Menu/index.vue +3 -0
  10. package/dist/runtime/blokkliPlugins/ItemAction/index.vue +23 -13
  11. package/dist/runtime/blokkliPlugins/ItemAction/index.vue.d.ts +20 -44
  12. package/dist/runtime/blokkliPlugins/TourItem/index.vue +10 -5
  13. package/dist/runtime/components/BlokkliEditable.vue +13 -13
  14. package/dist/runtime/components/BlokkliField.vue +3 -0
  15. package/dist/runtime/components/BlokkliField.vue.d.ts +3 -3
  16. package/dist/runtime/components/BlokkliItem.vue +1 -1
  17. package/dist/runtime/components/BlokkliItem.vue.d.ts +4 -2
  18. package/dist/runtime/components/BlokkliProvider.vue +12 -8
  19. package/dist/runtime/components/Edit/Actions/index.vue +27 -16
  20. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +26 -10
  21. package/dist/runtime/components/Edit/ArtboardTooltip/index.vue +3 -0
  22. package/dist/runtime/components/Edit/Dialog/index.vue +6 -4
  23. package/dist/runtime/components/Edit/DraggableList.vue +15 -7
  24. package/dist/runtime/components/Edit/DraggableList.vue.d.ts +5 -5
  25. package/dist/runtime/components/Edit/EditProvider.vue +29 -16
  26. package/dist/runtime/components/Edit/EditProvider.vue.d.ts +1 -0
  27. package/dist/runtime/components/Edit/Features/AddList/index.vue +9 -11
  28. package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +9 -6
  29. package/dist/runtime/components/Edit/Features/Analyze/Renderer.vue +1 -1
  30. package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodesTarget.vue +15 -11
  31. package/dist/runtime/components/Edit/Features/Anchors/Renderer.vue +19 -102
  32. package/dist/runtime/components/Edit/Features/Artboard/Renderer.vue +3 -0
  33. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +28 -52
  34. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/ScheduleSection.vue +154 -0
  35. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/ScheduleSection.vue.d.ts +27 -0
  36. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/index.vue +222 -0
  37. package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/index.vue.d.ts +11 -0
  38. package/dist/runtime/components/Edit/Features/BlockScheduler/index.vue +96 -0
  39. package/dist/runtime/components/Edit/Features/BlockScheduler/index.vue.d.ts +2 -0
  40. package/dist/runtime/components/Edit/Features/Clipboard/index.vue +15 -16
  41. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Item/index.vue +51 -0
  42. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/{Group → Item}/index.vue.d.ts +9 -13
  43. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +46 -66
  44. package/dist/runtime/components/Edit/Features/Comments/index.vue +1 -1
  45. package/dist/runtime/components/Edit/Features/Conversions/index.vue +4 -7
  46. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +2 -2
  47. package/dist/runtime/components/Edit/Features/Debug/index.vue +4 -1
  48. package/dist/runtime/components/Edit/Features/Delete/index.vue +1 -1
  49. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +13 -5
  50. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +14 -11
  51. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +30 -18
  52. package/dist/runtime/components/Edit/Features/Duplicate/index.vue +6 -8
  53. package/dist/runtime/components/Edit/Features/Edit/index.vue +15 -21
  54. package/dist/runtime/components/Edit/Features/EditForm/index.vue +7 -6
  55. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +8 -3
  56. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue.d.ts +2 -2
  57. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +29 -12
  58. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue.d.ts +2 -2
  59. package/dist/runtime/components/Edit/Features/EditableField/index.vue +40 -42
  60. package/dist/runtime/components/Edit/Features/Fragments/Dialog/index.vue +11 -9
  61. package/dist/runtime/components/Edit/Features/Fragments/index.vue +3 -3
  62. package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue +16 -25
  63. package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue +5 -7
  64. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +5 -5
  65. package/dist/runtime/components/Edit/Features/Library/index.vue +27 -23
  66. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +6 -3
  67. package/dist/runtime/components/Edit/Features/MediaLibrary/index.vue +15 -12
  68. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +2 -2
  69. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +7 -6
  70. package/dist/runtime/components/Edit/Features/Options/index.vue +6 -6
  71. package/dist/runtime/components/Edit/Features/Publish/Dialog/index.vue +68 -15
  72. package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Page/index.vue +15 -15
  73. package/dist/runtime/components/Edit/Features/Search/index.vue +4 -1
  74. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +3 -3
  75. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +34 -11
  76. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +21 -20
  77. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue.d.ts +2 -2
  78. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +3 -3
  79. package/dist/runtime/components/Edit/Features/Selection/OverlayFallback/index.vue +2 -2
  80. package/dist/runtime/components/Edit/Features/Selection/index.vue +61 -27
  81. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +2 -2
  82. package/dist/runtime/components/Edit/Features/Structure/List/Item/index.vue +13 -6
  83. package/dist/runtime/components/Edit/Features/Tour/Overlay/index.vue +3 -0
  84. package/dist/runtime/components/Edit/Features/Transform/index.vue +2 -27
  85. package/dist/runtime/components/Edit/Features/Translations/index.vue +7 -7
  86. package/dist/runtime/components/Edit/Features/Validations/SidebarItem/index.vue +5 -5
  87. package/dist/runtime/components/Edit/Features/index.vue +17 -7
  88. package/dist/runtime/components/Edit/Form/Toggle/index.vue +4 -3
  89. package/dist/runtime/components/Edit/Form/Toggle/index.vue.d.ts +12 -2
  90. package/dist/runtime/components/Edit/InfoBox/index.vue +6 -2
  91. package/dist/runtime/components/Edit/InfoBox/index.vue.d.ts +12 -2
  92. package/dist/runtime/components/Edit/{Features/Publish/Dialog/ScheduleDate.vue → ScheduleDate/index.vue} +6 -58
  93. package/dist/runtime/components/Edit/{Features/Publish/Dialog/ScheduleDate.vue.d.ts → ScheduleDate/index.vue.d.ts} +11 -1
  94. package/dist/runtime/components/Edit/ShortcutIndicator/index.vue +3 -0
  95. package/dist/runtime/components/Edit/Transition/Height.vue +95 -0
  96. package/dist/runtime/components/Edit/Transition/Height.vue.d.ts +36 -0
  97. package/dist/runtime/components/Edit/index.d.ts +3 -1
  98. package/dist/runtime/components/Edit/index.js +5 -1
  99. package/dist/runtime/css/output.css +1 -1
  100. package/dist/runtime/helpers/animationProvider.d.ts +2 -1
  101. package/dist/runtime/helpers/animationProvider.js +6 -2
  102. package/dist/runtime/helpers/composables/useStateBasedCache.d.ts +4 -0
  103. package/dist/runtime/helpers/composables/useStateBasedCache.js +13 -0
  104. package/dist/runtime/helpers/definitionProvider.d.ts +1 -1
  105. package/dist/runtime/helpers/dom/index.d.ts +1 -1
  106. package/dist/runtime/helpers/domProvider.d.ts +10 -16
  107. package/dist/runtime/helpers/domProvider.js +80 -135
  108. package/dist/runtime/helpers/index.d.ts +1 -8
  109. package/dist/runtime/helpers/index.js +1 -84
  110. package/dist/runtime/helpers/providers/blocks.d.ts +10 -0
  111. package/dist/runtime/helpers/providers/blocks.js +91 -0
  112. package/dist/runtime/helpers/providers/directive.d.ts +24 -0
  113. package/dist/runtime/helpers/{editableProvider.js → providers/directive.js} +90 -29
  114. package/dist/runtime/helpers/providers/element.d.ts +6 -0
  115. package/dist/runtime/helpers/providers/element.js +35 -0
  116. package/dist/runtime/helpers/providers/fields.d.ts +8 -0
  117. package/dist/runtime/helpers/providers/fields.js +47 -0
  118. package/dist/runtime/helpers/selectionProvider.d.ts +11 -11
  119. package/dist/runtime/helpers/selectionProvider.js +38 -45
  120. package/dist/runtime/helpers/stateProvider.d.ts +1 -0
  121. package/dist/runtime/helpers/stateProvider.js +21 -15
  122. package/dist/runtime/helpers/themeProvider.d.ts +2 -1
  123. package/dist/runtime/helpers/themeProvider.js +24 -14
  124. package/dist/runtime/helpers/typesProvider.js +10 -26
  125. package/dist/runtime/helpers/uiProvider.d.ts +3 -2
  126. package/dist/runtime/helpers/uiProvider.js +11 -15
  127. package/dist/runtime/icons/calendar.svg +1 -0
  128. package/dist/runtime/icons/clock.svg +1 -0
  129. package/dist/runtime/icons/comment_add.svg +1 -5
  130. package/dist/runtime/icons/delete.svg +1 -8
  131. package/dist/runtime/icons/duplicate.svg +1 -12
  132. package/dist/runtime/icons/edit.svg +1 -8
  133. package/dist/runtime/icons/reusable.svg +1 -5
  134. package/dist/runtime/plugins/{blokkliEditable.js → blokkliDirectives.js} +14 -20
  135. package/dist/runtime/types/index.d.ts +55 -36
  136. package/package.json +1 -1
  137. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue +0 -63
  138. package/dist/runtime/helpers/editableProvider.d.ts +0 -14
  139. /package/dist/runtime/plugins/{blokkliEditable.d.ts → blokkliDirectives.d.ts} +0 -0
@@ -91,53 +91,36 @@ const {
91
91
  $t,
92
92
  state,
93
93
  dom,
94
- definitions
94
+ definitions,
95
+ blocks
95
96
  } = useBlokkli();
96
97
  const shouldRender = computed(() => state.editMode.value === "editing");
97
98
  const searchText = ref("");
98
99
  const itemEntityType = runtimeConfig.itemEntityType;
99
100
  const favorites = storage.use("blockFavorites", []);
100
- const activeField = computed(() => {
101
- if (selection.activeFieldKey.value) {
102
- const el = document.querySelector(
103
- `[data-field-key="${selection.activeFieldKey.value}"]`
104
- );
105
- if (el && el instanceof HTMLElement) {
106
- const label = el.dataset.fieldLabel;
107
- const name = el.dataset.fieldName;
108
- const isNested = el.dataset.fieldIsNested === "true";
109
- const hostEntityType = el.dataset.hostEntityType;
110
- const hostEntityUuid = el.dataset.hostEntityUuid;
111
- if (label && name && hostEntityType && hostEntityUuid) {
112
- return { label, name, hostEntityType, hostEntityUuid, isNested };
113
- }
114
- }
115
- }
116
- return void 0;
117
- });
118
101
  const getAllowedTypesForSelected = (p) => {
119
- if (types.itemBundlesWithNested.includes(p.itemBundle)) {
120
- return types.fieldConfig.forEntityTypeAndBundle(itemEntityType, p.itemBundle).flatMap((v) => v.allowedBundles).filter(Boolean);
102
+ if (types.itemBundlesWithNested.includes(p.bundle)) {
103
+ return types.fieldConfig.forEntityTypeAndBundle(itemEntityType, p.bundle).flatMap((v) => v.allowedBundles).filter(Boolean);
121
104
  }
122
- if (p.hostType === itemEntityType) {
123
- return types.fieldConfig.forEntityTypeAndBundle(itemEntityType, p.hostBundle).flatMap((v) => v.allowedBundles).filter(Boolean);
105
+ if (p.host.type === itemEntityType) {
106
+ return types.fieldConfig.forEntityTypeAndBundle(itemEntityType, p.host.bundle).flatMap((v) => v.allowedBundles).filter(Boolean);
124
107
  } else {
125
108
  return types.getFieldConfig(
126
109
  context.value.entityType,
127
110
  context.value.entityBundle,
128
- p.hostFieldName
111
+ p.host.fieldName
129
112
  )?.allowedBundles || [];
130
113
  }
131
114
  };
132
- const bundlesForRenderedFields = computed(
133
- () => dom.registeredFieldTypes.value.flatMap((field) => {
115
+ const bundlesForRenderedFields = computed(() => {
116
+ return dom.registeredFieldTypes.value.flatMap((field) => {
134
117
  return types.getFieldConfig(
135
118
  field.entityType,
136
119
  field.entityBundle,
137
120
  field.fieldName
138
121
  )?.allowedBundles || [];
139
- }).filter(onlyUnique)
140
- );
122
+ }).filter(onlyUnique);
123
+ });
141
124
  const generallyAvailableBundles = computed(
142
125
  () => types.generallyAvailableBundles.filter(
143
126
  (v) => (
@@ -147,15 +130,8 @@ const generallyAvailableBundles = computed(
147
130
  )
148
131
  );
149
132
  const selectableBundles = computed(() => {
150
- if (selection.blocks.value.length) {
151
- return selection.blocks.value.flatMap((v) => getAllowedTypesForSelected(v));
152
- }
153
- if (activeField.value && activeField.value.hostEntityType === context.value.entityType) {
154
- return types.getFieldConfig(
155
- context.value.entityType,
156
- context.value.entityBundle,
157
- activeField.value.name
158
- )?.allowedBundles || [];
133
+ if (selection.items.value.length) {
134
+ return selection.items.value.flatMap((v) => getAllowedTypesForSelected(v));
159
135
  }
160
136
  return generallyAvailableBundles.value.map((v) => v.id || "");
161
137
  });
@@ -191,18 +167,18 @@ const sortedList = computed(() => {
191
167
  });
192
168
  const renderKey = ref("");
193
169
  const getBundlesForAppendCommands = () => {
194
- if (selection.blocks.value.length !== 1) {
170
+ const item = selection.item.value;
171
+ if (!item) {
195
172
  return [];
196
173
  }
197
- const block = selection.blocks.value[0];
198
174
  const field = types.getFieldConfig(
199
- block.hostType,
200
- block.hostBundle,
201
- block.hostFieldName
175
+ item.host.type,
176
+ item.host.bundle,
177
+ item.host.fieldName
202
178
  );
203
179
  if (field) {
204
180
  if (field.cardinality !== -1) {
205
- const key = getFieldKey(block.hostUuid, block.hostFieldName);
181
+ const key = getFieldKey(item.host.uuid, item.host.fieldName);
206
182
  const count = state.getFieldBlockCount(key);
207
183
  if (count >= field.cardinality) {
208
184
  return [];
@@ -213,7 +189,7 @@ const getBundlesForAppendCommands = () => {
213
189
  return [];
214
190
  };
215
191
  const getAppendEndCommands = () => {
216
- if (selection.blocks.value.length !== 0) {
192
+ if (selection.items.value.length !== 0) {
217
193
  return [];
218
194
  }
219
195
  return types.fieldConfig.forEntityTypeAndBundle(
@@ -279,7 +255,7 @@ const getInsertCommands = (block) => {
279
255
  if (!block) {
280
256
  return [];
281
257
  }
282
- const nestedFields = types.fieldConfig.forEntityTypeAndBundle(itemEntityType, block.itemBundle).map((field) => {
258
+ const nestedFields = types.fieldConfig.forEntityTypeAndBundle(itemEntityType, block.bundle).map((field) => {
283
259
  return {
284
260
  ...field,
285
261
  uuid: block.uuid
@@ -307,8 +283,8 @@ const getInsertCommands = (block) => {
307
283
  });
308
284
  }
309
285
  );
310
- if (block.hostType === runtimeConfig.itemEntityType) {
311
- const parentBlock = dom.findBlock(block.hostUuid);
286
+ if (block.host.type === runtimeConfig.itemEntityType) {
287
+ const parentBlock = blocks.getBlock(block.host.uuid);
312
288
  if (parentBlock) {
313
289
  getInsertCommands(parentBlock).forEach((parentCommand) => {
314
290
  commands.push(parentCommand);
@@ -318,7 +294,7 @@ const getInsertCommands = (block) => {
318
294
  return commands;
319
295
  };
320
296
  const commandCallbackAppend = (bundle) => {
321
- const block = selection.blocks.value[0];
297
+ const block = selection.items.value[0];
322
298
  if (!block) {
323
299
  return;
324
300
  }
@@ -326,9 +302,9 @@ const commandCallbackAppend = (bundle) => {
326
302
  bundle,
327
303
  afterUuid: selection.uuids.value[0],
328
304
  host: {
329
- type: block.hostType,
330
- uuid: block.hostUuid,
331
- fieldName: block.hostFieldName
305
+ type: block.host.type,
306
+ uuid: block.host.uuid,
307
+ fieldName: block.host.fieldName
332
308
  }
333
309
  });
334
310
  };
@@ -353,7 +329,7 @@ defineCommands(() => {
353
329
  }
354
330
  return [
355
331
  ...getAppendCommands(),
356
- ...getInsertCommands(selection.blocks.value[0]),
332
+ ...getInsertCommands(selection.items.value[0]),
357
333
  ...getAppendEndCommands()
358
334
  ];
359
335
  });
@@ -0,0 +1,154 @@
1
+ <template>
2
+ <div class="bk-schedule-section">
3
+ <FormToggle v-model="isEnabled" :disabled="disabled">
4
+ <div class="bk-schedule-section-toggle-title">
5
+ <Icon :name="icon" />
6
+ <div class="bk-schedule-section-toggle-title-label">{{ label }}</div>
7
+ </div>
8
+ </FormToggle>
9
+
10
+ <TransitionHeight opacity>
11
+ <div v-if="isEnabled" class="bk-schedule-section-content">
12
+ <div
13
+ v-if="hasMixedDates && !overrideMode"
14
+ class="bk-schedule-section-mixed"
15
+ >
16
+ <InfoBox :text="mixedDatesMessage" />
17
+ <button type="button" class="bk-button" @click="enableOverride">
18
+ {{ $t("blockSchedulerOverride", "Set date for all") }}
19
+ </button>
20
+ </div>
21
+
22
+ <div v-if="!hasMixedDates || overrideMode">
23
+ <ScheduleDate v-model="selectedDate" />
24
+ </div>
25
+ </div>
26
+ </TransitionHeight>
27
+ </div>
28
+ </template>
29
+
30
+ <script setup>
31
+ import { ref, computed, watch, useBlokkli } from "#imports";
32
+ import {
33
+ FormToggle,
34
+ ScheduleDate,
35
+ InfoBox,
36
+ Icon,
37
+ TransitionHeight
38
+ } from "#blokkli/components";
39
+ const props = defineProps({
40
+ label: { type: String, required: true },
41
+ icon: { type: null, required: true },
42
+ items: { type: Array, required: true },
43
+ supportedBundles: { type: Array, required: true },
44
+ disabled: { type: Boolean, required: false, default: false }
45
+ });
46
+ const { $t, ui } = useBlokkli();
47
+ const modelValue = defineModel({ type: null });
48
+ const isEnabled = ref(false);
49
+ const selectedDate = ref(void 0);
50
+ const overrideMode = ref(false);
51
+ const hasMixedDates = computed(() => {
52
+ const supportedItems2 = props.items.filter(
53
+ (item) => props.supportedBundles.includes(item.bundle)
54
+ );
55
+ if (supportedItems2.length === 0) {
56
+ return false;
57
+ }
58
+ const dates = supportedItems2.map((item) => item.date);
59
+ if (dates.every((date) => date == null)) {
60
+ return false;
61
+ }
62
+ const firstDate = dates[0];
63
+ const allSame = dates.every((date) => date === firstDate);
64
+ return !allSame;
65
+ });
66
+ const commonDate = computed(() => {
67
+ if (hasMixedDates.value) {
68
+ return void 0;
69
+ }
70
+ const supportedItems2 = props.items.filter(
71
+ (item) => props.supportedBundles.includes(item.bundle)
72
+ );
73
+ const dates = supportedItems2.map((item) => item.date).filter((date) => date != null);
74
+ if (dates.length === 0) {
75
+ return void 0;
76
+ }
77
+ return dates[0] || void 0;
78
+ });
79
+ const mixedDatesMessage = computed(() => {
80
+ const supportedItems2 = props.items.filter(
81
+ (item) => props.supportedBundles.includes(item.bundle)
82
+ );
83
+ const dates = supportedItems2.map((item) => item.date).filter((date) => date != null);
84
+ const uniqueDates = [...new Set(dates)];
85
+ const formattedDates = uniqueDates.map((date) => ui.formatDate(date)).join(", ");
86
+ const message = $t(
87
+ "blockSchedulerMixedDates",
88
+ "Selected blocks have different dates: @dates"
89
+ );
90
+ return message.replace("@dates", formattedDates);
91
+ });
92
+ function getTomorrowDate() {
93
+ const tomorrow = /* @__PURE__ */ new Date();
94
+ tomorrow.setDate(tomorrow.getDate() + 1);
95
+ tomorrow.setHours(12, 0, 0, 0);
96
+ return tomorrow.toISOString();
97
+ }
98
+ function getMostCommonDate() {
99
+ const supportedItems2 = props.items.filter(
100
+ (item) => props.supportedBundles.includes(item.bundle)
101
+ );
102
+ const dates = supportedItems2.map((item) => item.date).filter((date) => date != null);
103
+ if (dates.length === 0) {
104
+ return void 0;
105
+ }
106
+ const dateCount = /* @__PURE__ */ new Map();
107
+ for (const date of dates) {
108
+ dateCount.set(date, (dateCount.get(date) || 0) + 1);
109
+ }
110
+ let mostCommonDate;
111
+ let maxCount = 0;
112
+ for (const [date, count] of dateCount.entries()) {
113
+ if (count > maxCount) {
114
+ maxCount = count;
115
+ mostCommonDate = date;
116
+ }
117
+ }
118
+ return mostCommonDate;
119
+ }
120
+ const supportedItems = props.items.filter(
121
+ (item) => props.supportedBundles.includes(item.bundle)
122
+ );
123
+ const hasAnyDate = supportedItems.some((item) => item.date != null);
124
+ if (hasAnyDate && !props.disabled) {
125
+ isEnabled.value = true;
126
+ if (commonDate.value) {
127
+ selectedDate.value = commonDate.value;
128
+ }
129
+ }
130
+ watch(isEnabled, (enabled) => {
131
+ if (!enabled) {
132
+ selectedDate.value = void 0;
133
+ overrideMode.value = false;
134
+ modelValue.value = null;
135
+ } else if (commonDate.value && !hasMixedDates.value) {
136
+ selectedDate.value = commonDate.value;
137
+ } else if (!selectedDate.value) {
138
+ selectedDate.value = getTomorrowDate();
139
+ }
140
+ });
141
+ watch(selectedDate, (date) => {
142
+ if (isEnabled.value) {
143
+ modelValue.value = date || null;
144
+ }
145
+ });
146
+ function enableOverride() {
147
+ overrideMode.value = true;
148
+ selectedDate.value = getMostCommonDate() || getTomorrowDate();
149
+ }
150
+ defineExpose({
151
+ isEnabled,
152
+ selectedDate
153
+ });
154
+ </script>
@@ -0,0 +1,27 @@
1
+ import type { BlokkliIcon } from '#blokkli-build/icons';
2
+ export type ScheduleItemData = {
3
+ uuid: string;
4
+ bundle: string;
5
+ date: string | null | undefined;
6
+ };
7
+ type __VLS_Props = {
8
+ label: string;
9
+ icon: BlokkliIcon;
10
+ items: ScheduleItemData[];
11
+ supportedBundles: string[];
12
+ disabled?: boolean;
13
+ };
14
+ type __VLS_PublicProps = __VLS_Props & {
15
+ modelValue?: string | null | undefined;
16
+ };
17
+ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {
18
+ isEnabled: import("vue").Ref<boolean, boolean>;
19
+ selectedDate: import("vue").Ref<string | undefined, string | undefined>;
20
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
21
+ "update:modelValue": (value: string | null | undefined) => any;
22
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
23
+ "onUpdate:modelValue"?: ((value: string | null | undefined) => any) | undefined;
24
+ }>, {
25
+ disabled: boolean;
26
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ export default _default;
@@ -0,0 +1,222 @@
1
+ <template>
2
+ <DialogModal
3
+ :title="$t('blockSchedulerDialogTitle', 'Manage scheduling')"
4
+ :submit-label="$t('blockSchedulerDialogSubmit', 'Save schedule')"
5
+ :width="900"
6
+ :lead="
7
+ $t(
8
+ 'blockSchedulerDialogLead',
9
+ 'Schedule automatic publishing and unpublishing dates for the selected blocks.'
10
+ )
11
+ "
12
+ :is-loading
13
+ :can-submit
14
+ @cancel="$emit('close')"
15
+ @submit="onSubmit"
16
+ >
17
+ <div class="bk-block-scheduler-dialog">
18
+ <ScheduleSection
19
+ v-model="publishOn"
20
+ icon="eye"
21
+ :label="$t('blockSchedulerDialogPublishOn', 'Publish on')"
22
+ :items="publishOnItems"
23
+ :supported-bundles="bundlesWithPublish"
24
+ :disabled="publishDisabled"
25
+ />
26
+
27
+ <ScheduleSection
28
+ v-model="unpublishOn"
29
+ icon="eye-off"
30
+ :label="$t('blockSchedulerDialogUnpublishOn', 'Unpublish on')"
31
+ :items="unpublishOnItems"
32
+ :supported-bundles="bundlesWithUnpublish"
33
+ :disabled="unpublishDisabled"
34
+ />
35
+
36
+ <div class="bk-block-scheduler-table">
37
+ <h3 class="bk-block-scheduler-table-title">
38
+ <span v-if="canSubmit">{{
39
+ $t("blockSchedulerChangesPreview", "Changes to be applied")
40
+ }}</span>
41
+ <span v-else>
42
+ {{ $t("blockSchedulerNoChanges", "No changes to be applied.") }}
43
+ </span>
44
+ </h3>
45
+ <table v-if="canSubmit" class="bk-table">
46
+ <thead>
47
+ <tr>
48
+ <th>{{ $t("bundle", "Bundle") }}</th>
49
+ <th>{{ $t("blockSchedulerDialogPublishOn", "Publish on") }}</th>
50
+ <th>
51
+ {{ $t("blockSchedulerDialogUnpublishOn", "Unpublish on") }}
52
+ </th>
53
+ </tr>
54
+ </thead>
55
+ <tbody>
56
+ <tr v-for="(row, index) in tableRows" :key="index">
57
+ <td>{{ row.bundle }}</td>
58
+ <td>{{ row.publishOn }}</td>
59
+ <td>{{ row.unpublishOn }}</td>
60
+ </tr>
61
+ </tbody>
62
+ </table>
63
+ </div>
64
+ </div>
65
+ </DialogModal>
66
+ </template>
67
+
68
+ <script setup>
69
+ import { falsy } from "#blokkli/helpers";
70
+ import { computed, useBlokkli, ref } from "#imports";
71
+ import ScheduleSection from "./ScheduleSection.vue";
72
+ import { DialogModal } from "#blokkli/components";
73
+ const props = defineProps({
74
+ uuids: { type: Array, required: true },
75
+ bundlesWithPublish: { type: Array, required: true },
76
+ bundlesWithUnpublish: { type: Array, required: true }
77
+ });
78
+ const emit = defineEmits(["close"]);
79
+ const { state, $t, adapter, ui, types } = useBlokkli();
80
+ const isLoading = ref(false);
81
+ const error = ref("");
82
+ const items = computed(() => {
83
+ return props.uuids.map((uuid) => {
84
+ return state.getFieldListItem(uuid);
85
+ }).filter(falsy).map((item) => {
86
+ return {
87
+ uuid: item.uuid,
88
+ bundle: item.bundle,
89
+ isPublished: !!item.editContext?.isPublished,
90
+ publishOn: item.editContext?.publishOn,
91
+ unpublishOn: item.editContext?.unpublishOn
92
+ };
93
+ });
94
+ });
95
+ const selectedBundles = computed(() => {
96
+ const bundles = items.value.map((item) => item.bundle);
97
+ return [...new Set(bundles)];
98
+ });
99
+ const publishDisabled = computed(() => {
100
+ return !selectedBundles.value.some(
101
+ (bundle) => props.bundlesWithPublish.includes(bundle)
102
+ );
103
+ });
104
+ const unpublishDisabled = computed(() => {
105
+ return !selectedBundles.value.some(
106
+ (bundle) => props.bundlesWithUnpublish.includes(bundle)
107
+ );
108
+ });
109
+ const publishOnItems = computed(() => {
110
+ return items.value.map((item) => ({
111
+ uuid: item.uuid,
112
+ bundle: item.bundle,
113
+ date: item.publishOn
114
+ }));
115
+ });
116
+ const unpublishOnItems = computed(() => {
117
+ return items.value.map((item) => ({
118
+ uuid: item.uuid,
119
+ bundle: item.bundle,
120
+ date: item.unpublishOn
121
+ }));
122
+ });
123
+ function getCommonDate(items2, supportedBundles) {
124
+ const supportedItems = items2.filter(
125
+ (item) => supportedBundles.includes(item.bundle)
126
+ );
127
+ if (supportedItems.length === 0) {
128
+ return void 0;
129
+ }
130
+ const dates = supportedItems.map((item) => item.date);
131
+ if (dates.every((date) => date == null)) {
132
+ return null;
133
+ }
134
+ const firstDate = dates[0];
135
+ const allSame = dates.every((date) => date === firstDate);
136
+ return allSame ? firstDate ?? null : void 0;
137
+ }
138
+ const publishOn = ref(
139
+ getCommonDate(publishOnItems.value, props.bundlesWithPublish)
140
+ );
141
+ const unpublishOn = ref(
142
+ getCommonDate(unpublishOnItems.value, props.bundlesWithUnpublish)
143
+ );
144
+ const tableRows = computed(() => {
145
+ return items.value.map((item) => {
146
+ const bundleDef = types.getBlockBundleDefinition(item.bundle);
147
+ const supportsPublish = props.bundlesWithPublish.includes(item.bundle);
148
+ const supportsUnpublish = props.bundlesWithUnpublish.includes(item.bundle);
149
+ let publishOnDisplay;
150
+ if (!supportsPublish) {
151
+ publishOnDisplay = $t("notSupported", "Not supported");
152
+ } else if (publishOn.value === void 0) {
153
+ publishOnDisplay = item.publishOn ? ui.formatDate(item.publishOn) : $t("notSet", "Not set");
154
+ } else if (publishOn.value) {
155
+ publishOnDisplay = ui.formatDate(publishOn.value);
156
+ } else {
157
+ publishOnDisplay = $t("notSet", "Not set");
158
+ }
159
+ let unpublishOnDisplay;
160
+ if (!supportsUnpublish) {
161
+ unpublishOnDisplay = $t("notSupported", "Not supported");
162
+ } else if (unpublishOn.value === void 0) {
163
+ unpublishOnDisplay = item.unpublishOn ? ui.formatDate(item.unpublishOn) : $t("notSet", "Not set");
164
+ } else if (unpublishOn.value) {
165
+ unpublishOnDisplay = ui.formatDate(unpublishOn.value);
166
+ } else {
167
+ unpublishOnDisplay = $t("notSet", "Not set");
168
+ }
169
+ return {
170
+ bundle: bundleDef?.label || item.bundle,
171
+ publishOn: publishOnDisplay,
172
+ unpublishOn: unpublishOnDisplay
173
+ };
174
+ });
175
+ });
176
+ const canSubmit = computed(() => {
177
+ return items.value.some((item) => {
178
+ const supportsPublish = props.bundlesWithPublish.includes(item.bundle);
179
+ const supportsUnpublish = props.bundlesWithUnpublish.includes(item.bundle);
180
+ if (supportsPublish && publishOn.value !== void 0 && item.publishOn !== publishOn.value) {
181
+ return true;
182
+ }
183
+ if (supportsUnpublish && unpublishOn.value !== void 0 && item.unpublishOn !== unpublishOn.value) {
184
+ return true;
185
+ }
186
+ return false;
187
+ });
188
+ });
189
+ async function onSubmit() {
190
+ isLoading.value = true;
191
+ const blocks = [];
192
+ items.value.forEach((item) => {
193
+ const supportsPublish = props.bundlesWithPublish.includes(item.bundle);
194
+ const supportsUnpublish = props.bundlesWithUnpublish.includes(item.bundle);
195
+ if (supportsPublish && publishOn.value !== void 0 && item.publishOn !== publishOn.value) {
196
+ blocks.push({
197
+ uuid: item.uuid,
198
+ type: "publish",
199
+ date: publishOn.value || void 0
200
+ });
201
+ }
202
+ if (supportsUnpublish && unpublishOn.value !== void 0 && item.unpublishOn !== unpublishOn.value) {
203
+ blocks.push({
204
+ uuid: item.uuid,
205
+ type: "unpublish",
206
+ date: unpublishOn.value || void 0
207
+ });
208
+ }
209
+ });
210
+ isLoading.value = true;
211
+ const isSuccess = await state.mutateWithLoadingState(
212
+ () => adapter.setBlockScheduleDate(blocks),
213
+ false,
214
+ $t("blockSchedulerSuccessMessage", "Successfully updated schedule dates.")
215
+ );
216
+ if (!isSuccess) {
217
+ error.value = "An unexpected error happened.";
218
+ return;
219
+ }
220
+ emit("close");
221
+ }
222
+ </script>
@@ -0,0 +1,11 @@
1
+ type __VLS_Props = {
2
+ uuids: string[];
3
+ bundlesWithPublish: string[];
4
+ bundlesWithUnpublish: string[];
5
+ };
6
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
+ close: () => any;
8
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ onClose?: (() => any) | undefined;
10
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ export default _default;
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <PluginItemAction
3
+ id="block-scheduler"
4
+ :title="$t('manageSchedule', 'Manage schedule...')"
5
+ :disabled
6
+ multiple
7
+ edit-only
8
+ meta
9
+ :weight="1e3"
10
+ :class="{
11
+ 'bk-has-schedule': selectionHasDates
12
+ }"
13
+ @click="onClick"
14
+ >
15
+ <template #icon>
16
+ <div class="bk-schedule-action-icon">
17
+ <Icon name="calendar" class="bk-item-action-icon" />
18
+ <Icon
19
+ v-if="selectionHasDates"
20
+ name="check"
21
+ class="bk-schedule-action-icon-check"
22
+ />
23
+ </div>
24
+ </template>
25
+ </PluginItemAction>
26
+ <Teleport to="body">
27
+ <BlokkliTransition name="slide-up">
28
+ <SchedulerDialog
29
+ v-if="isVisible"
30
+ :uuids="selectedUuids"
31
+ :bundles-with-publish="bundlesWithPublish"
32
+ :bundles-with-unpublish="bundlesWithUnpublish"
33
+ @close="onClose"
34
+ />
35
+ </BlokkliTransition>
36
+ </Teleport>
37
+ </template>
38
+
39
+ <script setup>
40
+ import { useBlokkli, defineBlokkliFeature, computed, ref } from "#imports";
41
+ import { PluginItemAction } from "#blokkli/plugins";
42
+ import { BlokkliTransition, Icon } from "#blokkli/components";
43
+ import SchedulerDialog from "./Dialog/index.vue";
44
+ defineBlokkliFeature({
45
+ id: "block-scheduler",
46
+ icon: "calendar",
47
+ label: "Block Scheduler",
48
+ description: "Adds support for scheduling blocks.",
49
+ requiredAdapterMethods: ["setBlockScheduleDate"]
50
+ });
51
+ const { $t, state, selection, types } = useBlokkli();
52
+ const bundlesWithPublish = computed(
53
+ () => types.generallyAvailableBundles.filter((v) => v.hasPublishOn).map((v) => v.id)
54
+ );
55
+ const bundlesWithUnpublish = computed(
56
+ () => types.generallyAvailableBundles.filter((v) => v.hasUnpublishOn).map((v) => v.id)
57
+ );
58
+ const selectedUuids = ref([]);
59
+ const isVisible = computed(() => {
60
+ return !!selectedUuids.value.length;
61
+ });
62
+ const selectionHasDates = computed(() => {
63
+ for (let i = 0; i < selection.uuids.value.length; i++) {
64
+ const uuid = selection.uuids.value[i];
65
+ if (!uuid) {
66
+ continue;
67
+ }
68
+ const block = state.getFieldListItem(uuid);
69
+ if (!block) {
70
+ continue;
71
+ }
72
+ if (block.editContext?.publishOn || block.editContext?.unpublishOn) {
73
+ return true;
74
+ }
75
+ }
76
+ return false;
77
+ });
78
+ const disabled = computed(() => {
79
+ const hasSupport = selection.bundles.value.some(
80
+ (bundle) => bundlesWithPublish.value.includes(bundle) || bundlesWithUnpublish.value.includes(bundle)
81
+ );
82
+ return !hasSupport;
83
+ });
84
+ function onClick() {
85
+ selectedUuids.value = [...selection.uuids.value];
86
+ }
87
+ function onClose() {
88
+ selectedUuids.value = [];
89
+ }
90
+ </script>
91
+
92
+ <script>
93
+ export default {
94
+ name: "BlockScheduler"
95
+ };
96
+ </script>
@@ -0,0 +1,2 @@
1
+ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ export default _default;