@astryxdesign/cli 0.1.4-canary.d813abd → 0.1.4-canary.e009fdd

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.
@@ -2,34 +2,36 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import {Collapsible} from '@astryxdesign/core/Collapsible';
5
+ import {Collapsible, CollapsibleGroup} from '@astryxdesign/core/Collapsible';
6
6
  import {Divider} from '@astryxdesign/core/Divider';
7
7
  import {Text} from '@astryxdesign/core/Text';
8
8
  import {VStack} from '@astryxdesign/core/Layout';
9
9
 
10
10
  export default function CollapsibleWithoutCard() {
11
11
  return (
12
- <VStack gap={3} style={{width: '100%', maxWidth: 400}}>
13
- <Collapsible trigger="Deployment Details">
14
- <Text type="body">
15
- Last deployed on April 18, 2026 at 3:42 PM by Sarah Chen. Build
16
- duration was 2m 14s with zero warnings.
17
- </Text>
18
- </Collapsible>
19
- <Divider />
20
- <Collapsible trigger="Environment Variables" defaultIsOpen={false}>
21
- <Text type="body">
22
- 12 variables configured. Last updated March 30, 2026. All secrets are
23
- encrypted at rest with AES-256.
24
- </Text>
25
- </Collapsible>
26
- <Divider />
27
- <Collapsible trigger="Build Logs" defaultIsOpen={false}>
28
- <Text type="body">
29
- Build completed successfully. 847 modules compiled, 0 errors, 0
30
- warnings. Bundle size: 142 KB gzipped.
31
- </Text>
32
- </Collapsible>
33
- </VStack>
12
+ <CollapsibleGroup type="single" defaultValue="deployment">
13
+ <VStack gap={3} style={{width: '100%', maxWidth: 400}}>
14
+ <Collapsible trigger="Deployment Details" value="deployment">
15
+ <Text type="body">
16
+ Last deployed on April 18, 2026 at 3:42 PM by Sarah Chen. Build
17
+ duration was 2m 14s with zero warnings.
18
+ </Text>
19
+ </Collapsible>
20
+ <Divider />
21
+ <Collapsible trigger="Environment Variables" value="environment">
22
+ <Text type="body">
23
+ 12 variables configured. Last updated March 30, 2026. All secrets
24
+ are encrypted at rest with AES-256.
25
+ </Text>
26
+ </Collapsible>
27
+ <Divider />
28
+ <Collapsible trigger="Build Logs" value="logs">
29
+ <Text type="body">
30
+ Build completed successfully. 847 modules compiled, 0 errors, 0
31
+ warnings. Bundle size: 142 KB gzipped.
32
+ </Text>
33
+ </Collapsible>
34
+ </VStack>
35
+ </CollapsibleGroup>
34
36
  );
35
37
  }
