From de1a57e4c6429db42fcec03b1aebcc91e5dc76e2 Mon Sep 17 00:00:00 2001 From: Root At Skic Date: Mon, 19 Oct 2026 20:39:24 +0300 Subject: [PATCH 1/2] Model page: Registry panel lists registry files, elements inside each - one collapsible header per .archify-registry file with its element count and an Open button that opens the registry view; files start collapsed, the Registry panel open - view types moved to views/viewTypes.ts so the diagram page can open a registry without a circular import - 0.7.1 --- CHANGELOG.md | 4 ++++ README.md | 2 +- package-lock.json | 4 ++-- package.json | 10 +++++----- src/views/diagramView.ts | 16 ++++++++++------ src/views/registryView.ts | 5 ++--- src/views/viewTypes.ts | 6 ++++++ src/webview/page.ts | 32 +++++++++++++++++++++++++++----- 8 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 src/views/viewTypes.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d2b212..fafc8a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.7.1 — 2026-10-19 + +- **Model page, Registry panel:** lists the registry files of the model, one collapsible header per file with its element count and an **Open** button that opens the registry view; expand a file to see its elements as cards. Before, all elements of all files were shown in one grid. + ## 0.7.0 — 2026-10-19 - **Models:** a folder with a `main.archify` at its top is a model, a set of diagrams that belong together. Opening `main.archify` shows the model page: name and description, the overview diagram if the file has one, the diagrams grouped by folder (click to open), and the registry with where each element is used. diff --git a/README.md b/README.md index 4a7060e..f7b1d01 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ online-shop/ 0300-components/api.archify ``` -- **The model page.** Click `main.archify` and you get the model's page: its name and description, the overview diagram if the file has one, then two collapsible panels: **Diagrams**, with a collapsible header per folder and a card per diagram (click to open), and **Registry**, the shared elements as cards with the diagrams each is used in. Open or closed is remembered per page. +- **The model page.** Click `main.archify` and you get the model's page: its name and description, the overview diagram if the file has one, then two collapsible panels: **Diagrams**, with a collapsible header per folder and a card per diagram (click to open), and **Registry**, one collapsible header per registry file (with an **Open** button for its view) and the file's elements as cards inside, each with the diagrams it is used in. Open or closed is remembered per page. - **Shared elements.** A registry file defines an element once (`type`, `label`, `sublabel`, `brand`, `description`, …). A diagram draws it with `ref: api` plus `pos` and `size`; it may override `label`, `sublabel` and `tag`, and may still define unshared elements inline. Hover a `ref` for the description, F12 jumps to the registry, completion after `ref:` lists the elements, unknown names appear in Problems. - **Links.** A registry element (or a component) with `diagram: 0300-components/api.archify` points at the diagram that explains it: double-click the node in the 2D view to open it. - **Cards.** A model diagram without `cards` of its own shows one card per shared element it draws, from the registry descriptions. The model page shows the registry as the same cards, each with the diagrams it is used in. diff --git a/package-lock.json b/package-lock.json index cecf77a..65f4bc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "archify-vscode-ext", - "version": "0.7.0", + "version": "0.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "archify-vscode-ext", - "version": "0.7.0", + "version": "0.7.1", "license": "MIT", "dependencies": { "three": "^0.186.1", diff --git a/package.json b/package.json index 8063330..d4326ef 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "archify-vscode-ext", "displayName": "Archify Diagram Viewer", - "description": "Archify diagrams in VS Code. Write diagrams as .archify files in YAML: they open as the interactive diagram, with live updates, validation, templates and completion. Also previews Archify's own JSON files (*.architecture.json, …) and opens rendered Archify HTML.", - "version": "0.7.0", + "description": "Archify diagrams in VS Code. Write diagrams as .archify files in YAML: they open as the interactive diagram, with live updates, validation, templates and completion. Also previews Archify's own JSON files (*.architecture.json, \u2026) and opens rendered Archify HTML.", + "version": "0.7.1", "publisher": "root-at-skic", "license": "MIT", "sponsor": { @@ -48,12 +48,12 @@ "commands": [ { "command": "archify.newDiagram", - "title": "Archify | New Diagram…", + "title": "Archify | New Diagram\u2026", "icon": "$(new-file)" }, { "command": "archify.newModel", - "title": "Archify | New Model…", + "title": "Archify | New Model\u2026", "icon": "$(new-folder)" }, { @@ -73,7 +73,7 @@ }, { "command": "archify.renderToHtml", - "title": "Archify | Render to HTML File…", + "title": "Archify | Render to HTML File\u2026", "icon": "$(file-code)" }, { diff --git a/src/views/diagramView.ts b/src/views/diagramView.ts index 2c8cebd..b520b20 100644 --- a/src/views/diagramView.ts +++ b/src/views/diagramView.ts @@ -14,9 +14,9 @@ import { handleWebviewMessage, WebviewMessage } from '../webview/messages'; import { makeNonce, messagePage, modelPage, prepareDiagramHtml } from '../webview/page'; import { viewer3dOption, viewerRoots } from '../webview/viewer3d'; -export const PREVIEW_VIEW_TYPE = 'archify.preview'; -/** Default editor for .archify files: the rendered diagram. */ -export const DIAGRAM_EDITOR_VIEW_TYPE = 'archify.diagram'; +import { DIAGRAM_EDITOR_VIEW_TYPE, PREVIEW_VIEW_TYPE, REGISTRY_VIEW_TYPE } from './viewTypes'; + +export { DIAGRAM_EDITOR_VIEW_TYPE, PREVIEW_VIEW_TYPE }; interface PreviewState { uri: string; @@ -59,7 +59,11 @@ class DiagramPreview implements vscode.Disposable { return; } if (message.type === 'openDiagram') { - void this.openLinked(message.path); + void this.openLinked(message.path, DIAGRAM_EDITOR_VIEW_TYPE); + return; + } + if (message.type === 'openRegistry') { + void this.openLinked(message.file, REGISTRY_VIEW_TYPE); return; } void handleWebviewMessage(message, this.uri, this.panel); @@ -96,7 +100,7 @@ class DiagramPreview implements vscode.Disposable { } /** Opens a diagram of the model, given its path relative to the model root. */ - private async openLinked(relativePath: string): Promise { + private async openLinked(relativePath: string, viewType: string): Promise { if (!this.root) return; const target = vscode.Uri.joinPath(this.root, ...relativePath.split('/')); try { @@ -105,7 +109,7 @@ class DiagramPreview implements vscode.Disposable { vscode.window.showWarningMessage(`Archify: ${relativePath} does not exist in this model.`); return; } - await vscode.commands.executeCommand('vscode.openWith', target, DIAGRAM_EDITOR_VIEW_TYPE, vscode.ViewColumn.Active); + await vscode.commands.executeCommand('vscode.openWith', target, viewType, vscode.ViewColumn.Active); } private showModelPage(model: ModelPanel): void { diff --git a/src/views/registryView.ts b/src/views/registryView.ts index 25d8779..d29e8ff 100644 --- a/src/views/registryView.ts +++ b/src/views/registryView.ts @@ -7,10 +7,9 @@ import { readText } from '../util/files'; import { log } from '../util/log'; import { handleWebviewMessage, WebviewMessage } from '../webview/messages'; import { makeNonce, registryPage } from '../webview/page'; -import { DIAGRAM_EDITOR_VIEW_TYPE } from './diagramView'; +import { DIAGRAM_EDITOR_VIEW_TYPE, REGISTRY_VIEW_TYPE } from './viewTypes'; -/** Default editor for .archify-registry files: the elements as cards, each with where it is used. */ -export const REGISTRY_VIEW_TYPE = 'archify.registry'; +export { REGISTRY_VIEW_TYPE }; class RegistryDocument implements vscode.CustomDocument { constructor(readonly uri: vscode.Uri) {} diff --git a/src/views/viewTypes.ts b/src/views/viewTypes.ts new file mode 100644 index 0000000..0830573 --- /dev/null +++ b/src/views/viewTypes.ts @@ -0,0 +1,6 @@ +/** Custom editor view types, in one place so views can refer to each other without importing each other. */ +export const PREVIEW_VIEW_TYPE = 'archify.preview'; +/** Default editor for .archify files: the rendered diagram. */ +export const DIAGRAM_EDITOR_VIEW_TYPE = 'archify.diagram'; +/** Default editor for .archify-registry files: the elements as cards. */ +export const REGISTRY_VIEW_TYPE = 'archify.registry'; diff --git a/src/webview/page.ts b/src/webview/page.ts index 526d69f..95072ee 100644 --- a/src/webview/page.ts +++ b/src/webview/page.ts @@ -189,6 +189,7 @@ function bridgeScript(options: PageOptions): string { // Collapsible panels of the model page; open/closed is kept in the webview state. function panelStates() { return (vscode.getState() || {}).modelPanels || {}; } function panel(key, className, title, count, defaultOpen) { + // count: a number or a short text such as "3 files". var details = el('details', 'archify-model-panel ' + className); var saved = panelStates()[key]; details.open = saved === undefined ? defaultOpen : saved; @@ -446,13 +447,30 @@ function bridgeScript(options: PageOptions): string { }); holder.appendChild(list); }); - // Registry elements as Archify info cards: the same cards a diagram shows below itself. + // Registry: one collapsible header per registry file, its elements as cards inside. if (model.registry.length) { - var registryPanel = panel('registry', 'archify-model-registry', 'Registry', model.registry.length, false); + var files = []; + var byFile = {}; + model.registry.forEach(function (element) { + if (!byFile[element.file]) { byFile[element.file] = []; files.push(element.file); } + byFile[element.file].push(element); + }); + files.sort(); + var registryPanel = panel('registry', 'archify-model-registry', 'Registry', files.length + (files.length === 1 ? ' file' : ' files'), true); body.appendChild(registryPanel); - var cards = el('div', 'cards archify-model-cards'); - model.registry.forEach(function (element) { cards.appendChild(elementCard(element)); }); - registryPanel.appendChild(cards); + files.forEach(function (file) { + var elements = byFile[file].slice().sort(function (a, b) { return a.line - b.line; }); + var filePanel = panel('registry:' + file, 'archify-model-folder archify-model-registry-file', file.replace(/\.archify-registry$/, ''), elements.length + (elements.length === 1 ? ' element' : ' elements'), false); + var open = el('button', 'archify-model-used-link archify-model-open-file', 'Open'); + open.type = 'button'; + open.title = 'Open ' + file; + open.addEventListener('click', function (event) { event.preventDefault(); event.stopPropagation(); post({ type: 'openRegistry', file: file, line: 0 }); }); + filePanel.firstChild.appendChild(open); + var cards = el('div', 'cards archify-model-cards'); + elements.forEach(function (element) { cards.appendChild(elementCard(element)); }); + filePanel.appendChild(cards); + registryPanel.appendChild(filePanel); + }); } if (anchor && anchor.parentNode) anchor.parentNode.insertBefore(body, anchor.nextSibling); else document.body.appendChild(body); } @@ -502,6 +520,10 @@ const MODEL_STYLE = ` .archify-model-folder > .archify-model-summary { padding: 0.55rem 0.75rem; font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--m-muted); font-family: ui-monospace, Menlo, monospace; } .archify-model-folder > .archify-model-summary:hover { color: var(--m-accent); } .archify-model-folder > .archify-model-list { margin: 0 0.75rem; } +.archify-model-registry-file > .archify-model-summary { text-transform: none; letter-spacing: 0; font-size: 0.8125rem; } +.archify-model-registry-file > .archify-model-cards { margin: 0.25rem 0.75rem 0; } +.archify-model-open-file { margin-left: 0.5rem; text-transform: none; letter-spacing: 0; font-family: inherit; } +.archify-model-open-file:hover { color: var(--m-accent); } .archify-model-diagrams > .archify-model-list { margin-top: 0.25rem; } .archify-model-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.5rem; } .archify-model-open { display: flex; flex-direction: column; gap: 0.2rem; width: 100%; padding: 0.7rem 0.85rem; text-align: left; cursor: pointer; font: inherit; color: var(--m-text); background: var(--m-panel); border: 1px solid var(--m-border); border-radius: 0.6rem; transition: border-color 0.15s, transform 0.15s; } -- 2.54.0 From 094ca2925f54670dd8f4cb1ce9ec71204465947c Mon Sep 17 00:00:00 2001 From: Root At Skic Date: Mon, 19 Oct 2026 20:44:09 +0300 Subject: [PATCH 2/2] Drop generated cards; registry descriptions become Elements tooltips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolveRefs no longer adds cards to a diagram; it returns node id → description, which the page sets as the tooltip of the matching row in Archify's Elements panel - hand-written cards pass through unchanged; docs and changelog --- CHANGELOG.md | 1 + README.md | 2 +- docs/model.md | 4 +-- src/model/format.ts | 55 +++++----------------------------------- src/model/prepare.ts | 4 ++- src/views/diagramView.ts | 3 ++- src/webview/page.ts | 13 ++++++++++ test/model.test.ts | 22 ++++------------ 8 files changed, 34 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fafc8a7..0709251 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 0.7.1 — 2026-10-19 +- **No generated cards.** The cards 0.7.0 generated under model diagrams from registry descriptions are gone; they repeated the Elements panel. The description now shows as the tooltip of the element's row in the Elements panel. Hand-written `cards:` are unchanged. - **Model page, Registry panel:** lists the registry files of the model, one collapsible header per file with its element count and an **Open** button that opens the registry view; expand a file to see its elements as cards. Before, all elements of all files were shown in one grid. ## 0.7.0 — 2026-10-19 diff --git a/README.md b/README.md index f7b1d01..401bb6c 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ online-shop/ - **The model page.** Click `main.archify` and you get the model's page: its name and description, the overview diagram if the file has one, then two collapsible panels: **Diagrams**, with a collapsible header per folder and a card per diagram (click to open), and **Registry**, one collapsible header per registry file (with an **Open** button for its view) and the file's elements as cards inside, each with the diagrams it is used in. Open or closed is remembered per page. - **Shared elements.** A registry file defines an element once (`type`, `label`, `sublabel`, `brand`, `description`, …). A diagram draws it with `ref: api` plus `pos` and `size`; it may override `label`, `sublabel` and `tag`, and may still define unshared elements inline. Hover a `ref` for the description, F12 jumps to the registry, completion after `ref:` lists the elements, unknown names appear in Problems. - **Links.** A registry element (or a component) with `diagram: 0300-components/api.archify` points at the diagram that explains it: double-click the node in the 2D view to open it. -- **Cards.** A model diagram without `cards` of its own shows one card per shared element it draws, from the registry descriptions. The model page shows the registry as the same cards, each with the diagrams it is used in. +- **Descriptions.** Under a model diagram, hovering a row of the **Elements** panel shows the registry description of that element. - **Registry view.** A `.archify-registry` file opens as its elements, as cards. Click one and a dialog shows its description, where it is defined and the diagrams that use it; click a diagram to open it. **Show Source** opens the YAML beside it. - **Elements and Connectors.** Under every diagram, Archify's node index is titled **Elements**, and a **Connectors** panel next to it lists every connection as "from → to" with its label. Hovering highlights the connector in the diagram; clicking keeps it highlighted and scrolls to it. - **Starting one.** *Archify | New Model…* (right-click a folder) copies one of the shipped examples into a new folder, named as you choose: **C4 - Standard Web App** (single-page app, API, database, cache, storage, identity provider), **C4 - E-Shop** (web shop, API, worker, queue, payment and email providers) or **C4 - Event-Based Integration** (event bus, router, dead-letter queue, event store, consumers). Each has a registry and context, container and component diagrams. For an empty model, *Archify | New Diagram… → Model* creates just a `main.archify`. diff --git a/docs/model.md b/docs/model.md index f5d5c1b..f2e0c36 100644 --- a/docs/model.md +++ b/docs/model.md @@ -64,9 +64,9 @@ components: - Before Archify runs, the extension replaces each `ref` component with the registry element plus the diagram's own fields, drops `description` and `diagram`, and hands Archify an ordinary component. - Connections, boundaries and everything else stay as they are and use the ids as before. -## Cards under a model diagram +## Descriptions under a model diagram -Archify shows `cards` (a coloured dot, a title, a few lines) below a diagram. A diagram inside a model that draws shared elements and defines no `cards` of its own gets one card per drawn element that has a `description` in the registry, in drawing order, with the dot colour of the element's type. Write your own `cards:` in the diagram to replace them. +Archify's **Elements** panel under a diagram lists its nodes. For a `ref` component the row's tooltip is the element's registry `description`. Archify's own `cards:` stay what they are: write them in the diagram when you want text blocks below it; nothing is generated. ## Links between diagrams diff --git a/src/model/format.ts b/src/model/format.ts index 2022e5d..a026fd0 100644 --- a/src/model/format.ts +++ b/src/model/format.ts @@ -55,42 +55,6 @@ export interface Registry { problems: ModelProblem[]; } -/** Archify card dot colour for a component type (the colours Archify gives the nodes). */ -const DOT_BY_TYPE: Record = { - frontend: 'cyan', - backend: 'emerald', - database: 'violet', - cloud: 'amber', - security: 'rose', - messagebus: 'orange', - external: 'slate', -}; - -export function dotForType(type?: string): string { - return DOT_BY_TYPE[type ?? ''] ?? 'slate'; -} - -export interface Card { - dot: string; - title: string; - items: string[]; -} - -/** - * Archify info cards for registry elements: one per element that has a - * description, titled by its label. What a diagram gets below itself when - * it draws shared elements and defines no cards of its own. - */ -export function cardsFromElements(elements: Iterable): Card[] { - const cards: Card[] = []; - for (const element of elements) { - if (!element.description) continue; - const items = [element.description.trim()]; - cards.push({ dot: dotForType(element.type), title: element.label ?? element.id, items }); - } - return cards; -} - export function isMainFile(fileName: string): boolean { return (fileName.split(/[\\/]/).pop() ?? '') === MAIN_FILE; } @@ -196,6 +160,8 @@ export interface ResolvedDiagram { links: Map; /** Registry element ids used by this diagram. */ used: Set; + /** Node id → registry description, for the Elements panel. */ + descriptions: Map; } export interface ResolveOptions { @@ -208,20 +174,19 @@ export interface ResolveOptions { * Expands `ref` components from the registry and strips what Archify does * not know. Component order and indexes are kept, so Archify's diagnostics * (JSON pointers) still point at the right component in the source file. - * A diagram without `cards` of its own gets cards from the descriptions of - * the shared elements it draws, so the registry text shows under the diagram. */ export function resolveRefs(doc: unknown, options: ResolveOptions): ResolvedDiagram { const problems: ModelProblem[] = []; const refs = new Map(); const links = new Map(); const used = new Set(); - if (!isObj(doc)) return { diagram: {}, problems, refs, links, used }; + const descriptions = new Map(); + if (!isObj(doc)) return { diagram: {}, problems, refs, links, used, descriptions }; const diagram: Obj = { ...doc }; delete diagram.model; const { registry } = options; const components = Array.isArray(doc.components) ? doc.components : undefined; - if (!components) return { diagram, problems, refs, links, used }; + if (!components) return { diagram, problems, refs, links, used, descriptions }; diagram.components = components.map((raw, index) => { if (!isObj(raw)) return raw; @@ -248,6 +213,7 @@ export function resolveRefs(doc: unknown, options: ResolveOptions): ResolvedDiag } used.add(ref); refs.set(index, element); + if (element.description) descriptions.set(id, element.description.trim()); for (const key of Object.keys(own)) { if ((COPIED_FIELDS as readonly string[]).includes(key) && !(OVERRIDABLE_FIELDS as readonly string[]).includes(key)) { problems.push({ @@ -267,14 +233,7 @@ export function resolveRefs(doc: unknown, options: ResolveOptions): ResolvedDiag if (link) links.set(id, link); return merged; }); - if (diagram.cards === undefined && refs.size) { - const seen = new Set(); - const elements: RegistryElement[] = []; - for (const element of refs.values()) if (!seen.has(element.id)) { seen.add(element.id); elements.push(element); } - const cards = cardsFromElements(elements); - if (cards.length) diagram.cards = cards; - } - return { diagram, problems, refs, links, used }; + return { diagram, problems, refs, links, used, descriptions }; } /** Group of a diagram inside a model: '' for the root folder, else the folder path with '/' separators. */ diff --git a/src/model/prepare.ts b/src/model/prepare.ts index 8f63d81..8cb4b03 100644 --- a/src/model/prepare.ts +++ b/src/model/prepare.ts @@ -16,6 +16,8 @@ export interface PreparedDiagram { problems: ModelProblem[]; /** Node id → diagram path relative to the model root. */ links: Map; + /** Node id → registry description. */ + descriptions: Map; } /** @@ -33,5 +35,5 @@ export async function prepareDiagram(models: ModelService, uri: vscode.Uri, text const prepared: DiagramSource = changed ? { ...source, diagram: resolved.diagram, json: JSON.stringify(resolved.diagram, null, 2) } : source; - return { source: prepared, root: found?.root, registry: found?.registry, problems: resolved.problems, links: resolved.links }; + return { source: prepared, root: found?.root, registry: found?.registry, problems: resolved.problems, links: resolved.links, descriptions: resolved.descriptions }; } diff --git a/src/views/diagramView.ts b/src/views/diagramView.ts index b520b20..8d310b1 100644 --- a/src/views/diagramView.ts +++ b/src/views/diagramView.ts @@ -199,10 +199,11 @@ class DiagramPreview implements vscode.Disposable { notice: result.evidenceNotice ? { kind: 'warning', text: result.evidenceNotice } : undefined, viewer3d: viewer3dOption(this.panel.webview, this.context.extensionUri), links: Object.fromEntries(prepared.links), + descriptions: Object.fromEntries(prepared.descriptions), model, }); // Nonces differ per render, so compare the renderer output instead. - const fingerprint = `${viewerTheme()}\u0000${result.evidenceNotice ?? ''}\u0000${JSON.stringify([model ?? null, [...prepared.links]])}\u0000${result.html}`; + const fingerprint = `${viewerTheme()}\u0000${result.evidenceNotice ?? ''}\u0000${JSON.stringify([model ?? null, [...prepared.links], [...prepared.descriptions]])}\u0000${result.html}`; if (!force && this.rendered && fingerprint === this.lastHtml) { void this.panel.webview.postMessage({ type: 'notice', notice: undefined }); return; diff --git a/src/webview/page.ts b/src/webview/page.ts index 95072ee..15624de 100644 --- a/src/webview/page.ts +++ b/src/webview/page.ts @@ -18,6 +18,8 @@ export interface PageOptions { links?: Record; /** The model page: metadata above the diagram, the diagram list and registry below. */ model?: ModelPanel; + /** Node id → registry description, shown as tooltips in the Elements panel. */ + descriptions?: Record; /** Registry page: the elements of one .archify-registry file. */ registry?: RegistryPanel; } @@ -77,6 +79,7 @@ function bridgeScript(options: PageOptions): string { links: options.links ?? {}, model: options.model, registry: options.registry, + descriptions: options.descriptions || {}, }; return `(function () { var config = ${scriptJson(config)}; @@ -322,6 +325,15 @@ function bridgeScript(options: PageOptions): string { document.body.appendChild(body); } + // Elements: registry descriptions as tooltips on Archify's node index rows. + function describeElements() { + var items = document.querySelectorAll('#node-outline .node-outline-item[data-outline-node]'); + Array.prototype.forEach.call(items, function (item) { + var text = config.descriptions[item.getAttribute('data-outline-node')]; + if (text) item.title = text; + }); + } + // Connectors: a rail panel next to Archify's Elements index, read from the // SVG's edges. Hover highlights the connector, click keeps it highlighted. function renderConnectors() { @@ -486,6 +498,7 @@ function bridgeScript(options: PageOptions): string { if (config.model) onReady(function () { renderModel(config.model); }); if (config.registry) onReady(function () { renderRegistry(config.registry); }); onReady(renderConnectors); + onReady(describeElements); if (config.notice) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function () { showNotice(config.notice); }); diff --git a/test/model.test.ts b/test/model.test.ts index af88282..b6bb7e5 100644 --- a/test/model.test.ts +++ b/test/model.test.ts @@ -3,8 +3,6 @@ import fs from 'node:fs'; import path from 'node:path'; import { test } from 'node:test'; import { - cardsFromElements, - dotForType, groupOf, hasDiagramBody, isMainFile, @@ -83,22 +81,12 @@ test('resolve: refs become full components, links and usage are collected', () = assert.deepEqual([...r.used].sort(), ['api', 'cache', 'customer', 'db', 'queue', 'web', 'worker']); assert.equal(r.refs.get(2)?.id, 'api'); assert.ok(!('model' in r.diagram)); - // Cards from the registry descriptions, in drawing order, one per element. - const cards = r.diagram.cards as { dot: string; title: string; items: string[] }[]; - assert.equal(cards.length, 7); - assert.deepEqual(cards[0], { dot: 'slate', title: 'Customer', items: ['Buys products; signs in with email or a social account.'] }); - assert.equal(cards.find((c) => c.title === 'API')?.dot, 'emerald'); -}); - -test('resolve: own cards win, no cards without refs or descriptions', () => { - const registry = registryOfModel(); + // Descriptions travel with the node ids, for the Elements panel; nothing is added to the diagram itself. + assert.ok(!('cards' in r.diagram)); + assert.equal(r.descriptions.get('customer'), 'Buys products; signs in with email or a social account.'); + assert.equal(r.descriptions.size, 7); const own = resolveRefs({ components: [{ ref: 'api', pos: [0, 0] }], cards: [{ dot: 'rose', title: 'Mine', items: ['kept'] }] }, { registry, fileName: 'x.archify' }); - assert.deepEqual(own.diagram.cards, [{ dot: 'rose', title: 'Mine', items: ['kept'] }]); - const inline = resolveRefs({ components: [{ id: 'a', type: 'backend', label: 'A', pos: [0, 0] }] }, { registry, fileName: 'x.archify' }); - assert.ok(!('cards' in inline.diagram)); - assert.equal(cardsFromElements([{ id: 'x', type: 'cloud', label: 'X', file: 'r', line: 0 }]).length, 0); - assert.equal(dotForType('messagebus'), 'orange'); - assert.equal(dotForType(undefined), 'slate'); + assert.deepEqual(own.diagram.cards, [{ dot: 'rose', title: 'Mine', items: ['kept'] }], 'hand-written cards pass through'); }); test('resolve: overrides, second id for the same element, inline elements and links', () => { -- 2.54.0