@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.
Files changed (79) hide show
  1. package/AGENTS.md +102 -0
  2. package/README.md +73 -0
  3. package/components/index.json +1270 -0
  4. package/components/recipes/README.md +41 -0
  5. package/components/recipes/recipes.json +922 -0
  6. package/components/registry/README.md +44 -0
  7. package/components/registry/_schema.json +47 -0
  8. package/components/registry/button.json +368 -0
  9. package/components/registry/checkbox.json +177 -0
  10. package/components/registry/data-viz-tooltips.json +409 -0
  11. package/components/registry/date-time-pickers.json +296 -0
  12. package/components/registry/drawer.json +222 -0
  13. package/components/registry/dropdown-picker.json +388 -0
  14. package/components/registry/filters.json +155 -0
  15. package/components/registry/form-item.json +281 -0
  16. package/components/registry/input.json +277 -0
  17. package/components/registry/link.json +186 -0
  18. package/components/registry/loose-tags.json +196 -0
  19. package/components/registry/menu.json +145 -0
  20. package/components/registry/modal.json +265 -0
  21. package/components/registry/navigation.json +425 -0
  22. package/components/registry/popover.json +216 -0
  23. package/components/registry/radio.json +238 -0
  24. package/components/registry/scheduler.json +188 -0
  25. package/components/registry/select.json +247 -0
  26. package/components/registry/severity.json +179 -0
  27. package/components/registry/switch.json +177 -0
  28. package/components/registry/table.json +275 -0
  29. package/components/registry/tabs.json +264 -0
  30. package/components/registry/tag.json +345 -0
  31. package/components/registry/tags-list.json +115 -0
  32. package/components/registry/toolbars.json +240 -0
  33. package/components/registry/tooltip.json +175 -0
  34. package/components/specs/README.md +72 -0
  35. package/components/specs/button.md +230 -0
  36. package/components/specs/checkbox.md +162 -0
  37. package/components/specs/data-viz-tooltips.md +93 -0
  38. package/components/specs/date-time-pickers.md +161 -0
  39. package/components/specs/drawer.md +162 -0
  40. package/components/specs/dropdown-picker.md +161 -0
  41. package/components/specs/filters.md +118 -0
  42. package/components/specs/form-item.md +130 -0
  43. package/components/specs/input.md +130 -0
  44. package/components/specs/link.md +131 -0
  45. package/components/specs/loose-tags.md +139 -0
  46. package/components/specs/menu.md +88 -0
  47. package/components/specs/modal.md +176 -0
  48. package/components/specs/navigation.md +181 -0
  49. package/components/specs/popover.md +118 -0
  50. package/components/specs/radio.md +144 -0
  51. package/components/specs/scheduler.md +133 -0
  52. package/components/specs/select.md +118 -0
  53. package/components/specs/switch.md +124 -0
  54. package/components/specs/table.md +115 -0
  55. package/components/specs/tabs.md +136 -0
  56. package/components/specs/tag.md +196 -0
  57. package/components/specs/tags-list.md +105 -0
  58. package/components/specs/toolbars.md +108 -0
  59. package/components/specs/tooltip.md +112 -0
  60. package/foundation/README.md +39 -0
  61. package/foundation/layout-shells.md +67 -0
  62. package/foundation/page-templates.md +69 -0
  63. package/foundation/panel-behaviours.md +61 -0
  64. package/foundation/screen-regions.md +62 -0
  65. package/index.js +75 -0
  66. package/layout/grid.json +34 -0
  67. package/layout/layouts.json +310 -0
  68. package/llms.txt +60 -0
  69. package/package.json +42 -0
  70. package/spec.manifest.json +407 -0
  71. package/tokens/README.md +125 -0
  72. package/tokens/component.json +34 -0
  73. package/tokens/kit-accents.json +14 -0
  74. package/tokens/primitive.json +130 -0
  75. package/tokens/purpose-map.json +67 -0
  76. package/tokens/semantic.dark.json +90 -0
  77. package/tokens/semantic.light.json +90 -0
  78. package/tokens/structural.json +35 -0
  79. package/tokens/variables.json +2018 -0
