@crombolo/backoffice-host 0.13.1 → 0.14.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.
Files changed (53) hide show
  1. package/assets/login.js +89 -2
  2. package/package.json +2 -2
  3. package/plugin/assistant/umbraco-package.json +1 -1
  4. package/plugin/branding/branding.js +9 -14
  5. package/plugin/branding/bundle-builder-labels.js +30 -1
  6. package/plugin/branding/localization-en.js +8 -0
  7. package/plugin/branding/sign-in.js +31 -0
  8. package/plugin/branding/theme.css +2 -0
  9. package/plugin/bundles-created-overview.js +31 -18
  10. package/plugin/bundles-installed.js +127 -61
  11. package/plugin/bundles-marketplace.js +1 -1
  12. package/plugin/changes-dashboard.js +8 -1
  13. package/plugin/download.js +19 -0
  14. package/plugin/form-picker.js +1 -1
  15. package/plugin/forms-client.js +5 -0
  16. package/plugin/forms-entries.js +30 -16
  17. package/plugin/forms-overview.js +55 -33
  18. package/plugin/localizations/ar.js +3 -39
  19. package/plugin/localizations/bs.js +3 -29
  20. package/plugin/localizations/cs.js +3 -24
  21. package/plugin/localizations/cy.js +3 -32
  22. package/plugin/localizations/da.js +3 -41
  23. package/plugin/localizations/de.js +3 -27
  24. package/plugin/localizations/es.js +3 -19
  25. package/plugin/localizations/fr.js +3 -26
  26. package/plugin/localizations/hr.js +3 -29
  27. package/plugin/localizations/it.js +3 -29
  28. package/plugin/localizations/ja.js +3 -11
  29. package/plugin/localizations/ko.js +3 -11
  30. package/plugin/localizations/nb.js +3 -18
  31. package/plugin/localizations/nl.js +3 -29
  32. package/plugin/localizations/pl.js +3 -11
  33. package/plugin/localizations/pt-br.js +0 -10
  34. package/plugin/localizations/pt.js +3 -39
  35. package/plugin/localizations/ru.js +3 -9
  36. package/plugin/localizations/sv.js +3 -20
  37. package/plugin/localizations/tr.js +3 -26
  38. package/plugin/localizations/uk.js +3 -9
  39. package/plugin/localizations/umbraco-package.json +22 -2
  40. package/plugin/localizations/vi.js +3 -42
  41. package/plugin/localizations/zh-tw.js +0 -6
  42. package/plugin/localizations/zh.js +0 -6
  43. package/plugin/seo/umbraco-package.json +1 -1
  44. package/plugin/sign-in/entry.js +20 -0
  45. package/plugin/sign-in/sign-in-dialog.js +127 -0
  46. package/plugin/sign-in/umbraco-package.json +15 -0
  47. package/plugin/two-factor-setup.js +147 -0
  48. package/plugin/umbraco-package.json +30 -30
  49. package/plugin/welcome-dashboard.js +2 -5
  50. package/plugin/workflow-designer.js +298 -187
  51. package/plugin/workflow-requests.js +19 -6
  52. package/src/shell.ts +4 -1
  53. package/plugin/branding/sysinfo.js +0 -89
@@ -1,9 +1,10 @@
1
1
  /**
2
- * The Workflow section's lists (story 028): what waits for the reader's
2
+ * The Workflows section's lists (story 028): what waits for the reader's
3
3
  * approval, every request in flight, and those decided. Each row links to the
4
4
  * page, whose Workflow tab is where a request is acted on.
5
5
  */
6
- import { css, html, LitElement, nothing } from '@umbraco-cms/backoffice/external/lit'
6
+ import { css, html, nothing } from '@umbraco-cms/backoffice/external/lit'
7
+ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'
7
8
  import { finished, inFlight, waitingForMe } from './workflow-client.js'
8
9
 
