diff --git a/plugins/ms-ai-architect/playground/ms-ai-architect-playground.html b/plugins/ms-ai-architect/playground/ms-ai-architect-playground.html index 7c0ef7d..7312635 100644 --- a/plugins/ms-ai-architect/playground/ms-ai-architect-playground.html +++ b/plugins/ms-ai-architect/playground/ms-ai-architect-playground.html @@ -176,6 +176,15 @@ .key-stat[data-modifier="high"] .key-stat__value { color: var(--color-severity-high); } .key-stat[data-modifier="medium"] .key-stat__value { color: var(--color-severity-medium); } .key-stat[data-modifier="low"] .key-stat__value { color: var(--color-severity-low); } + + /* Tier 3 A4 — Screen-tabs (segmented). Inline her per scope-regel + (plugin standalone). Kandidat for hoisting til shared/ i Sesjon 6. */ + .screen-tabs { display: flex; gap: var(--space-1); padding: 4px; background: var(--color-bg-soft); border-radius: var(--radius-md); width: fit-content; margin: 0 0 var(--space-4) 0; } + .screen-tab { padding: var(--space-2) var(--space-3); font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); background: transparent; border: none; border-radius: var(--radius-sm); cursor: pointer; color: var(--color-text-secondary); font-family: inherit; } + .screen-tab:hover { color: var(--color-text-primary); } + .screen-tab[aria-current="true"] { background: var(--color-surface); color: var(--color-text-primary); box-shadow: var(--shadow-sm); } + .screen { display: none; } + .screen[data-active="true"] { display: block; } @@ -1565,6 +1574,45 @@ return count; } + // Aggregert verdict for project-surface page-shell. Henter parsed.verdict + // fra alle reports og kollapser til én pille: block > go-with-conditions + // > approved > n-a. Tom reports{} -> 'n-a' per Sesjon 2-risk-flagg. + function inferProjectVerdict(project) { + const reports = (project && project.reports) || {}; + const verdicts = []; + for (const k in reports) { + const v = reports[k] && reports[k].parsed && reports[k].parsed.verdict; + if (v) verdicts.push(String(v).toLowerCase()); + } + if (verdicts.length === 0) return 'n-a'; + for (let i = 0; i < verdicts.length; i++) { + if (verdicts[i] === 'block' || verdicts[i] === 'failed') return 'block'; + } + for (let i = 0; i < verdicts.length; i++) { + const v = verdicts[i]; + if (v === 'go-with-conditions' || v === 'warning') return 'go-with-conditions'; + } + let allGo = true; + for (let i = 0; i < verdicts.length; i++) { + const v = verdicts[i]; + if (v !== 'go' && v !== 'approved' && v !== 'allow') { allGo = false; break; } + } + return allGo ? 'approved' : 'n-a'; + } + + function inferProjectLastUpdated(project) { + const reports = (project && project.reports) || {}; + let latest = null; + for (const k in reports) { + const r = reports[k]; + if (r && r.updatedAt) { + if (!latest || r.updatedAt > latest) latest = r.updatedAt; + } + } + const ts = latest || (project && project.createdAt) || ''; + return ts ? String(ts).slice(0, 10) : '–'; + } + function projectMeterBand(filled, total) { if (total === 0) return '4'; // tom = "krever oppmerksomhet" const pct = filled / total; @@ -1647,17 +1695,20 @@ })(); const orgName = (store.state.shared.organization && store.state.shared.organization.name) || ''; - const heroHtml = ( - '
' + - '

' + (orgName ? 'Hei, ' + escapeHtml(orgName) : 'ms-ai-architect') + '

' + - '

' + (orgName - ? 'Velg hvor du vil starte. Felles state er aktiv og forhåndsutfyller skjemaer.' - : 'Single-file arkitektur-rådgivning for Microsoft AI-stakken. Start med onboarding for å aktivere felles state.' - ) + '

' + - '
' - ); - - const projectsSection = ( + const activeReportCount = projects.reduce(function (a, p) { return a + projectReportCount(p); }, 0); + const homeShell = renderPageShell({ + eyebrow: 'HJEM', + title: 'Hei, ' + (orgName || 'venn'), + lede: orgName + ? 'Velg arbeidsspor eller utforsk eksisterende prosjekter. Felles state er aktiv og forhåndsutfyller skjemaer.' + : 'Single-file arkitektur-rådgivning for Microsoft AI-stakken. Start med onboarding for å aktivere felles state.', + verdict: 'n-a', + keyStats: [ + { label: 'PROSJEKTER', value: projects.length }, + { label: 'AKTIVE RAPPORTER', value: activeReportCount } + ] + }, + tracksHtml + '
' + '
' + '

