From fc42d511c0a5830a259d8017c79f760a52cd0812 Mon Sep 17 00:00:00 2001 From: Sean Archibeque Date: Wed, 29 May 2024 09:55:08 -0600 Subject: [PATCH] MWPW-148298 - [LocUI] URL validation (#2335) Validate URLs in configuration before letting users start a project --- libs/blocks/locui/actions/view.js | 14 ++++++++++++++ libs/blocks/locui/loc/index.js | 28 +++++++++++++++++++++++++--- libs/blocks/locui/locui.css | 16 ++++++++++++++++ libs/blocks/locui/url/tabs.js | 11 +++++++---- libs/blocks/locui/url/view.js | 4 ++-- 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/libs/blocks/locui/actions/view.js b/libs/blocks/locui/actions/view.js index 9396bc32df..55c2d728d0 100644 --- a/libs/blocks/locui/actions/view.js +++ b/libs/blocks/locui/actions/view.js @@ -19,6 +19,7 @@ import { } from './index.js'; export default function Actions() { + const hasErrors = urls.value.filter((url) => !url.valid)?.length > 0; const canAct = allowSyncToLangstore.value || allowSendForLoc.value || allowRollout.value @@ -27,6 +28,19 @@ export default function Actions() { const canReRollAll = languages.value.some((lang) => lang.status === 'completed'); const canRollAll = languages.value.some((lang) => lang.status === 'translated'); + if (hasErrors) { + return html` +
+
+
+ + Please fix errors in project to proceed. +
+
+
+ `; + } + if (projectCancelled.value) { return html`
diff --git a/libs/blocks/locui/loc/index.js b/libs/blocks/locui/loc/index.js index 9cc540a4be..f61a23b45a 100644 --- a/libs/blocks/locui/loc/index.js +++ b/libs/blocks/locui/loc/index.js @@ -23,6 +23,23 @@ const urlParams = new URLSearchParams(window.location.search); let resourcePath; let previewPath; +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))); + setStatus('details', 'info', 'Validating Project URLs'); + for (const res of reqs) { + const projectUrl = projectUrls.find((url) => url.href === res.url); + projectUrl.valid = res.ok; + } + } catch (error) { + setStatus('details', 'error', 'There was an error validating project URLs.', error); + } + } + return projectUrls; +} + export function getUrls(jsonUrls) { const { locales } = getConfig(); // Assume all URLs will be the same locale as the first URL @@ -84,9 +101,15 @@ async function loadDetails() { return rdx; }, []); languages.value = projectLangs; - urls.value = projectUrls; + setStatus('details', 'info', 'Validating Project Configuration'); + urls.value = await validatedUrls(projectUrls); if (json.settings) loadProjectSettings(json.settings.data); - setStatus('details'); + const errors = urls.value.filter((url) => !url.valid); + if (errors?.length > 0) { + setStatus('details', 'error', 'Invalid URLs.', errors.map((url) => (`${url.href} was not found.`))); + } else { + setStatus('details'); + } } catch { setStatus('details', 'error', 'Error loading languages and URLs.'); } @@ -99,7 +122,6 @@ async function loadHeading() { resourcePath = json.resourcePath; previewPath = json.preview.url; const path = resourcePath.replace(/\.[^/.]+$/, ''); - setStatus('details'); const projectName = json.edit.name.split('.').shift().replace('-', ' '); heading.value = { name: projectName, editUrl: json.edit.url, path }; window.document.title = `${projectName} - LocUI`; diff --git a/libs/blocks/locui/locui.css b/libs/blocks/locui/locui.css index 6607d88757..e9592e5b87 100644 --- a/libs/blocks/locui/locui.css +++ b/libs/blocks/locui/locui.css @@ -107,6 +107,7 @@ span.locui-sync-badge-mono { background-color: #0f7c41; height: 26px; border-radius: 2px; + cursor: pointer; } .locui-status-toast-section { @@ -421,6 +422,21 @@ li.locui-url { border-bottom: 1px solid #ccc; } +li.locui-url.error .locui-url-path { + color: red; + display: flex; + align-items: center; + gap: 10px; +} + +li.locui-url.error .locui-url-path span { + color: white; + background-color: red; + border-radius: 5px; + padding: 0 5px; + font-size: 12px; +} + li.locui-url:last-child { border-bottom: unset; } diff --git a/libs/blocks/locui/url/tabs.js b/libs/blocks/locui/url/tabs.js index 4e79f0905e..4f82fcf538 100644 --- a/libs/blocks/locui/url/tabs.js +++ b/libs/blocks/locui/url/tabs.js @@ -1,4 +1,5 @@ import { html, signal, useEffect, useMemo } from '../../../deps/htm-preact.js'; +import { urls } from '../utils/state.js'; import { setActions, openWord, handleAction } from './index.js'; function useSignal(value) { @@ -8,18 +9,20 @@ function useSignal(value) { function Actions({ item }) { const isExcel = item.value.path.endsWith('.json') ? ' locui-url-action-edit-excel' : ' locui-url-action-edit-word'; const isDisabled = (status) => (!status || status !== 200 ? ' disabled' : ''); + const itemUrl = urls.value.find((url) => url.pathname === item.value.path + || url.langstore.pathname === item.value.path); return html`
+ class="locui-url-action locui-url-action-edit${isExcel}${!itemUrl?.valid ? ' disabled' : ''}" + onClick=${(e) => { if (itemUrl.valid) openWord(e, item); }}>Edit + onClick=${(e) => { if (itemUrl.valid) handleAction(e, item, true); }}>Preview + onClick=${(e) => { if (itemUrl.valid) handleAction(e, item); }}>Live
`; } diff --git a/libs/blocks/locui/url/view.js b/libs/blocks/locui/url/view.js index 7600c2a1fb..29bcd4083f 100644 --- a/libs/blocks/locui/url/view.js +++ b/libs/blocks/locui/url/view.js @@ -6,9 +6,9 @@ export default function Url({ suffix, item }) { const langstorePath = item.langstore?.pathname; return html` -
  • +
  • Path

    -

    ${sourcePath}

    +

    ${sourcePath}${!item.valid ? html`NOT FOUND` : ''}

    <${Tabs} suffix=${suffix[0]} path=${sourcePath} /> ${langstorePath && html`