@crombolo/backoffice-host 0.10.0 → 0.12.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.
- package/package.json +2 -2
- package/plugin/addresses-dashboard.js +100 -0
- package/plugin/assistant/umbraco-package.json +1 -1
- package/plugin/audit-dashboard.js +369 -0
- package/plugin/changes-dashboard.js +245 -8
- package/plugin/forms-client.js +7 -0
- package/plugin/forms-entries.js +2 -1
- package/plugin/forms-layout.js +128 -0
- package/plugin/forms-overview.js +484 -134
- package/plugin/localizations/umbraco-package.json +1 -1
- package/plugin/report-client.js +21 -0
- package/plugin/seo/umbraco-package.json +1 -1
- package/plugin/tsx-editors.js +5 -5
- package/plugin/umbraco-package.json +53 -1
- package/plugin/webhook-storage.js +107 -0
- package/plugin/welcome-dashboard.js +1 -1
package/plugin/report-client.js
CHANGED
|
@@ -11,3 +11,24 @@ export async function fetchReport() {
|
|
|
11
11
|
if (!response.ok) throw new Error(`change report responded ${response.status}`)
|
|
12
12
|
return response.json()
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
const apiBase = () =>
|
|
16
|
+
`${(document.querySelector('base')?.getAttribute('href') ?? '/umbraco/').replace(/\/$/, '')}/crombolo/api`
|
|
17
|
+
|
|
18
|
+
/** Where a pending import's answers download as the file the bundle can carry. */
|
|
19
|
+
export const answersUrl = (bundleId) =>
|
|
20
|
+
`${apiBase()}/transfers/${encodeURIComponent(bundleId)}/resolutions`
|
|
21
|
+
|
|
22
|
+
/** Answers, re-checks or imports a pending content bundle; the body says how it went. */
|
|
23
|
+
export async function transferAction(bundleId, verb, body = {}) {
|
|
24
|
+
const response = await fetch(`${apiBase()}/transfers/${encodeURIComponent(bundleId)}/${verb}`, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
credentials: 'include',
|
|
27
|
+
headers: { accept: 'application/json', 'content-type': 'application/json' },
|
|
28
|
+
body: JSON.stringify(body),
|
|
29
|
+
})
|
|
30
|
+
const result = await response.json().catch(() => ({}))
|
|
31
|
+
if (response.status === 403)
|
|
32
|
+
return { ok: false, message: 'You are not allowed to import content.' }
|
|
33
|
+
return { ok: response.ok, ...result }
|
|
34
|
+
}
|
package/plugin/tsx-editors.js
CHANGED
|
@@ -73,11 +73,11 @@ export function withLayout(content, alias) {
|
|
|
73
73
|
export const TSX = 'tsx'
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* The virtual directory a view is opened in. It mirrors `
|
|
77
|
-
* a view's `../schema/content-types.d.ts` resolves in the editor exactly as
|
|
78
|
-
* resolves for `tsc`.
|
|
76
|
+
* The virtual directory a view is opened in. It mirrors `components/` on disk so
|
|
77
|
+
* that a view's `../schema/content-types.d.ts` resolves in the editor exactly as
|
|
78
|
+
* it resolves for `tsc`.
|
|
79
79
|
*/
|
|
80
|
-
const
|
|
80
|
+
const COMPONENTS = 'file:///components'
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* `bundler` module resolution, which is what the site's tsconfig uses and what
|
|
@@ -226,7 +226,7 @@ function teachDialect(editors) {
|
|
|
226
226
|
const model = monaco.editor.createModel(
|
|
227
227
|
created.getValue(),
|
|
228
228
|
'typescript',
|
|
229
|
-
monaco.Uri.parse(`${
|
|
229
|
+
monaco.Uri.parse(`${COMPONENTS}/view-${++opened}.tsx`),
|
|
230
230
|
)
|
|
231
231
|
editor.setModel(model)
|
|
232
232
|
created.dispose()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../backoffice-dist/dist/umbraco-package-schema.json",
|
|
3
3
|
"name": "Crombolo",
|
|
4
4
|
"id": "Crombolo.Core",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.12.1",
|
|
6
6
|
"allowPublicAccess": false,
|
|
7
7
|
"extensions": [
|
|
8
8
|
{
|
|
@@ -62,6 +62,41 @@
|
|
|
62
62
|
}
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
|
+
{
|
|
66
|
+
"type": "workspaceView",
|
|
67
|
+
"alias": "Crombolo.WorkspaceView.Webhook.Storage",
|
|
68
|
+
"name": "Crombolo Webhook Storage View",
|
|
69
|
+
"element": "/crombolo-plugin/webhook-storage.js",
|
|
70
|
+
"weight": 100,
|
|
71
|
+
"meta": {
|
|
72
|
+
"label": "Where it's kept",
|
|
73
|
+
"pathname": "where-kept",
|
|
74
|
+
"icon": "icon-box"
|
|
75
|
+
},
|
|
76
|
+
"conditions": [
|
|
77
|
+
{
|
|
78
|
+
"alias": "Umb.Condition.WorkspaceAlias",
|
|
79
|
+
"match": "Umb.Workspace.Webhook"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "dashboard",
|
|
85
|
+
"alias": "Crombolo.Dashboard.Addresses",
|
|
86
|
+
"name": "Crombolo Page Addresses Dashboard",
|
|
87
|
+
"element": "/crombolo-plugin/addresses-dashboard.js",
|
|
88
|
+
"weight": 6,
|
|
89
|
+
"meta": {
|
|
90
|
+
"label": "Page addresses",
|
|
91
|
+
"pathname": "addresses"
|
|
92
|
+
},
|
|
93
|
+
"conditions": [
|
|
94
|
+
{
|
|
95
|
+
"alias": "Umb.Condition.SectionAlias",
|
|
96
|
+
"match": "Umb.Section.Settings"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
65
100
|
{
|
|
66
101
|
"type": "dashboard",
|
|
67
102
|
"alias": "Crombolo.Dashboard.Changes",
|
|
@@ -79,6 +114,23 @@
|
|
|
79
114
|
}
|
|
80
115
|
]
|
|
81
116
|
},
|
|
117
|
+
{
|
|
118
|
+
"type": "dashboard",
|
|
119
|
+
"alias": "Crombolo.Dashboard.AuditLog",
|
|
120
|
+
"name": "Crombolo Audit Log Dashboard",
|
|
121
|
+
"element": "/crombolo-plugin/audit-dashboard.js",
|
|
122
|
+
"weight": 4,
|
|
123
|
+
"meta": {
|
|
124
|
+
"label": "Audit log",
|
|
125
|
+
"pathname": "audit-log"
|
|
126
|
+
},
|
|
127
|
+
"conditions": [
|
|
128
|
+
{
|
|
129
|
+
"alias": "Umb.Condition.SectionAlias",
|
|
130
|
+
"match": "Umb.Section.Settings"
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
},
|
|
82
134
|
{
|
|
83
135
|
"type": "dashboard",
|
|
84
136
|
"alias": "Crombolo.Dashboard.Welcome",
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Where it's kept", on a webhook's screen: with the site's files, or in this
|
|
3
|
+
* environment only. Moving one is the server's decision to allow; this shows
|
|
4
|
+
* what it said and asks it. docs/webhooks.md.
|
|
5
|
+
*/
|
|
6
|
+
import { css, html, nothing } from '@umbraco-cms/backoffice/external/lit'
|
|
7
|
+
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'
|
|
8
|
+
import { UMB_WEBHOOK_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/webhook'
|
|
9
|
+
|
|
10
|
+
const base = () =>
|
|
11
|
+
`${(document.querySelector('base')?.getAttribute('href') ?? '/umbraco/').replace(/\/$/, '')}/crombolo/api/webhooks`
|
|
12
|
+
|
|
13
|
+
const PLACES = {
|
|
14
|
+
files: {
|
|
15
|
+
label: "With the site's files",
|
|
16
|
+
detail:
|
|
17
|
+
'Kept in the site’s code and deployed with it. A header that holds a secret names a server setting instead, written as env:NAME.',
|
|
18
|
+
},
|
|
19
|
+
database: {
|
|
20
|
+
label: 'In this environment only',
|
|
21
|
+
detail: 'Kept on this site alone, not in its code. A secret may be typed into a header.',
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default class CromboloWebhookStorageElement extends UmbLitElement {
|
|
26
|
+
static properties = {
|
|
27
|
+
_state: { state: true },
|
|
28
|
+
_busy: { state: true },
|
|
29
|
+
_message: { state: true },
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#unique
|
|
33
|
+
|
|
34
|
+
constructor() {
|
|
35
|
+
super()
|
|
36
|
+
this._state = undefined
|
|
37
|
+
this._busy = false
|
|
38
|
+
this._message = ''
|
|
39
|
+
this.consumeContext(UMB_WEBHOOK_WORKSPACE_CONTEXT, (context) => {
|
|
40
|
+
this.observe(context?.unique, (unique) => {
|
|
41
|
+
this.#unique = unique
|
|
42
|
+
this.#load()
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async #load() {
|
|
48
|
+
if (!this.#unique) return
|
|
49
|
+
const response = await fetch(`${base()}/${encodeURIComponent(this.#unique)}/store`, {
|
|
50
|
+
credentials: 'include',
|
|
51
|
+
headers: { accept: 'application/json' },
|
|
52
|
+
})
|
|
53
|
+
this._state = response.ok ? await response.json() : { missing: true }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async #move(store) {
|
|
57
|
+
this._busy = true
|
|
58
|
+
this._message = ''
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(`${base()}/${encodeURIComponent(this.#unique)}/store`, {
|
|
61
|
+
method: 'PUT',
|
|
62
|
+
credentials: 'include',
|
|
63
|
+
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
64
|
+
body: JSON.stringify({ store }),
|
|
65
|
+
})
|
|
66
|
+
const body = await response.json().catch(() => ({}))
|
|
67
|
+
if (!response.ok)
|
|
68
|
+
this._message = [body.reason, ...(body.problems ?? [])].filter(Boolean).join(' ')
|
|
69
|
+
await this.#load()
|
|
70
|
+
} finally {
|
|
71
|
+
this._busy = false
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
render() {
|
|
76
|
+
const state = this._state
|
|
77
|
+
if (!state) return html`<uui-box><uui-loader></uui-loader></uui-box>`
|
|
78
|
+
if (state.missing)
|
|
79
|
+
return html`<uui-box><p>Save the webhook first, then choose where it is kept.</p></uui-box>`
|
|
80
|
+
const other = state.store === 'files' ? 'database' : 'files'
|
|
81
|
+
return html`<uui-box headline="Where it's kept">
|
|
82
|
+
<p><strong>${PLACES[state.store].label}.</strong> ${PLACES[state.store].detail}</p>
|
|
83
|
+
${
|
|
84
|
+
state.available[other]
|
|
85
|
+
? html`<uui-button
|
|
86
|
+
look="secondary"
|
|
87
|
+
?disabled=${this._busy}
|
|
88
|
+
label=${`Keep it ${PLACES[other].label.toLowerCase()}`}
|
|
89
|
+
@click=${() => this.#move(other)}
|
|
90
|
+
>Keep it ${PLACES[other].label.toLowerCase()}</uui-button>`
|
|
91
|
+
: html`<p class="fine">${state.unavailable[other]}</p>`
|
|
92
|
+
}
|
|
93
|
+
${this._message ? html`<p class="problem" role="alert">${this._message}</p>` : nothing}
|
|
94
|
+
</uui-box>`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static styles = css`
|
|
98
|
+
.fine {
|
|
99
|
+
color: var(--uui-color-text-alt, #555);
|
|
100
|
+
}
|
|
101
|
+
.problem {
|
|
102
|
+
color: var(--uui-color-danger, #b00);
|
|
103
|
+
}
|
|
104
|
+
`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
customElements.define('crombolo-webhook-storage', CromboloWebhookStorageElement)
|
|
@@ -19,7 +19,7 @@ const STEPS = [
|
|
|
19
19
|
{
|
|
20
20
|
title: 'Write a template',
|
|
21
21
|
body: html`Templates are <strong>TSX</strong>, not Razor. A template is a file in
|
|
22
|
-
<code>
|
|
22
|
+
<code>components/</code> that default-exports a component and receives the page as
|
|
23
23
|
<code>model</code>; <code>export const layout = 'alias'</code> names its master.
|
|
24
24
|
The editor under Settings → Templates writes that shape for you.`,
|
|
25
25
|
},
|