Verified with the coordinated workspace changes by devkit full run 2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed). This shared UI pass does not mark the individual module reviews complete.
115 lines
7.9 KiB
JavaScript
115 lines
7.9 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
function read(relativePath) {
|
|
return readFileSync(fileURLToPath(new URL(relativePath, import.meta.url)), "utf8");
|
|
}
|
|
|
|
const profiles = `${read("../src/features/mail/MailProfileManagement.tsx")}\n${read("../src/features/mail/MailProfilePolicyEditor.tsx")}`;
|
|
const mailbox = read("../src/features/mail/MailboxPage.tsx");
|
|
const mailApi = read("../src/api/mail.ts");
|
|
const bounces = read("../src/features/mail/MailBouncePage.tsx");
|
|
const legacyImport = read("../src/features/mail/MailLegacyImportPage.tsx");
|
|
const moduleSource = read("../src/module.ts");
|
|
const styles = read("../src/styles/mail-profiles.css");
|
|
const migration = read("../../docs/INTERFACE_PATTERN_MIGRATION.md");
|
|
|
|
assert.match(profiles, /ActionBlockerHint,[\s\S]*DocumentationHelpLink/);
|
|
for (const sharedComponent of ["ConnectionTree", "ConfirmDialog", "Dialog", "LoadingFrame"]) {
|
|
assert.match(profiles, new RegExp(`\\b${sharedComponent}\\b`));
|
|
}
|
|
assert.match(profiles, /topicId: "mail\.profiles-and-policy"/);
|
|
assert.match(profiles, /disabledReason: credentialMutationBlocker/);
|
|
assert.match(profiles, /disabledReason=\{editorSaveBlocker\}/);
|
|
assert.match(profiles, /disabledReason=\{policySaveBlocker\}/);
|
|
assert.match(profiles, /smtpActionDisabledReason=\{smtpTestBlocker\}/);
|
|
assert.match(profiles, /folder_mappings: draft\.imapFolderMappings/);
|
|
assert.match(profiles, /listMailProfileImapFolders[\s\S]*listImapFolders/);
|
|
assert.match(profiles, /onLookupImapFolders=\{\(\) => void runImapFolderLookup\(\)\}/);
|
|
assert.match(profiles, /imapFolderLookupResult=\{imapFolderResult\}/);
|
|
|
|
assert.match(mailbox, /ActionBlockerHint/);
|
|
assert.match(mailbox, /DocumentationHelpLink/);
|
|
assert.match(mailbox, /topicId: "mail\.workflow\.read-mailbox"/);
|
|
assert.match(mailbox, /disabledReason=\{folderReloadBlocker\}/);
|
|
assert.match(mailbox, /folder_mappings\?\.inbox/);
|
|
assert.match(mailbox, /detected_folder_mappings\?\.inbox/);
|
|
const openFolderNode = mailbox.slice(mailbox.indexOf(" function openFolderNode("), mailbox.indexOf(" function toggleFolderNode("));
|
|
assert.doesNotMatch(openFolderNode, /toggleFolderNode\(/, "Folder labels select; only the folder button expands or collapses.");
|
|
assert.match(openFolderNode, /setSelectedFolderGroup\(\{ id: node\.id, label: node\.label \}\)/);
|
|
assert.match(openFolderNode, /messageDetailRequestRef\.current \+= 1/, "Selecting a grouping invalidates pending message detail.");
|
|
assert.match(mailbox, /selectedFolderGroup\?\.id \?\? findFolderNodeId/);
|
|
assert.match(mailbox, /<WorkspaceFrame[^>]*height="viewport"/);
|
|
assert.match(mailbox, /<WorkspaceActionBar\s+title="i18n:govoplan-mail\.mailbox_workspace"\s+titleHelp=\{<DocumentationHelpLink reference=\{MAILBOX_DOCUMENTATION\} \/>\}\s+variant="workspace"\s+scope="workspace"[\s\S]*refreshable[\s\S]*onReload: \(\) => void reloadMailbox\(\)/);
|
|
assert.ok(mailbox.indexOf("<WorkspaceActionBar") < mailbox.indexOf('<aside className="file-tree-panel"'), "Mailbox actions remain outside all selectable panes.");
|
|
assert.equal((mailbox.match(/<WorkspaceActionBar/g) ?? []).length, 1, "One persistent page-wide action bar.");
|
|
assert.doesNotMatch(mailbox, /mailbox-toolbar|<ToolbarGroup/);
|
|
assert.match(mailbox, /const MAILBOX_READ_OPTIONS = \{ cache: "no-store" \}/);
|
|
assert.match(mailbox, /listMailServerProfiles\(settings, false, undefined, MAILBOX_READ_OPTIONS\)/);
|
|
for (const helper of ["listMailServerProfiles", "listMailboxFolders", "bootstrapMailbox", "listMailboxMessages", "getMailboxMessage"]) {
|
|
const start = mailApi.indexOf(`export async function ${helper}(`);
|
|
const end = mailApi.indexOf("\nexport async function ", start + 1);
|
|
const source = mailApi.slice(start, end < 0 ? undefined : end);
|
|
assert.match(source, /options\?: MailboxReadOptions/, `${helper} supports a scoped fresh read.`);
|
|
assert.match(source, /\}\), options\)/, `${helper} passes the read options to Core without global invalidation.`);
|
|
}
|
|
assert.match(mailbox, /<Dialog open=\{mailToolsOpen\}[\s\S]*mailbox_refresh_tools[\s\S]*refresh_mailbox_profiles[\s\S]*refresh_mailbox_folder_catalogue[\s\S]*refresh_mailbox_message_index[\s\S]*mailbox_related_tools/);
|
|
const refreshMailbox = mailbox.slice(mailbox.indexOf(" async function reloadMailbox("), mailbox.indexOf(" function selectProfile("));
|
|
assert.match(refreshMailbox, /await loadProfiles\(\)[\s\S]*if \(selectedFolderGroup\) await refreshFolderCatalogue\(result.selected\)/);
|
|
assert.match(refreshMailbox, /requestAuthority !== authorityRef.current/);
|
|
assert.match(refreshMailbox, /profileId === selectedProfileIdRef.current/);
|
|
assert.match(refreshMailbox, /if \(!preservePreview\) setSelectedMessage\(null\)/, "Failed preview refresh keeps the previously loaded message.");
|
|
assert.doesNotMatch(refreshMailbox, /sendMail|appendMail|moveMail|deleteMail|setFlags|createMail/, "Mailbox reload must remain provider-read-only.");
|
|
assert.match(mailbox, /onKeyDown=\{\(event\) => \{[\s\S]*event\.key === "Enter" \|\| event\.key === " "/);
|
|
|
|
assert.match(bounces, /DocumentationHelpLink/);
|
|
assert.match(bounces, /topicId: "mail\.bounce-processing"/);
|
|
assert.match(bounces, /<ConfirmDialog[\s\S]*confirmLabel="Remove watcher"[\s\S]*tone="danger"/);
|
|
assert.match(bounces, /disabledReason=\{saveWatcherBlocker\}/);
|
|
|
|
for (const sharedComponent of ["PageLayout", "PageActionBar", "SelectionList", "DataGrid", "Dialog", "ConfirmDialog", "ToggleSwitch", "StatusBadge"]) {
|
|
assert.match(legacyImport, new RegExp(`\\b${sharedComponent}\\b`));
|
|
}
|
|
assert.match(legacyImport, /archetype="collection"/);
|
|
assert.match(legacyImport, /variant="collection"[\s\S]*refreshable[\s\S]*reloadAction=/);
|
|
assert.match(legacyImport, /topicId: "mail\.workflow\.legacy-pop3-import"/);
|
|
assert.match(legacyImport, /helpContextId="mail\.pop3"[\s\S]*helpTopicId="mail\.workflow\.legacy-pop3-import"/);
|
|
for (const helpContextId of [
|
|
"mail.pop3.source-editor",
|
|
"mail.pop3.action.reload",
|
|
"mail.pop3.action.save-source",
|
|
"mail.pop3.action.import",
|
|
"mail.pop3.field.transport-security",
|
|
"mail.pop3.field.max-message-size",
|
|
"mail.pop3.field.max-batch-size",
|
|
"mail.pop3.field.password",
|
|
"mail.pop3.field.delete-after-import",
|
|
"mail.pop3.confirm-delete-source",
|
|
]) {
|
|
assert.match(
|
|
legacyImport,
|
|
new RegExp(`helpContextId(?:=|:\\s*)"${helpContextId.replaceAll(".", "\\.")}"`)
|
|
);
|
|
}
|
|
assert.match(legacyImport, /data-help-context-id="mail\.pop3\.field\.message-selection"/);
|
|
assert.match(legacyImport, /<ConfirmDialog[\s\S]*tone="danger"[\s\S]*onConfirm=\{\(\) => void runImport\(\)\}/);
|
|
assert.match(legacyImport, /legacy_import_enabled: false[\s\S]*is_active: false[\s\S]*createMailServerCredential[\s\S]*updateMailServerEndpoint/);
|
|
assert.match(legacyImport, /expected_transport_revision: preview\.transport_revision/);
|
|
|
|
assert.doesNotMatch(`${profiles}\n${mailbox}\n${bounces}\n${legacyImport}`, /window\.(?:alert|confirm)\(/);
|
|
assert.doesNotMatch(`${profiles}\n${mailbox}\n${bounces}\n${legacyImport}\n${moduleSource}`, /@govoplan\/(?:campaign|files|docs|calendar)-webui|govoplan_(?:campaign|files|docs|calendar)/);
|
|
assert.match(moduleSource, /"mail\.profiles"/);
|
|
assert.match(styles, /@media \(max-width: 900px\)[\s\S]*\.mail-profile-transport-summary[\s\S]*grid-template-columns: 1fr/);
|
|
assert.match(styles, /@media \(max-width: 1280px\)[\s\S]*\.mailbox-shell\.file-manager-shell[\s\S]*grid-template-columns:/);
|
|
assert.doesNotMatch(styles, /\.mailbox-toolbar/, "Core owns workspace toolbar wrapping and action ordering.");
|
|
assert.match(styles, /@media \(max-width: 760px\)[\s\S]*\.mailbox-message-row[\s\S]*grid-template-columns: 1fr/);
|
|
|
|
for (const archetype of ["Directory/explorer", "Administration/configuration", "Effective-policy editor", "Evidence/reporting"]) {
|
|
assert.match(migration, new RegExp(archetype.replace("/", "\\/")));
|
|
}
|
|
assert.match(migration, /Shared `Dialog` owns focus entry, Escape handling, focus containment, and focus\s+return/);
|
|
assert.match(migration, /Passwords are write-only[\s\S]*saved\s+state marker/);
|
|
|
|
console.log("Mail surfaces satisfy the recorded interface pattern-language contract.");
|