diff --git a/blocks/browse/da-browse/da-browse.js b/blocks/browse/da-browse/da-browse.js
index 4b9ac5b5..ca47b03d 100644
--- a/blocks/browse/da-browse/da-browse.js
+++ b/blocks/browse/da-browse/da-browse.js
@@ -1,6 +1,7 @@
import { LitElement, html, nothing } from 'da-lit';
-import { DA_ORIGIN } from '../../shared/constants.js';
-import { daFetch, getFirstSheet } from '../../shared/utils.js';
+import { DA_HLX } from '../../shared/constants.js';
+import { getFirstSheet } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
import { getNx, sanitizePathParts } from '../../../scripts/utils.js';
// Components
@@ -82,8 +83,12 @@ export default class DaBrowse extends LitElement {
async getEditor(reFetch) {
const DEF_EDIT = '/edit#';
+ if (DA_HLX) { // TODO handle editor path for hlx6
+ return DEF_EDIT;
+ }
+
if (reFetch) {
- const resp = await daFetch(`${DA_ORIGIN}/config/${this.details.owner}/`);
+ const resp = await daApi.getConfig(`/${this.details.owner}/`);
if (!resp.ok) return DEF_EDIT;
const json = await resp.json();
diff --git a/blocks/browse/da-list-item/da-list-item.js b/blocks/browse/da-list-item/da-list-item.js
index f40a50eb..a06fa9c3 100644
--- a/blocks/browse/da-list-item/da-list-item.js
+++ b/blocks/browse/da-list-item/da-list-item.js
@@ -1,6 +1,6 @@
import { LitElement, html, nothing, until } from 'da-lit';
-import { DA_ORIGIN } from '../../shared/constants.js';
-import { daFetch, aemAdmin } from '../../shared/utils.js';
+import { aemAdmin } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
import { getNx } from '../../../scripts/utils.js';
import getEditPath from '../shared.js';
import { formatDate } from '../../edit/da-versions/helpers.js';
@@ -73,7 +73,7 @@ export default class DaListItem extends LitElement {
}
async updateDAStatus() {
- const resp = await daFetch(`${DA_ORIGIN}/versionlist${this.path}`);
+ const resp = await daApi.getVersionList(this.path);
if (!resp.ok) return;
const json = await resp.json();
if (json.length === 0) {
@@ -131,10 +131,6 @@ export default class DaListItem extends LitElement {
this._preview = null;
this._live = null;
- const formData = new FormData();
- formData.append('destination', newPath);
- const opts = { body: formData, method: 'POST' };
-
this.name = newName;
this.path = newPath;
this.rename = false;
@@ -142,7 +138,7 @@ export default class DaListItem extends LitElement {
this.date = Date.now();
const showStatus = setTimeout(() => { this.setStatus('Renaming', 'Please be patient. Renaming items with many children can take time.'); }, 5000);
- const resp = await daFetch(`${DA_ORIGIN}/move${oldPath}`, opts);
+ const resp = await daApi.move(oldPath, newPath);
if (resp.status === 204) {
clearTimeout(showStatus);
@@ -204,7 +200,7 @@ export default class DaListItem extends LitElement {
let externalUrlPromise;
if (this.ext === 'link') {
path = nothing;
- externalUrlPromise = daFetch(`${DA_ORIGIN}/source${this.path}`)
+ externalUrlPromise = daApi.getSource(this.path)
.then((response) => response.json())
.then((data) => data.externalUrl);
}
@@ -216,8 +212,8 @@ export default class DaListItem extends LitElement {
` : html`
+
`}
-
${this.name}
${this.ext === 'link' ? nothing : this.renderDate()}
`;
diff --git a/blocks/browse/da-list/da-list.js b/blocks/browse/da-list/da-list.js
index c57e006f..e99a7c2f 100644
--- a/blocks/browse/da-list/da-list.js
+++ b/blocks/browse/da-list/da-list.js
@@ -1,7 +1,8 @@
import { LitElement, html, repeat, nothing } from 'da-lit';
-import { DA_ORIGIN } from '../../shared/constants.js';
+import { DA_HLX } from '../../shared/constants.js';
import { getNx, sanitizePathParts } from '../../../scripts/utils.js';
-import { daFetch, aemAdmin } from '../../shared/utils.js';
+import { aemAdmin } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
import '../da-list-item/da-list-item.js';
@@ -97,12 +98,33 @@ export default class DaList extends LitElement {
this.dispatchEvent(event);
}
+ transformList(json) {
+ if (!DA_HLX) return json;
+
+ /*
+ * name without extension
+ * ext is the extension
+ * lastModified is last-modified in millis
+ * path is full plus original name with extension
+ */
+
+ const transformed = [];
+ for (const item of json) {
+ const [name, ext] = item.name.split('.');
+ const lastModified = new Date(item['last-modified']).getTime();
+ const path = `${this.fullpath}/${item.name}`;
+
+ transformed.push({ name, ext, lastModified, path });
+ }
+ return transformed;
+ }
+
async getList() {
try {
- const resp = await daFetch(`${DA_ORIGIN}/list${this.fullpath}`);
+ const resp = await daApi.getList(this.fullpath);
if (resp.permissions) this.handlePermissions(resp.permissions);
const json = await resp.json();
- return json;
+ return this.transformList(json);
} catch {
this._emptyMessage = 'Not permitted';
return [];
@@ -212,24 +234,23 @@ export default class DaList extends LitElement {
const moveToTrash = api === 'move' && !item.path.includes('/.trash/') && item.destination.includes('/.trash/');
try {
- while (continuation) {
- let body;
-
- if (type !== 'delete') {
- body = new FormData();
- body.append('destination', item.destination);
- if (continuationToken) body.append('continuation-token', continuationToken);
- }
-
- const opts = { method, body };
- const resp = await daFetch(`${DA_ORIGIN}/${api}${item.path}`, opts);
- if (resp.status === 204) {
- continuation = false;
- break;
+ if (type === 'delete') {
+ const resp = await daApi.deleteSource(item.path);
+ if (resp.status !== 204) throw new Error('Could not delete');
+ } else {
+ while (continuation) {
+ const resp = await (api === 'move'
+ ? daApi.move(item.path, item.destination, continuationToken)
+ : daApi.copy(item.path, item.destination, continuationToken));
+
+ if (resp.status === 204) {
+ continuation = false;
+ break;
+ }
+ const json = await resp.json();
+ ({ continuationToken } = json);
+ if (!continuationToken) continuation = false;
}
- const json = await resp.json();
- ({ continuationToken } = json);
- if (!continuationToken) continuation = false;
}
item.isChecked = false;
diff --git a/blocks/browse/da-list/helpers/utils.js b/blocks/browse/da-list/helpers/utils.js
index 6a8f59e1..9ab01fe2 100644
--- a/blocks/browse/da-list/helpers/utils.js
+++ b/blocks/browse/da-list/helpers/utils.js
@@ -1,6 +1,6 @@
-import { SUPPORTED_FILES, DA_ORIGIN } from '../../../shared/constants.js';
+import { SUPPORTED_FILES } from '../../../shared/constants.js';
import { sanitizePath, sanitizePathParts } from '../../../../scripts/utils.js';
-import { daFetch } from '../../../shared/utils.js';
+import { daApi } from '../../../shared/da-api.js';
const MAX_DEPTH = 1000;
@@ -84,14 +84,11 @@ export async function getFullEntryList(entries) {
export async function handleUpload(list, fullpath, file) {
const { data, path } = file;
- const formData = new FormData();
- formData.append('data', data);
- const opts = { method: 'POST', body: formData };
const sanitizedPath = sanitizePath(path);
const postpath = `${fullpath}${sanitizedPath}`;
try {
- await daFetch(`${DA_ORIGIN}/source${postpath}`, opts);
+ await daApi.saveSource(postpath, { blob: data, method: 'POST' });
file.imported = true;
const [displayName] = sanitizedPath.split('/').slice(1);
diff --git a/blocks/browse/da-new/da-new.js b/blocks/browse/da-new/da-new.js
index 7b027675..4a7a05f2 100644
--- a/blocks/browse/da-new/da-new.js
+++ b/blocks/browse/da-new/da-new.js
@@ -2,6 +2,7 @@ import { LitElement, html } from 'da-lit';
import { saveToDa } from '../../shared/utils.js';
import { getNx } from '../../../scripts/utils.js';
import getEditPath from '../shared.js';
+import { daApi } from '../../shared/da-api.js';
// Styles & Icons
const { default: getStyle } = await import(`${getNx()}/utils/styles.js`);
@@ -68,6 +69,7 @@ export default class DaNew extends LitElement {
let ext;
let formData;
+ let method = 'PUT';
switch (this._createType) {
case 'document':
ext = 'html';
@@ -83,6 +85,12 @@ export default class DaNew extends LitElement {
new Blob([JSON.stringify({ externalUrl: this._externalUrl })], { type: 'application/json' }),
);
break;
+ case 'folder':
+ if (daApi.isHlx) {
+ this._createName += '/';
+ method = 'POST';
+ }
+ break;
default:
break;
}
@@ -92,7 +100,7 @@ export default class DaNew extends LitElement {
if (ext && ext !== 'link') {
window.location = editPath;
} else {
- await saveToDa({ path, formData });
+ await saveToDa({ path, formData, method });
const item = { name: this._createName, path };
if (ext) item.ext = ext;
this.sendNewItem(item);
diff --git a/blocks/browse/da-search/da-search.js b/blocks/browse/da-search/da-search.js
index 05aa2704..b20e67fa 100644
--- a/blocks/browse/da-search/da-search.js
+++ b/blocks/browse/da-search/da-search.js
@@ -1,7 +1,6 @@
import { LitElement, html, nothing } from 'da-lit';
-import { DA_ORIGIN } from '../../shared/constants.js';
import { getNx } from '../../../scripts/utils.js';
-import { daFetch } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
const { crawl, Queue } = await import(`${getNx()}/public/utils/tree.js`);
@@ -69,7 +68,7 @@ export default class DaSearch extends LitElement {
let match;
try {
- const resp = await daFetch(`${DA_ORIGIN}/source${file.path}`);
+ const resp = await daApi.getSource(file.path);
const text = await resp.text();
// Log empty files
// eslint-disable-next-line no-console
@@ -163,14 +162,11 @@ export default class DaSearch extends LitElement {
let retryCount = prevRetry;
const getFile = async () => {
- const getResp = await daFetch(`${DA_ORIGIN}/source${file.path}`);
+ const getResp = await daApi.getSource(file.path);
const text = await getResp.text();
const replacedText = text.replaceAll(this._term, replace.value);
const blob = new Blob([replacedText], { type: 'text/html' });
- const formData = new FormData();
- formData.append('data', blob);
- const opts = { method: 'PUT', body: formData };
- const postResp = await daFetch(`${DA_ORIGIN}/source${file.path}`, opts);
+ const postResp = await daApi.saveSource(file.path, { blob });
if (!postResp.ok) return { error: 'Error saving file' };
this._matches += 1;
return file;
diff --git a/blocks/edit/da-assets/da-assets.js b/blocks/edit/da-assets/da-assets.js
index 72781bd8..dfdb7cf5 100644
--- a/blocks/edit/da-assets/da-assets.js
+++ b/blocks/edit/da-assets/da-assets.js
@@ -1,7 +1,7 @@
import { DOMParser as proseDOMParser, Fragment } from 'da-y-wrapper';
import { getNx } from '../../../scripts/utils.js';
-import { DA_ORIGIN } from '../../shared/constants.js';
import { daFetch, getFirstSheet } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
import getPathDetails from '../../shared/pathDetails.js';
const { loadStyle } = await import(`${getNx()}/scripts/nexter.js`);
@@ -15,7 +15,7 @@ const CONFS = {};
async function fetchConf(path) {
if (CONFS[path]) return CONFS[path];
- const resp = await daFetch(`${DA_ORIGIN}/config${path}`);
+ const resp = await daApi.getConfig(path);
if (!resp.ok) return null;
fullConfJsons[path] = await resp.json();
@@ -37,7 +37,7 @@ async function fetchValue(path, key) {
}
function constructConfigPaths(owner, repo) {
- return [`/${owner}/${repo}/`, `/${owner}/`];
+ return [`/${owner}/${repo}/`];
}
// Note: this is called externally to determine if the button should be visible.
diff --git a/blocks/edit/da-content/helpers/index.js b/blocks/edit/da-content/helpers/index.js
index 0224bbad..d8ee8f01 100644
--- a/blocks/edit/da-content/helpers/index.js
+++ b/blocks/edit/da-content/helpers/index.js
@@ -1,8 +1,7 @@
-import { DA_ORIGIN } from '../../../shared/constants.js';
-import { daFetch } from '../../../shared/utils.js';
+import { daApi } from '../../../shared/da-api.js';
async function getConfSheet(org) {
- const resp = await daFetch(`${DA_ORIGIN}/config/${org}/`);
+ const resp = await daApi.getConfig(`/${org}/`);
if (!resp.ok) return null;
const json = await resp.json();
return json?.data?.data || json?.data;
diff --git a/blocks/edit/da-library/helpers/helpers.js b/blocks/edit/da-library/helpers/helpers.js
index 0f98d176..c558aa93 100644
--- a/blocks/edit/da-library/helpers/helpers.js
+++ b/blocks/edit/da-library/helpers/helpers.js
@@ -1,13 +1,12 @@
// eslint-disable-next-line import/no-unresolved
import { DOMParser } from 'da-y-wrapper';
-import { getDaAdmin } from '../../../shared/constants.js';
import getPathDetails from '../../../shared/pathDetails.js';
import { daFetch, getFirstSheet } from '../../../shared/utils.js';
+import { daApi } from '../../../shared/da-api.js';
import { getConfKey, openAssets } from '../../da-assets/da-assets.js';
import { fetchKeyAutocompleteData } from '../../prose/plugins/slashMenu/keyAutocomplete.js';
import { sanitizeName } from '../../../../scripts/utils.js';
-const DA_ORIGIN = getDaAdmin();
const REPLACE_CONTENT = '';
const DA_CONFIG = '/.da/config.json';
const DA_PLUGINS = [
@@ -68,7 +67,7 @@ export async function getItems(sources, listType, format) {
}
async function getDaLibraries(owner, repo) {
- const resp = await daFetch(`${DA_ORIGIN}/source/${owner}/${repo}${DA_CONFIG}`);
+ const resp = await daApi.getSource(`/${owner}/${repo}${DA_CONFIG}`);
if (!resp.ok) return [];
const json = await resp.json();
@@ -159,7 +158,7 @@ function calculateSources(org, repo, sheetPath) {
}
async function getConfigLibraries(org, repo) {
- const resp = await daFetch(`${DA_ORIGIN}/config/${org}/${repo}/`);
+ const resp = await daApi.getConfig(`/${org}/${repo}/`);
if (!resp.ok) return null;
const { library } = await resp.json();
if (!library) return null;
@@ -256,6 +255,25 @@ export function getPreviewUrl(previewUrl) {
const [, , org, site, ...split] = url.pathname.split('/');
return `https://main--${site}--${org}.aem.page/${split.join('/')}`;
}
+ if (url.origin === daApi.origin) {
+ if (daApi.isHlx) {
+ // HLX6: /org/sites/repo/source/path...
+ // Assuming previewUrl is sourceUrl.
+ // If path is /org/sites/repo/source/rest
+ // Site is repo. Org is org.
+ const parts = url.pathname.split('/');
+ // parts: ['', org, 'sites', repo, 'source', ...rest]
+ if (parts[2] === 'sites' && parts[4] === 'source') {
+ const org = parts[1];
+ const repo = parts[3];
+ const rest = parts.slice(5).join('/');
+ return `https://main--${repo}--${org}.aem.page/${rest}`;
+ }
+ } else {
+ const [, , org, site, ...split] = url.pathname.split('/');
+ return `https://main--${site}--${org}.aem.page/${split.join('/')}`;
+ }
+ }
} catch {
return false;
}
@@ -275,7 +293,13 @@ export function getEdsUrlVars(url) {
const [, org, site] = urlObj.pathname.split('/');
return [org, site, 'main'];
}
- if (urlObj.origin.includes('admin.da.live')) {
+ if (urlObj.origin.includes('admin.da.live') || urlObj.origin === daApi.origin) {
+ if (daApi.isHlx && urlObj.origin === daApi.origin) {
+ const parts = urlObj.pathname.split('/');
+ if (parts[2] === 'sites' && parts[4] === 'source') {
+ return [parts[1], parts[3], 'main'];
+ }
+ }
const [, , org, site] = urlObj.pathname.split('/');
return [org, site, 'main'];
}
diff --git a/blocks/edit/da-title/da-title.js b/blocks/edit/da-title/da-title.js
index 6a3ecc0b..051179a8 100644
--- a/blocks/edit/da-title/da-title.js
+++ b/blocks/edit/da-title/da-title.js
@@ -7,8 +7,8 @@ import {
saveDaVersion,
getCdnConfig,
} from '../utils/helpers.js';
-import { DA_ORIGIN } from '../../shared/constants.js';
import { daFetch, getFirstSheet } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
import inlinesvg from '../../shared/inlinesvg.js';
import getSheet from '../../shared/sheet.js';
@@ -66,6 +66,7 @@ export default class DaTitle extends LitElement {
}
handleError(json, action, icon) {
+ // eslint-disable-next-line no-console
console.log('handleError', json, action, icon);
this._status = { ...json.error, action };
icon.classList.remove('is-sending');
@@ -172,8 +173,8 @@ export default class DaTitle extends LitElement {
.catch(() => []);
const [org, site] = await Promise.all([
- fetchSingleConfig(`${DA_ORIGIN}/config/${owner}`),
- fetchSingleConfig(`${DA_ORIGIN}/config/${owner}/${repo}`),
+ fetchSingleConfig(daApi.getConfigUrl(`/${owner}`)),
+ fetchSingleConfig(daApi.getConfigUrl(`/${owner}/${repo}`)),
]);
this.config = { org, site };
return this.config;
diff --git a/blocks/edit/da-versions/da-versions.js b/blocks/edit/da-versions/da-versions.js
index f2195a1a..3f8dcd90 100644
--- a/blocks/edit/da-versions/da-versions.js
+++ b/blocks/edit/da-versions/da-versions.js
@@ -1,8 +1,7 @@
import { LitElement, html, nothing } from 'da-lit';
import getSheet from '../../shared/sheet.js';
-import { DA_ORIGIN } from '../../shared/constants.js';
+import { daApi } from '../../shared/da-api.js';
import { formatDate, formatVersions } from './helpers.js';
-import { daFetch } from '../../shared/utils.js';
const sheet = await getSheet('/blocks/edit/da-versions/da-versions.css');
@@ -23,7 +22,7 @@ export default class DaVersions extends LitElement {
async getVersions() {
this._loading = true;
this._versions = null;
- const resp = await daFetch(`${DA_ORIGIN}/versionlist${this.path}`);
+ const resp = await daApi.getVersionList(this.path);
if (!resp.ok) {
this._loading = false;
return;
@@ -49,7 +48,7 @@ export default class DaVersions extends LitElement {
if (!entryEl.classList.contains('is-open')) {
entryEl.classList.toggle('is-open');
}
- const detail = { url: `${DA_ORIGIN}${entry.url}` };
+ const detail = { url: `${daApi.origin}${entry.url}` };
const opts = { detail, bubbles: true, composed: true };
const event = new CustomEvent('preview', opts);
this.dispatchEvent(event);
@@ -67,7 +66,7 @@ export default class DaVersions extends LitElement {
const opts = { method: 'POST' };
if (entry.label) opts.body = JSON.stringify({ label: entry.label });
- const res = await daFetch(`${DA_ORIGIN}/versionsource${this.path}`, opts);
+ const res = await daApi.getVersionSource(this.path, opts);
if (res.status !== 201) return;
this._newVersion = null;
diff --git a/blocks/edit/prose/index.js b/blocks/edit/prose/index.js
index 9af37f1e..96d9d6c6 100644
--- a/blocks/edit/prose/index.js
+++ b/blocks/edit/prose/index.js
@@ -31,7 +31,8 @@ import linkConverter from './plugins/linkConverter.js';
import linkTextSync from './plugins/linkTextSync.js';
import sectionPasteHandler from './plugins/sectionPasteHandler.js';
import base64Uploader from './plugins/base64uploader.js';
-import { COLLAB_ORIGIN, DA_ORIGIN } from '../../shared/constants.js';
+import { COLLAB_ORIGIN } from '../../shared/constants.js';
+import { daApi } from '../../shared/da-api.js';
import toggleLibrary from '../da-library/da-library.js';
import { checkDoc } from '../edit.js';
import { debounce, initDaMetadata } from '../utils/helpers.js';
@@ -297,7 +298,7 @@ export default function initProse({ path, permissions }) {
const ydoc = new Y.Doc();
const server = COLLAB_ORIGIN;
- const roomName = `${DA_ORIGIN}${new URL(path).pathname}`;
+ const roomName = `${daApi.origin}${new URL(path).pathname}`;
const opts = { protocols: ['yjs'] };
diff --git a/blocks/edit/prose/plugins/base64uploader.js b/blocks/edit/prose/plugins/base64uploader.js
index f9865893..0c999126 100644
--- a/blocks/edit/prose/plugins/base64uploader.js
+++ b/blocks/edit/prose/plugins/base64uploader.js
@@ -1,7 +1,7 @@
import { Plugin } from 'da-y-wrapper';
import getPathDetails from '../../../shared/pathDetails.js';
-import { daFetch } from '../../../shared/utils.js';
-import { DA_ORIGIN, CON_ORIGIN } from '../../../shared/constants.js';
+import { daApi } from '../../../shared/da-api.js';
+import { CON_ORIGIN } from '../../../shared/constants.js';
const FPO_IMG_URL = '/blocks/edit/img/fpo.svg';
@@ -45,9 +45,7 @@ export default function base64Uploader() {
uploadPromises.push((async () => {
const resp = await fetch(src);
const blob = await resp.blob();
- const body = new FormData();
- body.append('data', blob);
- await daFetch(`${DA_ORIGIN}/source${path}`, { body, method: 'POST' });
+ await daApi.saveSource(path, { blob, method: 'POST' });
})());
});
diff --git a/blocks/edit/utils/helpers.js b/blocks/edit/utils/helpers.js
index 450a2ad2..5933deaa 100644
--- a/blocks/edit/utils/helpers.js
+++ b/blocks/edit/utils/helpers.js
@@ -1,7 +1,8 @@
-import { AEM_ORIGIN, DA_ORIGIN } from '../../shared/constants.js';
+import { AEM_ORIGIN } from '../../shared/constants.js';
import { sanitizePathParts } from '../../../../scripts/utils.js';
import prose2aem from '../../shared/prose2aem.js';
import { daFetch } from '../../shared/utils.js';
+import { daApi } from '../../shared/da-api.js';
export function isURL(text) {
try {
@@ -205,11 +206,7 @@ async function saveHtml(fullPath) {
const html = prose2aem(editor, false);
const blob = new Blob([html], { type: 'text/html' });
- const formData = new FormData();
- formData.append('data', blob);
-
- const opts = { method: 'PUT', body: formData };
- return daFetch(fullPath, opts);
+ return daApi.saveSource(fullPath, { blob });
}
function formatSheetData(jData) {
@@ -295,36 +292,27 @@ export function convertSheets(sheets) {
async function saveJson(fullPath, sheets, jsonToSave, dataType = 'blob') {
const json = jsonToSave || convertSheets(sheets);
- const formData = new FormData();
-
- if (dataType === 'blob') {
- const blob = new Blob([JSON.stringify(json)], { type: 'application/json' });
- formData.append('data', blob);
- }
-
- if (dataType === 'config') {
- formData.append('config', JSON.stringify(json));
- }
+ const blob = new Blob([JSON.stringify(json)], { type: 'application/json' });
+ const props = dataType === 'config' ? { config: json } : undefined;
- const opts = { method: 'PUT', body: formData };
- return daFetch(fullPath, opts);
+ return daApi.saveSource(fullPath, { blob, props });
}
export function saveToDa(pathname, sheet) {
const suffix = sheet ? '.json' : '.html';
- const fullPath = `${DA_ORIGIN}/source${pathname}${suffix}`;
+
+ const fullPath = `${pathname}${suffix}`;
if (!sheet) return saveHtml(fullPath);
return saveJson(fullPath, sheet);
}
export function saveDaConfig(pathname, sheet) {
- const fullPath = `${DA_ORIGIN}/config${pathname}`;
- return saveJson(fullPath, sheet, null, 'config');
+ return daApi.saveSource(`${pathname}`, { blob: new Blob([JSON.stringify(sheet)], { type: 'application/json' }), props: { config: sheet } });
}
export async function saveDaVersion(pathname, ext = 'html') {
- const fullPath = `${DA_ORIGIN}/versionsource${pathname}.${ext}`;
+ const fullPath = `${pathname}.${ext}`;
const opts = {
method: 'POST',
@@ -332,7 +320,8 @@ export async function saveDaVersion(pathname, ext = 'html') {
};
try {
- await daFetch(fullPath, opts);
+ // eslint-disable-next-line no-undef
+ await daApi.getVersionSource(fullPath, opts);
} catch {
// eslint-disable-next-line no-console
console.log('Error creating auto version on publish.');
@@ -364,8 +353,8 @@ async function getRoleRequestDetails(action) {
export async function requestRole(org, site, action) {
let json = JSON.parse(AEM_PERMISSION_TPL);
- const fullpath = `${DA_ORIGIN}/source/${org}/${site}/.da/aem-permission-requests.json`;
- const resp = await daFetch(fullpath);
+ const fullpath = `/${org}/${site}/.da/aem-permission-requests.json`;
+ const resp = await daApi.getSource(fullpath);
if (resp.ok) {
json = await resp.json();
}
diff --git a/blocks/shared/api/da-admin.js b/blocks/shared/api/da-admin.js
new file mode 100644
index 00000000..23e8f393
--- /dev/null
+++ b/blocks/shared/api/da-admin.js
@@ -0,0 +1,84 @@
+import { daFetch } from '../fetch.js';
+
+export default class DaAdminApi {
+ constructor(origin) {
+ this.origin = origin;
+ this.isHlx = false;
+ }
+
+ getSourceUrl(path) {
+ return `${this.origin}/source${path}`;
+ }
+
+ getConfigUrl(path) {
+ return `${this.origin}/config${path}`;
+ }
+
+ getListUrl(path) {
+ return `${this.origin}/list${path}`;
+ }
+
+ getVersionListUrl(path) {
+ return `${this.origin}/versionlist${path}`;
+ }
+
+ getVersionSourceUrl(path) {
+ return `${this.origin}/versionsource${path}`;
+ }
+
+ async getSource(path) {
+ return daFetch(this.getSourceUrl(path));
+ }
+
+ async deleteSource(path) {
+ return daFetch(this.getSourceUrl(path), { method: 'DELETE' });
+ }
+
+ async saveSource(path, { formData, blob, props, method = 'PUT' } = {}) {
+ const opts = { method };
+ const form = formData || new FormData();
+ if (blob || props) {
+ if (blob) form.append('data', blob);
+ if (props) form.append('props', JSON.stringify(props));
+ }
+ if ([...form.keys()].length) opts.body = form;
+
+ const daResp = await daFetch(this.getSourceUrl(path), opts);
+ if (!daResp.ok) return undefined;
+ return daResp;
+ }
+
+ async getConfig(path) {
+ return daFetch(this.getConfigUrl(path));
+ }
+
+ async getList(path) {
+ return daFetch(this.getListUrl(path));
+ }
+
+ async getVersionList(path) {
+ return daFetch(this.getVersionListUrl(path));
+ }
+
+ async getVersionSource(path) {
+ return daFetch(this.getVersionSourceUrl(path));
+ }
+
+ async move(path, destination, continuationToken) {
+ const body = new FormData();
+ body.append('destination', destination);
+ if (continuationToken) body.append('continuation-token', continuationToken);
+
+ const url = `${this.origin}/move${path}`;
+ return daFetch(url, { method: 'POST', body });
+ }
+
+ async copy(path, destination, continuationToken) {
+ const body = new FormData();
+ body.append('destination', destination);
+ if (continuationToken) body.append('continuation-token', continuationToken);
+
+ const url = `${this.origin}/copy${path}`;
+ return daFetch(url, { method: 'POST', body });
+ }
+}
diff --git a/blocks/shared/api/da-hlx6.js b/blocks/shared/api/da-hlx6.js
new file mode 100644
index 00000000..7ef1fe8e
--- /dev/null
+++ b/blocks/shared/api/da-hlx6.js
@@ -0,0 +1,99 @@
+import { daFetch } from '../fetch.js';
+
+const getPathParts = (path) => {
+ const parts = path.split('/').filter((p) => p);
+ return {
+ org: parts[0],
+ repo: parts[1],
+ rest: parts.slice(2).join('/'),
+ };
+};
+
+export default class DaHlx6Api {
+ constructor(origin) {
+ this.origin = origin;
+ this.isHlx = true;
+ }
+
+ getSourceUrl(path) {
+ const { org, repo, rest } = getPathParts(path);
+ if (!repo) return `${this.origin}/source${path}`;
+ return `${this.origin}/${org}/sites/${repo}/source/${rest}`;
+ }
+
+ getConfigUrl(path) {
+ const { org, repo } = getPathParts(path);
+
+ // TODO: migrate to api.aem.live when ready
+ // cannot work as is because auth... not the same token is required
+ // https://admin.hlx.page/config/kptdobe/sites/daplayground.json
+ return `https://admin.hlx.page/config/${org}/sites/${repo}.json`;
+
+ // return `${this.origin}/${org}/sites/${repo}/config/`;
+ }
+
+ getListUrl(path) {
+ const { org, repo, rest } = getPathParts(path);
+ if (!repo) return `${this.origin}/list${path}`;
+ // HLX6 uses the source endpoint for listing as well (if it's a folder)
+ return `${this.origin}/${org}/sites/${repo}/source/${rest}`;
+ }
+
+ getVersionListUrl(path) {
+ return `${this.origin}/versionlist${path}`;
+ }
+
+ getVersionSourceUrl(path) {
+ return `${this.origin}/versionsource${path}`;
+ }
+
+ async getSource(path) {
+ return daFetch(this.getSourceUrl(path));
+ }
+
+ async deleteSource(path) {
+ return daFetch(this.getSourceUrl(path), { method: 'DELETE' });
+ }
+
+ async saveSource(path, { blob, method = 'PUT' } = {}) {
+ const opts = { method, body: blob };
+ const daResp = await daFetch(this.getSourceUrl(path), opts);
+ if (!daResp.ok) return undefined;
+ return daResp;
+ }
+
+ async getConfig(path) {
+ return daFetch(this.getConfigUrl(path));
+ }
+
+ async getList(path) {
+ return daFetch(this.getListUrl(path));
+ }
+
+ async getVersionList(path) {
+ return daFetch(this.getVersionListUrl(path));
+ }
+
+ async getVersionSource(path) {
+ return daFetch(this.getVersionSourceUrl(path));
+ }
+
+ async move(path, destination, continuationToken) {
+ const body = new FormData();
+ body.append('destination', destination);
+ if (continuationToken) body.append('continuation-token', continuationToken);
+
+ // Assuming HLX6 follows similar pattern or we fallback to what was generated before
+ const url = `${this.origin}/move${path}`;
+ return daFetch(url, { method: 'POST', body });
+ }
+
+ async copy(path, destination, continuationToken) {
+ const body = new FormData();
+ body.append('destination', destination);
+ if (continuationToken) body.append('continuation-token', continuationToken);
+
+ const url = `${this.origin}/copy${path}`;
+ return daFetch(url, { method: 'POST', body });
+ }
+}
diff --git a/blocks/shared/constants.js b/blocks/shared/constants.js
index 6f6bdc09..3cb4eb23 100644
--- a/blocks/shared/constants.js
+++ b/blocks/shared/constants.js
@@ -15,12 +15,14 @@ export const SUPPORTED_FILES = {
const DA_ADMIN_ENVS = {
local: 'http://localhost:8787',
+ hlx6: 'https://api.aem.live',
stage: 'https://stage-admin.da.live',
prod: 'https://admin.da.live',
};
const DA_COLLAB_ENVS = {
local: 'ws://localhost:4711',
+ hlx6: 'wss://collab-hlx6.da.live',
stage: 'wss://stage-collab.da.live',
prod: 'wss://collab.da.live',
};
@@ -60,7 +62,12 @@ export const getDaAdmin = (() => {
})();
export const DA_ORIGIN = (() => getDaEnv(window.location, 'da-admin', DA_ADMIN_ENVS))();
+export const DA_HLX = DA_ADMIN_ENVS.hlx6 === DA_ORIGIN;
export const COLLAB_ORIGIN = (() => getDaEnv(window.location, 'da-collab', DA_COLLAB_ENVS))();
+
+export const DA_ORIGINS = ['https://da.live', 'https://da.page', 'https://admin.da.live', 'https://admin.da.page', 'https://stage-admin.da.live', 'https://content.da.live', 'https://stage-content.da.live', 'http://localhost:8787'];
+export const AEM_ORIGINS = ['https://admin.hlx.page', 'https://admin.aem.live', 'https://api.aem.live'];
+
export const CON_ORIGIN = (() => getDaEnv(window.location, 'da-content', DA_CONTENT_ENVS))();
export const LIVE_PREVIEW_DOMAIN = (() => getDaEnv(window.location, 'da-live-preview', DA_LIVE_PREVIEW_ENVS))();
diff --git a/blocks/shared/da-api.js b/blocks/shared/da-api.js
new file mode 100644
index 00000000..da3b819d
--- /dev/null
+++ b/blocks/shared/da-api.js
@@ -0,0 +1,8 @@
+import { DA_ORIGIN, DA_HLX } from './constants.js';
+import DaAdminApi from './api/da-admin.js';
+import DaHlx6Api from './api/da-hlx6.js';
+
+const DaApi = DA_HLX ? DaHlx6Api : DaAdminApi;
+
+export default DaApi;
+export const daApi = new DaApi(DA_ORIGIN);
diff --git a/blocks/shared/fetch.js b/blocks/shared/fetch.js
new file mode 100644
index 00000000..ad37314a
--- /dev/null
+++ b/blocks/shared/fetch.js
@@ -0,0 +1,73 @@
+import { DA_ORIGINS, AEM_ORIGINS } from './constants.js';
+
+const { getNx } = await import('../../scripts/utils.js');
+const ALLOWED_TOKEN = [...DA_ORIGINS, ...AEM_ORIGINS];
+
+let imsDetails;
+
+export async function initIms() {
+ if (imsDetails) return imsDetails;
+ const { loadIms } = await import(`${getNx()}/utils/ims.js`);
+
+ try {
+ imsDetails = await loadIms();
+ return imsDetails;
+ } catch {
+ return null;
+ }
+}
+
+export const daFetch = async (url, opts = {}) => {
+ opts.headers = opts.headers || {};
+ let accessToken;
+ if (localStorage.getItem('nx-ims')) {
+ ({ accessToken } = await initIms());
+ const canToken = ALLOWED_TOKEN.some((origin) => new URL(url).origin === origin);
+ if (accessToken && canToken) {
+ opts.headers.Authorization = `Bearer ${accessToken.token}`;
+ if (AEM_ORIGINS.some((origin) => new URL(url).origin === origin)) {
+ opts.headers['x-content-source-authorization'] = `Bearer ${accessToken.token}`;
+ }
+ }
+ }
+ const resp = await fetch(url, opts);
+ if (resp.status === 401 && opts.noRedirect !== true) {
+ // Only attempt sign-in if the request is for DA.
+ if (DA_ORIGINS.some((origin) => url.startsWith(origin))) {
+ // If the user has an access token, but are not permitted, redirect them to not found.
+ if (accessToken) {
+ // eslint-disable-next-line no-console
+ console.warn('You see the 404 page because you have no access to this page', url);
+ window.location = `${window.location.origin}/not-found`;
+ return { ok: false };
+ }
+ // eslint-disable-next-line no-console
+ console.warn('You need to sign in because you are not authorized to access this page', url);
+ const { loadIms, handleSignIn } = await import(`${getNx()}/utils/ims.js`);
+ await loadIms();
+ handleSignIn();
+ }
+ }
+
+ // TODO: Properly support 403 - DA Admin sometimes gives 401s and sometimes 403s.
+ if (resp.status === 403) {
+ return resp;
+ }
+
+ // If child actions header is present, use it.
+ // This is a hint as to what can be done with the children.
+ if (resp.headers?.get('x-da-child-actions')) {
+ resp.permissions = resp.headers.get('x-da-child-actions').split('=').pop().split(',');
+ return resp;
+ }
+
+ // Use the self actions hint if child actions are not present.
+ if (resp.headers?.get('x-da-actions')) {
+ resp.permissions = resp.headers?.get('x-da-actions')?.split('=').pop().split(',');
+ return resp;
+ }
+
+ // Support legacy admin.role.all
+ resp.permissions = ['read', 'write'];
+ return resp;
+};
diff --git a/blocks/shared/pathDetails.js b/blocks/shared/pathDetails.js
index a95193f3..61ee4a97 100644
--- a/blocks/shared/pathDetails.js
+++ b/blocks/shared/pathDetails.js
@@ -1,5 +1,6 @@
-import { CON_ORIGIN, DA_ORIGIN } from './constants.js';
+import { CON_ORIGIN } from './constants.js';
import { sanitizePathParts } from '../../scripts/utils.js';
+import { daApi } from './da-api.js';
let currpath;
let currhash;
@@ -16,16 +17,17 @@ function getOrgDetails({ editor, pathParts, ext }) {
const parent = ext === null ? `/${fullPath}` : '/';
const parentName = ext === null ? pathParts[0] : 'Root';
const name = editor === 'config' && ext === null ? 'config' : pathParts[0];
- const daApi = editor === 'config' ? 'config' : 'source';
let path = ext === 'html' && !fullPath.endsWith('.html') ? `${fullPath}.html` : fullPath;
if (editor === 'sheet' && !path.endsWith('.json')) path = `${path}.${ext}`;
+ const sourceUrl = editor === 'config' ? daApi.getConfigUrl(`/${path}`) : daApi.getSourceUrl(`/${path}`);
+
return {
owner: pathParts[0],
name,
parent,
parentName,
- sourceUrl: `${DA_ORIGIN}/${daApi}/${path}`,
+ sourceUrl,
};
}
@@ -36,17 +38,18 @@ function getRepoDetails({ editor, pathParts, ext }) {
const parent = ext === null ? `/${org}/${repo}` : `/${org}`;
const parentName = ext === null ? repo : org;
const name = editor === 'config' ? `${repo} config` : repo;
- const daApi = editor === 'config' ? 'config' : 'source';
let path = ext === 'html' && !fullPath.endsWith('.html') ? `${fullPath}.html` : fullPath;
if (editor === 'sheet' && !path.endsWith('.json')) path = `${path}.${ext}`;
+ const sourceUrl = editor === 'config' ? daApi.getConfigUrl(`/${path}`) : daApi.getSourceUrl(`/${path}`);
+
return {
owner: org,
repo,
name,
parent,
parentName,
- sourceUrl: `${DA_ORIGIN}/${daApi}/${path}`,
+ sourceUrl,
previewUrl: `https://main--${repo}--${org}.aem.live`,
contentUrl: `${CON_ORIGIN}/${fullPath}`,
};
@@ -66,16 +69,17 @@ function getFullDetails({ editor, pathParts, ext }) {
const parent = `/${pathParts.join('/')}`;
const parentName = pathParts.pop();
- const daApi = editor === 'config' ? 'config' : 'source';
const path = ext === 'html' && !fullPath.endsWith('.html') && editor !== 'sheet' ? `${fullPath}.html` : fullPath;
+ const sourceUrl = editor === 'config' ? daApi.getConfigUrl(`/${path}`) : daApi.getSourceUrl(`/${path}`);
+
return {
owner: org,
repo,
name: ext === null ? 'config' : name,
parent: ext === null ? `${parent}/${name}` : parent,
parentName: ext === null ? name : parentName,
- sourceUrl: `${DA_ORIGIN}/${daApi}/${path}`,
+ sourceUrl,
previewUrl: `https://main--${repo}--${org}.aem.live${pathname}`,
contentUrl: `${CON_ORIGIN}/${fullPath}`,
};
@@ -149,7 +153,7 @@ export default function getPathDetails(loc) {
let path = ext === 'html' && !fullpath.endsWith('.html') ? `${fullpath}.html` : fullpath;
if (editor === 'sheet' && !path.endsWith('.json')) path = `${path}.${ext}`;
- details = { ...details, origin: DA_ORIGIN, fullpath: path, depth, view: editor };
+ details = { ...details, origin: daApi.origin, fullpath: path, depth, view: editor };
return details;
}
diff --git a/blocks/shared/utils.js b/blocks/shared/utils.js
index 53652cc2..fc31a030 100644
--- a/blocks/shared/utils.js
+++ b/blocks/shared/utils.js
@@ -1,80 +1,8 @@
-import { DA_ORIGIN, CON_ORIGIN, getLivePreviewUrl } from './constants.js';
+import { daFetch, initIms } from './fetch.js';
+import { daApi } from './da-api.js';
+import { CON_ORIGIN, getLivePreviewUrl } from './constants.js';
-const { getNx } = await import('../../scripts/utils.js');
-
-// TODO: INFRA
-const DA_ORIGINS = ['https://da.live', 'https://da.page', 'https://admin.da.live', 'https://admin.da.page', 'https://stage-admin.da.live', 'https://content.da.live', 'https://stage-content.da.live', 'http://localhost:8787'];
-const AEM_ORIGINS = ['https://admin.hlx.page', 'https://admin.aem.live'];
-const ALLOWED_TOKEN = [...DA_ORIGINS, ...AEM_ORIGINS];
-
-let imsDetails;
-
-export async function initIms() {
- if (imsDetails) return imsDetails;
- const { loadIms } = await import(`${getNx()}/utils/ims.js`);
-
- try {
- imsDetails = await loadIms();
- return imsDetails;
- } catch {
- return null;
- }
-}
-
-export const daFetch = async (url, opts = {}) => {
- opts.headers = opts.headers || {};
- let accessToken;
- if (localStorage.getItem('nx-ims')) {
- ({ accessToken } = await initIms());
- const canToken = ALLOWED_TOKEN.some((origin) => new URL(url).origin === origin);
- if (accessToken && canToken) {
- opts.headers.Authorization = `Bearer ${accessToken.token}`;
- if (AEM_ORIGINS.some((origin) => new URL(url).origin === origin)) {
- opts.headers['x-content-source-authorization'] = `Bearer ${accessToken.token}`;
- }
- }
- }
- const resp = await fetch(url, opts);
- if (resp.status === 401 && opts.noRedirect !== true) {
- // Only attempt sign-in if the request is for DA.
- if (DA_ORIGINS.some((origin) => url.startsWith(origin))) {
- // If the user has an access token, but are not permitted, redirect them to not found.
- if (accessToken) {
- // eslint-disable-next-line no-console
- console.warn('You see the 404 page because you have no access to this page', url);
- window.location = `${window.location.origin}/not-found`;
- return { ok: false };
- }
- // eslint-disable-next-line no-console
- console.warn('You need to sign in because you are not authorized to access this page', url);
- const { loadIms, handleSignIn } = await import(`${getNx()}/utils/ims.js`);
- await loadIms();
- handleSignIn();
- }
- }
-
- // TODO: Properly support 403 - DA Admin sometimes gives 401s and sometimes 403s.
- if (resp.status === 403) {
- return resp;
- }
-
- // If child actions header is present, use it.
- // This is a hint as to what can be done with the children.
- if (resp.headers?.get('x-da-child-actions')) {
- resp.permissions = resp.headers.get('x-da-child-actions').split('=').pop().split(',');
- return resp;
- }
-
- // Use the self actions hint if child actions are not present.
- if (resp.headers?.get('x-da-actions')) {
- resp.permissions = resp.headers?.get('x-da-actions')?.split('=').pop().split(',');
- return resp;
- }
-
- // Support legacy admin.role.all
- resp.permissions = ['read', 'write'];
- return resp;
-};
+export { daFetch, initIms };
export async function aemAdmin(path, api, method = 'POST') {
const [owner, repo, ...parts] = path.slice(1).split('/');
@@ -91,18 +19,11 @@ export async function aemAdmin(path, api, method = 'POST') {
}
}
-export async function saveToDa({ path, formData, blob, props, preview = false }) {
- const opts = { method: 'PUT' };
-
- const form = formData || new FormData();
- if (blob || props) {
- if (blob) form.append('data', blob);
- if (props) form.append('props', JSON.stringify(props));
- }
- if ([...form.keys()].length) opts.body = form;
-
- const daResp = await daFetch(`${DA_ORIGIN}/source${path}`, opts);
- if (!daResp.ok) return undefined;
+export async function saveToDa({
+ path, formData, blob, props, preview = false, method = 'PUT',
+}) {
+ const daResp = await daApi.saveSource(path, { formData, blob, props, method });
+ if (!daResp || !daResp.ok) return undefined;
if (!preview) return undefined;
return aemAdmin(path, 'preview');
}
@@ -141,7 +62,7 @@ export async function livePreviewLogin(owner, repo) {
*/
export async function checkLockdownImages(owner) {
try {
- const resp = await daFetch(`${DA_ORIGIN}/config/${owner}`);
+ const resp = await daApi.getConfig(`/${owner}`);
if (!resp.ok) return false;
const config = await resp.json();
diff --git a/blocks/start/index.js b/blocks/start/index.js
index dc8edf78..91314453 100644
--- a/blocks/start/index.js
+++ b/blocks/start/index.js
@@ -1,6 +1,6 @@
import { getNx, sanitizePathParts } from '../../scripts/utils.js';
-import { DA_ORIGIN } from '../shared/constants.js';
import { daFetch } from '../shared/utils.js';
+import { daApi } from '../shared/da-api.js';
const { crawl } = await import(`${getNx()}/public/utils/tree.js`);
@@ -47,13 +47,13 @@ async function bulkAemAdmin(org, site, files) {
}
export async function copyConfig(sourcePath, org, site) {
- const destText = await getText(sourcePath, org, site, `${DA_ORIGIN}/config${sourcePath}/`);
+ const destText = await getText(sourcePath, org, site, daApi.getConfigUrl(`${sourcePath}/`));
if (!destText) return { ok: false };
const body = new FormData();
body.append('config', destText);
const opts = { method: 'PUT', body };
- return daFetch(`${DA_ORIGIN}/config/${org}/${site}/`, opts);
+ return daFetch(daApi.getConfigUrl(`/${org}/${site}/`), opts);
}
export async function copyContent(sourcePath, org, site, setStatus) {
@@ -69,13 +69,13 @@ export async function copyContent(sourcePath, org, site, setStatus) {
let blob;
if (ext === 'json' || ext === 'html' || ext === 'svg') {
- const destText = await getText(sourcePath, org, site, `${DA_ORIGIN}/source${path}`);
+ const destText = await getText(sourcePath, org, site, daApi.getSourceUrl(path));
if (destText) {
const type = MIME_TYPES[ext];
blob = new Blob([destText], { type });
}
} else {
- const sourceBlob = await getBlob(`${DA_ORIGIN}/source${path}`);
+ const sourceBlob = await getBlob(daApi.getSourceUrl(path));
if (sourceBlob) blob = sourceBlob;
}
@@ -87,11 +87,7 @@ export async function copyContent(sourcePath, org, site, setStatus) {
// Save the file
const savePath = path.replace(sourcePath, `/${org}/${site}`);
- const body = new FormData();
-
- body.append('data', blob);
- const opts = { method: 'POST', body };
- const putResp = await daFetch(`${DA_ORIGIN}/source${savePath}`, opts);
+ const putResp = await daApi.saveSource(savePath, { blob, method: 'POST' });
file.ok = putResp.ok;
};
diff --git a/blocks/start/start.js b/blocks/start/start.js
index 262785dc..62abc005 100644
--- a/blocks/start/start.js
+++ b/blocks/start/start.js
@@ -1,14 +1,12 @@
import { LitElement, html, nothing } from 'da-lit';
-import { getDaAdmin } from '../shared/constants.js';
import getSheet from '../shared/sheet.js';
import { daFetch } from '../shared/utils.js';
+import { daApi } from '../shared/da-api.js';
import { copyConfig, copyContent, previewContent } from './index.js';
import { sanitizePathParts } from '../../scripts/utils.js';
const sheet = await getSheet('/blocks/start/start.css');
-const DA_ORIGIN = getDaAdmin();
-
const AEM_TEMPLATES = [
{
title: 'AEM Boilerplate',
@@ -71,7 +69,7 @@ async function fetchConfig(org, body) {
let opts;
if (body) opts = { method: 'POST', body };
- return daFetch(`${DA_ORIGIN}/config/${org}/`, opts);
+ return daApi.getConfig(`/${org}/`, opts);
}
export async function loadConfig(org) {
@@ -170,7 +168,7 @@ class DaStart extends LitElement {
if (hasDemo) {
this._disableCreate = true;
- const resp = await daFetch(`${DA_ORIGIN}/list/${this.org}/${this.site}`);
+ const resp = await daApi.getList(`/${this.org}/${this.site}`);
const json = await resp.json();
if (json.length > 0) {
this._errorText = 'The target site is not empty. Choose no demo content or a different site.';
@@ -291,7 +289,7 @@ class DaStart extends LitElement {
renderOne() {
return html`