@@ -0,0 +1,179 @@
1
+ {
2
+ "name": "severity",
3
+ "component": "Severity",
4
+ "display": "Severity",
5
+ "tier": "atom",
6
+ "family": "Tag",
7
+ "source": "src/components/severity.vue (Severity) + severity-stripe.vue + severity-picker.vue + dashboard/severity-count-box.vue + severity-db.vue",
8
+ "status": "core",
9
+ "summary": "The severity INDICATOR — a coloured dot (+ optional label + tooltip) for a severity LEVEL (down / critical / major / warning / clear / up / maintenance / unreachable / unknown / …). Distinct from MStatusTag, which maps status STRINGS to tag-* pills. Used 80×. Renders --severity-<level>; can take `severity` directly or resolve it live from a monitor (objectId / instance / counter) via DB workers.",
10
+ "variants": [
11
+ {
12
+ "name": "dot",
13
+ "what": "2px --severity-<level> border + light --severity-<level>-dot-box centre (down = solid, 0px border)",
14
+ "usage": "default"
15
+ },
16
+ {
17
+ "name": "dot+label",
18
+ "what": "dot + Capitalize(level) text (displayText=true)",
19
+ "usage": ""
20
+ },
21
+ {
22
+ "name": "solid-chip",
23
+ "what": "filled pill: background --severity-<level> + white text (the plain mode)",
24
+ "usage": ""
25
+ },
26
+ {
27
+ "name": "text",
28
+ "what": "coloured numeric/value text in --severity-<level>, JetBrains Mono (.text mode)",
29
+ "usage": ""
30
+ },
31
+ {
32
+ "name": "bg-fill",
33
+ "what": "row/cell: --severity-<level>-lighter tint + 1px --severity-<level> border (generateSeverityBg / .bg)",
34
+ "usage": ""
35
+ },
36
+ {
37
+ "name": "stripe",
38
+ "what": "severity-stripe.vue — coloured left rule on a list row/card",
39
+ "usage": ""
40
+ },
41
+ {
42
+ "name": "picker",
43
+ "what": "severity-picker.vue / compliance-severity-picker — choose a level",
44
+ "usage": ""
45
+ },
46
+ {
47
+ "name": "count-box",
48
+ "what": "dashboard/severity-count-box.vue — count per severity",
49
+ "usage": ""
50
+ },
51
+ {
52
+ "name": "switch",
53
+ "what": "alert severity toggle — see Atoms/Radio (severity-switch)",
54
+ "usage": ""
55
+ }
56
+ ],
57
+ "sizes": [
58
+ {
59
+ "name": "default",
60
+ "value": "small dot",
61
+ "note": "single size"
62
+ }
63
+ ],
64
+ "states": [
65
+ {
66
+ "name": "static",
67
+ "what": "`severity` prop set directly"
68
+ },
69
+ {
70
+ "name": "live",
71
+ "what": "resolves from objectId / instance / counter via severityDBWorker + the live EVENT_SEVERITY_COUNTER_DB_CHANGED bus event"
72
+ },
73
+ {
74
+ "name": "unknown",
75
+ "what": "default when unresolved → --severity-unknown grey"
76
+ }
77
+ ],
78
+ "severityLevels": {
79
+ "$note": "each level -> --severity-<level> (the dot/text colour) + --severity-<level>-dot-box (the halo). Resolve via tokens/variables.json. QUIRK (mirrored from severity.less): `up` = green ring (--severity-clear) + a critical/light-red centre (--severity-critical-dot-box); `down`/`disable` have no -dot-box (down renders solid).",
80
+ "levels": [
81
+ "up",
82
+ "clear",
83
+ "critical",
84
+ "down",
85
+ "major",
86
+ "warning",
87
+ "maintenance",
88
+ "unreachable",
89
+ "suspended",
90
+ "disable",
91
+ "stop",
92
+ "none",
93
+ "unknown"
94
+ ]
95
+ },
96
+ "props": {
97
+ "severity": "String — the level (else live-resolved)",
98
+ "objectId": "[Number,String] — monitor id / name / IP to live-resolve from the DB worker",
99
+ "instance": "String — for instance-level severity",
100
+ "counter": "String — for counter-level severity",
101
+ "displayText": "Boolean (false) — show the Capitalize(severity) label beside the dot",
102
+ "disableTooltip": "Boolean (false)",
103
+ "center": "Boolean (true)",
104
+ "shadow": "Boolean (true) — the dot halo (severity-dot-shadow)"
105
+ },
106
+ "events": {
107
+ "udpate:severity": "(sic — misspelled in source) the resolved level after live lookup"
108
+ },
109
+ "decisionFlow": [
110
+ "Showing a monitor/alert SEVERITY level (critical/major/warning/clear/up/down/…)? -> Severity (dot).",
111
+ "Showing a STATUS string (up/down/running/failed/poweredoff…) as a pill? -> MStatusTag (Tag family).",
112
+ "Need a coloured stripe down a list row/card? -> severity-stripe.",
113
+ "Let the user pick a severity level (policy/condition forms)? -> severity-picker.",
114
+ "Show counts per severity on a dashboard? -> severity-count-box."
115
+ ],
116
+ "do": [
117
+ "Use Severity for severity LEVELS; MStatusTag for status STRINGS.",
118
+ "Pass `severity` directly when you already have it; use objectId/instance/counter only for live resolution.",
119
+ "Resolve colours via --severity-<level> (+ --severity-<level>-dot-box for the halo)."
120
+ ],
121
+ "dont": [
122
+ "Don't route alert/monitor severity through MStatusTag — its TAG_MAP lacks major/warning/clear, so they render as a grey plain tag (F7).",
123
+ "Don't hardcode severity colours — use the --severity-* tokens.",
124
+ "Don't rely on the dot colour alone for a11y — set displayText or keep the tooltip."
125
+ ],
126
+ "knownIssues": {
127
+ "F1": {
128
+ "severity": "Low",
129
+ "issue": "emit name is misspelled `udpate:severity` in source."
130
+ },
131
+ "F2": {
132
+ "severity": "Low",
133
+ "a11y": true,
134
+ "issue": "colour-dot only by default — set displayText / keep the tooltip so severity isn't colour-only (WCAG 1.4.1)."
135
+ }
136
+ },
137
+ "tokensUsed": [
138
+ "--severity-up",
139
+ "--severity-clear",
140
+ "--severity-critical",
141
+ "--severity-down",
142
+ "--severity-major",
143
+ "--severity-warning",
144
+ "--severity-maintenance",
145
+ "--severity-unreachable",
146
+ "--severity-suspended",
147
+ "--severity-disable",
148
+ "--severity-none",
149
+ "--severity-unknown",
150
+ "--severity-critical-dot-box",
151
+ "--severity-warning-dot-box",
152
+ "--severity-major-dot-box",
153
+ "--severity-critical-lighter",
154
+ "--severity-major-lighter",
155
+ "--severity-warning-lighter",
156
+ "--severity-clear-lighter",
157
+ "--severity-down-lighter"
158
+ ],
159
+ "related": [
160
+ "tag",
161
+ "filters",
162
+ "table"
163
+ ],
164
+ "storybook": "Atoms/Severity",
165
+ "figma": {
166
+ "status": "todo"
167
+ },
168
+ "renderShapesNote": "The same severity.less class set renders dot / solid-chip / text / bg-fill (mode = a class on the element). Severity is ALSO shown via the chart/graph layer using the same --severity-* tokens: topology graph-node colour, RUM apdex map markers, heatmap cells, availability segments (see data-viz-tooltips / table) — cross-referenced, not duplicated.",
169
+ "a11y": {
170
+ "summary": "Must NOT be colour-only (F2) — pair the dot with a label (displayText) or keep the tooltip; announce live changes meaningfully.",
171
+ "issues": [
172
+ "Colour-only by default (WCAG 1.4.1).",
173
+ "Verify dot vs halo contrast."
174
+ ],
175
+ "doc": "Atoms/Severity/Accessibility",
176
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
177
+ },
178
+ "slots": "none — presentational (renders the dot + optional label from props; no slots)"
179
+ }
@@ -0,0 +1,177 @@
1
+ {
2
+ "name": "switch",
3
+ "component": "MSwitch",
4
+ "display": "Switch",
5
+ "tier": "atom",
6
+ "family": "Selection Controls",
7
+ "source": "mkit",
8
+ "sourceFile": "ui/components/Switch/Switch.vue",
9
+ "status": "core",
10
+ "maturity": "stable",
11
+ "summary": "Instant on/off toggle for a setting that applies immediately. Controlled.",
12
+ "variants": [],
13
+ "sizes": [
14
+ {
15
+ "name": "small",
16
+ "value": "~20x44px",
17
+ "note": ""
18
+ },
19
+ {
20
+ "name": "default",
21
+ "value": "22x44px",
22
+ "note": ""
23
+ }
24
+ ],
25
+ "states": [
26
+ {
27
+ "name": "off",
28
+ "what": "gray knob"
29
+ },
30
+ {
31
+ "name": "on",
32
+ "what": "green knob"
33
+ },
34
+ {
35
+ "name": "disabled",
36
+ "what": "no toggle"
37
+ },
38
+ {
39
+ "name": "loading",
40
+ "what": "spinner in knob"
41
+ }
42
+ ],
43
+ "model": {
44
+ "prop": "checked",
45
+ "event": "change"
46
+ },
47
+ "props": {
48
+ "checked": {
49
+ "type": "boolean",
50
+ "default": false,
51
+ "note": "v-model"
52
+ },
53
+ "size": {
54
+ "type": "string",
55
+ "default": "default",
56
+ "enum": [
57
+ "small",
58
+ "default"
59
+ ]
60
+ },
61
+ "disabled": {
62
+ "type": "boolean",
63
+ "default": false
64
+ },
65
+ "loading": {
66
+ "type": "boolean",
67
+ "default": false
68
+ },
69
+ "defaultChecked": {
70
+ "type": "boolean",
71
+ "note": "NO-OP (F1) — overridden by :checked"
72
+ },
73
+ "autoFocus": {
74
+ "type": "boolean",
75
+ "default": false
76
+ }
77
+ },
78
+ "events": [
79
+ "change"
80
+ ],
81
+ "slots": [
82
+ "checked (on label, unused)",
83
+ "unchecked (off label, unused)"
84
+ ],
85
+ "anatomy": [
86
+ "track",
87
+ "knob (gray off → green on)",
88
+ "optional on/off label slots"
89
+ ],
90
+ "styling": {
91
+ "trackOff": "#fff light / #172336 dark",
92
+ "trackOn": "same as off (no change)",
93
+ "knobOff": "#a5bad0 (neutral-light)",
94
+ "knobOn": "#14b053 (green)",
95
+ "size": "22x44px default"
96
+ },
97
+ "accessibility": {
98
+ "role": "switch",
99
+ "keyboard": "Space/Enter toggle",
100
+ "ariaChecked": "true when on; MISSING when off (F4)",
101
+ "focus": "no visible ring (F3)",
102
+ "targetSize": "~22px (F5)"
103
+ },
104
+ "do": [
105
+ "Use for immediate on/off settings; show :loading while persisting.",
106
+ "Control via v-model / :checked."
107
+ ],
108
+ "dont": [
109
+ "Using a switch in a form that needs explicit Save (use MCheckbox).",
110
+ "Relying on :defaultChecked (no-op, F1)."
111
+ ],
112
+ "whenToUse": "Immediate on/off settings (enable feature, toggle status).",
113
+ "decisionFlow": [
114
+ "Mutually-exclusive options? -> MRadio.",
115
+ "Applies immediately (no Save)? -> Switch.",
116
+ "Committed only on form Save (opt-in/consent/multi-select)? -> MCheckbox."
117
+ ],
118
+ "usageRules": {
119
+ "switch": {
120
+ "useWhen": "single binary setting that applies the moment you toggle it",
121
+ "dontUse": "if saved with a form (use checkbox) or one-of-many (use radio)",
122
+ "example": "Enable notifications; monitor on/off"
123
+ },
124
+ "loading": {
125
+ "useWhen": "the toggle triggers an async persist; block re-toggle until resolved"
126
+ },
127
+ "disabled": {
128
+ "useWhen": "setting exists but can't change in current state/permission"
129
+ },
130
+ "size=small": {
131
+ "useWhen": "dense rows/tables"
132
+ }
133
+ },
134
+ "insteadOf": [
135
+ "raw a-switch"
136
+ ],
137
+ "tokensUsed": [
138
+ "--white-regular",
139
+ "--neutral-light",
140
+ "--secondary-green"
141
+ ],
142
+ "usage": {
143
+ "total": 136,
144
+ "files": 88,
145
+ "labelSlots": 0
146
+ },
147
+ "knownIssues": [
148
+ "F1 (medium): defaultChecked is a no-op — MSwitch always passes :checked (default false) which overrides it. Use :checked/v-model.",
149
+ "F2 (medium): on/off changes only the knob color (gray→green) + position; the track color never changes — subtler, color-leaning signal.",
150
+ "F3 (high, a11y): no visible focus ring (outline:none) — WCAG 2.4.7. Add :focus-visible.",
151
+ "F4 (medium, a11y): aria-checked is set when on but missing when off — AT may not announce off. Ensure aria-checked=false.",
152
+ "F5 (low, a11y): ~22px height below the 44px touch target."
153
+ ],
154
+ "related": [
155
+ "MCheckbox",
156
+ "MRadio"
157
+ ],
158
+ "changelog": [
159
+ "2026-06-05: added (Playground/States/Sizes).",
160
+ "2026-06-06: full deep-dive — examples fixed to :checked (F1); on/off measured; enhanced standard + Option B pages; a11y F3/F4/F5."
161
+ ],
162
+ "storybook": "Atoms/Switch",
163
+ "figma": {
164
+ "status": "todo",
165
+ "component": "Switch"
166
+ },
167
+ "a11y": {
168
+ "summary": "role=switch; Space/Enter toggle; aria-checked=true when on. ~22×44px (sub-44 target).",
169
+ "issues": [
170
+ "No visible focus ring.",
171
+ "aria-checked missing in the OFF state.",
172
+ "On/off signalled mainly by knob colour — add a non-colour cue."
173
+ ],
174
+ "doc": "Atoms/Switch/Accessibility",
175
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
176
+ }
177
+ }
@@ -0,0 +1,275 @@
1
+ {
2
+ "name": "table",
3
+ "display": "Table (Grid)",
4
+ "tier": "organism",
5
+ "family": "Table",
6
+ "source": "src/components/crud/_base-grid.vue (MGrid) — wraps the Kendo Vue Grid (@progress/kendo-vue-grid) + gridWorker/arrayWorker. Usually driven by FlotoPaginatedCrud.",
7
+ "status": "stable",
8
+ "summary": "The product's primary data table. Resizable/reorderable/sortable columns, client + server paging, grouping, selection (with bulk-action bar), expandable detail rows, per-column cell slots. MGrid is the grid; FlotoPaginatedCrud is the fetch+paginate wrapper around it.",
9
+ "variants": [
10
+ {
11
+ "name": "basic",
12
+ "what": "columns + rows, sortable",
13
+ "usage": ""
14
+ },
15
+ {
16
+ "name": "selectable",
17
+ "what": "checkboxes + bulk bar",
18
+ "usage": ""
19
+ },
20
+ {
21
+ "name": "expandable",
22
+ "what": "detail rows",
23
+ "usage": ""
24
+ },
25
+ {
26
+ "name": "grouping",
27
+ "what": "grouped rows + counts",
28
+ "usage": ""
29
+ },
30
+ {
31
+ "name": "cell-types",
32
+ "what": "per-column cell slots",
33
+ "usage": ""
34
+ },
35
+ {
36
+ "name": "pagination",
37
+ "what": "client/server paging",
38
+ "usage": ""
39
+ },
40
+ {
41
+ "name": "tree",
42
+ "what": "hierarchical",
43
+ "usage": ""
44
+ },
45
+ {
46
+ "name": "pivot",
47
+ "what": "pivot/report grid",
48
+ "usage": ""
49
+ }
50
+ ],
51
+ "sizes": [],
52
+ "states": [
53
+ {
54
+ "name": "default",
55
+ "what": "normal"
56
+ },
57
+ {
58
+ "name": "hover",
59
+ "what": "row highlight"
60
+ },
61
+ {
62
+ "name": "selected",
63
+ "what": "checked + accent bar"
64
+ },
65
+ {
66
+ "name": "expanded",
67
+ "what": "detail row open"
68
+ },
69
+ {
70
+ "name": "empty",
71
+ "what": "no records"
72
+ },
73
+ {
74
+ "name": "loading",
75
+ "what": "content loader"
76
+ }
77
+ ],
78
+ "usage": {
79
+ "MGrid": 75,
80
+ "FlotoPaginatedCrud": 76,
81
+ "topModules": [
82
+ "settings",
83
+ "apm",
84
+ "ncm",
85
+ "slo",
86
+ "alert"
87
+ ]
88
+ },
89
+ "props": {
90
+ "columns": {
91
+ "type": "Array",
92
+ "required": true,
93
+ "note": "column defs (field, title, width, cell template, sortable)"
94
+ },
95
+ "data": {
96
+ "type": "Array",
97
+ "note": "the rows (client mode)"
98
+ },
99
+ "selectable": {
100
+ "type": "Boolean",
101
+ "default": false,
102
+ "note": "checkbox column + selection"
103
+ },
104
+ "expandable": {
105
+ "type": "Boolean",
106
+ "default": false,
107
+ "note": "chevron column + detailRow slot"
108
+ },
109
+ "paging": {
110
+ "type": "Boolean",
111
+ "default": false
112
+ },
113
+ "defaultPageSize": {
114
+ "type": "Number",
115
+ "default": 50
116
+ },
117
+ "defaultSort": {
118
+ "type": "Object/Array",
119
+ "note": "initial sort"
120
+ },
121
+ "defaultGroup": {
122
+ "type": "String/Array",
123
+ "note": "grouping column(s)"
124
+ },
125
+ "filters": {
126
+ "type": "Object/Array"
127
+ },
128
+ "searchTerm": {
129
+ "type": "String",
130
+ "note": "external search; with use-search-term-loading shows a spinner"
131
+ },
132
+ "maxAllowedSelection": {
133
+ "type": "Number",
134
+ "note": "cap selection count (0 = unlimited)"
135
+ },
136
+ "preSelectedItems": {
137
+ "type": "Array"
138
+ },
139
+ "selectionDisabledItems": {
140
+ "type": "Array"
141
+ },
142
+ "disablePreSelectedItem": {
143
+ "type": "Boolean",
144
+ "default": false
145
+ },
146
+ "hideSelectionInfo": {
147
+ "type": "Boolean",
148
+ "default": false,
149
+ "note": "hide the 'N selected' tag"
150
+ },
151
+ "rowHeight": {
152
+ "type": "Number",
153
+ "note": "virtualization row height (non-paging mode)"
154
+ },
155
+ "totalCount": {
156
+ "type": "Number",
157
+ "note": "server total"
158
+ },
159
+ "externalSkip": {
160
+ "type": "Number",
161
+ "note": "server paging offset"
162
+ },
163
+ "externalTake": {
164
+ "type": "Number",
165
+ "note": "server page size"
166
+ },
167
+ "useExpandKey": {
168
+ "type": "Boolean",
169
+ "default": false
170
+ },
171
+ "useSearchTermLoading": {
172
+ "type": "Boolean",
173
+ "default": false
174
+ }
175
+ },
176
+ "slots": {
177
+ "perColumn": "a slot per column field renders that cell (status, name, tags, severity, value, duration, action, monitorType, timestamp, count, …)",
178
+ "detailRow": "expanded row content (when expandable)"
179
+ },
180
+ "events": {
181
+ "selection-change": "selection set changed",
182
+ "selection-change-single": "single-select changed",
183
+ "column-change": "columns reordered/resized/toggled",
184
+ "data-state-change": "sort/filter/page changed (server mode)",
185
+ "loaded": "data loaded"
186
+ },
187
+ "consumerClasses": [
188
+ "hide-expand-column",
189
+ "hide-header",
190
+ "hide-grouping",
191
+ "tabular-content-grid",
192
+ "service-grid",
193
+ "rum-grid",
194
+ "mgrid-container"
195
+ ],
196
+ "tokensUsed": [
197
+ "--grid-header-bg",
198
+ "--border-color",
199
+ "--neutral-lightest",
200
+ "--neutral-lighter",
201
+ "--primary",
202
+ "--neutral-dark",
203
+ "--page-background-color"
204
+ ],
205
+ "decisionFlow": [
206
+ "Need to fetch + paginate a list with CRUD? -> FlotoPaginatedCrud (wraps MGrid; handles fetch/paging/search/filters).",
207
+ "Have data already in memory to show in a table? -> MGrid with :data + :columns.",
208
+ "Large/server dataset? -> MGrid server paging (external-take/external-skip + total-count + @data-state-change).",
209
+ "Rows need actions? -> a row-actions kebab cell (FlotoGridActions); multi-select -> selectable + the bulk-action bar.",
210
+ "Rows have drill-down detail? -> expandable + the detailRow slot.",
211
+ "Just a few static key/values, not a dataset? -> a definition list / cards, NOT a grid."
212
+ ],
213
+ "usageRules": {
214
+ "crudList": {
215
+ "useWhen": "a fetched, paginated, searchable list (the default)",
216
+ "how": "FlotoPaginatedCrud + columns",
217
+ "example": "settings list views, inventory"
218
+ },
219
+ "inMemory": {
220
+ "useWhen": "data already loaded",
221
+ "how": "MGrid :data :columns",
222
+ "example": "drill-down sub-tables, preview grids"
223
+ },
224
+ "selectable": {
225
+ "useWhen": "bulk operations on rows",
226
+ "how": "selectable + selection-change + the bulk-action bar",
227
+ "example": "monitor bulk enable/disable/delete"
228
+ },
229
+ "expandable": {
230
+ "useWhen": "each row has detail",
231
+ "how": "expandable + detailRow slot",
232
+ "example": "discovered services, trace spans, interface details"
233
+ }
234
+ },
235
+ "do": [
236
+ "Use FlotoPaginatedCrud for fetched lists",
237
+ "Server-page large datasets",
238
+ "Put row actions in a kebab cell; multi-select via the bulk bar",
239
+ "Keep the header visible in empty/loading states"
240
+ ],
241
+ "dont": [
242
+ "Don't use a grid for a handful of static key/values (use a list/cards)",
243
+ "Don't client-load huge datasets (server-page)",
244
+ "Don't hand-roll selection/paging — MGrid/FlotoPaginatedCrud own it"
245
+ ],
246
+ "knownIssues": {
247
+ "F1": {
248
+ "severity": "Low",
249
+ "issue": "Heavy: Kendo grid + 2 web workers (gridWorker/arrayWorker) — not trivially renderable outside the app (Storybook shows reproductions)."
250
+ },
251
+ "F2": {
252
+ "severity": "Medium",
253
+ "a11y": true,
254
+ "issue": "Kendo grid semantics — verify rows/cells expose proper table roles, sort state (aria-sort), and selection (aria-selected); the custom cell slots can lose them."
255
+ }
256
+ },
257
+ "storybook": "Organisms/Table",
258
+ "related": [
259
+ "popover (row-actions kebab + bulk-action bar)",
260
+ "tag (status cells)",
261
+ "checkbox (selection)",
262
+ "dropdown-picker (column filters)"
263
+ ],
264
+ "figma": {
265
+ "status": "todo"
266
+ },
267
+ "a11y": {
268
+ "summary": "Expose grid semantics (role=grid/table, row, columnheader); sortable headers → aria-sort; selectable rows → aria-selected (header = select-all); arrow-key cell nav; announce 'No records'/loading via a live region.",
269
+ "issues": [
270
+ "Verify the Kendo grid actually exposes the above (semantics / aria-sort / live region)."
271
+ ],
272
+ "doc": "Organisms/Table/Accessibility",
273
+ "$note": "Catalogue-wide gap SF-001 = no visible :focus-visible ring; tracked in findings/."
274
+ }
275
+ }