Mine prosjekter

' + @@ -1671,9 +1722,7 @@ root.innerHTML = ( renderTopbar('Hjem') + '
' + - heroHtml + - tracksHtml + - projectsSection + + homeShell + '
' ); } @@ -1709,6 +1758,11 @@ ]; let currentProjectTab = 'regulatory'; + // Screen-tabs på project-surface (A4 Tier 3): Oversikt / Rapporter / + // Kontekst / Eksport. Default 'rapporter' = primær arbeidsflate (eksisterende + // category-tabs + panels). Andre skjermer er stub i Sesjon 2 og fylles ut + // i senere sesjoner. + let currentProjectScreen = 'rapporter'; function findProject(id) { const list = store.state.projects || []; @@ -1734,6 +1788,7 @@ store.state.projects.push(project); store.state.activeProjectId = id; currentProjectTab = 'regulatory'; + currentProjectScreen = 'rapporter'; return project; } @@ -1931,30 +1986,36 @@ const reportTotal = CATALOG.commands.filter(function (c) { return c.produces_report; }).length; const reportFilled = projectReportCount(project); - const scenarioChips = (project.scenarios || []).map(function (sid) { - const s = SCENARIOS.find(function (x) { return x.id === sid; }); - return '' + escapeHtml(s ? s.name : sid) + ''; - }).join(''); - const dateChip = 'opprettet ' + escapeHtml((project.createdAt || '').slice(0, 10)) + ''; - const progressChip = '' + reportFilled + '/' + reportTotal + ' rapporter'; - - const headerHtml = ( - '
' + - '
' + - '
' + - '

' + escapeHtml(project.name) + '

' + - (project.description ? '

' + escapeHtml(project.description) + '