9
10
  const STATE = {
@@ -13,15 +14,27 @@ const STATE = {
13
14
  withdrawn: ['default', 'Withdrawn'],
14
15
  }
15
16
 
16
- const pageLink = (key) => {
17
+ /** The page's Workflow tab: the editor's route is `edit/<key>/<variant>/view/<tab>`. */
18
+ const pageLink = (item) => {
17
19
  const base = (document.querySelector('base')?.getAttribute('href') ?? '/umbraco/').replace(
18
20
  /\/$/,
19
21
  '',
20
22
  )
21
- return `${base}/section/content/workspace/document/edit/${key}/view/workflow`
23
+ return `${base}/section/content/workspace/document/edit/${item.nodeKey}/${encodeURIComponent(item.variant ?? 'invariant')}/view/workflow`
22
24
  }
23
25
 
24
- class CromboloWorkflowListElement extends LitElement {
26
+ /**
27
+ * Navigates within the backoffice, as Umbraco's own code does, so the page
28
+ * opens on its Workflow tab without reloading the app. A modified click still
29
+ * opens a new tab.
30
+ */
31
+ function openInBackoffice(event, href) {
32
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0) return
33
+ event.preventDefault()
34
+ history.pushState(null, '', href)
35
+ }
36
+
37
+ class CromboloWorkflowListElement extends UmbLitElement {
25
38
  static properties = {
26
39
  _items: { state: true },
27
40
  _message: { state: true },
@@ -76,7 +89,7 @@ class CromboloWorkflowListElement extends LitElement {
76
89
  const [color, label] = STATE[item.state] ?? ['default', item.state]
77
90
  const waiting = item.stages.filter((s) => s.state === 'waiting').map((s) => s.alias)
78
91
  return html`<uui-table-row>
79
- <uui-table-cell><a href=${pageLink(item.nodeKey)}>${item.nodeName}</a></uui-table-cell>
92
+ <uui-table-cell><a href=${pageLink(item)} @click=${(e) => openInBackoffice(e, pageLink(item))}>${item.nodeName}</a></uui-table-cell>
80
93
  <uui-table-cell>${item.workflow.name}</uui-table-cell>
81
94
  <uui-table-cell>${item.action === 'unpublish' ? 'Taking it down' : 'Publishing'}</uui-table-cell>
82
95
  <uui-table-cell>
package/src/shell.ts CHANGED
@@ -34,6 +34,8 @@ export interface LoginShellSettings {
34
34
  * the browser resumes the OAuth flow rather than landing on a blank editor.
35
35
  */
36
36
  returnUrl?: string
37
+ /** "Sign in with …" buttons, one per backoffice identity provider (story 031). */
38
+ externalProviders?: ReadonlyArray<{ name: string; url: string }>
37
39
  }
38
40
 
39
41
  const escapeHtml = (value: string): string =>
@@ -131,7 +133,8 @@ ${noscript(`${graphics}/login-logo-alternative`)}
131
133
  ${settings.usernameIsEmail ? 'username-is-email' : ''}
132
134
  ${settings.allowUserInvite ? 'allow-user-invite' : ''}
133
135
  ${settings.allowPasswordReset ? 'allow-password-reset' : ''}
134
- ${settings.disableLocalLogin ? 'disable-local-login' : ''}>
136
+ ${settings.disableLocalLogin ? 'disable-local-login' : ''}
137
+ external-providers="${escapeHtml(JSON.stringify(settings.externalProviders ?? []))}">
135
138
  </crombolo-login>
136
139
  </body>
137
140
  </html>
@@ -1,89 +0,0 @@
1
- /**
2
- * The System information modal, reached from the header logo popover.
3
- *
4
- * It names the product in four places that no localisation key covers: three
5
- * row labels built as plain strings in `sysinfo.element.js`, and the heading it
6
- * puts above the text it copies to the clipboard.
7
- *
8
- * The rows are corrected at their source rather than in the DOM. The element
9
- * assembles every row into one string and assigns it to `_systemInformation`, a
10
- * lit reactive property, so wrapping that property's setter corrects the rows
11
- * before they are ever rendered — no observer, and no reaching into a shadow
12
- * root. The clipboard heading is prepended inside a private method that nothing
13
- * can reach, so that one is taken on the way out to the clipboard instead.
14
- */
15
-
16
- /**
17
- * The exact phrases to correct. Spelled out rather than replacing the product
18
- * name wherever it appears, because the same text carries the browser's user
19
- * agent and the current URL — a blanket replacement would rewrite whatever a
20
- * site happens to have in its address.
21
- */
22
- const PHRASES = [
23
- 'Umbraco build version',
24
- 'Umbraco assembly version',
25
- 'Umbraco client version',
26
- 'Umbraco system information',
27
- ]
28
-
29
- /** A fixed point: its own output contains none of the phrases, so re-applying it changes nothing. */
30
- export function rebrandSysinfo(text) {
31
- if (typeof text !== 'string') return text
32
- let corrected = text
33
- for (const phrase of PHRASES) {
34
- corrected = corrected.replaceAll(phrase, phrase.replace('Umbraco', 'Crombolo'))
35
- }
36
- return corrected
37
- }
38
-
39
- /** True when the string is the modal's clipboard payload rather than someone's own copy. */
40
- export function isSysinfoClipboardText(text) {
41
- return typeof text === 'string' && text.includes('Umbraco system information')
42
- }
43
-
44
- /**
45
- * Wraps the reactive property's setter. Does nothing at all if the accessor is
46
- * not where lit puts it, so an upstream change costs the correction and never
47
- * an error.
48
- */
49
- function patchRows(element) {
50
- const accessor = Object.getOwnPropertyDescriptor(element?.prototype ?? {}, '_systemInformation')
51
- if (!accessor?.get || !accessor?.set) return false
52
- Object.defineProperty(element.prototype, '_systemInformation', {
53
- ...accessor,
54
- get() {
55
- return accessor.get.call(this)
56
- },
57
- set(value) {
58
- accessor.set.call(this, rebrandSysinfo(value))
59
- },
60
- })
61
- return true
62
- }
63
-
64
- /**
65
- * Corrects the heading on its way to the clipboard. Installed only once the
66
- * modal's element exists — so a session that never opens System information
67
- * never patches anything — and it passes every other string through untouched.
68
- */
69
- function patchClipboard() {
70
- const clipboard = navigator.clipboard
71
- if (typeof clipboard?.writeText !== 'function') return
72
- const write = clipboard.writeText.bind(clipboard)
73
- try {
74
- clipboard.writeText = (text) =>
75
- write(isSysinfoClipboardText(text) ? rebrandSysinfo(text) : text)
76
- } catch {
77
- // A read-only `writeText` leaves the copied heading stale, which is the
78
- // one thing here worth less than a working copy button.
79
- }
80
- }
81
-
82
- export const onInit = () => {
83
- customElements
84
- .whenDefined('umb-sysinfo')
85
- .then((element) => {
86
- if (patchRows(element)) patchClipboard()
87
- })
88
- .catch(() => {})
89
- }