@tailor-cms/tce-preview-runtime 0.4.0-beta.2 → 0.4.0-beta.4
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 +4 -3
- package/src/App.vue +44 -8
- package/src/components/AppBar.vue +1 -1
- package/src/components/BottomPanel.vue +88 -12
- package/src/components/MainLayout.vue +5 -1
- package/src/components/MutationList.vue +39 -0
- package/src/components/PreviewPanel.vue +0 -2
- package/src/components/SplashLoader.vue +2 -2
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-cms/tce-preview-runtime",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.4",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@mdi/font": "7.2.96",
|
|
6
6
|
"@vitejs/plugin-vue": "4.3.4",
|
|
7
7
|
"@vueuse/core": "10.4.1",
|
|
8
|
+
"date-fns": "^3.2.0",
|
|
8
9
|
"ky": "1.0.1",
|
|
9
10
|
"lodash": "^4.17.21",
|
|
10
11
|
"sass": "1.68.0",
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
"vue": "3.3.4",
|
|
16
17
|
"vue-tsc": "1.8.13",
|
|
17
18
|
"vue3-ts-jsoneditor": "2.9.0",
|
|
18
|
-
"vuetify": "3.
|
|
19
|
+
"vuetify": "3.4.0"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"@tailor-cms/eslint-config": "0.0.2"
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
"dev": "vite",
|
|
28
29
|
"build": "vue-tsc --noEmit && vite build",
|
|
29
30
|
"serve": "vite preview",
|
|
30
|
-
"lint": "eslint --ext .
|
|
31
|
+
"lint": "eslint --ext .ts,.vue .",
|
|
31
32
|
"lint:fix": "pnpm lint --fix"
|
|
32
33
|
}
|
|
33
34
|
}
|
package/src/App.vue
CHANGED
|
@@ -5,17 +5,33 @@ import ky from 'ky';
|
|
|
5
5
|
import AppBar from './components/AppBar.vue';
|
|
6
6
|
import MainLayout from './components/MainLayout.vue';
|
|
7
7
|
|
|
8
|
+
interface ContentElement {
|
|
9
|
+
id: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
const appUrl = new URL(window.location.href);
|
|
9
13
|
const apiPrefix = '/tce-server';
|
|
10
14
|
const api = ky.create({ prefixUrl: apiPrefix });
|
|
11
15
|
const wsProtocol = appUrl.protocol === 'http:' ? 'ws:' : 'wss:';
|
|
12
16
|
const ws = new WebSocket(`${wsProtocol}//${appUrl.host}${apiPrefix}`);
|
|
13
17
|
|
|
14
|
-
const element = ref(
|
|
18
|
+
const element = ref<ContentElement>();
|
|
19
|
+
const userState = ref({});
|
|
20
|
+
|
|
15
21
|
onMounted(async () => {
|
|
16
|
-
element
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
const { element: elementVal, userState: userStateVal } = await getElement();
|
|
23
|
+
element.value = elementVal;
|
|
24
|
+
userState.value = userStateVal;
|
|
25
|
+
ws.addEventListener('message', (message) => {
|
|
26
|
+
const event = JSON.parse(message.data);
|
|
27
|
+
const elementId = element.value?.id;
|
|
28
|
+
if (elementId && elementId !== event.entityId) return;
|
|
29
|
+
if (event.type === 'userState:update') {
|
|
30
|
+
userState.value = event.payload;
|
|
31
|
+
}
|
|
32
|
+
if (event.type === 'element:update') {
|
|
33
|
+
element.value = event.payload;
|
|
34
|
+
}
|
|
19
35
|
});
|
|
20
36
|
});
|
|
21
37
|
|
|
@@ -23,10 +39,9 @@ function timeout(ms: number) {
|
|
|
23
39
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
24
40
|
}
|
|
25
41
|
|
|
26
|
-
async function getElement() {
|
|
42
|
+
async function getElement(): Promise<any> {
|
|
27
43
|
try {
|
|
28
|
-
|
|
29
|
-
return response?.element || {};
|
|
44
|
+
return api('content-element').json();
|
|
30
45
|
} catch (error) {
|
|
31
46
|
console.log('Error on element get', error);
|
|
32
47
|
await timeout(2000);
|
|
@@ -34,12 +49,33 @@ async function getElement() {
|
|
|
34
49
|
return getElement();
|
|
35
50
|
}
|
|
36
51
|
}
|
|
52
|
+
|
|
53
|
+
async function resetElement() {
|
|
54
|
+
const id = element.value?.id;
|
|
55
|
+
if (!id) return;
|
|
56
|
+
await resetState();
|
|
57
|
+
const path = `content-element/${id}/reset-element`;
|
|
58
|
+
return api.post(path);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function resetState() {
|
|
62
|
+
const id = element.value?.id;
|
|
63
|
+
if (!id) return;
|
|
64
|
+
const path = `content-element/${id}/reset-state`;
|
|
65
|
+
return api.post(path);
|
|
66
|
+
}
|
|
37
67
|
</script>
|
|
38
68
|
|
|
39
69
|
<template>
|
|
40
70
|
<v-app>
|
|
41
71
|
<AppBar />
|
|
42
|
-
<MainLayout
|
|
72
|
+
<MainLayout
|
|
73
|
+
:element="element"
|
|
74
|
+
:user-state="userState"
|
|
75
|
+
class="mt-14"
|
|
76
|
+
@reset-element="resetElement"
|
|
77
|
+
@reset-state="resetState"
|
|
78
|
+
/>
|
|
43
79
|
</v-app>
|
|
44
80
|
</template>
|
|
45
81
|
|
|
@@ -1,26 +1,75 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-show="isLoaded">
|
|
3
|
-
<v-tabs
|
|
4
|
-
<v-tab
|
|
3
|
+
<v-tabs v-model="state.selectedTab">
|
|
4
|
+
<v-tab :value="1">
|
|
5
|
+
<VChip append-icon="mdi-pen" class="mr-2" color="indigo" size="small">
|
|
6
|
+
{{ state.elementHistory.length }}
|
|
7
|
+
</VChip>
|
|
8
|
+
Authoring history
|
|
9
|
+
</v-tab>
|
|
10
|
+
<v-tab :value="2">
|
|
11
|
+
<VChip
|
|
12
|
+
append-icon="mdi-account"
|
|
13
|
+
class="mr-2"
|
|
14
|
+
color="green"
|
|
15
|
+
size="small"
|
|
16
|
+
>
|
|
17
|
+
{{ state.userInteractions.length }}
|
|
18
|
+
</VChip>
|
|
19
|
+
End-User state history
|
|
20
|
+
</v-tab>
|
|
5
21
|
</v-tabs>
|
|
6
22
|
<div class="pa-6">
|
|
7
|
-
<
|
|
8
|
-
v-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
23
|
+
<v-window v-model="state.selectedTab">
|
|
24
|
+
<v-window-item :value="1">
|
|
25
|
+
<VBtn
|
|
26
|
+
class="mb-4"
|
|
27
|
+
color="indigo-darken-4"
|
|
28
|
+
variant="tonal"
|
|
29
|
+
@click="$emit('resetElement')"
|
|
30
|
+
>
|
|
31
|
+
<VIcon class="mr-2 left">mdi-refresh</VIcon>
|
|
32
|
+
Reset content element
|
|
33
|
+
</VBtn>
|
|
34
|
+
<MutationList :changes="state.elementHistory" />
|
|
35
|
+
</v-window-item>
|
|
36
|
+
<v-window-item :value="2">
|
|
37
|
+
<VBtn
|
|
38
|
+
class="mb-4"
|
|
39
|
+
color="indigo-darken-4"
|
|
40
|
+
variant="tonal"
|
|
41
|
+
@click="$emit('resetState')"
|
|
42
|
+
>
|
|
43
|
+
<VIcon class="mr-2 left">mdi-refresh</VIcon>
|
|
44
|
+
Reset state context
|
|
45
|
+
</VBtn>
|
|
46
|
+
<MutationList :changes="state.userInteractions" />
|
|
47
|
+
</v-window-item>
|
|
48
|
+
</v-window>
|
|
14
49
|
</div>
|
|
15
50
|
</div>
|
|
16
51
|
</template>
|
|
17
52
|
|
|
18
53
|
<script setup lang="ts">
|
|
19
|
-
import
|
|
54
|
+
import { reactive, watch } from 'vue';
|
|
55
|
+
import { format as formatDate } from 'date-fns';
|
|
20
56
|
|
|
21
|
-
|
|
57
|
+
import MutationList from './MutationList.vue';
|
|
22
58
|
|
|
23
|
-
|
|
59
|
+
defineEmits(['resetElement', 'resetState']);
|
|
60
|
+
const props = defineProps<{
|
|
61
|
+
isLoaded: Boolean;
|
|
62
|
+
element: any;
|
|
63
|
+
userState: any;
|
|
64
|
+
}>();
|
|
65
|
+
|
|
66
|
+
const state = reactive({
|
|
67
|
+
selectedTab: 1,
|
|
68
|
+
elementHistory: [] as any[],
|
|
69
|
+
userInteractions: [] as any[],
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const orderContentElementKeys = (val: any) => {
|
|
24
73
|
return [
|
|
25
74
|
'id',
|
|
26
75
|
'uid',
|
|
@@ -41,4 +90,31 @@ const orderKeys = (val: any) => {
|
|
|
41
90
|
return acc;
|
|
42
91
|
}, {});
|
|
43
92
|
};
|
|
93
|
+
|
|
94
|
+
watch(
|
|
95
|
+
() => props.element,
|
|
96
|
+
(val) => {
|
|
97
|
+
if (val.updatedAt === state.elementHistory[0]?.data?.updatedAt) return;
|
|
98
|
+
state.elementHistory.unshift({
|
|
99
|
+
id: state.elementHistory.length,
|
|
100
|
+
title: formatDate(val.updatedAt, 'HH:mm:ss'),
|
|
101
|
+
data: orderContentElementKeys(val),
|
|
102
|
+
});
|
|
103
|
+
state.selectedTab = 1;
|
|
104
|
+
},
|
|
105
|
+
{ deep: true },
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
watch(
|
|
109
|
+
() => props.userState,
|
|
110
|
+
(val) => {
|
|
111
|
+
state.userInteractions.unshift({
|
|
112
|
+
id: state.userInteractions.length,
|
|
113
|
+
title: formatDate(new Date(), 'HH:mm:ss'),
|
|
114
|
+
data: val,
|
|
115
|
+
});
|
|
116
|
+
state.selectedTab = 2;
|
|
117
|
+
},
|
|
118
|
+
{ deep: true },
|
|
119
|
+
);
|
|
44
120
|
</script>
|
|
@@ -7,7 +7,8 @@ import PreviewPanel from './PreviewPanel.vue';
|
|
|
7
7
|
import SplashLoader from './SplashLoader.vue';
|
|
8
8
|
import { useGlobalState } from '../state';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
defineEmits(['resetElement', 'resetState']);
|
|
11
|
+
const props = defineProps<{ element: any; userState: any }>();
|
|
11
12
|
|
|
12
13
|
const { isDark } = useGlobalState();
|
|
13
14
|
const isLoaded = ref(false);
|
|
@@ -51,7 +52,10 @@ onMounted(() => {
|
|
|
51
52
|
id="panelBottom"
|
|
52
53
|
:element="props.element"
|
|
53
54
|
:is-loaded="isLoaded"
|
|
55
|
+
:user-state="props.userState"
|
|
54
56
|
class="preview-panel-bottom"
|
|
57
|
+
@reset-element="$emit('resetElement')"
|
|
58
|
+
@reset-state="$emit('resetState')"
|
|
55
59
|
/>
|
|
56
60
|
</main>
|
|
57
61
|
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VDataIterator :items="changes" :items-per-page="50" expand-on-click>
|
|
3
|
+
<template #default="{ items, isExpanded, toggleExpand }">
|
|
4
|
+
<template v-for="(item, index) in items" :key="item.raw.id">
|
|
5
|
+
<v-card
|
|
6
|
+
:disabled="index === 0"
|
|
7
|
+
:ripple="false"
|
|
8
|
+
class="mb-1"
|
|
9
|
+
@click="toggleExpand(item)"
|
|
10
|
+
>
|
|
11
|
+
<v-card-title class="d-flex align-center">
|
|
12
|
+
<v-icon color="orange-darken-3" icon="mdi-update" size="18" start />
|
|
13
|
+
<div class="text-body-1">{{ item.raw.title }}</div>
|
|
14
|
+
</v-card-title>
|
|
15
|
+
<v-card-text v-if="isExpanded(item) || index === 0">
|
|
16
|
+
<JsonEditor
|
|
17
|
+
:main-menu-bar="false"
|
|
18
|
+
:status-bar="false"
|
|
19
|
+
:value="item.raw.data"
|
|
20
|
+
mode="text"
|
|
21
|
+
/>
|
|
22
|
+
</v-card-text>
|
|
23
|
+
</v-card>
|
|
24
|
+
</template>
|
|
25
|
+
</template>
|
|
26
|
+
</VDataIterator>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import JsonEditor from 'vue3-ts-jsoneditor';
|
|
31
|
+
|
|
32
|
+
defineProps<{ changes: any[] }>();
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<style scoped lang="scss">
|
|
36
|
+
.v-card--disabled > :not(.v-card__loader) {
|
|
37
|
+
opacity: 1 !important;
|
|
38
|
+
}
|
|
39
|
+
</style>
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
:src="VITE_EDIT_RUNTIME_URL"
|
|
7
7
|
class="flex-1-1-100"
|
|
8
8
|
frameBorder="0"
|
|
9
|
-
sandbox="allow-scripts"
|
|
10
9
|
title="Edit component container"
|
|
11
10
|
>
|
|
12
11
|
</iframe>
|
|
@@ -17,7 +16,6 @@
|
|
|
17
16
|
:src="VITE_DISPLAY_RUNTIME_URL"
|
|
18
17
|
class="flex-1-1-100"
|
|
19
18
|
frameBorder="0"
|
|
20
|
-
sandbox="allow-scripts"
|
|
21
19
|
title="Display component container"
|
|
22
20
|
>
|
|
23
21
|
</iframe>
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
<img :src="logo" alt="Logo" width="88" />
|
|
7
7
|
</div>
|
|
8
8
|
<div class="splash-loader__text text-body-1">
|
|
9
|
-
<div>Booting
|
|
9
|
+
<div>Booting Content Element Kit....</div>
|
|
10
10
|
<v-progress-linear
|
|
11
11
|
v-if="isFirstBoot"
|
|
12
12
|
:model-value="progress"
|
|
13
13
|
class="my-3"
|
|
14
14
|
/>
|
|
15
|
-
<div class="font-weight-bold">Beta preview v0.
|
|
15
|
+
<div class="font-weight-bold">Beta preview v0.4.0</div>
|
|
16
16
|
</div>
|
|
17
17
|
</div>
|
|
18
18
|
</div>
|