@@ -110,7 +110,7 @@ export default function ClassicGalleryTemplate() {
110
110
 
111
111
  return (
112
112
  <Layout
113
- height="auto"
113
+ height="fill"
114
114
  content={
115
115
  <LayoutContent padding={0}>
116
116
  <Center axis="horizontal">
@@ -729,7 +729,7 @@ function TableCard<T extends {id: string}>({
729
729
  export default function DashboardTemplate() {
730
730
  return (
731
731
  <Layout
732
- height="auto"
732
+ height="fill"
733
733
  content={
734
734
  <LayoutContent padding={6}>
735
735
  <VStack gap={6}>
@@ -209,7 +209,7 @@ const COMPONENT_CATEGORIES = [
209
209
  export default function DocumentationOverviewPage() {
210
210
  return (
211
211
  <Layout
212
- height="auto"
212
+ height="fill"
213
213
  contentWidth={1200}
214
214
  content={
215
215
  <LayoutContent padding={8}>
@@ -0,0 +1,580 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * Incident Console — an on-call incident response tool.
7
+ *
8
+ * Frame-first layout (see `npx astryx docs layout`), distilled from
9
+ * product-scale apps built with the design system:
10
+ *
11
+ * Frame: header | grouped incident rows (fill) | inspector 380 (resizable)
12
+ *
13
+ * Responsive contract:
14
+ * > 1024px header | rows | inspector 380
15
+ * <= 1024px inspector hidden; rows keep full width
16
+ *
17
+ * Container policy (tracker archetype): dense data renders as rows —
18
+ * edge-to-edge lists grouped by status, zero cards. Status is carried by
19
+ * StatusDot (severity) and Token (state), not decorative badges.
20
+ */
21
+
22
+ import {useMemo, useState, type CSSProperties} from 'react';
23
+
24
+ import {
25
+ HStack,
26
+ Layout,
27
+ LayoutContent,
28
+ LayoutHeader,
29
+ StackItem,
30
+ VStack,
31
+ } from '@astryxdesign/core/Layout';
32
+ import {ResizeHandle, useResizable} from '@astryxdesign/core/Resizable';
33
+ import {LayoutPanel} from '@astryxdesign/core/Layout';
34
+ import {Heading, Text} from '@astryxdesign/core/Text';
35
+ import {Button} from '@astryxdesign/core/Button';
36
+ import {Icon} from '@astryxdesign/core/Icon';
37
+ import {Divider} from '@astryxdesign/core/Divider';
38
+ import {EmptyState} from '@astryxdesign/core/EmptyState';
39
+ import {List, ListItem} from '@astryxdesign/core/List';
40
+ import {MetadataList, MetadataListItem} from '@astryxdesign/core/MetadataList';
41
+ import {
42
+ PowerSearch,
43
+ usePowerSearchConfig,
44
+ } from '@astryxdesign/core/PowerSearch';
45
+ import type {PowerSearchFilter} from '@astryxdesign/core/PowerSearch';
46
+ import {
47
+ SegmentedControl,
48
+ SegmentedControlItem,
49
+ } from '@astryxdesign/core/SegmentedControl';
50
+ import {StatusDot} from '@astryxdesign/core/StatusDot';
51
+ import {Timestamp} from '@astryxdesign/core/Timestamp';
52
+ import {Token} from '@astryxdesign/core/Token';
53
+ import {useMediaQuery} from '@astryxdesign/core/hooks';
54
+ import {BellAlertIcon, PlusIcon} from '@heroicons/react/24/outline';
55
+
56
+ const styles: Record<string, CSSProperties> = {
57
+ contentFill: {
58
+ height: '100%',
59
+ minHeight: 0,
60
+ },
61
+ searchRow: {
62
+ padding: 'var(--spacing-3)',
63
+ },
64
+ groupHeader: {
65
+ padding: 'var(--spacing-2) var(--spacing-3)',
66
+ backgroundColor: 'var(--color-background-muted)',
67
+ },
68
+ rows: {
69
+ overflowY: 'auto',
70
+ minHeight: 0,
71
+ },
72
+ inspector: {
73
+ padding: 'var(--spacing-4)',
74
+ height: '100%',
75
+ overflowY: 'auto',
76
+ },
77
+ };
78
+
79
+ type Severity = 'sev1' | 'sev2' | 'sev3';
80
+ type Status = 'investigating' | 'mitigated' | 'resolved';
81
+
82
+ interface TimelineEvent {
83
+ at: string;
84
+ label: string;
85
+ detail: string;
86
+ }
87
+
88
+ interface Incident extends Record<string, unknown> {
89
+ id: string;
90
+ title: string;
91
+ service: string;
92
+ severity: Severity;
93
+ status: Status;
94
+ commander: string;
95
+ startedAt: string;
96
+ impact: string;
97
+ timeline: TimelineEvent[];
98
+ }
99
+
100
+ // Deterministic fixtures: fixed ISO timestamps, no clocks, no randomness.
101
+ const INCIDENTS: Incident[] = [
102
+ {
103
+ id: 'INC-2417',
104
+ title: 'Checkout API elevated 5xx rate',
105
+ service: 'checkout-api',
106
+ severity: 'sev1',
107
+ status: 'investigating',
108
+ commander: 'Priya Raman',
109
+ startedAt: '2026-06-30T21:14:00Z',
110
+ impact: '12% of checkout requests failing in us-east',
111
+ timeline: [
112
+ {
113
+ at: '2026-06-30T21:14:00Z',
114
+ label: 'Incident declared',
115
+ detail: 'Paging monitor: checkout-api 5xx > 5% for 10m',
116
+ },
117
+ {
118
+ at: '2026-06-30T21:19:00Z',
119
+ label: 'Commander assigned',
120
+ detail: 'Priya Raman took command',
121
+ },
122
+ {
123
+ at: '2026-06-30T21:31:00Z',
124
+ label: 'Suspect identified',
125
+ detail: 'Deploy 8f31c2 correlates with error onset',
126
+ },
127
+ ],
128
+ },
129
+ {
130
+ id: 'INC-2416',
131
+ title: 'Search indexing lag above 30 minutes',
132
+ service: 'search-indexer',
133
+ severity: 'sev2',
134
+ status: 'investigating',
135
+ commander: 'Marcus Webb',
136
+ startedAt: '2026-06-30T19:42:00Z',
137
+ impact: 'New listings not searchable; stale results served',
138
+ timeline: [
139
+ {
140
+ at: '2026-06-30T19:42:00Z',
141
+ label: 'Incident declared',
142
+ detail: 'Indexing lag alarm crossed 30m threshold',
143
+ },
144
+ {
145
+ at: '2026-06-30T20:05:00Z',
146
+ label: 'Mitigation attempted',
147
+ detail: 'Doubled indexer worker pool; lag still climbing',
148
+ },
149
+ ],
150
+ },
151
+ {
152
+ id: 'INC-2415',
153
+ title: 'Webhook delivery retries exhausting queue',
154
+ service: 'webhooks',
155
+ severity: 'sev3',
156
+ status: 'investigating',
157
+ commander: 'Ana Duarte',
158
+ startedAt: '2026-06-30T18:20:00Z',
159
+ impact: 'Third-party webhook delivery delayed up to 15m',
160
+ timeline: [
161
+ {
162
+ at: '2026-06-30T18:20:00Z',
163
+ label: 'Incident declared',
164
+ detail: 'Queue depth alarm on webhook-delivery',
165
+ },
166
+ ],
167
+ },
168
+ {
169
+ id: 'INC-2414',
170
+ title: 'Payments settlement job stalled',
171
+ service: 'payments',
172
+ severity: 'sev1',
173
+ status: 'mitigated',
174
+ commander: 'Priya Raman',
175
+ startedAt: '2026-06-30T14:03:00Z',
176
+ impact: 'Settlement batch delayed; no customer-visible impact',
177
+ timeline: [
178
+ {
179
+ at: '2026-06-30T14:03:00Z',
180
+ label: 'Incident declared',
181
+ detail: 'Settlement job heartbeat missed twice',
182
+ },
183
+ {
184
+ at: '2026-06-30T14:26:00Z',
185
+ label: 'Mitigated',
186
+ detail: 'Job restarted on standby worker; batch draining',
187
+ },
188
+ ],
189
+ },
190
+ {
191
+ id: 'INC-2413',
192
+ title: 'CDN cache hit ratio degraded in eu-west',
193
+ service: 'edge-cdn',
194
+ severity: 'sev2',
195
+ status: 'mitigated',
196
+ commander: 'Tom Okafor',
197
+ startedAt: '2026-06-30T11:47:00Z',
198
+ impact: 'Origin load 3x baseline; p95 latency +180ms in EU',
199
+ timeline: [
200
+ {
201
+ at: '2026-06-30T11:47:00Z',
202
+ label: 'Incident declared',
203
+ detail: 'Cache hit ratio dropped below 80%',
204
+ },
205
+ {
206
+ at: '2026-06-30T12:12:00Z',
207
+ label: 'Mitigated',
208
+ detail: 'Rolled back cache-key config change',
209
+ },
210
+ ],
211
+ },
212
+ {
213
+ id: 'INC-2412',
214
+ title: 'Login rate limiting misfiring for SSO users',
215
+ service: 'auth',
216
+ severity: 'sev2',
217
+ status: 'resolved',
218
+ commander: 'Ana Duarte',
219
+ startedAt: '2026-06-29T22:31:00Z',
220
+ impact: 'SSO users intermittently blocked at login',
221
+ timeline: [
222
+ {
223
+ at: '2026-06-29T22:31:00Z',
224
+ label: 'Incident declared',
225
+ detail: 'Support surge: SSO login failures',
226
+ },
227
+ {
228
+ at: '2026-06-29T23:02:00Z',
229
+ label: 'Mitigated',
230
+ detail: 'Raised limiter threshold for SSO IdP ranges',
231
+ },
232
+ {
233
+ at: '2026-06-30T09:15:00Z',
234
+ label: 'Resolved',
235
+ detail: 'Limiter keying fixed to per-user; monitors green 8h',
236
+ },
237
+ ],
238
+ },
239
+ {
240
+ id: 'INC-2411',
241
+ title: 'Notification digests sent twice',
242
+ service: 'notifications',
243
+ severity: 'sev3',
244
+ status: 'resolved',
245
+ commander: 'Marcus Webb',
246
+ startedAt: '2026-06-29T08:12:00Z',
247
+ impact: 'Duplicate daily digest for ~40k users',
248
+ timeline: [
249
+ {
250
+ at: '2026-06-29T08:12:00Z',
251
+ label: 'Incident declared',
252
+ detail: 'Duplicate-send reports from support',
253
+ },
254
+ {
255
+ at: '2026-06-29T10:40:00Z',
256
+ label: 'Resolved',
257
+ detail: 'Dedup key restored in scheduler; backfill verified',
258
+ },
259
+ ],
260
+ },
261
+ ];
262
+
263
+ const STATUS_ORDER: Status[] = ['investigating', 'mitigated', 'resolved'];
264
+
265
+ const STATUS_LABEL: Record<Status, string> = {
266
+ investigating: 'Investigating',
267
+ mitigated: 'Mitigated',
268
+ resolved: 'Resolved',
269
+ };
270
+
271
+ const STATUS_TOKEN_COLOR: Record<Status, 'red' | 'yellow' | 'green'> = {
272
+ investigating: 'red',
273
+ mitigated: 'yellow',
274
+ resolved: 'green',
275
+ };
276
+
277
+ const SEVERITY_DOT: Record<Severity, 'error' | 'warning' | 'neutral'> = {
278
+ sev1: 'error',
279
+ sev2: 'warning',
280
+ sev3: 'neutral',
281
+ };
282
+
283
+ const SERVICE_VALUES = [
284
+ {value: 'checkout-api', label: 'checkout-api'},
285
+ {value: 'search-indexer', label: 'search-indexer'},
286
+ {value: 'webhooks', label: 'webhooks'},
287
+ {value: 'payments', label: 'payments'},
288
+ {value: 'edge-cdn', label: 'edge-cdn'},
289
+ {value: 'auth', label: 'auth'},
290
+ {value: 'notifications', label: 'notifications'},
291
+ ];
292
+
293
+ const SEVERITY_VALUES = [
294
+ {value: 'sev1', label: 'SEV1'},
295
+ {value: 'sev2', label: 'SEV2'},
296
+ {value: 'sev3', label: 'SEV3'},
297
+ ];
298
+
299
+ const fieldDefs = [
300
+ {key: 'title', type: 'string', label: 'Title'},
301
+ {key: 'service', type: 'enum', label: 'Service', enumValues: SERVICE_VALUES},
302
+ {
303
+ key: 'severity',
304
+ type: 'enum',
305
+ label: 'Severity',
306
+ enumValues: SEVERITY_VALUES,
307
+ },
308
+ {key: 'commander', type: 'string', label: 'Commander'},
309
+ ] as const;
310
+
311
+ function IncidentRows({
312
+ incidents,
313
+ selectedId,
314
+ onSelect,
315
+ }: {
316
+ incidents: Incident[];
317
+ selectedId: string | null;
318
+ onSelect: (id: string) => void;
319
+ }) {
320
+ const groups = STATUS_ORDER.map(status => ({
321
+ status,
322
+ items: incidents.filter(incident => incident.status === status),
323
+ })).filter(group => group.items.length > 0);
324
+
325
+ if (groups.length === 0) {
326
+ return (
327
+ <EmptyState
328
+ title="No matching incidents"
329
+ description="Adjust the status filter or clear search filters."
330
+ icon={<Icon icon={BellAlertIcon} size="lg" />}
331
+ />
332
+ );
333
+ }
334
+
335
+ return (
336
+ <VStack gap={0}>
337
+ {groups.map(group => (
338
+ <VStack gap={0} key={group.status}>
339
+ <HStack gap={2} vAlign="center" style={styles.groupHeader}>
340
+ <Text type="label" color="secondary">
341
+ {STATUS_LABEL[group.status]}
342
+ </Text>
343
+ <Text type="supporting" color="secondary">
344
+ {group.items.length}
345
+ </Text>
346
+ </HStack>
347
+ <List density="compact" hasDividers>
348
+ {group.items.map(incident => (
349
+ <ListItem
350
+ key={incident.id}
351
+ label={incident.title}
352
+ description={`${incident.id} · ${incident.service} · ${incident.impact}`}
353
+ startContent={
354
+ <StatusDot
355
+ variant={SEVERITY_DOT[incident.severity]}
356
+ label={incident.severity.toUpperCase()}
357
+ isPulsing={
358
+ incident.severity === 'sev1' &&
359
+ incident.status === 'investigating'
360
+ }
361
+ />
362
+ }
363
+ endContent={
364
+ <HStack gap={3} vAlign="center">
365
+ <Token
366
+ size="sm"
367
+ color={STATUS_TOKEN_COLOR[incident.status]}
368
+ label={STATUS_LABEL[incident.status]}
369
+ />
370
+ <Timestamp
371
+ value={incident.startedAt}
372
+ format="relative"
373
+ color="secondary"
374
+ />
375
+ </HStack>
376
+ }
377
+ onClick={() => onSelect(incident.id)}
378
+ isSelected={incident.id === selectedId}
379
+ />
380
+ ))}
381
+ </List>
382
+ </VStack>
383
+ ))}
384
+ </VStack>
385
+ );
386
+ }
387
+
388
+ function IncidentInspector({incident}: {incident: Incident}) {
389
+ const nextAction =
390
+ incident.status === 'investigating'
391
+ ? 'Mark mitigated'
392
+ : incident.status === 'mitigated'
393
+ ? 'Resolve'
394
+ : 'Reopen';
395
+
396
+ return (
397
+ <VStack gap={4} style={styles.inspector}>
398
+ <VStack gap={2}>
399
+ <HStack gap={2} vAlign="center">
400
+ <StatusDot
401
+ variant={SEVERITY_DOT[incident.severity]}
402
+ label={incident.severity.toUpperCase()}
403
+ />
404
+ <Text type="supporting" color="secondary">
405
+ {incident.id}
406
+ </Text>
407
+ <Token
408
+ size="sm"
409
+ color={STATUS_TOKEN_COLOR[incident.status]}
410
+ label={STATUS_LABEL[incident.status]}
411
+ />
412
+ </HStack>
413
+ <Heading level={2}>{incident.title}</Heading>
414
+ </VStack>
415
+
416
+ <HStack gap={2}>
417
+ <Button label={nextAction} size="sm" />
418
+ <Button label="Escalate" variant="secondary" size="sm" />
419
+ </HStack>
420
+
421
+ <Divider />
422
+
423
+ <MetadataList columns="single" label={{position: 'start', width: 96}}>
424
+ <MetadataListItem label="Service">
425
+ <Text type="body">{incident.service}</Text>
426
+ </MetadataListItem>
427
+ <MetadataListItem label="Severity">
428
+ <Text type="body">{incident.severity.toUpperCase()}</Text>
429
+ </MetadataListItem>
430
+ <MetadataListItem label="Commander">
431
+ <Text type="body">{incident.commander}</Text>
432
+ </MetadataListItem>
433
+ <MetadataListItem label="Started">
434
+ <Timestamp value={incident.startedAt} format="date_time" />
435
+ </MetadataListItem>
436
+ <MetadataListItem label="Impact">
437
+ <Text type="body">{incident.impact}</Text>
438
+ </MetadataListItem>
439
+ </MetadataList>
440
+
441
+ <Divider />
442
+
443
+ <VStack gap={2}>
444
+ <Heading level={3}>Timeline</Heading>
445
+ <List density="compact">
446
+ {incident.timeline.map(event => (
447
+ <ListItem
448
+ key={`${event.at}-${event.label}`}
449
+ label={event.label}
450
+ description={event.detail}
451
+ endContent={
452
+ <Timestamp value={event.at} format="time" color="secondary" />
453
+ }
454
+ />
455
+ ))}
456
+ </List>
457
+ </VStack>
458
+ </VStack>
459
+ );
460
+ }
461
+
462
+ export default function IncidentConsolePage() {
463
+ const [statusFilter, setStatusFilter] = useState('all');
464
+ const [filters, setFilters] = useState<PowerSearchFilter[]>([]);
465
+ const [selectedId, setSelectedId] = useState<string | null>(INCIDENTS[0].id);
466
+ const {config, applyFilters} = usePowerSearchConfig(fieldDefs, 'Incidents');
467
+
468
+ // Responsive contract: the inspector is hidden at <= 1024px so the row
469
+ // list keeps its full width (never compress dense rows).
470
+ const isNarrow = useMediaQuery('(max-width: 1024px)');
471
+
472
+ const inspectorPanel = useResizable({
473
+ defaultSize: 380,
474
+ minSizePx: 320,
475
+ maxSizePx: 480,
476
+ });
477
+
478
+ const visible = useMemo(() => {
479
+ const searched = applyFilters(filters, INCIDENTS);
480
+ return statusFilter === 'all'
481
+ ? searched
482
+ : searched.filter(incident => incident.status === statusFilter);
483
+ }, [filters, applyFilters, statusFilter]);
484
+
485
+ const selected = visible.find(incident => incident.id === selectedId) ?? null;
486
+
487
+ const openCount = INCIDENTS.filter(
488
+ incident => incident.status === 'investigating',
489
+ ).length;
490
+
491
+ return (
492
+ <Layout
493
+ height="fill"
494
+ header={
495
+ <LayoutHeader hasDivider>
496
+ <HStack gap={3} vAlign="center">
497
+ <StackItem size="fill">
498
+ <HStack gap={2} vAlign="center">
499
+ <Heading level={1}>Incidents</Heading>
500
+ <Text type="supporting" color="secondary">
501
+ {openCount} investigating
502
+ </Text>
503
+ </HStack>
504
+ </StackItem>
505
+ <SegmentedControl
506
+ label="Filter by status"
507
+ value={statusFilter}
508
+ onChange={setStatusFilter}
509
+ size="sm">
510
+ <SegmentedControlItem label="All" value="all" />
511
+ <SegmentedControlItem
512
+ label="Investigating"
513
+ value="investigating"
514
+ />
515
+ <SegmentedControlItem label="Mitigated" value="mitigated" />
516
+ <SegmentedControlItem label="Resolved" value="resolved" />
517
+ </SegmentedControl>
518
+ <Button
519
+ label="Declare incident"
520
+ icon={<Icon icon={PlusIcon} size="sm" />}
521
+ size="sm"
522
+ />
523
+ </HStack>
524
+ </LayoutHeader>
525
+ }
526
+ content={
527
+ <LayoutContent padding={0}>
528
+ <VStack gap={0} style={styles.contentFill}>
529
+ <HStack style={styles.searchRow}>
530
+ <StackItem size="fill">
531
+ <PowerSearch
532
+ config={config}
533
+ filters={filters}
534
+ onChange={newFilters => setFilters([...newFilters])}
535
+ placeholder="Search incidents..."
536
+ resultCount={visible.length}
537
+ />
538
+ </StackItem>
539
+ </HStack>
540
+ <StackItem size="fill" style={styles.rows}>
541
+ <IncidentRows
542
+ incidents={visible}
543
+ selectedId={selected?.id ?? null}
544
+ onSelect={setSelectedId}
545
+ />
546
+ </StackItem>
547
+ </VStack>
548
+ </LayoutContent>
549
+ }
550
+ end={
551
+ isNarrow ? undefined : (
552
+ <>
553
+ <ResizeHandle
554
+ direction="horizontal"
555
+ hasDivider
556
+ isAlwaysVisible={false}
557
+ resizable={inspectorPanel.props}
558
+ label="Resize inspector"
559
+ />
560
+ <LayoutPanel
561
+ width={inspectorPanel.size}
562
+ padding={0}
563
+ label="Incident details">
564
+ {selected ? (
565
+ <IncidentInspector incident={selected} />
566
+ ) : (
567
+ <EmptyState
568
+ title="No incident selected"
569
+ description="Select an incident to see details and timeline."
570
+ icon={<Icon icon={BellAlertIcon} size="lg" />}
571
+ isCompact
572
+ />
573
+ )}
574
+ </LayoutPanel>
575
+ </>
576
+ )
577
+ }
578
+ />
579
+ );
580
+ }
@@ -0,0 +1,12 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('../../../../core/src/docs-types').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'page',
6
+ name: 'Incident Console',
7
+ displayName: 'Incident Console',
8
+ description:
9
+ 'On-call incident response console: grouped dense incident rows with severity dots, PowerSearch filtering, status segmented control, and a resizable inspector panel with metadata and timeline. Frame-first tracker archetype: rows, not cards.',
10
+ isReady: false,
11
+ category: 'Tools - Incident Console',
12
+ };