@live-change/content-frontend 0.2.5 → 0.2.6
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/front/src/components/MetadataEditor.vue +57 -0
- package/front/src/components/PageEditor.vue +33 -10
- package/package.json +10 -10
- package/server/init.js +68 -56
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<auto-input v-model="editable.title" :definition="properties.title" />
|
|
3
|
+
|
|
4
|
+
</template>
|
|
5
|
+
|
|
6
|
+
<script setup>
|
|
7
|
+
|
|
8
|
+
import AutoInput from '@live-change/frontend-auto-form/AutoInput.vue'
|
|
9
|
+
|
|
10
|
+
import { computed, watch, ref, onMounted, inject } from 'vue'
|
|
11
|
+
import { toRefs } from "@vueuse/core"
|
|
12
|
+
|
|
13
|
+
const isMounted = ref(false)
|
|
14
|
+
onMounted(() => isMounted.value = true)
|
|
15
|
+
|
|
16
|
+
const props = defineProps({
|
|
17
|
+
objectType: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true
|
|
20
|
+
},
|
|
21
|
+
object: {
|
|
22
|
+
type: String,
|
|
23
|
+
required: true
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const { objectType, object } = props
|
|
28
|
+
|
|
29
|
+
import { useApi, path, live } from '@live-change/vue3-ssr'
|
|
30
|
+
const api = useApi()
|
|
31
|
+
const p = path()
|
|
32
|
+
|
|
33
|
+
const definition = api.getServiceDefinition('content').models.Metadata
|
|
34
|
+
const properties = definition.properties
|
|
35
|
+
|
|
36
|
+
import { synchronized } from "@live-change/vue3-components"
|
|
37
|
+
|
|
38
|
+
const metadata = await live(p.content.objectOwnedMetadata({ objectType, object }))
|
|
39
|
+
|
|
40
|
+
const synchronizedMetadata = synchronized({
|
|
41
|
+
source: metadata,
|
|
42
|
+
update: api.actions.content.setOrUpdateObjectOwnedMetadata,
|
|
43
|
+
identifiers: { object, objectType },
|
|
44
|
+
recursive: true,
|
|
45
|
+
autoSave: false,
|
|
46
|
+
onSave: () => toast.add({ severity: 'info', summary: 'Public access saved', life: 1500 })
|
|
47
|
+
}).value
|
|
48
|
+
|
|
49
|
+
const editable = synchronizedMetadata.value
|
|
50
|
+
const save = synchronizedMetadata.save
|
|
51
|
+
const changed = synchronizedMetadata.changed
|
|
52
|
+
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style scoped>
|
|
56
|
+
|
|
57
|
+
</style>
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Accordion v-if="pageData" :multiple="true" class="w-full">
|
|
2
|
+
<Accordion v-if="pageData" :multiple="true" class="w-full mb-2">
|
|
3
3
|
<AccordionTab>
|
|
4
4
|
<template #header>
|
|
5
5
|
<UrlsInfo targetType="content_Page" :target="pageId" class="w-full" />
|
|
6
6
|
</template>
|
|
7
7
|
<Urls :key="pageId" targetType="content_Page" :target="pageId" />
|
|
8
8
|
</AccordionTab>
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
<AccordionTab>
|
|
10
|
+
<template #header>
|
|
11
|
+
<span class="font-bold mr-1">Public access: {{ publicAccessLevel }}</span>
|
|
12
|
+
</template>
|
|
13
|
+
<AccessControl objectType="content_Page" :object="pageId" />
|
|
14
|
+
</AccordionTab>
|
|
15
|
+
<AccordionTab>
|
|
16
|
+
<template #header>
|
|
17
|
+
<span v-if="metadata" class="font-bold mr-1">Title: {{ metadata.title }}</span>
|
|
18
|
+
<span v-else class="font-bold text-red-600">Metadata not set</span>
|
|
19
|
+
</template>
|
|
20
|
+
<MetadataEditor objectType="content_Page" :object="pageId" :key="pageId"></MetadataEditor>
|
|
11
21
|
</AccordionTab>
|
|
12
|
-
<AccordionTab header="Header III">
|
|
13
|
-
Content
|
|
14
|
-
</AccordionTab>-->
|
|
15
22
|
</Accordion>
|
|
16
23
|
|
|
17
24
|
<DocumentEditor v-if="pageData" targetType="content_Page" :target="pageId"
|
|
@@ -25,7 +32,7 @@
|
|
|
25
32
|
class="p-button p-component p-button-sm p-button-outlined p-button-secondary cursor-auto inline-block"
|
|
26
33
|
:class="{ 'p-disabled': saveState == 'saving' }">
|
|
27
34
|
<span class="pi p-button-icon p-button-icon-left"
|
|
28
|
-
:class="[
|
|
35
|
+
:class="[saveState == 'saving' ? 'pi-sync' : 'pi-hashtag' ]" />
|
|
29
36
|
<span class="p-button-label">{{ ( version ?? 0 ).toFixed().padStart(10, '0') }}</span>
|
|
30
37
|
</button>
|
|
31
38
|
<Button icon="pi pi-save" label="Publish" class="p-button-success p-button-sm" type="button"
|
|
@@ -46,6 +53,8 @@
|
|
|
46
53
|
|
|
47
54
|
import { UrlsInfo, Urls, NotFound } from '@live-change/url-frontend'
|
|
48
55
|
import { DocumentEditor, EditorMenu } from "@live-change/wysiwyg-frontend"
|
|
56
|
+
import { AccessControl } from '@live-change/access-control-frontend'
|
|
57
|
+
import MetadataEditor from "./MetadataEditor.vue"
|
|
49
58
|
import contentConfig from "./contentConfig.js";
|
|
50
59
|
|
|
51
60
|
import { computed, watch, ref, onMounted, inject } from 'vue'
|
|
@@ -88,11 +97,26 @@
|
|
|
88
97
|
const liveCanonicalUrlPath = computed(
|
|
89
98
|
() => p.url.targetOwnedCanonical({ targetType: 'content_Page', target: pageId.value })
|
|
90
99
|
)
|
|
91
|
-
const
|
|
100
|
+
const livePublicAccessPath = computed(
|
|
101
|
+
() => p.accessControl.objectOwnedPublicAccess({ objectType: 'content_Page', object: pageId.value })
|
|
102
|
+
)
|
|
103
|
+
const liveMetadataPath = computed(
|
|
104
|
+
() => p.content.objectOwnedMetadata({ objectType: 'content_Page', object: pageId.value })
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const [pageData, canonicalUrlData, publicAccessData, metadata] = await Promise.all([
|
|
92
108
|
live(livePagePath),
|
|
93
|
-
live(liveCanonicalUrlPath)
|
|
109
|
+
live(liveCanonicalUrlPath),
|
|
110
|
+
live(livePublicAccessPath),
|
|
111
|
+
live(liveMetadataPath)
|
|
94
112
|
])
|
|
95
113
|
|
|
114
|
+
const publicAccessLevel = computed(() => {
|
|
115
|
+
if(publicAccessData?.sessionRoles?.includes('reader')) return 'session'
|
|
116
|
+
if(publicAccessData?.userRoles?.includes('reader')) return 'user'
|
|
117
|
+
return 'none'
|
|
118
|
+
})
|
|
119
|
+
|
|
96
120
|
function publish() {
|
|
97
121
|
const snapshotVersion = version.value
|
|
98
122
|
|
|
@@ -116,7 +140,6 @@
|
|
|
116
140
|
}
|
|
117
141
|
})
|
|
118
142
|
|
|
119
|
-
|
|
120
143
|
}
|
|
121
144
|
|
|
122
145
|
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/content-frontend",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"memDev": "lcli memDev --enableSessions --initScript ./init.js --dbAccess",
|
|
6
6
|
"localDevInit": "rm tmp.db; lcli localDev --enableSessions --initScript ./init.js",
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@fortawesome/fontawesome-free": "^6.1.1",
|
|
24
|
-
"@live-change/cli": "0.7.
|
|
25
|
-
"@live-change/dao": "0.5.
|
|
26
|
-
"@live-change/dao-vue3": "0.5.
|
|
27
|
-
"@live-change/dao-websocket": "0.5.
|
|
28
|
-
"@live-change/framework": "0.7.
|
|
29
|
-
"@live-change/image-service": "0.3.
|
|
30
|
-
"@live-change/session-service": "0.3.
|
|
24
|
+
"@live-change/cli": "0.7.4",
|
|
25
|
+
"@live-change/dao": "0.5.8",
|
|
26
|
+
"@live-change/dao-vue3": "0.5.8",
|
|
27
|
+
"@live-change/dao-websocket": "0.5.8",
|
|
28
|
+
"@live-change/framework": "0.7.4",
|
|
29
|
+
"@live-change/image-service": "0.3.2",
|
|
30
|
+
"@live-change/session-service": "0.3.2",
|
|
31
31
|
"@live-change/vue3-components": "0.2.15",
|
|
32
32
|
"@live-change/vue3-ssr": "0.2.15",
|
|
33
33
|
"@tiptap/extension-highlight": "^2.0.0-beta.33",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"vue3-scroll-border": "0.1.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@live-change/codeceptjs-helper": "0.7.
|
|
57
|
+
"@live-change/codeceptjs-helper": "0.7.4",
|
|
58
58
|
"@wdio/selenium-standalone-service": "^7.20.8",
|
|
59
59
|
"codeceptjs": "^3.3.4",
|
|
60
60
|
"generate-password": "1.7.0",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"author": "",
|
|
67
67
|
"license": "ISC",
|
|
68
68
|
"description": "",
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "323185f6d910912093b3c92df102d0f938cef367"
|
|
70
70
|
}
|
package/server/init.js
CHANGED
|
@@ -3,67 +3,70 @@ const App = require('@live-change/framework')
|
|
|
3
3
|
const app = App.app()
|
|
4
4
|
|
|
5
5
|
module.exports = async function(services) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
async function createPage(pageId) {
|
|
7
|
+
const documentId = App.encodeIdentifier(['content_Page', pageId])
|
|
8
|
+
const snapshotId = App.encodeIdentifier([documentId, (0).toFixed().padStart(10, '0')])
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const documentContent = {
|
|
11
|
+
"type": "doc",
|
|
12
|
+
"content": [].concat(new Array(2).fill(
|
|
13
|
+
{
|
|
14
|
+
"type": "paragraph",
|
|
15
|
+
"content": [
|
|
16
|
+
{
|
|
17
|
+
"type": "text",
|
|
18
|
+
"text": "test"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "text",
|
|
22
|
+
"marks": [
|
|
23
|
+
{
|
|
24
|
+
"type": "bold"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"text": "est"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
))
|
|
32
|
+
}
|
|
33
|
+
const documentTime = new Date()
|
|
12
34
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
"type": "paragraph",
|
|
18
|
-
"content": [
|
|
19
|
-
{
|
|
20
|
-
"type": "text",
|
|
21
|
-
"text": "test"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"type": "text",
|
|
25
|
-
"marks": [
|
|
26
|
-
{
|
|
27
|
-
"type": "bold"
|
|
28
|
-
}
|
|
29
|
-
],
|
|
30
|
-
"text": "est"
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
))
|
|
35
|
-
}
|
|
36
|
-
const documentTime = new Date()
|
|
35
|
+
await services.content.models.Page.create({
|
|
36
|
+
id: pageId
|
|
37
|
+
})
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
await services.prosemirror.models.Document.create({
|
|
40
|
+
id: documentId,
|
|
41
|
+
ownerType: 'content_Page',
|
|
42
|
+
owner: pageId,
|
|
43
|
+
type: 'content',
|
|
44
|
+
purpose: 'page',
|
|
45
|
+
version: 1,
|
|
46
|
+
content: documentContent,
|
|
47
|
+
created: documentTime,
|
|
48
|
+
lastModified: documentTime
|
|
49
|
+
})
|
|
50
|
+
await services.prosemirror.models.Snapshot.create({
|
|
51
|
+
id: snapshotId,
|
|
52
|
+
document: documentId,
|
|
53
|
+
version: 1,
|
|
54
|
+
content: documentContent,
|
|
55
|
+
timestamp: documentTime,
|
|
56
|
+
})
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
content: documentContent,
|
|
50
|
-
created: documentTime,
|
|
51
|
-
lastModified: documentTime
|
|
52
|
-
})
|
|
53
|
-
await services.prosemirror.models.Snapshot.create({
|
|
54
|
-
id: snapshotId,
|
|
55
|
-
document: documentId,
|
|
56
|
-
version: 1,
|
|
57
|
-
content: documentContent,
|
|
58
|
-
timestamp: documentTime,
|
|
59
|
-
})
|
|
58
|
+
await services.content.models.Content.create({
|
|
59
|
+
id: documentId,
|
|
60
|
+
objectType: 'content_Page',
|
|
61
|
+
object: pageId,
|
|
62
|
+
snapshot: snapshotId
|
|
63
|
+
})
|
|
64
|
+
}
|
|
60
65
|
|
|
61
|
-
await services
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
snapshot: snapshotId
|
|
66
|
-
})
|
|
66
|
+
const user1 = await createUser(services,
|
|
67
|
+
'Test User 1', 'test1@test.com', 'Testy123', 'u1', ['writer', 'administrator'])
|
|
68
|
+
|
|
69
|
+
await createPage('one')
|
|
67
70
|
|
|
68
71
|
await services.accessControl.models.PublicAccess.create({
|
|
69
72
|
id: App.encodeIdentifier(['content_Page', 'one']),
|
|
@@ -93,4 +96,13 @@ module.exports = async function(services) {
|
|
|
93
96
|
target: 'one'
|
|
94
97
|
})
|
|
95
98
|
|
|
99
|
+
await createPage('two')
|
|
100
|
+
|
|
101
|
+
await services.url.models.Canonical.create({
|
|
102
|
+
id: App.encodeIdentifier(['content_Page', 'two']),
|
|
103
|
+
domain: '',
|
|
104
|
+
path: 'test2',
|
|
105
|
+
targetType: 'content_Page',
|
|
106
|
+
target: 'two'
|
|
107
|
+
})
|
|
96
108
|
}
|