' : '') + - '
' + - '
' + - '' + - '' + - '
' + - '
' + - '
' + dateChip + progressChip + scenarioChips + '
' + - '
' + // Action-bar (Tilbake / Slett) flyttet under page-shell-headeren — + // page__header har dedikert verdict-slot som ikke tar arbitrary HTML. + const actionBar = ( + '
' + + '' + + '' + + '
' ); - // Tabs per CATALOG.categories + // Screen-tabs (A4 Tier 3): Oversikt / Rapporter / Kontekst / Eksport. + // Sesjon 2: Rapporter er primær; andre er stub-skjermer som fylles ut + // i Sesjon 3-6. + const SCREENS = [ + { id: 'oversikt', label: 'Oversikt' }, + { id: 'rapporter', label: 'Rapporter' }, + { id: 'kontekst', label: 'Kontekst' }, + { id: 'eksport', label: 'Eksport' } + ]; + const screenTabsHtml = ''; + + // Tabs per CATALOG.categories — kun synlig under "Rapporter"-skjermen. const tabsHtml = '
' + CATALOG.categories.map(function (cat) { const isActive = currentProjectTab === cat.id; return ( @@ -1982,12 +2043,79 @@ ); }).join(''); + const scenarioChipsList = (project.scenarios || []).map(function (sid) { + const s = SCENARIOS.find(function (x) { return x.id === sid; }); + return '
  • ' + escapeHtml(s ? s.name : sid) + '
  • '; + }).join(''); + + const oversiktHtml = ( + '
    ' + + '
    ' + + '' + + '
    ' + + '

    Oversikt

    ' + + '

    Opprettet ' + escapeHtml((project.createdAt || '').slice(0, 10)) + '. ' + reportFilled + ' av ' + reportTotal + ' rapporter generert.

    ' + + (scenarioChipsList ? '

    Scenarioer:

      ' + scenarioChipsList + '
    ' : '') + + '

    Sesjon 3+: aggregerte verdict-pillen, recommended-next-actions og top-risks vises her.

    ' + + '
    ' + + '
    ' + + '
    ' + ); + + const rapporterHtml = ( + '
    ' + + tabsHtml + + panelsHtml + + '
    ' + ); + + const kontekstHtml = ( + '
    ' + + '
    ' + + '' + + '
    ' + + '

    Kontekst

    ' + + '

    Fellesfeltene fra onboarding gjenbrukes automatisk i alle command-skjemaer. Bruk for å oppdatere.

    ' + + '

    Sesjon 3+: snapshot av de 20 fellesfeltene og hva som er prefilled per command vises her.

    ' + + '
    ' + + '
    ' + + '
    ' + ); + + const eksportHtml = ( + '
    ' + + '
    ' + + '' + + '
    ' + + '

    Eksport

    ' + + '

    Bruk Eksporter i topbar for hele state. Per-prosjekt eksport (PDF/Markdown) kommer i Sesjon 6.

    ' + + '
    ' + + '
    ' + + '
    ' + ); + + const projectShell = renderPageShell({ + eyebrow: 'PROSJEKT', + title: project.name, + lede: project.description || '', + verdict: inferProjectVerdict(project), + keyStats: [ + { label: 'RAPPORTER', value: reportFilled + '/' + reportTotal }, + { label: 'SIST OPPDATERT', value: inferProjectLastUpdated(project) } + ] + }, + actionBar + + screenTabsHtml + + oversiktHtml + + rapporterHtml + + kontekstHtml + + eksportHtml + ); + root.innerHTML = ( renderTopbar('Prosjekt: ' + escapeHtml(project.name)) + '
    ' + - headerHtml + - tabsHtml + - panelsHtml + + projectShell + '
    ' ); } @@ -2092,18 +2220,27 @@ const q = (catalogSearchQuery || '').trim().toLowerCase(); const totalMatches = CATALOG.commands.filter(function (c) { return catalogMatches(c, q); }).length; const countText = totalMatches + ' av ' + CATALOG.commands.length + ' treff' + (q ? ' for «' + escapeHtml(catalogSearchQuery) + '»' : ''); + const catalogShell = renderPageShell({ + eyebrow: 'KATALOG', + title: 'Command-katalog', + lede: '24 kommandoer i 5 fagområder. Filtrer for å finne det du trenger, åpne skjema for å bygge en pipeline-streng.', + verdict: 'n-a', + keyStats: [ + { label: 'KOMMANDOER', value: 24 }, + { label: 'AGENTER', value: 12 }, + { label: 'SKILLS', value: 5 } + ] + }, + '
    ' + + '' + + '' + countText + '' + + '
    ' + + '
    ' + renderCatalogGroupsHtml() + '
    ' + ); root.innerHTML = ( renderTopbar('Katalog') + '
    ' + - '
    ' + - '

    Command-katalog

    ' + - '

    24 commands gruppert i 5 kategorier. Åpne skjema for å bygge en pipeline-streng som kopieres til terminalen og kjøres med Claude Code.

    ' + - '
    ' + - '
    ' + - '' + - '' + countText + '' + - '
    ' + - '
    ' + renderCatalogGroupsHtml() + '
    ' + + catalogShell + '
    ' ); } @@ -3873,20 +4010,26 @@ '
    ' ); + const onboardingShell = renderPageShell({ + eyebrow: 'ONBOARDING', + title: 'Bli kjent med oss', + lede: 'Oppgi virksomhetskontekst slik at vi kan tilpasse arkitekturråd til din situasjon. 20 felles felter gjenbrukes på tvers av alle commands.', + verdict: 'n-a', + keyStats: [] + }, + '
    ' + + sidebar + + '
    ' + + errorSummary + + '
    ' + groupsHtml + '
    ' + + actionBar + + '
    ' + + '
    ' + ); + root.innerHTML = ( '
    ' + - '
    ' + - sidebar + - '
    ' + - '
    ' + - '

    Velkommen til ms-ai-architect

    ' + - '

    Fyll inn 20 felles felter — de gjenbrukes på tvers av alle commands og forhåndsutfyller skjemaer per prosjekt.

    ' + - '
    ' + - errorSummary + - '
    ' + groupsHtml + '
    ' + - actionBar + - '
    ' + - '
    ' + + onboardingShell + '
    ' ); } @@ -4137,6 +4280,24 @@ }); }; + ACTIONS['project-screen'] = function (ev, el) { + const screen = el.dataset.screen; + if (!screen) return; + currentProjectScreen = screen; + // Toggle aria-current på screen-tabs + data-active på .screen-paneler + // uten full re-render (bevarer evt textarea-input i panels). + const root = getSurfaceEl('project'); + if (!root) return; + const tabs = root.querySelectorAll('.screen-tab'); + tabs.forEach(function (t) { + t.setAttribute('aria-current', t.dataset.screen === screen ? 'true' : 'false'); + }); + const screens = root.querySelectorAll('.screen[data-screen-id]'); + screens.forEach(function (s) { + s.setAttribute('data-active', s.dataset.screenId === screen ? 'true' : 'false'); + }); + }; + ACTIONS['parse'] = function (ev, el) { const commandId = el.dataset.command; if (!commandId) return;