From 670c1302ce2fd3edcdff4b702a2c9015f1d81e86 Mon Sep 17 00:00:00 2001 From: rofe Date: Thu, 18 Dec 2025 15:15:52 +0100 Subject: [PATCH 01/10] fix: add org level permissions to new org --- blocks/start/start.js | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/blocks/start/start.js b/blocks/start/start.js index 6d63a06d..8edb07e4 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -125,9 +125,64 @@ class DaStart extends LitElement { async submitForm(e) { e.preventDefault(); + + // Check if this is a new org + const orgCheckResp = await daFetch(`${DA_ORIGIN}/list/${this.org}/`); + const isNewOrg = !orgCheckResp.ok; + const opts = { method: 'PUT' }; const resp = await daFetch(e.target.action, opts); if (!resp.ok) return; + + // If this is a new org, create org-level permissions + if (isNewOrg && window.adobeIMS?.isSignedInUser()) { + try { + const profile = await window.adobeIMS.getProfile(); + const { email } = profile; + + const configJson = { + data: { + total: 2, + limit: 2, + offset: 0, + data: [{ key: '', value: '' }], + ':colWidths': [169, 169], + }, + permissions: { + total: 2, + limit: 2, + offset: 0, + data: [ + { + path: 'CONFIG', + groups: email, + actions: 'write', + comments: 'The ability to set configurations for an org.', + }, + { + path: '/ + **', + groups: email, + actions: 'write', + comments: 'The ability to create content.', + }, + ], + ':colWidths': [169, 169, 169, 300], + }, + ':names': ['data', 'permissions'], + ':version': 3, + ':type': 'multi-sheet', + }; + + const body = new FormData(); + body.append('config', JSON.stringify(configJson)); + const configOpts = { method: 'PUT', body }; + await daFetch(`${DA_ORIGIN}/config/${this.org}/`, configOpts); + } catch (err) { + // eslint-disable-next-line no-console + console.error('Failed to create org permissions:', err); + } + } + this.goToNextStep(e); } From 85fd82ba5fb3a353b6531674a70dd896c9bedaf3 Mon Sep 17 00:00:00 2001 From: Alexandre Capt Date: Thu, 18 Dec 2025 16:47:40 +0100 Subject: [PATCH 02/10] feat: auto submit form if org and site are provided (#708) * feat: auto submit form if org and site are provided * chore: provide feedback if error --- blocks/start/start.css | 28 +++++++++ blocks/start/start.js | 132 +++++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 52 deletions(-) diff --git a/blocks/start/start.css b/blocks/start/start.css index 67d257c2..59909b2b 100644 --- a/blocks/start/start.css +++ b/blocks/start/start.css @@ -128,6 +128,27 @@ div.git-input input { background: #434d58; } +.go-button.is-loading { + background: #004da3; + cursor: wait; + position: relative; +} + +.go-button .spinner { + display: inline-block; + width: 18px; + height: 18px; + background: no-repeat center / 18px url('/blocks/edit/img/Smock_Refresh_18_N.svg'); + filter: brightness(0) invert(1); + animation: spin 1s linear infinite; +} + +@keyframes spin { + 100% { + transform: rotate(360deg); + } +} + div.git-input input::placeholder { font-style: italic; } @@ -141,6 +162,13 @@ div.text-container { } } +p.error-text { + color: #d73220; + font-weight: 800; + margin: 12px; + text-align: center; +} + div.template-container { display: flex; justify-content: center; diff --git a/blocks/start/start.js b/blocks/start/start.js index 8edb07e4..d8705b53 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -44,6 +44,7 @@ class DaStart extends LitElement { _goText: { state: true }, _statusText: { state: true }, _templates: { state: true }, + _loading: { state: true }, }; constructor() { @@ -52,8 +53,9 @@ class DaStart extends LitElement { this.activeStep = 1; this.org = urlParams.get('org'); this.site = urlParams.get('site'); - this.url = this.site && this.org ? `https://github.com/${this.org}/${this.site}` : ''; - this.goEnabled = this.site && this.org; + this.autoSubmit = this.site && this.org; + this.url = this.autoSubmit ? `https://github.com/${this.org}/${this.site}` : ''; + this.goEnabled = this.autoSubmit; this._demoContent = false; this._goText = 'Make something wonderful'; } @@ -64,6 +66,19 @@ class DaStart extends LitElement { this._templates = AEM_TEMPLATES; } + async firstUpdated() { + if (this.autoSubmit) { + const form = this.shadowRoot.querySelector('form'); + if (form) { + const event = { + preventDefault: () => {}, + target: form, + }; + await this.submitForm(event); + } + } + } + goToNextStep(e) { this.showOpen = false; this.showDone = false; @@ -126,61 +141,71 @@ class DaStart extends LitElement { async submitForm(e) { e.preventDefault(); - // Check if this is a new org - const orgCheckResp = await daFetch(`${DA_ORIGIN}/list/${this.org}/`); - const isNewOrg = !orgCheckResp.ok; + // Check if user is signed in + if (!window.adobeIMS?.isSignedInUser()) { + this._errorText = 'You need to sign in to create a new org.'; + return; + } + // Check if user has an email address + const { email } = await window.adobeIMS.getProfile(); + if (!email) { + this._errorText = 'Make sure your profile contains an email address.'; + return; + } + + this._loading = true; const opts = { method: 'PUT' }; - const resp = await daFetch(e.target.action, opts); - if (!resp.ok) return; - // If this is a new org, create org-level permissions - if (isNewOrg && window.adobeIMS?.isSignedInUser()) { - try { - const profile = await window.adobeIMS.getProfile(); - const { email } = profile; + // Check if this is a new org + const orgCheckResp = await daFetch(e.target.action); + if (orgCheckResp.status === 404) { + const configJson = { + data: { + total: 2, + limit: 2, + offset: 0, + data: [{ key: '', value: '' }], + ':colWidths': [169, 169], + }, + permissions: { + total: 2, + limit: 2, + offset: 0, + data: [ + { + path: 'CONFIG', + groups: email, + actions: 'write', + comments: 'The ability to set configurations for an org.', + }, + { + path: '/ + **', + groups: email, + actions: 'write', + comments: 'The ability to create content.', + }, + ], + ':colWidths': [169, 169, 169, 300], + }, + ':names': ['data', 'permissions'], + ':version': 3, + ':type': 'multi-sheet', + }; - const configJson = { - data: { - total: 2, - limit: 2, - offset: 0, - data: [{ key: '', value: '' }], - ':colWidths': [169, 169], - }, - permissions: { - total: 2, - limit: 2, - offset: 0, - data: [ - { - path: 'CONFIG', - groups: email, - actions: 'write', - comments: 'The ability to set configurations for an org.', - }, - { - path: '/ + **', - groups: email, - actions: 'write', - comments: 'The ability to create content.', - }, - ], - ':colWidths': [169, 169, 169, 300], - }, - ':names': ['data', 'permissions'], - ':version': 3, - ':type': 'multi-sheet', - }; + opts.body = new FormData(); + opts.body.append('config', JSON.stringify(configJson)); + } - const body = new FormData(); - body.append('config', JSON.stringify(configJson)); - const configOpts = { method: 'PUT', body }; - await daFetch(`${DA_ORIGIN}/config/${this.org}/`, configOpts); - } catch (err) { - // eslint-disable-next-line no-console - console.error('Failed to create org permissions:', err); + const resp = await daFetch(e.target.action, opts); + this._loading = false; + if (!resp.ok) { + if (resp.status === 401 || resp.status === 403) { + this._errorText = 'You are not authorized to create this site. Check your permissions.'; + } else { + this._errorText = 'The site could not be created. Check the console logs or contact an administrator.'; } + return; } this.goToNextStep(e); @@ -210,9 +235,12 @@ class DaStart extends LitElement { - +
+

${this._errorText ? this._errorText : nothing}

Paste your AEM codebase URL above.

Don't have one, yet? Pick a template below.

From b464cb0886f78e6b0d851b2dba32eb46655712a3 Mon Sep 17 00:00:00 2001 From: rofe Date: Fri, 19 Dec 2025 11:31:06 +0100 Subject: [PATCH 03/10] fix: add org level permissions to new org --- blocks/start/start.js | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index d8705b53..6ede7482 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -143,23 +143,23 @@ class DaStart extends LitElement { // Check if user is signed in if (!window.adobeIMS?.isSignedInUser()) { - this._errorText = 'You need to sign in to create a new org.'; - return; - } - - // Check if user has an email address - const { email } = await window.adobeIMS.getProfile(); - if (!email) { - this._errorText = 'Make sure your profile contains an email address.'; + this._errorText = 'You need to sign in first.'; return; } this._loading = true; - const opts = { method: 'PUT' }; - // Check if this is a new org - const orgCheckResp = await daFetch(e.target.action); + // Check if this is a new org and add org-level permissions + const orgUrl = e.target.action.substring(0, e.target.action.lastIndexOf('/')); + const orgCheckResp = await daFetch(orgUrl); if (orgCheckResp.status === 404) { + // Check if user has an email address + const { email } = await window.adobeIMS.getProfile(); + if (!email) { + this._errorText = 'Make sure your profile contains an email address.'; + return; + } + const configJson = { data: { total: 2, @@ -193,11 +193,19 @@ class DaStart extends LitElement { ':type': 'multi-sheet', }; - opts.body = new FormData(); - opts.body.append('config', JSON.stringify(configJson)); + const body = new FormData([['config', JSON.stringify(configJson)]]); + const orgResp = await daFetch(orgUrl, { method: 'PUT', body }); + if (!orgResp.ok) { + if (orgResp.status === 401 || orgResp.status === 403) { + this._errorText = 'You are not authorized to create this org. Check your permissions.'; + } else { + this._errorText = 'The org could not be created. Check the console logs or contact an administrator.'; + } + return; + } } - const resp = await daFetch(e.target.action, opts); + const resp = await daFetch(e.target.action, { method: 'PUT' }); this._loading = false; if (!resp.ok) { if (resp.status === 401 || resp.status === 403) { From 059b58f7b3b4b41c5cb6cdae4fe6c28e35143fa1 Mon Sep 17 00:00:00 2001 From: rofe Date: Fri, 19 Dec 2025 15:39:25 +0100 Subject: [PATCH 04/10] chore: pr feedback --- blocks/start/start.js | 70 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index 6ede7482..d12c2107 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -32,6 +32,39 @@ const AEM_TEMPLATES = [ }, ]; +const ORG_CONFIG = { + data: { + total: 2, + limit: 2, + offset: 0, + data: [{ key: '', value: '' }], + ':colWidths': [169, 169], + }, + permissions: { + total: 2, + limit: 2, + offset: 0, + data: [ + { + path: 'CONFIG', + groups: '$EMAIL$', + actions: 'write', + comments: 'The ability to set configurations for an org.', + }, + { + path: '/ + **', + groups: '$EMAIL$', + actions: 'write', + comments: 'The ability to create content.', + }, + ], + ':colWidths': [169, 169, 169, 300], + }, + ':names': ['data', 'permissions'], + ':version': 3, + ':type': 'multi-sheet', +}; + class DaStart extends LitElement { static properties = { activeStep: { state: true }, @@ -160,40 +193,9 @@ class DaStart extends LitElement { return; } - const configJson = { - data: { - total: 2, - limit: 2, - offset: 0, - data: [{ key: '', value: '' }], - ':colWidths': [169, 169], - }, - permissions: { - total: 2, - limit: 2, - offset: 0, - data: [ - { - path: 'CONFIG', - groups: email, - actions: 'write', - comments: 'The ability to set configurations for an org.', - }, - { - path: '/ + **', - groups: email, - actions: 'write', - comments: 'The ability to create content.', - }, - ], - ':colWidths': [169, 169, 169, 300], - }, - ':names': ['data', 'permissions'], - ':version': 3, - ':type': 'multi-sheet', - }; - - const body = new FormData([['config', JSON.stringify(configJson)]]); + const orgConfigJson = JSON.stringify(ORG_CONFIG).replace('$EMAIL$', email); + const body = new FormData([['config', orgConfigJson]]); + const orgResp = await daFetch(orgUrl, { method: 'PUT', body }); if (!orgResp.ok) { if (orgResp.status === 401 || orgResp.status === 403) { From 2e2e8e34947db934896c891c7fc48e7e8c359233 Mon Sep 17 00:00:00 2001 From: rofe Date: Sun, 21 Dec 2025 17:53:35 +0100 Subject: [PATCH 05/10] fix: formdata error --- blocks/start/start.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index d12c2107..2cfca736 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -194,7 +194,8 @@ class DaStart extends LitElement { } const orgConfigJson = JSON.stringify(ORG_CONFIG).replace('$EMAIL$', email); - const body = new FormData([['config', orgConfigJson]]); + const body = new FormData(); + body.append('config', orgConfigJson); const orgResp = await daFetch(orgUrl, { method: 'PUT', body }); if (!orgResp.ok) { From af143c22e3af4344563e60e6a2d44e65fa8bf48f Mon Sep 17 00:00:00 2001 From: rofe Date: Sun, 21 Dec 2025 18:00:16 +0100 Subject: [PATCH 06/10] fix: lost event target error --- blocks/start/start.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index 2cfca736..10f81bcd 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -173,6 +173,7 @@ class DaStart extends LitElement { async submitForm(e) { e.preventDefault(); + const siteUrl = e.target.action; // Check if user is signed in if (!window.adobeIMS?.isSignedInUser()) { @@ -183,7 +184,7 @@ class DaStart extends LitElement { this._loading = true; // Check if this is a new org and add org-level permissions - const orgUrl = e.target.action.substring(0, e.target.action.lastIndexOf('/')); + const orgUrl = siteUrl.substring(0, siteUrl.lastIndexOf('/')); const orgCheckResp = await daFetch(orgUrl); if (orgCheckResp.status === 404) { // Check if user has an email address @@ -208,7 +209,7 @@ class DaStart extends LitElement { } } - const resp = await daFetch(e.target.action, { method: 'PUT' }); + const resp = await daFetch(siteUrl, { method: 'PUT' }); this._loading = false; if (!resp.ok) { if (resp.status === 401 || resp.status === 403) { From 8771c7f974aa8b1cbb1927d6c6fa24905ef30626 Mon Sep 17 00:00:00 2001 From: rofe Date: Sun, 21 Dec 2025 18:04:46 +0100 Subject: [PATCH 07/10] fix: org url with slash --- blocks/start/start.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index 10f81bcd..239c2c60 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -184,7 +184,7 @@ class DaStart extends LitElement { this._loading = true; // Check if this is a new org and add org-level permissions - const orgUrl = siteUrl.substring(0, siteUrl.lastIndexOf('/')); + const orgUrl = siteUrl.substring(0, siteUrl.lastIndexOf('/') + 1); const orgCheckResp = await daFetch(orgUrl); if (orgCheckResp.status === 404) { // Check if user has an email address From 1c07a9625d5e9b1b710a597d2536690fa1822415 Mon Sep 17 00:00:00 2001 From: rofe Date: Sun, 21 Dec 2025 18:06:31 +0100 Subject: [PATCH 08/10] fix: org url without slash --- blocks/start/start.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index 239c2c60..10f81bcd 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -184,7 +184,7 @@ class DaStart extends LitElement { this._loading = true; // Check if this is a new org and add org-level permissions - const orgUrl = siteUrl.substring(0, siteUrl.lastIndexOf('/') + 1); + const orgUrl = siteUrl.substring(0, siteUrl.lastIndexOf('/')); const orgCheckResp = await daFetch(orgUrl); if (orgCheckResp.status === 404) { // Check if user has an email address From f5b77fe312f9d8a8ef9c580101e584dc0dcdc716 Mon Sep 17 00:00:00 2001 From: rofe Date: Sun, 21 Dec 2025 18:09:06 +0100 Subject: [PATCH 09/10] chore: code sync app reminder --- blocks/start/start.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index 10f81bcd..97e228af 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -273,7 +273,7 @@ class DaStart extends LitElement {
-

Don't forget the AEM Code Bot.

+

Don't forget to add the AEM Code Sync App to your repository.

`; From 017dcde57ba23e26f5db3bdf4b241d1c28d23e39 Mon Sep 17 00:00:00 2001 From: Raphael Wegmueller Date: Mon, 22 Dec 2025 17:34:21 +0100 Subject: [PATCH 10/10] fix: copy permission setting code from sandbox app (#713) --- blocks/start/start.js | 120 +++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/blocks/start/start.js b/blocks/start/start.js index 97e228af..237dcb0c 100644 --- a/blocks/start/start.js +++ b/blocks/start/start.js @@ -32,38 +32,78 @@ const AEM_TEMPLATES = [ }, ]; -const ORG_CONFIG = { - data: { - total: 2, - limit: 2, - offset: 0, - data: [{ key: '', value: '' }], - ':colWidths': [169, 169], - }, - permissions: { - total: 2, - limit: 2, - offset: 0, - data: [ - { - path: 'CONFIG', - groups: '$EMAIL$', - actions: 'write', - comments: 'The ability to set configurations for an org.', - }, - { - path: '/ + **', - groups: '$EMAIL$', - actions: 'write', - comments: 'The ability to create content.', - }, +const ORG_CONFIG = `{ + "data": { + "total": 1, + "limit": 1, + "offset": 0, + "data": [{}] + }, + "permissions": { + "total": 2, + "limit": 2, + "offset": 0, + "data": [ + { + "path": "CONFIG", + "groups": "{{EMAIL}}", + "actions": "write", + "comments": "The ability to set configurations for an org." + }, + { + "path": "/ + **", + "groups": "{{EMAIL}}", + "actions": "write", + "comments": "The ability to create content." + } + ] + }, + ":names": [ + "data", + "permissions" ], - ':colWidths': [169, 169, 169, 300], - }, - ':names': ['data', 'permissions'], - ':version': 3, - ':type': 'multi-sheet', -}; + ":version": 3, + ":type": "multi-sheet" +}`; + +async function fetchConfig(org, body) { + let opts; + if (body) opts = { method: 'POST', body }; + + return daFetch(`${DA_ORIGIN}/config/${org}/`, opts); +} + +export async function loadConfig(org) { + const resp = await fetchConfig(org); + + const result = { status: resp.status }; + + if (!resp.ok) { + if (resp.status === 403 && resp.status === 401) { + result.message = 'You are not authorized to change this organization.'; + } + } else { + const json = await resp.json(); + if (json) result.json = json; + } + + return result; +} + +export async function saveConfig(org, email, existingConfig) { + const defConfigStr = ORG_CONFIG.replaceAll('{{EMAIL}}', email); + const defConfig = JSON.parse(defConfigStr); + + // Preserve the existing config + if (existingConfig?.data) defConfig.data = existingConfig; + + const body = new FormData(); + body.append('config', JSON.stringify(defConfig)); + + const resp = await fetchConfig(org, body); + + return { status: resp.status }; +} class DaStart extends LitElement { static properties = { @@ -183,28 +223,24 @@ class DaStart extends LitElement { this._loading = true; - // Check if this is a new org and add org-level permissions - const orgUrl = siteUrl.substring(0, siteUrl.lastIndexOf('/')); - const orgCheckResp = await daFetch(orgUrl); - if (orgCheckResp.status === 404) { + const { status: orgLoadStatus } = await loadConfig(this.org); + if (orgLoadStatus === 404) { // Check if user has an email address const { email } = await window.adobeIMS.getProfile(); if (!email) { this._errorText = 'Make sure your profile contains an email address.'; + this._loading = false; return; } - const orgConfigJson = JSON.stringify(ORG_CONFIG).replace('$EMAIL$', email); - const body = new FormData(); - body.append('config', orgConfigJson); - - const orgResp = await daFetch(orgUrl, { method: 'PUT', body }); - if (!orgResp.ok) { - if (orgResp.status === 401 || orgResp.status === 403) { + const { status: orgSaveStatus } = await saveConfig(this.org, email); + if (orgSaveStatus !== 201) { + if (orgSaveStatus === 401 || orgSaveStatus === 403) { this._errorText = 'You are not authorized to create this org. Check your permissions.'; } else { this._errorText = 'The org could not be created. Check the console logs or contact an administrator.'; } + this._loading = false; return; } }