@mtdt/observeops-ds-spec 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +102 -0
- package/README.md +73 -0
- package/components/index.json +1270 -0
- package/components/recipes/README.md +41 -0
- package/components/recipes/recipes.json +922 -0
- package/components/registry/README.md +44 -0
- package/components/registry/_schema.json +47 -0
- package/components/registry/button.json +368 -0
- package/components/registry/checkbox.json +177 -0
- package/components/registry/data-viz-tooltips.json +409 -0
- package/components/registry/date-time-pickers.json +296 -0
- package/components/registry/drawer.json +222 -0
- package/components/registry/dropdown-picker.json +388 -0
- package/components/registry/filters.json +155 -0
- package/components/registry/form-item.json +281 -0
- package/components/registry/input.json +277 -0
- package/components/registry/link.json +186 -0
- package/components/registry/loose-tags.json +196 -0
- package/components/registry/menu.json +145 -0
- package/components/registry/modal.json +265 -0
- package/components/registry/navigation.json +425 -0
- package/components/registry/popover.json +216 -0
- package/components/registry/radio.json +238 -0
- package/components/registry/scheduler.json +188 -0
- package/components/registry/select.json +247 -0
- package/components/registry/severity.json +179 -0
- package/components/registry/switch.json +177 -0
- package/components/registry/table.json +275 -0
- package/components/registry/tabs.json +264 -0
- package/components/registry/tag.json +345 -0
- package/components/registry/tags-list.json +115 -0
- package/components/registry/toolbars.json +240 -0
- package/components/registry/tooltip.json +175 -0
- package/components/specs/README.md +72 -0
- package/components/specs/button.md +230 -0
- package/components/specs/checkbox.md +162 -0
- package/components/specs/data-viz-tooltips.md +93 -0
- package/components/specs/date-time-pickers.md +161 -0
- package/components/specs/drawer.md +162 -0
- package/components/specs/dropdown-picker.md +161 -0
- package/components/specs/filters.md +118 -0
- package/components/specs/form-item.md +130 -0
- package/components/specs/input.md +130 -0
- package/components/specs/link.md +131 -0
- package/components/specs/loose-tags.md +139 -0
- package/components/specs/menu.md +88 -0
- package/components/specs/modal.md +176 -0
- package/components/specs/navigation.md +181 -0
- package/components/specs/popover.md +118 -0
- package/components/specs/radio.md +144 -0
- package/components/specs/scheduler.md +133 -0
- package/components/specs/select.md +118 -0
- package/components/specs/switch.md +124 -0
- package/components/specs/table.md +115 -0
- package/components/specs/tabs.md +136 -0
- package/components/specs/tag.md +196 -0
- package/components/specs/tags-list.md +105 -0
- package/components/specs/toolbars.md +108 -0
- package/components/specs/tooltip.md +112 -0
- package/foundation/README.md +39 -0
- package/foundation/layout-shells.md +67 -0
- package/foundation/page-templates.md +69 -0
- package/foundation/panel-behaviours.md +61 -0
- package/foundation/screen-regions.md +62 -0
- package/index.js +75 -0
- package/layout/grid.json +34 -0
- package/layout/layouts.json +310 -0
- package/llms.txt +60 -0
- package/package.json +42 -0
- package/spec.manifest.json +407 -0
- package/tokens/README.md +125 -0
- package/tokens/component.json +34 -0
- package/tokens/kit-accents.json +14 -0
- package/tokens/primitive.json +130 -0
- package/tokens/purpose-map.json +67 -0
- package/tokens/semantic.dark.json +90 -0
- package/tokens/semantic.light.json +90 -0
- package/tokens/structural.json +35 -0
- package/tokens/variables.json +2018 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Page templates — product coverage
|
|
2
|
+
|
|
3
|
+
The canonical page types. All six catalogued templates are confirmed across the product, plus a handful
|
|
4
|
+
of archetypes/variants the sweep surfaced (Graph canvas, Utility tool, System/status, and two wizard shapes).
|
|
5
|
+
|
|
6
|
+
## The variants (catalogued)
|
|
7
|
+
|
|
8
|
+
| Template | What | Storybook |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| **List view** | paginated collection (`FlotoPaginatedCrud` + table + toolbar) | Page templates → List view |
|
|
11
|
+
| **Form view** | create/edit a record on an `MRow`/`MCol` grid; often in a drawer | Form view |
|
|
12
|
+
| **Detail view** | one record: header + status/severity + tabs + panels/charts | Detail view |
|
|
13
|
+
| **Dashboard view** | widget grid + global time range | Dashboard view |
|
|
14
|
+
| **Explorer view** | left panel + query/filter + results | Explorer view |
|
|
15
|
+
| **Wizard flow** | stepper + step body + Back/Next | Wizard flow |
|
|
16
|
+
|
|
17
|
+
## Where each is used in the product
|
|
18
|
+
|
|
19
|
+
| Template | Pages / flows (modules · files) |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| **List view** (dominant) | Inventory grid; **settings** CRUD across ~15 submodules (monitoring, users, roles, compliance/benchmarks, ncm device templates, snmp-trap, policy lists, plugin-library, group-settings, …); alert **stream** + correlated alerts; ncm **explorer** + ncm-approval; **audit** log; apm **services**; rum list; **trap-viewer** list; dashboard **column-mappers**; reports list. |
|
|
22
|
+
| **Form view** | settings create/edit (business-hour, discovery profile, user, role, benchmark, log-parser, …); **policy** create/edit (left type-menu + form); inventory drawer forms (wan-link, container-runtime, credential-selection — `FlotoDrawerForm` 40%); **my-account** profile/preferences; **system settings** forms (mail, proxy, DNS — horizontal layout). |
|
|
23
|
+
| **Detail view** | monitor/**device-template** (tabbed *template-swapper*); **alert detail** (severity + time-range + dynamic overview tabs + collaboration); apm service/database/api-endpoint/transaction details; **rum** drill-downs; **slo** details + history; netroute drilldown; trap-viewer details; log surrounding-events. |
|
|
24
|
+
| **Dashboard view** | **dashboard** editor + **NOC player** (full-screen variant); alert **dashboard**; log-dashboard; flow dashboard; apm overview; ncm overview + compliance; inventory **heatmap** dashboard; netroute dashboard mode. |
|
|
25
|
+
| **Explorer view** | **log search** (query builder + hierarchy tree); **metric-explorer** (three-pane: saved-views + metric-picker + chart); apm **explorer** (saved-views + filters); flow **explorer**; rum; netroute; **topology** graph. |
|
|
26
|
+
| **Wizard flow** | **report builder** (5 steps, `MMenu` stepper: Type→General→Template→Schedule→Review); **network discovery** (multi-route: profile → configure → progress → result); **integration setup** (slack/teams/jira/service-now — single-view numbered steps); 2FA / setup-guide onboarding. |
|
|
27
|
+
|
|
28
|
+
## Coverage verdict
|
|
29
|
+
|
|
30
|
+
All six templates are present and well-used. The sweep also found these the catalogue should acknowledge:
|
|
31
|
+
|
|
32
|
+
- **Graph / Canvas view (new archetype)** — see findings. Strong candidate for a 7th template.
|
|
33
|
+
- **Utility-tool form** — settings/utility (`ping`, `dns-resolver`, `snmp-walk`, `telnet`, `cli-command`):
|
|
34
|
+
a stateless input-form + results, no CRUD/persistence. A Form sub-type worth naming.
|
|
35
|
+
- **System / status message page** — `_disk-space-full`, upgrade/restore progress, `_404`, `_unauthorized`,
|
|
36
|
+
report-renderer. Message/print pages under Login/Public/Empty shells.
|
|
37
|
+
|
|
38
|
+
## Notable / different findings
|
|
39
|
+
|
|
40
|
+
- **Topology graph canvas is a distinct archetype** (`modules/topology/views/topology-map.vue`): a Cytoscape
|
|
41
|
+
interactive graph with pan/zoom, **minimap** (cytoscape-navigator), node-drag with saved positions,
|
|
42
|
+
Full-View vs Tree-View re-layout (D3 force in a web worker), and rich keyboard shortcuts. It is neither a
|
|
43
|
+
Dashboard nor an Explorer → document as **Graph / Canvas view**.
|
|
44
|
+
- **Detail-as-template-swapper** (`inventory/views/device-template.vue`): the tab bar swaps **entire
|
|
45
|
+
templates** (dashboard / metric-explorer / policy-list), not just content sections — a detail variant.
|
|
46
|
+
- **List ⇄ Dashboard view toggle**: apm services, rum, netroute toggle one page between an `MGrid` table and
|
|
47
|
+
a `vue-grid-layout` widget board — a list/dashboard hybrid.
|
|
48
|
+
- **Two wizard shapes**: (a) **multi-route stateful** (report builder, discovery — real routes + polling +
|
|
49
|
+
polymorphic step components); (b) **single-view stepped** (integration setup — numbered steps inside one
|
|
50
|
+
view). The Storybook wizard example matches (a); (b) is a lighter variant.
|
|
51
|
+
- **Live-tail / streaming** pages (`log/live-tail.vue`, `trap-viewer/live-trap-viewer.vue`) — a streaming
|
|
52
|
+
variant of List/Explorer.
|
|
53
|
+
- **Full-screen Dashboard** (NOC player) — a Dashboard variant that drops the shell for an immersive,
|
|
54
|
+
auto-rotating board with its own control bar.
|
|
55
|
+
|
|
56
|
+
## Best practices
|
|
57
|
+
|
|
58
|
+
- Pick the template by **what the page is for** (browse → List; one record → Form/Detail; metrics →
|
|
59
|
+
Dashboard; query a dataset → Explorer; guided task → Wizard), then assemble from the catalogued components.
|
|
60
|
+
- **List views**: title + live count in the header, primary **Add** top-right, filters in the toolbar, a
|
|
61
|
+
**bulk-action bar** only on selection, severity/status via Severity/Tag, always paginate.
|
|
62
|
+
- **Forms**: 6/6 `MRow`/`MCol`, full-width for textareas; complex forms prefer **`MTab` sub-sections** over
|
|
63
|
+
multi-route; destructive saves confirm via Modal; settings forms full-screen via `hideSettingsMenu`.
|
|
64
|
+
- **Drawers over routes** for create/edit/detail off a list — the product's default record surface
|
|
65
|
+
(`FlotoDrawerForm`, 40–90% width).
|
|
66
|
+
- **Detail headers**: use the **Severity dot** for severity *levels* and **Tag** for status *strings* —
|
|
67
|
+
they are not interchangeable.
|
|
68
|
+
- For a graph/canvas page, reuse the topology pattern (tree + canvas + minimap + saved positions + keyboard
|
|
69
|
+
nav) rather than rebuilding it.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Panel behaviours — product coverage
|
|
2
|
+
|
|
3
|
+
How panels open, move and resize. The five catalogued behaviours are confirmed and heavily used — but the
|
|
4
|
+
sweep shows the product's real overlay/panel vocabulary is **wider**: Modal, Expandable rows, Popover, a
|
|
5
|
+
fixed Bulk-action bar, resizable table columns, and the full-screen OmniBox all recur enough to belong here.
|
|
6
|
+
|
|
7
|
+
## The variants (catalogued) — with product usage
|
|
8
|
+
|
|
9
|
+
| Behaviour | Count | Where (files) |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| **Drawer (slide-over)** | **146 usages / 30 files** | `_base-drawer.vue` (FlotoDrawer) · `crud/_base-drawer-form.vue` (FlotoDrawerForm); inventory forms (wan-link / container-runtime / credential, 40%); **apm/rum drill-downs (90%)**; ncm (ViewDetail / Restore / Firmware / Compare / Terminal); widget-selector; topology detail; alert correlation-drawer; settings CRUD forms. |
|
|
12
|
+
| **Collapsible** | **19 files** | `filters/vertical-filter` groups; navbar hover-expand; metric-explorer `MCollapse` metric hierarchy; settings sections; the collapsible left tree. |
|
|
13
|
+
| **Resizable / split** | **~2–3 true splits** | **`splitpanes` library** in `settings/views/main.vue` (left menu + content) and **topology** (tree + graph); `apm/.../trace-drill-down` chart-split-pane (CSS). Genuinely drag-resizable panes are rare. |
|
|
14
|
+
| **Affix / sticky** | mostly CSS/JS | monitor-details sticky header; `monitor-sidebar` scroll-offset (JS-managed); report-wizard footer; ncm bulk-action bar; time-range pickers pinned in headers. **No `<a-affix>` widget** — sticky is CSS/flex/JS, not a component. |
|
|
15
|
+
| **Dashboard tiles** | **5 files** | `widgets/widgets.vue` (vue-grid-layout: drag + resize + reorder) · dashboard · ncm overview · apm · flow. Plus **VueMasonryWall** (inventory heatmap) as a responsive masonry variant. |
|
|
16
|
+
|
|
17
|
+
## Additional behaviours the sweep surfaced (not in the catalogued 5)
|
|
18
|
+
|
|
19
|
+
| Behaviour | Count | Where / what |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| **Modal** | **37 files** | `_base-confirm-modal.vue` (FlotoConfirmModal), metric-explorer (anomaly/compare/arithmetic/forecast/outlier), error-modal, suppress-alert (**form-in-modal**), ncm compare/terminal/firmware, approval-request. Confirm-delete and form-in-modal are everyday flows. |
|
|
22
|
+
| **Expandable rows** | **9 files** | inline row→detail expansion: alert stream grid, log-grid, apm tree-list, ncm triggered-policies, pivot-table. A list interaction distinct from drawer/modal. |
|
|
23
|
+
| **Popover** | **20+** | `_base-popper.vue`; user-dropdown, column/filter selectors, date pickers, the alert-dashboard sub-tab dropdowns. Small, non-blocking, contextual. |
|
|
24
|
+
| **Bulk-action bar** | **2 files** | `_base-bulk-action-bar.vue` + rediscover bulk-provision toolbar — a **fixed bottom** bar that animates in on selection. |
|
|
25
|
+
| **Resizable columns** | **50+ tables** | Ant table `minResizableWidth` — column drag-resize (distinct from pane-resize). |
|
|
26
|
+
| **Full-screen overlay** | a few | **OmniBox** global search (portal, blocks the page), ScreenBlocker, NOC-player full-screen, fixed top-right toast notifications. |
|
|
27
|
+
|
|
28
|
+
## Coverage verdict
|
|
29
|
+
|
|
30
|
+
- The catalogued **five are real and well-exercised** — Drawer is the dominant record surface (146 usages).
|
|
31
|
+
- **Recommended additions** to the Panel-behaviours page (they're as common as the five): **Modal**
|
|
32
|
+
(confirm + form-in-modal), **Expandable rows**, **Popover**, **Bulk-action bar**, **Resizable columns**,
|
|
33
|
+
and the **OmniBox full-screen overlay**. Several already exist as *components* (Modal, Popover, BulkActionBar)
|
|
34
|
+
but aren't framed as *behaviours* on the foundation page.
|
|
35
|
+
- **Two clarifications:** "Resizable / split" in product means the **`splitpanes` library** (rare, ~2–3
|
|
36
|
+
places), not the 20+ the raw grep implied (those were resizable *columns*). "Affix" is **CSS/JS sticky**,
|
|
37
|
+
not an `<a-affix>` widget.
|
|
38
|
+
|
|
39
|
+
## Notable / different findings
|
|
40
|
+
|
|
41
|
+
- **Drawer width is semantic**: ~40% for create/edit forms, **90% for deep drill-downs** (apm traces, rum
|
|
42
|
+
sessions, apm database) — almost a full-page surface that keeps list context.
|
|
43
|
+
- **Modal vs Drawer is a deliberate split**: small action/confirm/collect → **Modal**; panel-sized,
|
|
44
|
+
scrollable record/detail → **Drawer**; high-complexity record → **full page/route**.
|
|
45
|
+
- **Masonry vs rigid grid**: dashboard tiles are usually `vue-grid-layout` (rigid, draggable) but the
|
|
46
|
+
inventory heatmap uses **VueMasonryWall** (responsive masonry) — same "tiles" idea, different reflow.
|
|
47
|
+
- **Bulk-action bar** is a unique floating surface (fixed, bottom, appears on selection) — neither modal nor
|
|
48
|
+
drawer.
|
|
49
|
+
- **No bottom-sheet** pattern exists — every side panel is a right-edge drawer.
|
|
50
|
+
|
|
51
|
+
## Best practices
|
|
52
|
+
|
|
53
|
+
- **Drawer = default off-list surface** (create/edit/detail). Always backdrop + ESC-to-close; 40% for forms,
|
|
54
|
+
90% only for genuine deep dives.
|
|
55
|
+
- **Modal** for confirm/collect (`FlotoConfirmModal`, `variant=error` for destructive); keep it small.
|
|
56
|
+
- **Collapsible** for *optional* detail — never hide required fields collapsed by default.
|
|
57
|
+
- **Resizable splits** (`splitpanes`) need a sensible min-width and a remembered default; don't let a pane
|
|
58
|
+
collapse to zero.
|
|
59
|
+
- **Affix** sparingly — pin only things useful while scrolling (filters, hierarchy sidebar, wizard footer).
|
|
60
|
+
- **Dashboard tiles**: snap to grid, persist size/position per board; use masonry only when tile heights
|
|
61
|
+
genuinely vary.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Screen regions — product coverage
|
|
2
|
+
|
|
3
|
+
Inside the content panel: the region stack (Page header → Toolbar → Body → Footer) and the content layout
|
|
4
|
+
the body takes. All four regions and four content layouts are confirmed; the sweep adds **three-pane** and
|
|
5
|
+
**chart-over-grid** content layouts, plus an **explorer control bar** and **time-range** region variant.
|
|
6
|
+
|
|
7
|
+
## Regions — with product usage
|
|
8
|
+
|
|
9
|
+
| Region | Required | Where (files) |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| **Page header** | yes | `FlotoPageHeader` everywhere (`before-title` / `title` / `after-title` slots), with `back-link`. Variant: **inline mini detail-header** (`inventory/components/monitor-details.vue`) — a sticky breadcrumb/status row inside the two-pane right panel. |
|
|
12
|
+
| **Toolbar / filter bar** | optional | `FlotoPaginatedCrud` `add-controls` slot: search + filter toggle + export (PDF/CSV) + column selector + create. Variant: **explorer control bar** (`MRadioGroup` type + filters + saved-view), and a **time-range picker / time-range slider** region under the header (dashboards, explorers). |
|
|
13
|
+
| **Body** | yes | table (`MGrid`) · form grid (`MRow`/`MCol`, 541/522 files) · dashboard (`vue-grid-layout`) · charts/data-viz · graph canvas. |
|
|
14
|
+
| **Footer / pagination** | optional | `FlotoPaginatedCrud` pager (server-side); form action bars (Save/Cancel in the form footer slot); the fixed **Bulk-action bar** at viewport bottom. |
|
|
15
|
+
|
|
16
|
+
## Content layouts — with product usage
|
|
17
|
+
|
|
18
|
+
| Content layout | Where (files) |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| **Single column** | most settings CRUD + forms + simple lists. |
|
|
21
|
+
| **Two-pane (tree/menu + content)** | `MonitorHierarchyLayout` (log/inventory/topology hierarchy); **Settings** (`splitpanes` left menu + content); policy create (`MMenu` type picker + form). |
|
|
22
|
+
| **Master-detail (list + drawer)** | alert, inventory, **ncm explorer** (multiple drawers), apm/rum drill-downs. |
|
|
23
|
+
| **Dashboard grid** | `vue-grid-layout` tiles (dashboard, ncm, apm, flow) + **masonry** (inventory heatmap). |
|
|
24
|
+
| **Three-pane** *(new)* | `metric-explorer/views/metric-explorer.vue`: saved-views sidebar + metric-picker (`MTab`+`MCollapse`) + chart. |
|
|
25
|
+
| **Chart-over-grid** *(new)* | `trap-viewer` (30% chart above 70% grid); log-dashboard (KPI cards above bubble chart + grid). |
|
|
26
|
+
|
|
27
|
+
## Coverage verdict
|
|
28
|
+
|
|
29
|
+
- **All four regions and the four catalogued content layouts are confirmed.**
|
|
30
|
+
- **Add two content layouts:** **three-pane** (saved-views + picker + content, in metric/apm explorers) and
|
|
31
|
+
**chart-over-grid** (a fixed chart region above a grid).
|
|
32
|
+
- **Add region variants worth naming:** the **explorer control bar** (between header and content in every
|
|
33
|
+
explorer) and the **global time-range** region (picker/slider) — both currently fold under "Toolbar /
|
|
34
|
+
filter bar" but behave as their own region.
|
|
35
|
+
- **Left-panel variants** are not one thing: **hierarchy tree** (log), **saved-views sidebar**
|
|
36
|
+
(metric/apm explorer), **metric-picker** (`MTab`+`MCollapse`), **vertical filter** (ncm) — document them
|
|
37
|
+
as distinct left-panel kinds within the two-pane layout.
|
|
38
|
+
|
|
39
|
+
## Notable / different findings
|
|
40
|
+
|
|
41
|
+
- The **explorer control bar** is the most consistent un-named region: `MRadioGroup` (explorer/chart type) +
|
|
42
|
+
filters + saved-view actions, sitting between the page header and the visualization in log/apm/flow/metric.
|
|
43
|
+
- **Time-range is a first-class region**, not a header afterthought — dashboards render a dedicated
|
|
44
|
+
`TimeRangeSlider` row, and explorers a `TimeRangePicker`, scoping the whole body.
|
|
45
|
+
- **Three-pane** (metric-explorer) genuinely exceeds two-pane — a collapsible saved-views rail **and** a
|
|
46
|
+
metric-picker panel **and** the chart.
|
|
47
|
+
- **Inline detail-header**: the two-pane right panel often gets a sticky `monitor-details` row that *acts as*
|
|
48
|
+
a page header but is a component — blurring "page header region" vs "detail component".
|
|
49
|
+
- Settings has **no explicit footer**; form Save/Cancel live in the form's footer slot, and pagination is
|
|
50
|
+
inside `FlotoPaginatedCrud`.
|
|
51
|
+
|
|
52
|
+
## Best practices
|
|
53
|
+
|
|
54
|
+
- Start every page with a **Page header** (title + breadcrumb) and put the **primary action** there.
|
|
55
|
+
- Add the **toolbar/filter bar** only when there's something to filter or bulk-act on; in explorers, give it
|
|
56
|
+
the **control-bar** treatment (type radio + filters + saved view).
|
|
57
|
+
- Put the **time-range** in its own region (header-right picker or a slider row) so it visibly scopes the
|
|
58
|
+
whole body.
|
|
59
|
+
- The body picks **one** content layout — don't combine a two-pane and a master-detail drawer on the same
|
|
60
|
+
screen; escalate to **three-pane** only when a saved-views rail *and* a picker are both needed.
|
|
61
|
+
- Map each region to its catalogued component (PageHeader · FilterBar/GridToolbar/BulkActionBar · Table/Form ·
|
|
62
|
+
FlotoPaginatedCrud pager) — see the Screen-regions **Usage** page for the linked table.
|
package/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/**
|
|
3
|
+
* @mtdt/observeops-ds-spec — thin loader.
|
|
4
|
+
*
|
|
5
|
+
* AI tools can simply READ the files (start at llms.txt → AGENTS.md → components/index.json).
|
|
6
|
+
* This module is a convenience for code: it exposes the parsed spec plus a few helpers.
|
|
7
|
+
* Heavy querying (search, validation) belongs to the MCP server, not here.
|
|
8
|
+
*/
|
|
9
|
+
const fs = require('fs')
|
|
10
|
+
const path = require('path')
|
|
11
|
+
|
|
12
|
+
const ROOT = __dirname
|
|
13
|
+
const readJSON = (rel) => JSON.parse(fs.readFileSync(path.join(ROOT, rel), 'utf8'))
|
|
14
|
+
const readText = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8')
|
|
15
|
+
|
|
16
|
+
const index = readJSON('components/index.json')
|
|
17
|
+
const recipes = readJSON('components/recipes/recipes.json')
|
|
18
|
+
const manifest = readJSON('spec.manifest.json')
|
|
19
|
+
const layout = { grid: readJSON('layout/grid.json'), layouts: readJSON('layout/layouts.json') }
|
|
20
|
+
const tokens = {
|
|
21
|
+
variables: readJSON('tokens/variables.json'),
|
|
22
|
+
structural: readJSON('tokens/structural.json'),
|
|
23
|
+
kitAccents: readJSON('tokens/kit-accents.json'),
|
|
24
|
+
purposeMap: readJSON('tokens/purpose-map.json'),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Full entry for one component: its index entry + its registry spec (or null if unknown). */
|
|
28
|
+
function getComponent(id) {
|
|
29
|
+
const entry = (index.components || []).find((c) => c.id === id)
|
|
30
|
+
if (!entry) return null
|
|
31
|
+
return { ...entry, registry: readJSON(`components/registry/${id}.json`) }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Resolve a token to its value(s). CSS `--var` → {light,dark,...}; LESS `@var` → string. null if unknown. */
|
|
35
|
+
function resolveToken(name) {
|
|
36
|
+
if (/^--/.test(name)) return tokens.variables[name] || null
|
|
37
|
+
if (/^@/.test(name)) {
|
|
38
|
+
if (tokens.kitAccents[name]) return tokens.kitAccents[name]
|
|
39
|
+
let found = null
|
|
40
|
+
const walk = (o) => {
|
|
41
|
+
for (const [k, v] of Object.entries(o)) {
|
|
42
|
+
if (k === name && typeof v !== 'object') found = v
|
|
43
|
+
else if (v && typeof v === 'object') walk(v)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
walk(tokens.structural)
|
|
47
|
+
return found
|
|
48
|
+
}
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Lightweight list of recipes (id + name + whenToUse) for selection. */
|
|
53
|
+
function listRecipes() {
|
|
54
|
+
return (recipes.recipes || []).map((r) => ({ id: r.id, name: r.name, whenToUse: r.whenToUse }))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Absolute path to any shipped spec file — for tools that prefer to read raw. */
|
|
58
|
+
function specPath(rel) {
|
|
59
|
+
return path.join(ROOT, rel)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
index,
|
|
64
|
+
recipes,
|
|
65
|
+
layout,
|
|
66
|
+
tokens,
|
|
67
|
+
manifest,
|
|
68
|
+
version: manifest.version,
|
|
69
|
+
contract: () => readText('AGENTS.md'),
|
|
70
|
+
llmsTxt: () => readText('llms.txt'),
|
|
71
|
+
getComponent,
|
|
72
|
+
resolveToken,
|
|
73
|
+
listRecipes,
|
|
74
|
+
specPath,
|
|
75
|
+
}
|
package/layout/grid.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$description": "The product's layout GRID — MRow / MCol (wrappers over Ant Design Vue 1.x a-row / a-col), a 12-column system. The single way form/page content is laid out.",
|
|
3
|
+
"system": "MRow + MCol",
|
|
4
|
+
"columns": 12,
|
|
5
|
+
"usage": "MRow ~540 files · MCol ~522 files",
|
|
6
|
+
"sizes": [
|
|
7
|
+
{ "size": 12, "pct": "100%", "use": "full width / single column", "count": "716×" },
|
|
8
|
+
{ "size": 6, "pct": "50%", "use": "half — the default form field width", "count": "729×" },
|
|
9
|
+
{ "size": 3, "pct": "25%", "use": "quarter — 4-up rows, compact fields", "count": "466×" },
|
|
10
|
+
{ "size": 4, "pct": "33.3%", "use": "third — 3-up rows", "count": "256×" },
|
|
11
|
+
{ "size": 2, "pct": "16.6%", "use": "sixth — dense rows", "count": "217×" },
|
|
12
|
+
{ "size": 5, "pct": "41.6%", "use": "occasional asymmetric split", "count": "125×" }
|
|
13
|
+
],
|
|
14
|
+
"gutter": {
|
|
15
|
+
"form": ":gutter=\"16\" — standard spacing between form fields/rows",
|
|
16
|
+
"structural": ":gutter=\"0\" — ONLY for structural wrappers (page headers, full-height containers)",
|
|
17
|
+
"token": "@padding-md = 16px"
|
|
18
|
+
},
|
|
19
|
+
"autoSize": "<MCol auto-size> shrinks the column to its content width — for action buttons / compact cells.",
|
|
20
|
+
"breakpoints": "Ant responsive props (xs/sm/md/lg/xl) supported via per-breakpoint size objects, but rarely used in-product (the app is desktop-first).",
|
|
21
|
+
"do": [
|
|
22
|
+
"Use MRow/MCol for all form field layouts.",
|
|
23
|
+
"Sizes: 6 = half, 12 = full, 3 = quarter, 4 = third.",
|
|
24
|
+
"gutter 16 for form rows; gutter 0 only for structural wrappers.",
|
|
25
|
+
"auto-size for action/compact cells; align inside a cell with flex utilities."
|
|
26
|
+
],
|
|
27
|
+
"dont": [
|
|
28
|
+
"Don't hand-roll a flex grid for form layouts.",
|
|
29
|
+
"Don't put a gutter on full-height structural wrappers (use gutter 0).",
|
|
30
|
+
"Don't nest deep grids where a single MRow of sized MCols works."
|
|
31
|
+
],
|
|
32
|
+
"tokensUsed": ["@padding-md"],
|
|
33
|
+
"storybook": "Foundations/Layout/Grid"
|
|
34
|
+
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$description": "The product's STRUCTURE layer above the grid — the app shell, the layout shells (4 route + 2 content), the page-level screen regions, the content layouts, and the panel behaviours. Pairs with layout/grid.json (the 12-col grid that fills these regions). Storybook: Foundations/Layout/*.",
|
|
3
|
+
"appShell": {
|
|
4
|
+
"$note": "The authenticated app frame — src/views/layouts/main.vue (component `Layout`). Nesting: MLayout(root, flex) > NavBar (left rail) + MLayout.contentContainer > Header (top) + MLayout.main-content-panel > FlotoScrollView > MLayoutContent (the page slot). Plus a global overlay layer.",
|
|
5
|
+
"regions": [
|
|
6
|
+
{
|
|
7
|
+
"region": "NavBar",
|
|
8
|
+
"where": "left",
|
|
9
|
+
"size": "@nav-icon-width 50px",
|
|
10
|
+
"component": "NavBar (layout/navbar.vue)",
|
|
11
|
+
"what": "primary icon rail — modules, logo, collapse; see Navigation/PrimaryNav",
|
|
12
|
+
"fixed": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"region": "Header",
|
|
16
|
+
"where": "top",
|
|
17
|
+
"size": "@header-height 55px",
|
|
18
|
+
"component": "Header (layout/header.vue)",
|
|
19
|
+
"what": "breadcrumb / back · global search trigger · notifications · user menu",
|
|
20
|
+
"fixed": true
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"region": "Content panel",
|
|
24
|
+
"where": "fill",
|
|
25
|
+
"size": "flex-1, scrolls",
|
|
26
|
+
"component": "MLayoutContent inside FlotoScrollView",
|
|
27
|
+
"what": "the routed page (the <slot/>); the only scrolling region",
|
|
28
|
+
"fixed": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"region": "Overlay layer",
|
|
32
|
+
"where": "portals / fixed",
|
|
33
|
+
"size": "—",
|
|
34
|
+
"component": "OmniBox · CustomNotification · AlertNotification · *ExpireNotification · PortalTarget(omnibox, interface-template)",
|
|
35
|
+
"what": "global, shell-level, above the content panel",
|
|
36
|
+
"fixed": true
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"$shellsNote": "4 ROUTE shells (selected by the app.vue switcher: not-logged-in → LoginLayout; else Layout; then route.meta.layout override wins) + 2 CONTENT layouts that render inside Layout. Corrected per foundation/layout-shells.md — MonitorHierarchyLayout has 0 route overrides.",
|
|
41
|
+
"shells": [
|
|
42
|
+
{
|
|
43
|
+
"name": "Layout",
|
|
44
|
+
"kind": "route",
|
|
45
|
+
"file": "views/layouts/main.vue",
|
|
46
|
+
"chrome": "NavBar + Header + scroll content + overlays",
|
|
47
|
+
"use": "every authenticated app page (the DEFAULT — no `layout` route override needed)",
|
|
48
|
+
"usage": "default for ~all routes",
|
|
49
|
+
"select": "Standard in-app page."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "LoginLayout",
|
|
53
|
+
"kind": "route",
|
|
54
|
+
"file": "views/layouts/login-layout.vue",
|
|
55
|
+
"chrome": "bare — MLayout > MLayoutContent > slot; no socket, no chrome",
|
|
56
|
+
"use": "login / reset / forgot-password + disk-full error; also the not-logged-in fallback",
|
|
57
|
+
"usage": "meta + unauth fallback",
|
|
58
|
+
"select": "Unauthenticated auth screen."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "EmptyLayout",
|
|
62
|
+
"kind": "route",
|
|
63
|
+
"file": "views/layouts/empty-layout.vue",
|
|
64
|
+
"chrome": "NO nav, NO header — padded (p-4) scroll content; keeps socket + local-DB",
|
|
65
|
+
"use": "full-bleed flow that still needs live data but not the chrome (print-safe report export)",
|
|
66
|
+
"usage": "1 route override · /reports/export/:id",
|
|
67
|
+
"select": "Full-screen flow, no nav/header, still authenticated + live."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "PublicLayout",
|
|
71
|
+
"kind": "route",
|
|
72
|
+
"file": "views/layouts/public-layout.vue",
|
|
73
|
+
"chrome": "like EmptyLayout, full-bleed (-m-4); socket + DB; isMotadataUpdatingOrRestoring",
|
|
74
|
+
"use": "public / system pages — upgrade or restore in progress",
|
|
75
|
+
"usage": "2 route overrides · /upgrade /restore",
|
|
76
|
+
"select": "Public/system page, no chrome."
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "MonitorHierarchyLayout",
|
|
80
|
+
"kind": "content",
|
|
81
|
+
"file": "views/layouts/monitor-hierarchy-layout.vue",
|
|
82
|
+
"chrome": "a CONTENT layout (renders inside Layout): two-pane — left hierarchy tree (collapsible, affixable, transition-width) + content via MRow/MCol gutter 0",
|
|
83
|
+
"use": "monitor / inventory / topology screens with a tree on the left",
|
|
84
|
+
"usage": "0 route overrides · component in 4 files",
|
|
85
|
+
"select": "Tree/hierarchy on the left + detail on the right (NOT a route shell)."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "Settings two-pane",
|
|
89
|
+
"kind": "content",
|
|
90
|
+
"file": "modules/settings/views/main.vue",
|
|
91
|
+
"chrome": "a CONTENT layout (inside Layout): splitpanes — left menu (MCollapse+MMenu, 15%) + RouterView (85%); hidden via meta.hideSettingsMenu",
|
|
92
|
+
"use": "every settings submodule",
|
|
93
|
+
"usage": "settings/views/main.vue",
|
|
94
|
+
"select": "Settings/admin: left menu + content."
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"screenRegions": {
|
|
98
|
+
"$note": "Inside the content panel, a standard page is composed of these regions (top → bottom). Reproduced as the Foundations/Layout/Screen regions story; map to components via index.json.",
|
|
99
|
+
"regions": [
|
|
100
|
+
{
|
|
101
|
+
"region": "Page header",
|
|
102
|
+
"component": "PageHeader (Toolbars) — title + breadcrumb + primary actions",
|
|
103
|
+
"usage": "page-header in 54 files",
|
|
104
|
+
"optional": false
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"region": "Toolbar / filter bar",
|
|
108
|
+
"component": "GridToolbar · FilterBar · BulkActionBar (Toolbars / Filters)",
|
|
109
|
+
"usage": "",
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"region": "Body",
|
|
114
|
+
"component": "Table · form (MRow/MCol grid) · dashboard grid · detail panes",
|
|
115
|
+
"usage": "MRow 541 · MCol 522",
|
|
116
|
+
"optional": false
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"region": "Footer / pagination",
|
|
120
|
+
"component": "FlotoPaginatedCrud pager · form action bar (Save/Cancel)",
|
|
121
|
+
"usage": "",
|
|
122
|
+
"optional": true
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"contentLayouts": [
|
|
127
|
+
{
|
|
128
|
+
"name": "Single column",
|
|
129
|
+
"what": "header + toolbar + body fill the content panel",
|
|
130
|
+
"use": "list views, simple forms",
|
|
131
|
+
"grid": "MRow/MCol gutter 16"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "Two-pane (tree/menu + content)",
|
|
135
|
+
"what": "left hierarchy/list/menu panel + right detail; left is collapsible/affixable",
|
|
136
|
+
"use": "explorers, settings (left menu + content)",
|
|
137
|
+
"grid": "MonitorHierarchyLayout · Settings splitpanes · left-side-list-view-panel (8 files)"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"name": "Master-detail (list + drawer)",
|
|
141
|
+
"what": "list/table + a FlotoDrawer slide-over for the record",
|
|
142
|
+
"use": "alert / inventory record views",
|
|
143
|
+
"grid": "Drawer (146 files)"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "Dashboard grid",
|
|
147
|
+
"what": "draggable/resizable widget tiles on a canvas (+ masonry variant)",
|
|
148
|
+
"use": "dashboards",
|
|
149
|
+
"grid": "vue-grid-layout (5 files), --dashboard-background"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "Three-pane",
|
|
153
|
+
"what": "saved-views rail + metric-picker + chart",
|
|
154
|
+
"use": "metric / apm explorers",
|
|
155
|
+
"grid": "metric-explorer (saved-views + MTab/MCollapse picker + chart)",
|
|
156
|
+
"$found": "product sweep"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "Chart-over-grid",
|
|
160
|
+
"what": "a fixed chart region above a grid",
|
|
161
|
+
"use": "trap viewer, log dashboards",
|
|
162
|
+
"grid": "trap-viewer (30% chart / 70% grid)",
|
|
163
|
+
"$found": "product sweep"
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"leftPanelVariants": [
|
|
167
|
+
"hierarchy tree (log)",
|
|
168
|
+
"saved-views sidebar (metric/apm)",
|
|
169
|
+
"metric-picker MTab+MCollapse",
|
|
170
|
+
"vertical filter (ncm)"
|
|
171
|
+
],
|
|
172
|
+
"pageTemplates": {
|
|
173
|
+
"$note": "The canonical page types (Storybook: Foundations/Layout/Page templates). Full region→component blueprints live in components/recipes/recipes.json — load the recipe id in parens.",
|
|
174
|
+
"templates": [
|
|
175
|
+
{
|
|
176
|
+
"name": "List view",
|
|
177
|
+
"recipe": "list-view",
|
|
178
|
+
"what": "paginated collection: header + toolbar + table + pager"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "Form view",
|
|
182
|
+
"recipe": "form-view",
|
|
183
|
+
"what": "create/edit one record on the MRow/MCol grid; often in a drawer"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"name": "Detail view",
|
|
187
|
+
"recipe": "detail-view",
|
|
188
|
+
"what": "one record: header + status/severity + tabs + panels/charts"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"name": "Dashboard view",
|
|
192
|
+
"recipe": "dashboard-view",
|
|
193
|
+
"what": "widget grid + global time range"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "Explorer view",
|
|
197
|
+
"recipe": "explorer-view",
|
|
198
|
+
"what": "left panel + query/filter + results"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "Wizard flow",
|
|
202
|
+
"recipe": "wizard-flow",
|
|
203
|
+
"what": "stepper + step body + Back/Next"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"name": "Graph / Canvas view",
|
|
207
|
+
"recipe": "graph-canvas",
|
|
208
|
+
"what": "hierarchy tree + interactive Cytoscape node graph (Topology)"
|
|
209
|
+
}
|
|
210
|
+
],
|
|
211
|
+
"variants": [
|
|
212
|
+
"utility-tool form",
|
|
213
|
+
"system/status page",
|
|
214
|
+
"live-tail / streaming",
|
|
215
|
+
"list⇄dashboard view-toggle",
|
|
216
|
+
"detail-as-template-swapper",
|
|
217
|
+
"two wizard shapes (multi-route stateful / single-view stepped)"
|
|
218
|
+
],
|
|
219
|
+
"flows": [
|
|
220
|
+
"bulk-action-flow",
|
|
221
|
+
"inline-edit-flow",
|
|
222
|
+
"search-filter-flow",
|
|
223
|
+
"export-flow",
|
|
224
|
+
"confirm-delete-flow (all in recipes.json)"
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
"panels": {
|
|
228
|
+
"$note": "Panel/overlay BEHAVIOURS — how surfaces open/move/resize. Reproduced as the Foundations/Layout/Panel behaviours story. Counts from foundation/panel-behaviours.md.",
|
|
229
|
+
"behaviours": [
|
|
230
|
+
{
|
|
231
|
+
"behaviour": "Drawer (slide-over)",
|
|
232
|
+
"component": "FlotoDrawer / a-drawer",
|
|
233
|
+
"usage": "146 files / 30",
|
|
234
|
+
"what": "right/left overlay for create/edit/detail; ~40% forms, ~90% deep drill-downs; backdrop; ESC to close"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"behaviour": "Modal",
|
|
238
|
+
"component": "a-modal / FlotoConfirmModal / MModal",
|
|
239
|
+
"usage": "37 files",
|
|
240
|
+
"what": "centered blocking overlay; confirm/collect; form-in-modal; variant=error for destructive"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"behaviour": "Collapsible panel",
|
|
244
|
+
"component": "MCollapse / a-collapse",
|
|
245
|
+
"usage": "19 files",
|
|
246
|
+
"what": "accordion sections; left-tree collapse (transition-width)"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"behaviour": "Expandable rows",
|
|
250
|
+
"component": "grid row expansion",
|
|
251
|
+
"usage": "9 files",
|
|
252
|
+
"what": "inline row→detail disclosure (alert stream, log-grid, apm tree-list)"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"behaviour": "Resizable / split",
|
|
256
|
+
"component": "splitpanes (library)",
|
|
257
|
+
"usage": "~3 true splits",
|
|
258
|
+
"what": "drag-to-resize panes (settings menu+content, topology tree+graph, apm trace)"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"behaviour": "Affix / sticky",
|
|
262
|
+
"component": "CSS/JS sticky (no <a-affix>)",
|
|
263
|
+
"usage": "scattered",
|
|
264
|
+
"what": "pin a panel/toolbar/footer on scroll (hierarchy sidebar, wizard footer, time-range)"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"behaviour": "Dashboard tiles",
|
|
268
|
+
"component": "vue-grid-layout (+ VueMasonryWall)",
|
|
269
|
+
"usage": "5 files",
|
|
270
|
+
"what": "drag + resize widget grid; masonry variant for varying tile heights"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"behaviour": "Bulk-action bar",
|
|
274
|
+
"component": "_base-bulk-action-bar",
|
|
275
|
+
"usage": "2 files",
|
|
276
|
+
"what": "fixed-bottom bar, appears on multi-selection"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"behaviour": "Popover",
|
|
280
|
+
"component": "floating-vue / _base-popper",
|
|
281
|
+
"usage": "20+",
|
|
282
|
+
"what": "small contextual, non-blocking overlay (menus, column selectors, sub-tabs)"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"behaviour": "Full-screen / OmniBox",
|
|
286
|
+
"component": "OmniBox (portal) · NOC-player",
|
|
287
|
+
"usage": "few",
|
|
288
|
+
"what": "global search / immersive overlay above everything"
|
|
289
|
+
}
|
|
290
|
+
],
|
|
291
|
+
"$notPanel": "Table resizable columns (Ant minResizableWidth, 50+ tables) are a GRID feature, not a panel behaviour."
|
|
292
|
+
},
|
|
293
|
+
"tokens": {
|
|
294
|
+
"@nav-icon-width": "50px (left rail)",
|
|
295
|
+
"@header-height": "55px (top header)",
|
|
296
|
+
"@navbar-height": "50px",
|
|
297
|
+
"@padding-md": "16px (content padding / gutter)",
|
|
298
|
+
"--nav-panel-bg": "left rail bg",
|
|
299
|
+
"--common-main-bg": "content area bg",
|
|
300
|
+
"--dashboard-background": "dashboard canvas bg",
|
|
301
|
+
"--border-color": "region dividers"
|
|
302
|
+
},
|
|
303
|
+
"storybook": {
|
|
304
|
+
"appShell": "Foundations/Layout/App shell",
|
|
305
|
+
"shells": "Foundations/Layout/Layout shells",
|
|
306
|
+
"screenRegions": "Foundations/Layout/Screen regions",
|
|
307
|
+
"panels": "Foundations/Layout/Panel behaviours",
|
|
308
|
+
"templates": "Foundations/Layout/Page templates (recipes.json)"
|
|
309
|
+
}
|
|
310
|
+
}
|