Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MWPW-151911 - [LocUI] URL validation enhancement #2430

Merged
merged 4 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions libs/blocks/locui/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async function findPageFragments(path) {
const isIndex = path.lastIndexOf('index');
const hlxPath = isIndex > 0 ? path.substring(0, isIndex) : path;
const doc = await fetchDocument(hlxPath);
if (!doc) return [];
if (!doc) return undefined;
// Decorate the doc, but don't load any blocks (i.e. do not use loadArea)
decorateSections(doc, true);
await decorateFooterPromo(doc);
Expand Down Expand Up @@ -103,6 +103,11 @@ async function findDeepFragments(path) {
const needsSearch = fragments.filter((fragment) => !searched.includes(fragment.pathname));
for (const search of needsSearch) {
const nestedFragments = await findPageFragments(search.pathname);
if (nestedFragments === undefined) {
search.valid = false;
searched.push(search.pathname);
break;
}
const newFragments = nestedFragments.filter((nested) => !searched.includes(nested.pathname)
&& !fragments.find((fragment) => fragment.pathname === nested.pathname));
if (newFragments?.length) fragments.push(...newFragments);
Expand All @@ -121,7 +126,7 @@ export async function findFragments() {
fragments.forEach((fragment) => {
// De-dupe across pages that share fragments
const dupe = acc.some((url) => url[0] === fragment.href);
if (!dupe) acc.push([fragment.href]);
if (!dupe) acc.push([fragment]);
});
}
return acc;
Expand Down
40 changes: 30 additions & 10 deletions libs/blocks/locui/actions/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ import { closeActionModal, findFragments, syncFragsLangstore } from './index.js'

function SyncFragments() {
const [fragments, setFragments] = useState(undefined);
const [errors, setErrors] = useState(undefined);

useEffect(() => {
let cancelled = false;
(async () => {
const find = await findFragments();
if (!cancelled) setFragments(find);
const found = await findFragments();
if (!cancelled) {
setFragments(found);
const invalid = found.filter((frag) => frag[0].valid !== undefined && !frag[0].valid);
setErrors(invalid.flat(1).map((err) => err.href));
}
})();
return () => { cancelled = true; };
}, []);
Expand All @@ -26,9 +31,16 @@ function SyncFragments() {
};

const locFragment = (fragment) => {
const disabled = !!urls.value.find((url) => url.href === fragment[0]);
const checked = syncFragments.value?.find((url) => url[0] === fragment[0]);
const url = new URL(fragment[0]);
const disabled = !!urls.value.find((url) => url.href === fragment[0].href);
const checked = syncFragments.value?.find((url) => url[0] === fragment[0].href);
const url = fragment[0];
if (errors.includes(url.href)) {
return html`
<div class=error-label>
<label>not found</label> ${url.pathname}
</div>
`;
}
return html`
<div
frag-url=${url.href}
Expand All @@ -42,23 +54,28 @@ function SyncFragments() {

const selectAllButton = () => {
if (!fragments?.length) return '';
const selected = syncFragments.value?.length === fragments?.length;
const toggle = () => { syncFragments.value = selected ? [] : fragments; };
const validFragments = fragments?.filter((url) => !errors.includes(url[0].href));
const selected = syncFragments.value?.length
&& syncFragments.value?.length === validFragments?.length;
const toggle = () => {
syncFragments.value = selected ? [] : validFragments.map((fragment) => [fragment[0].href]);
};
if (!validFragments?.length) return '';
return html`
<div
class="select-all${selected ? ' selected' : ''}"
title="Select All"
title="Select All Valid"
onClick=${toggle}>✓</div>
`;
};

const syncing = html`<div class=inline-loading>Scanning project for un-synced fragments</div>`;
const allFound = html`<div>✓ All Fragments have been added to this project.</div>`;
const allFound = html`<div>✓ All valid fragments have been added to this project.</div>`;
const fragmentStatus = fragments === undefined ? syncing : allFound;

return html`
<div class=locui-fragments-container>
<div class=locui-fragments-list>
<div class=locui-fragments-list>
<span class="un-synced-label${fragments?.length ? ' show' : ''}">
Un-synced fragments found in docs:
</div>
Expand All @@ -68,6 +85,9 @@ function SyncFragments() {
${selectAllButton()}
</div>
</div>
${errors?.length ? html`<div class=locui-fragment-errors>
Some fragments returned errors during validation. To sync these fragments, please fix errors and try again.
</div>` : ''}
`;
}

Expand Down
2 changes: 1 addition & 1 deletion libs/blocks/locui/actions/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function Actions() {
<div class=locui-section-heading>
<div>
<h2 class="locui-section-label cancelled">Project has errors</h2>
<i>Please fix errors in project to proceed.</i>
<i>Some URLs returned errors during validation. To create this project, please fix errors and try again.</i>
</div>
</div>
</div>
Expand Down
11 changes: 10 additions & 1 deletion libs/blocks/locui/loc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,20 @@ const urlParams = new URLSearchParams(window.location.search);
let resourcePath;
let previewPath;

async function validateUrl(url) {
try {
const request = await fetch(url.href);
return request;
} catch (error) {
return { ok: false, url: url.href };
}
}

async function validatedUrls(projectUrls) {
const validateUrls = [...projectUrls];
while (validateUrls.length) {
try {
const reqs = await Promise.all(validateUrls.splice(0, 49).map((url) => fetch(url.href)));
const reqs = await Promise.all(validateUrls.splice(0, 49).map(validateUrl));
setStatus('details', 'info', 'Validating Project URLs');
for (const res of reqs) {
const projectUrl = projectUrls.find((url) => url.href === res.url);
Expand Down
19 changes: 19 additions & 0 deletions libs/blocks/locui/locui.css
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,25 @@ button.locui-url-action-view {
overflow-y: auto;
}

.locui-fragment-errors {
color: red;
font-size: 16px;
font-style: italic;
}

.error-label {
display: flex;
align-items: center;
gap: 4px;
}

.error-label label {
color: red;
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
}

.locui-fragment {
cursor: pointer;
display: flex;
Expand Down
8 changes: 5 additions & 3 deletions libs/blocks/locui/status/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ export function renderLinks(str) {

function renderDescription(description) {
let message = description;
if (Array.isArray(description) && description.length > 1) {
message = html`<ol>${description.map((desc) => html`<li>${renderLinks(desc)}</li>`)}</ol>`;
} else return renderLinks(message[0]);
if (Array.isArray(description)) {
if (description.length > 1) {
message = html`<ol>${description.map((desc) => html`<li>${renderLinks(desc)}</li>`)}</ol>`;
} else return renderLinks(message[0]);
}
return message;
}

Expand Down
Loading