@oxygen-cms/ui 1.9.1 → 2.1.0
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.
- package/package.json +1 -1
- package/src/CrudApi.js +39 -0
- package/src/PagesApi.js +2 -0
- package/src/PartialsApi.js +7 -0
- package/src/components/ContentResourceEdit.vue +980 -0
- package/src/components/{PageEdit.vue → PageEditWysiwyg.vue} +1 -1
- package/src/components/ResourceList.vue +8 -3
- package/src/components/VersionsDrawer.vue +386 -0
- package/src/components/content/PartialNodeView.vue +1 -1
- package/src/components/pages/CreatePageDropdown.vue +5 -5
- package/src/components/pages/PageActions.vue +67 -0
- package/src/components/pages/PageChooseParent.vue +170 -0
- package/src/components/pages/PageEdit.vue +149 -0
- package/src/components/pages/PageList.vue +1 -1
- package/src/components/{PageNestedRow.vue → pages/PageNestedRow.vue} +3 -3
- package/src/components/{PageStatusIcon.vue → pages/PageStatusIcon.vue} +1 -1
- package/src/components/{PageTable.vue → pages/PageTable.vue} +5 -5
- package/src/components/partials/CreatePartialDropdown.vue +1 -1
- package/src/components/{PartialActions.vue → partials/PartialActions.vue} +1 -1
- package/src/components/partials/PartialEdit.vue +49 -0
- package/src/components/{PartialList.vue → partials/PartialList.vue} +3 -3
- package/src/components/{PartialStatusIcon.vue → partials/PartialStatusIcon.vue} +1 -1
- package/src/components/{PartialTable.vue → partials/PartialTable.vue} +1 -1
- package/src/icons.js +11 -2
- package/src/modules/PagesPartials.js +10 -27
- package/src/components/LegacyPage.vue +0 -263
- package/src/components/PageActions.vue +0 -151
- /package/src/components/{PageNestedPagination.vue → pages/PageNestedPagination.vue} +0 -0
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
|
|
102
102
|
<script>
|
|
103
103
|
import ContentEditor from "./content/ContentEditor.vue";
|
|
104
|
-
import PagesApi from "../PagesApi";
|
|
104
|
+
import PagesApi from "../PagesApi.js";
|
|
105
105
|
import CodeEditor from "./CodeEditor.vue";
|
|
106
106
|
import {morphToNotification} from "../api.js";
|
|
107
107
|
export default {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
<b-input v-model.lazy="searchQuery" rounded :placeholder="'Search ' + displayName" icon="search" icon-pack="fas" class="mr-3"></b-input>
|
|
12
12
|
|
|
13
|
-
<component
|
|
14
|
-
|
|
13
|
+
<component :is="createDropdownComponent"
|
|
14
|
+
v-if="!inTrash"
|
|
15
15
|
class="mr-3"
|
|
16
16
|
@created="fetchData" />
|
|
17
17
|
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
<component :is="tableComponent" :paginated-items="paginatedItems" :on-page-change="page => paginatedItems.currentPage = page" :detailed="!searchQuery" :on-sort="onSort">
|
|
26
26
|
<template #actions="slotProps">
|
|
27
27
|
<div class="buttons" style="min-width: 18rem">
|
|
28
|
-
<
|
|
28
|
+
<b-button v-if="hasView" rounded icon-left="eye" tag="router-link" :to="{ path: '/' + routePrefix + '/' + slotProps.row.id, query: { fullscreen: 'true', fullPage: 'true', mode: 'preview', versions: 'false' } }" size="is-small">View</b-button>
|
|
29
29
|
<b-button rounded icon-left="pencil-alt" tag="router-link" :to="'/' + routePrefix + '/' + slotProps.row.id" size="is-small">Edit</b-button>
|
|
30
|
+
<component :is="actionsComponent" :item="slotProps.row" @update="updateItem" @reload="fetchData"></component>
|
|
30
31
|
<b-button
|
|
31
32
|
v-if="inTrash" rounded outlined icon-left="recycle"
|
|
32
33
|
size="is-small" @click="restoreItem(slotProps.row.id)">Restore
|
|
@@ -68,6 +69,10 @@ export default {
|
|
|
68
69
|
createDropdownComponent: {
|
|
69
70
|
type: Object,
|
|
70
71
|
required: true
|
|
72
|
+
},
|
|
73
|
+
hasView: {
|
|
74
|
+
type: Boolean,
|
|
75
|
+
default: true
|
|
71
76
|
}
|
|
72
77
|
},
|
|
73
78
|
data() {
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<transition name="slide-right">
|
|
3
|
+
<div v-if="active" class="versions-drawer">
|
|
4
|
+
<div class="drawer-overlay" @click="close"></div>
|
|
5
|
+
<div class="drawer-content">
|
|
6
|
+
<div class="drawer-header px-4 py-3 has-background-light" style="border-bottom: 1px solid #dbdbdb;">
|
|
7
|
+
<div class="is-flex is-align-items-center">
|
|
8
|
+
<h2 class="title is-5 mb-0 is-flex-grow-1">Version History</h2>
|
|
9
|
+
<b-button icon-left="times" size="is-small" @click="close">Close</b-button>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="drawer-body is-relative">
|
|
14
|
+
<b-loading :active="versionsLoading" :is-full-page="false"></b-loading>
|
|
15
|
+
|
|
16
|
+
<div v-if="!versionsLoading && versions.length === 0" class="has-text-centered py-6 has-text-grey">
|
|
17
|
+
No versions found
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div v-for="version in versions" :key="version.id" class="version-row px-4 py-3" :class="{ 'is-current': isHeadVersion(version), 'is-editing': version.id === currentVersionId }">
|
|
21
|
+
<div class="is-flex is-align-items-start">
|
|
22
|
+
<div class="is-flex-grow-1">
|
|
23
|
+
<div class="is-flex is-align-items-center mb-1">
|
|
24
|
+
<strong>{{ version.title }}</strong>
|
|
25
|
+
<b-tag v-if="version.id === currentVersionId" type="is-primary" size="is-small" class="ml-2">
|
|
26
|
+
<span class="ml-1">This version</span>
|
|
27
|
+
</b-tag>
|
|
28
|
+
<b-tag v-if="isHeadVersion(version)" type="is-success" size="is-small" class="ml-2" icon="star">
|
|
29
|
+
Latest
|
|
30
|
+
</b-tag>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="is-size-7 has-text-grey">
|
|
33
|
+
<span v-if="version.updatedBy">{{ version.updatedBy.fullName }} • </span>
|
|
34
|
+
{{ formatDateTime(version.updatedAt) }}
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<b-field class="is-flex" style="gap: 0.25rem;">
|
|
39
|
+
<p v-if="hasPublish" class="control">
|
|
40
|
+
<b-button
|
|
41
|
+
icon-left="globe-asia"
|
|
42
|
+
size="is-small"
|
|
43
|
+
:disabled="version.stage == publishedStage"
|
|
44
|
+
@click="publishVersion(version)"
|
|
45
|
+
>
|
|
46
|
+
{{ version.stage == publishedStage ? 'Published' : 'Publish' }}
|
|
47
|
+
</b-button></p>
|
|
48
|
+
|
|
49
|
+
<p class="control">
|
|
50
|
+
<b-button icon-left="eye" size="is-small" @click="viewVersion(version)">
|
|
51
|
+
View
|
|
52
|
+
</b-button></p>
|
|
53
|
+
|
|
54
|
+
<p class="control">
|
|
55
|
+
<b-button
|
|
56
|
+
v-if="version.id !== currentVersionId"
|
|
57
|
+
icon-left="pencil-alt"
|
|
58
|
+
size="is-small"
|
|
59
|
+
@click="editVersion(version)"
|
|
60
|
+
>
|
|
61
|
+
Edit
|
|
62
|
+
</b-button></p>
|
|
63
|
+
|
|
64
|
+
<p class="control">
|
|
65
|
+
<b-dropdown
|
|
66
|
+
:disabled="shouldDisableDropdown(version)"
|
|
67
|
+
position="is-bottom-left"
|
|
68
|
+
aria-role="menu">
|
|
69
|
+
<template #trigger>
|
|
70
|
+
<b-button icon-left="bars" size="is-small"></b-button>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<!-- SLOT: Resource-specific actions (e.g., "View on Site" for pages) -->
|
|
74
|
+
<slot
|
|
75
|
+
name="version-dropdown-actions"
|
|
76
|
+
:version="version"
|
|
77
|
+
:is-published="version.stage === publishedStage"
|
|
78
|
+
></slot>
|
|
79
|
+
|
|
80
|
+
<b-dropdown-item
|
|
81
|
+
v-if="!isHeadVersion(version)"
|
|
82
|
+
aria-role="menuitem"
|
|
83
|
+
@click="makeHeadVersion(version)"
|
|
84
|
+
>
|
|
85
|
+
<b-icon icon="arrow-up"></b-icon>
|
|
86
|
+
Promote to Latest Version
|
|
87
|
+
</b-dropdown-item>
|
|
88
|
+
|
|
89
|
+
<b-dropdown-item
|
|
90
|
+
v-if="!isHeadVersion(version) && !version.deletedAt"
|
|
91
|
+
aria-role="menuitem"
|
|
92
|
+
@click="deleteVersion(version)"
|
|
93
|
+
>
|
|
94
|
+
<b-icon icon="trash"></b-icon>
|
|
95
|
+
Delete Version
|
|
96
|
+
</b-dropdown-item>
|
|
97
|
+
|
|
98
|
+
<b-dropdown-item
|
|
99
|
+
v-if="version.deletedAt"
|
|
100
|
+
aria-role="menuitem"
|
|
101
|
+
@click="forceDeleteVersion(version)"
|
|
102
|
+
>
|
|
103
|
+
<b-icon icon="trash"></b-icon>
|
|
104
|
+
Delete Forever
|
|
105
|
+
</b-dropdown-item>
|
|
106
|
+
|
|
107
|
+
<b-dropdown-item
|
|
108
|
+
v-if="version.deletedAt"
|
|
109
|
+
aria-role="menuitem"
|
|
110
|
+
@click="restoreVersion(version)"
|
|
111
|
+
>
|
|
112
|
+
<b-icon icon="recycle"></b-icon>
|
|
113
|
+
Restore Version
|
|
114
|
+
</b-dropdown-item>
|
|
115
|
+
</b-dropdown>
|
|
116
|
+
</p>
|
|
117
|
+
</b-field>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</transition>
|
|
124
|
+
</template>
|
|
125
|
+
|
|
126
|
+
<script>
|
|
127
|
+
export default {
|
|
128
|
+
name: "VersionsDrawer",
|
|
129
|
+
props: {
|
|
130
|
+
active: {
|
|
131
|
+
type: Boolean,
|
|
132
|
+
default: false
|
|
133
|
+
},
|
|
134
|
+
resourceId: {
|
|
135
|
+
type: Number,
|
|
136
|
+
required: true
|
|
137
|
+
},
|
|
138
|
+
currentVersionId: {
|
|
139
|
+
type: Number,
|
|
140
|
+
default: null
|
|
141
|
+
},
|
|
142
|
+
resourceApi: {
|
|
143
|
+
type: Object,
|
|
144
|
+
required: true
|
|
145
|
+
},
|
|
146
|
+
publishedStage: {
|
|
147
|
+
type: Number,
|
|
148
|
+
required: false,
|
|
149
|
+
default: null
|
|
150
|
+
},
|
|
151
|
+
hasVersionActions: {
|
|
152
|
+
type: Boolean,
|
|
153
|
+
default: false // e.g., true for pages (View on Site), false for partials
|
|
154
|
+
},
|
|
155
|
+
hasPublish: {
|
|
156
|
+
type: Boolean,
|
|
157
|
+
default: true // Whether this resource type supports publish functionality
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
data() {
|
|
161
|
+
return {
|
|
162
|
+
versions: [],
|
|
163
|
+
versionsLoading: false
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
watch: {
|
|
167
|
+
active(newVal) {
|
|
168
|
+
if (newVal) {
|
|
169
|
+
this.loadVersions();
|
|
170
|
+
}
|
|
171
|
+
this.$emit('update:active', newVal);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
mounted() {
|
|
175
|
+
// Load versions if drawer is active on initial mount (e.g., from URL query param)
|
|
176
|
+
if (this.active) {
|
|
177
|
+
this.loadVersions();
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
methods: {
|
|
181
|
+
shouldDisableDropdown(version) {
|
|
182
|
+
const isHead = this.isHeadVersion(version);
|
|
183
|
+
const isPublished = this.hasPublish && this.publishedStage !== null && version.stage === this.publishedStage;
|
|
184
|
+
const isDeleted = version.deletedAt;
|
|
185
|
+
|
|
186
|
+
// Disable if head version that's not published and not deleted (original behavior, only if has publish)
|
|
187
|
+
if (this.hasPublish && isHead && !isPublished && !isDeleted) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Also disable if no actions will be available
|
|
192
|
+
const hasPromoteAction = !isHead;
|
|
193
|
+
const hasRestoreAction = isDeleted;
|
|
194
|
+
const hasDeleteAction = !isHead && !isDeleted;
|
|
195
|
+
const hasForceDeleteAction = isDeleted;
|
|
196
|
+
const hasSlotActions = this.hasVersionActions && (!this.hasPublish || isPublished);
|
|
197
|
+
|
|
198
|
+
const hasAnyAction = hasPromoteAction || hasRestoreAction || hasDeleteAction || hasForceDeleteAction || hasSlotActions;
|
|
199
|
+
|
|
200
|
+
return !hasAnyAction;
|
|
201
|
+
},
|
|
202
|
+
async loadVersions() {
|
|
203
|
+
this.versionsLoading = true;
|
|
204
|
+
try {
|
|
205
|
+
const response = await this.resourceApi.listVersions(this.resourceId);
|
|
206
|
+
this.versions = response.items || [];
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error('Failed to load versions:', error);
|
|
209
|
+
} finally {
|
|
210
|
+
this.versionsLoading = false;
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
close() {
|
|
214
|
+
this.$emit('update:active', false);
|
|
215
|
+
},
|
|
216
|
+
isHeadVersion(version) {
|
|
217
|
+
return version.headVersion === null;
|
|
218
|
+
},
|
|
219
|
+
formatDateTime(dateString) {
|
|
220
|
+
const date = new Date(dateString);
|
|
221
|
+
return date.toLocaleString();
|
|
222
|
+
},
|
|
223
|
+
async publishVersion(version) {
|
|
224
|
+
this.$emit('publish', version.id);
|
|
225
|
+
await this.loadVersions();
|
|
226
|
+
},
|
|
227
|
+
viewVersion(version) {
|
|
228
|
+
// Open in fullscreen preview mode with full page layout, close versions drawer
|
|
229
|
+
this.$emit('navigate', version.id, {
|
|
230
|
+
fullscreen: true,
|
|
231
|
+
fullPage: true,
|
|
232
|
+
mode: 'preview',
|
|
233
|
+
versions: false
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
editVersion(version) {
|
|
237
|
+
const options = {};
|
|
238
|
+
|
|
239
|
+
// Only force preview mode for non-head versions (historical versions)
|
|
240
|
+
if (!this.isHeadVersion(version)) {
|
|
241
|
+
options.mode = 'preview';
|
|
242
|
+
}
|
|
243
|
+
// For head versions, don't set mode - let the component use user's default preference
|
|
244
|
+
|
|
245
|
+
this.$emit('navigate', version.id, options);
|
|
246
|
+
// Don't close the drawer - the parent will handle navigation with query param
|
|
247
|
+
},
|
|
248
|
+
async makeHeadVersion(version) {
|
|
249
|
+
this.$buefy.dialog.confirm({
|
|
250
|
+
message: `Promote this version to the latest version? The existing 'latest' will become a historical version instead.`,
|
|
251
|
+
confirmText: 'Make Current',
|
|
252
|
+
type: 'is-warning',
|
|
253
|
+
onConfirm: async () => {
|
|
254
|
+
this.$emit('make-head', version.id);
|
|
255
|
+
await this.loadVersions();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
async deleteVersion(version) {
|
|
260
|
+
// Soft delete - no confirmation needed
|
|
261
|
+
try {
|
|
262
|
+
await this.resourceApi.delete(version.id);
|
|
263
|
+
this.$buefy.toast.open({
|
|
264
|
+
message: 'Version deleted successfully',
|
|
265
|
+
type: 'is-success'
|
|
266
|
+
});
|
|
267
|
+
await this.loadVersions();
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error('Failed to delete version:', error);
|
|
270
|
+
this.$buefy.toast.open({
|
|
271
|
+
message: 'Failed to delete version',
|
|
272
|
+
type: 'is-danger'
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
async forceDeleteVersion(version) {
|
|
277
|
+
// Permanent delete - uses confirmForceDelete which has built-in confirmation
|
|
278
|
+
await this.resourceApi.confirmForceDelete(version.id);
|
|
279
|
+
await this.loadVersions();
|
|
280
|
+
},
|
|
281
|
+
async restoreVersion(version) {
|
|
282
|
+
try {
|
|
283
|
+
await this.resourceApi.restoreAndNotify(version.id);
|
|
284
|
+
await this.loadVersions();
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error('Failed to restore version:', error);
|
|
287
|
+
this.$buefy.toast.open({
|
|
288
|
+
message: 'Failed to restore version',
|
|
289
|
+
type: 'is-danger'
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
</script>
|
|
296
|
+
|
|
297
|
+
<style scoped lang="scss">
|
|
298
|
+
@import "../styles/_variables.scss";
|
|
299
|
+
.versions-drawer {
|
|
300
|
+
position: fixed;
|
|
301
|
+
top: 0;
|
|
302
|
+
left: 0;
|
|
303
|
+
right: 0;
|
|
304
|
+
bottom: 0;
|
|
305
|
+
z-index: 40;
|
|
306
|
+
pointer-events: none;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.drawer-overlay {
|
|
310
|
+
position: absolute;
|
|
311
|
+
top: 0;
|
|
312
|
+
left: 0;
|
|
313
|
+
right: 0;
|
|
314
|
+
bottom: 0;
|
|
315
|
+
background: rgba(0, 0, 0, 0.5);
|
|
316
|
+
pointer-events: all;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.drawer-content {
|
|
320
|
+
position: absolute;
|
|
321
|
+
top: 0;
|
|
322
|
+
right: 0;
|
|
323
|
+
bottom: 0;
|
|
324
|
+
width: 700px;
|
|
325
|
+
max-width: 90vw;
|
|
326
|
+
background: white;
|
|
327
|
+
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
|
|
328
|
+
display: flex;
|
|
329
|
+
flex-direction: column;
|
|
330
|
+
pointer-events: all;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.drawer-header {
|
|
334
|
+
flex-shrink: 0;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.drawer-body {
|
|
338
|
+
flex: 1;
|
|
339
|
+
overflow-y: auto;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.version-row {
|
|
343
|
+
border-bottom: 1px solid #f5f5f5;
|
|
344
|
+
transition: background-color 0.2s;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.version-row:hover {
|
|
348
|
+
background-color: #fafafa;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.version-row.is-current {
|
|
352
|
+
background-color: $success-light;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.version-row.is-current:not(.is-editing) {
|
|
356
|
+
border-left: 4px solid $success;
|
|
357
|
+
padding-left: calc(1rem - 4px);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.version-row.is-editing {
|
|
361
|
+
background-color: $info-light;
|
|
362
|
+
border-left: 4px solid $info;
|
|
363
|
+
padding-left: calc(1rem - 4px);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/* Slide transition from right */
|
|
367
|
+
.slide-right-enter-active,
|
|
368
|
+
.slide-right-leave-active {
|
|
369
|
+
transition: transform 0.3s ease;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.slide-right-enter-active .drawer-overlay,
|
|
373
|
+
.slide-right-leave-active .drawer-overlay {
|
|
374
|
+
transition: opacity 0.3s ease;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.slide-right-enter .drawer-content,
|
|
378
|
+
.slide-right-leave-to .drawer-content {
|
|
379
|
+
transform: translateX(100%);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.slide-right-enter .drawer-overlay,
|
|
383
|
+
.slide-right-leave-to .drawer-overlay {
|
|
384
|
+
opacity: 0;
|
|
385
|
+
}
|
|
386
|
+
</style>
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
import { nodeViewProps, NodeViewWrapper } from '@tiptap/vue-2'
|
|
89
89
|
import ContentEditor from "./ContentEditor.vue";
|
|
90
90
|
import PartialsApi from "../../PartialsApi.js";
|
|
91
|
-
import PartialList from "../PartialList.vue";
|
|
91
|
+
import PartialList from "../partials/PartialList.vue";
|
|
92
92
|
|
|
93
93
|
export default {
|
|
94
94
|
name: "PartialNodeView",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
<span style="flex: 1;">
|
|
65
65
|
<strong>{{ selectedParent.title }}</strong> - {{ selectedParent.slug }}
|
|
66
66
|
</span>
|
|
67
|
-
<a
|
|
67
|
+
<a style="color: #f14668; cursor: pointer; margin-left: 0.5rem;" @click.stop="clearSelectedParent">
|
|
68
68
|
<b-icon icon="times" size="is-small"></b-icon>
|
|
69
69
|
</a>
|
|
70
70
|
</div>
|
|
@@ -97,9 +97,6 @@ export default {
|
|
|
97
97
|
default: false
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
|
-
created() {
|
|
101
|
-
this.fetchPages();
|
|
102
|
-
},
|
|
103
100
|
data() {
|
|
104
101
|
return {
|
|
105
102
|
title: '',
|
|
@@ -125,6 +122,9 @@ export default {
|
|
|
125
122
|
watch: {
|
|
126
123
|
'parentSearchQuery': 'fetchPages'
|
|
127
124
|
},
|
|
125
|
+
created() {
|
|
126
|
+
this.fetchPages();
|
|
127
|
+
},
|
|
128
128
|
methods: {
|
|
129
129
|
slugifyTitle(str) {
|
|
130
130
|
return slugify(str);
|
|
@@ -173,7 +173,7 @@ export default {
|
|
|
173
173
|
this.$buefy.toast.open(morphToNotification(response));
|
|
174
174
|
this.close();
|
|
175
175
|
this.$emit('created', response.item);
|
|
176
|
-
this.$router.push('/pages/' + response.item.id
|
|
176
|
+
this.$router.push('/pages/' + response.item.id);
|
|
177
177
|
} catch(e) {
|
|
178
178
|
// Error handled by API layer
|
|
179
179
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="page-actions">
|
|
3
|
+
<b-button v-if="item.stage !== STAGE_PUBLISHED" rounded size="is-small" icon-left="globe-asia" class="mr-2" @click="publish">Publish</b-button>
|
|
4
|
+
|
|
5
|
+
<b-button rounded size="is-small" icon-left="folder-open" class="mr-2" @click="isMoveModalActive = true">Move</b-button>
|
|
6
|
+
|
|
7
|
+
<b-modal v-model="isMoveModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal>
|
|
8
|
+
<div class="modal-card choose-parent-modal" style="width: 640px">
|
|
9
|
+
<header class="modal-card-head">
|
|
10
|
+
<p class="modal-card-title">Move "{{ item.title }}"</p>
|
|
11
|
+
<button type="button" class="delete" @click="isMoveModalActive = false"/>
|
|
12
|
+
</header>
|
|
13
|
+
<section class="modal-card-body choose-parent-modal-body">
|
|
14
|
+
<PageChooseParent
|
|
15
|
+
:current-parent-id="item.parent"
|
|
16
|
+
:exclude-page-id="item.id"
|
|
17
|
+
label="Parent Page"
|
|
18
|
+
@select="setParentPage"
|
|
19
|
+
/>
|
|
20
|
+
</section>
|
|
21
|
+
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
|
|
22
|
+
<b-button label="Close" @click="isMoveModalActive = false" />
|
|
23
|
+
</footer>
|
|
24
|
+
</div>
|
|
25
|
+
</b-modal>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script>
|
|
30
|
+
import PagesApi from "../../PagesApi.js";
|
|
31
|
+
import {morphToNotification} from "../../api.js";
|
|
32
|
+
import PageChooseParent from "./PageChooseParent.vue";
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
name: "PageActions",
|
|
36
|
+
components: { PageChooseParent },
|
|
37
|
+
props: {
|
|
38
|
+
item: { type: Object, required: true }
|
|
39
|
+
},
|
|
40
|
+
data() {
|
|
41
|
+
return {
|
|
42
|
+
STAGE_PUBLISHED: PagesApi.STAGE_PUBLISHED,
|
|
43
|
+
pagesApi: new PagesApi(),
|
|
44
|
+
isMoveModalActive: false
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
methods: {
|
|
48
|
+
async publish() {
|
|
49
|
+
let item = await this.pagesApi.publish(this.item.id);
|
|
50
|
+
this.$emit('update', item);
|
|
51
|
+
},
|
|
52
|
+
async setParentPage(parentPage) {
|
|
53
|
+
let data = await this.pagesApi.update({id: this.item.id, parent: parentPage.id, autoConvertToDraft: 'no', version: false});
|
|
54
|
+
this.$buefy.toast.open(morphToNotification(data));
|
|
55
|
+
this.isMoveModalActive = false;
|
|
56
|
+
this.$emit('reload');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
<style scoped>
|
|
64
|
+
.choose-parent-modal, .choose-parent-modal-body{
|
|
65
|
+
overflow: visible;
|
|
66
|
+
}
|
|
67
|
+
</style>
|