@stackwright-pro/pulse 0.2.0 → 0.2.1-alpha.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/README.md +364 -39
- package/dist/collectionData-3ZJA4PEZ.mjs +10 -0
- package/dist/index.d.mts +79 -1
- package/dist/index.d.ts +79 -1
- package/dist/index.js +416 -13
- package/dist/index.mjs +377 -12
- package/package.json +13 -6
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ pnpm add @stackwright-pro/pulse
|
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
**Peer Dependencies:**
|
|
23
|
+
|
|
23
24
|
```bash
|
|
24
25
|
pnpm add react react-dom @tanstack/react-query
|
|
25
26
|
```
|
|
@@ -33,10 +34,7 @@ import { Pulse, PulseIndicator } from '@stackwright-pro/pulse';
|
|
|
33
34
|
|
|
34
35
|
function EquipmentPanel() {
|
|
35
36
|
return (
|
|
36
|
-
<Pulse
|
|
37
|
-
fetcher={() => fetch('/api/equipment').then(r => r.json())}
|
|
38
|
-
interval={5000}
|
|
39
|
-
>
|
|
37
|
+
<Pulse fetcher={() => fetch('/api/equipment').then((r) => r.json())} interval={5000}>
|
|
40
38
|
{(equipment, meta) => (
|
|
41
39
|
<>
|
|
42
40
|
<PulseIndicator meta={meta} />
|
|
@@ -64,7 +62,7 @@ const EquipmentSchema = z.object({
|
|
|
64
62
|
function EquipmentPanel() {
|
|
65
63
|
return (
|
|
66
64
|
<Pulse
|
|
67
|
-
fetcher={() => fetch('/api/equipment').then(r => r.json())}
|
|
65
|
+
fetcher={() => fetch('/api/equipment').then((r) => r.json())}
|
|
68
66
|
schema={EquipmentSchema}
|
|
69
67
|
interval={5000}
|
|
70
68
|
>
|
|
@@ -88,8 +86,8 @@ function CustomEquipmentPanel() {
|
|
|
88
86
|
maxStaleAge={60000}
|
|
89
87
|
loadingState={<SkeletonLoader />}
|
|
90
88
|
errorState={(meta) => (
|
|
91
|
-
<ErrorBanner
|
|
92
|
-
message="Failed to load equipment"
|
|
89
|
+
<ErrorBanner
|
|
90
|
+
message="Failed to load equipment"
|
|
93
91
|
lastUpdated={meta.lastUpdated}
|
|
94
92
|
onRetry={meta.refetch}
|
|
95
93
|
/>
|
|
@@ -147,27 +145,27 @@ function CustomEquipmentPanel() {
|
|
|
147
145
|
```tsx
|
|
148
146
|
interface PulseProps<T> {
|
|
149
147
|
// Core
|
|
150
|
-
fetcher: () => Promise<T>;
|
|
148
|
+
fetcher: () => Promise<T>; // Your data fetching function
|
|
151
149
|
children: (data: T, meta: PulseMeta) => React.ReactNode;
|
|
152
|
-
|
|
150
|
+
|
|
153
151
|
// Polling config
|
|
154
|
-
interval?: number;
|
|
155
|
-
enabled?: boolean;
|
|
156
|
-
retryCount?: number;
|
|
157
|
-
refetchOnWindowFocus?: boolean;
|
|
158
|
-
|
|
152
|
+
interval?: number; // Poll interval in ms (default: 5000, min: 1000)
|
|
153
|
+
enabled?: boolean; // Enable/disable polling (default: true)
|
|
154
|
+
retryCount?: number; // Number of retries on error (default: 3)
|
|
155
|
+
refetchOnWindowFocus?: boolean; // Refetch on window focus (default: true)
|
|
156
|
+
|
|
159
157
|
// State thresholds (in milliseconds)
|
|
160
|
-
staleThreshold?: number;
|
|
161
|
-
maxStaleAge?: number;
|
|
162
|
-
|
|
158
|
+
staleThreshold?: number; // Show stale warning (default: 30000)
|
|
159
|
+
maxStaleAge?: number; // Show error state (default: 60000)
|
|
160
|
+
|
|
163
161
|
// Validation
|
|
164
|
-
schema?: ZodSchema<T>;
|
|
165
|
-
|
|
162
|
+
schema?: ZodSchema<T>; // Optional Zod schema
|
|
163
|
+
|
|
166
164
|
// Custom state UI
|
|
167
165
|
loadingState?: React.ReactNode;
|
|
168
166
|
errorState?: React.ReactNode | ((meta: PulseMeta) => React.ReactNode);
|
|
169
167
|
emptyState?: React.ReactNode;
|
|
170
|
-
showStaleDataOnError?: boolean;
|
|
168
|
+
showStaleDataOnError?: boolean; // Show data during error (default: true)
|
|
171
169
|
}
|
|
172
170
|
```
|
|
173
171
|
|
|
@@ -175,12 +173,12 @@ interface PulseProps<T> {
|
|
|
175
173
|
|
|
176
174
|
```tsx
|
|
177
175
|
interface PulseMeta {
|
|
178
|
-
lastUpdated: Date;
|
|
179
|
-
isStale: boolean;
|
|
180
|
-
isError: boolean;
|
|
181
|
-
isLoading: boolean;
|
|
182
|
-
errorCount: number;
|
|
183
|
-
refetch: () => void;
|
|
176
|
+
lastUpdated: Date; // Timestamp of last successful fetch
|
|
177
|
+
isStale: boolean; // Data older than staleThreshold
|
|
178
|
+
isError: boolean; // Data older than maxStaleAge or fetch failed
|
|
179
|
+
isLoading: boolean; // Currently fetching
|
|
180
|
+
errorCount: number; // Number of consecutive errors
|
|
181
|
+
refetch: () => void; // Manual refresh trigger
|
|
184
182
|
state: 'loading' | 'live' | 'stale' | 'error';
|
|
185
183
|
}
|
|
186
184
|
```
|
|
@@ -189,14 +187,14 @@ interface PulseMeta {
|
|
|
189
187
|
|
|
190
188
|
```tsx
|
|
191
189
|
interface PulseIndicatorProps {
|
|
192
|
-
meta: PulseMeta;
|
|
193
|
-
showSeconds?: boolean;
|
|
194
|
-
className?: string;
|
|
190
|
+
meta: PulseMeta; // Required meta object
|
|
191
|
+
showSeconds?: boolean; // Show "Xs ago" (default: true)
|
|
192
|
+
className?: string; // Additional CSS classes
|
|
195
193
|
labels?: {
|
|
196
|
-
live?: string;
|
|
197
|
-
syncing?: string;
|
|
198
|
-
stale?: string;
|
|
199
|
-
error?: string;
|
|
194
|
+
live?: string; // Custom live label
|
|
195
|
+
syncing?: string; // Custom syncing label
|
|
196
|
+
stale?: string; // Custom stale label
|
|
197
|
+
error?: string; // Custom error label
|
|
200
198
|
};
|
|
201
199
|
}
|
|
202
200
|
```
|
|
@@ -228,12 +226,12 @@ const result = usePulse<T>({
|
|
|
228
226
|
|
|
229
227
|
The `fetcher` prop accepts **any** async function. This makes Pulse work with:
|
|
230
228
|
|
|
231
|
-
| Source
|
|
232
|
-
|
|
229
|
+
| Source | Example Fetcher |
|
|
230
|
+
| ------------ | ---------------------------------------------- |
|
|
233
231
|
| REST/OpenAPI | `() => fetch('/api/data').then(r => r.json())` |
|
|
234
|
-
| WebSocket
|
|
235
|
-
| GraphQL
|
|
236
|
-
| SSE
|
|
232
|
+
| WebSocket | `() => websocket.nextMessage()` |
|
|
233
|
+
| GraphQL | `() => client.query({ query: MY_QUERY })` |
|
|
234
|
+
| SSE | `() => eventSource.nextEvent()` |
|
|
237
235
|
|
|
238
236
|
See [SOURCE_ADAPTERS.md](./docs/SOURCE_ADAPTERS.md) for planned first-party adapter documentation.
|
|
239
237
|
|
|
@@ -343,6 +341,333 @@ For a full working demo, see [examples/marine-logistics-demo/src/pages/dashboard
|
|
|
343
341
|
|
|
344
342
|
See [docs/SOURCE_ADAPTERS.md](./docs/SOURCE_ADAPTERS.md) for planned adapter documentation.
|
|
345
343
|
|
|
344
|
+
## Collection Binding (Phase 3 - Killer Pro Feature)
|
|
345
|
+
|
|
346
|
+
The collection binding system connects **OpenAPI data** → **Prebuild** → **Pulse** → **Dashboard Components** for a complete live data experience.
|
|
347
|
+
|
|
348
|
+
### Architecture
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
352
|
+
│ DASHBOARD OTTER │
|
|
353
|
+
│ Generates YAML with {{ collection.field }} template syntax │
|
|
354
|
+
└─────────────────────────────────┬────────────────────────────────────────┘
|
|
355
|
+
│
|
|
356
|
+
▼
|
|
357
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
358
|
+
│ stackwright.yml │
|
|
359
|
+
│ integrations: │
|
|
360
|
+
│ - name: logistics-api │
|
|
361
|
+
│ spec: ./openapi.yaml │
|
|
362
|
+
│ collections: │
|
|
363
|
+
│ - endpoint: /equipment │
|
|
364
|
+
└─────────────────────────────────┬────────────────────────────────────────┘
|
|
365
|
+
│
|
|
366
|
+
▼
|
|
367
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
368
|
+
│ PREBUILD (pnpm prebuild) │
|
|
369
|
+
│ OpenAPIPlugin generates: │
|
|
370
|
+
│ - src/generated/logistics-api/provider.ts (CollectionProvider) │
|
|
371
|
+
│ - src/generated/logistics-api/schemas.ts (Zod schemas) │
|
|
372
|
+
│ - src/generated/logistics-api/types.ts (TypeScript types) │
|
|
373
|
+
└─────────────────────────────────┬────────────────────────────────────────┘
|
|
374
|
+
│
|
|
375
|
+
▼
|
|
376
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
377
|
+
│ PulseCollectionProvider │
|
|
378
|
+
│ Wraps dashboard with live collection context │
|
|
379
|
+
│ - Creates fetchers from prebuild providers │
|
|
380
|
+
│ - Polls at configured intervals (5s, 30s, 300s, etc.) │
|
|
381
|
+
│ - Provides data via React context │
|
|
382
|
+
└─────────────────────────────────┬────────────────────────────────────────┘
|
|
383
|
+
│
|
|
384
|
+
▼
|
|
385
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
386
|
+
│ Pulse-Enabled Components │
|
|
387
|
+
│ MetricCardPulse, DataTablePulse, StatusBadgePulse │
|
|
388
|
+
│ - Auto-bind to collection data │
|
|
389
|
+
│ - Support template syntax {{ collection.field }} │
|
|
390
|
+
│ - Built-in aggregation (count, sum, avg) │
|
|
391
|
+
│ - Live indicator with stale/error states │
|
|
392
|
+
└──────────────────────────────────────────────────────────────────────────┘
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Quick Start
|
|
396
|
+
|
|
397
|
+
#### 1. Configure OpenAPI in `stackwright.yml`
|
|
398
|
+
|
|
399
|
+
```yaml
|
|
400
|
+
integrations:
|
|
401
|
+
- name: logistics-api
|
|
402
|
+
spec: ./openapi.yaml
|
|
403
|
+
auth:
|
|
404
|
+
type: bearer
|
|
405
|
+
token: ${API_TOKEN}
|
|
406
|
+
collections:
|
|
407
|
+
- endpoint: /equipment
|
|
408
|
+
slug_field: id
|
|
409
|
+
- endpoint: /locations
|
|
410
|
+
slug_field: id
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### 2. Run Prebuild
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
pnpm prebuild
|
|
417
|
+
# Generates src/generated/logistics-api/*
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### 3. Use Pulse Components in Pages
|
|
421
|
+
|
|
422
|
+
```yaml
|
|
423
|
+
# pages/dashboard/content.yml
|
|
424
|
+
content:
|
|
425
|
+
meta:
|
|
426
|
+
title: 'Live Equipment Dashboard'
|
|
427
|
+
|
|
428
|
+
content_items:
|
|
429
|
+
# Wrap with Pulse provider for live data
|
|
430
|
+
- type: pulse_provider
|
|
431
|
+
label: equipment-live
|
|
432
|
+
collections:
|
|
433
|
+
- name: equipment
|
|
434
|
+
endpoint: /api/equipment
|
|
435
|
+
refreshInterval: 5000
|
|
436
|
+
items:
|
|
437
|
+
- type: grid
|
|
438
|
+
columns: 4
|
|
439
|
+
items:
|
|
440
|
+
- type: metric_card_pulse
|
|
441
|
+
collection: equipment
|
|
442
|
+
field: items.length
|
|
443
|
+
label: 'Total Equipment'
|
|
444
|
+
icon: Truck
|
|
445
|
+
|
|
446
|
+
- type: metric_card_pulse
|
|
447
|
+
collection: equipment
|
|
448
|
+
field: items
|
|
449
|
+
label: 'Active'
|
|
450
|
+
aggregate: count
|
|
451
|
+
aggregateField: status
|
|
452
|
+
filter: '{"status": "active"}'
|
|
453
|
+
icon: CheckCircle
|
|
454
|
+
|
|
455
|
+
- type: data_table_pulse
|
|
456
|
+
collection: equipment
|
|
457
|
+
columns:
|
|
458
|
+
- field: id
|
|
459
|
+
header: ID
|
|
460
|
+
sortable: true
|
|
461
|
+
- field: name
|
|
462
|
+
header: Name
|
|
463
|
+
- field: status
|
|
464
|
+
header: Status
|
|
465
|
+
type: badge
|
|
466
|
+
sortBy: name
|
|
467
|
+
sortDirection: asc
|
|
468
|
+
limit: 20
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Component Reference
|
|
472
|
+
|
|
473
|
+
### `pulse_provider`
|
|
474
|
+
|
|
475
|
+
Wraps content with live collection data. All child Pulse components automatically bind to these collections.
|
|
476
|
+
|
|
477
|
+
```yaml
|
|
478
|
+
- type: pulse_provider
|
|
479
|
+
label: equipment-live
|
|
480
|
+
collections:
|
|
481
|
+
- name: equipment # Collection name for binding
|
|
482
|
+
endpoint: /api/equipment # OpenAPI endpoint
|
|
483
|
+
refreshInterval: 5000 # Poll every 5 seconds
|
|
484
|
+
filter: # Optional server-side filter
|
|
485
|
+
status: active
|
|
486
|
+
items:
|
|
487
|
+
# Child components here
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
Props:
|
|
491
|
+
| Prop | Type | Description |
|
|
492
|
+
|------|------|-------------|
|
|
493
|
+
| `label` | string | Unique identifier |
|
|
494
|
+
| `collections` | CollectionBinding[] | Collections to fetch |
|
|
495
|
+
| `collections[].name` | string | Collection name for binding |
|
|
496
|
+
| `collections[].endpoint` | string | API endpoint path |
|
|
497
|
+
| `collections[].refreshInterval` | number | Poll interval in ms (default: 5000) |
|
|
498
|
+
| `collections[].filter` | object | Server-side filter params |
|
|
499
|
+
|
|
500
|
+
### `metric_card_pulse`
|
|
501
|
+
|
|
502
|
+
KPI card with auto-bound live data.
|
|
503
|
+
|
|
504
|
+
```yaml
|
|
505
|
+
- type: metric_card_pulse
|
|
506
|
+
collection: equipment # Collection to bind
|
|
507
|
+
field: items.length # Field or expression
|
|
508
|
+
label: 'Total Equipment' # Display label
|
|
509
|
+
icon: Truck # Icon name
|
|
510
|
+
aggregate: count # Optional: count, sum, avg
|
|
511
|
+
aggregateField: status # Field for aggregation
|
|
512
|
+
filter: '{"status": "active"}' # Optional: filter items
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Props:
|
|
516
|
+
| Prop | Type | Description |
|
|
517
|
+
|------|------|-------------|
|
|
518
|
+
| `collection` | string | Collection name |
|
|
519
|
+
| `field` | string | Field path (supports dots) |
|
|
520
|
+
| `label` | string | Card label |
|
|
521
|
+
| `icon` | ReactNode | Icon component |
|
|
522
|
+
| `color` | string | Accent color (hex) |
|
|
523
|
+
| `trend` | 'up' \| 'down' \| 'stable' | Trend direction |
|
|
524
|
+
| `trendValue` | string | Trend display value |
|
|
525
|
+
| `aggregate` | 'count' \| 'sum' \| 'avg' | Aggregate function |
|
|
526
|
+
| `aggregateField` | string | Field for aggregation |
|
|
527
|
+
| `filter` | string | JSON filter string |
|
|
528
|
+
|
|
529
|
+
### `data_table_pulse`
|
|
530
|
+
|
|
531
|
+
Sortable table with live data binding.
|
|
532
|
+
|
|
533
|
+
```yaml
|
|
534
|
+
- type: data_table_pulse
|
|
535
|
+
collection: equipment
|
|
536
|
+
columns:
|
|
537
|
+
- field: id
|
|
538
|
+
header: ID
|
|
539
|
+
sortable: true
|
|
540
|
+
- field: name
|
|
541
|
+
header: Name
|
|
542
|
+
- field: status
|
|
543
|
+
header: Status
|
|
544
|
+
type: badge
|
|
545
|
+
sortBy: name
|
|
546
|
+
sortDirection: asc
|
|
547
|
+
limit: 20
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Props:
|
|
551
|
+
| Prop | Type | Description |
|
|
552
|
+
|------|------|-------------|
|
|
553
|
+
| `collection` | string | Collection name |
|
|
554
|
+
| `columns` | Column[] | Column definitions |
|
|
555
|
+
| `sortBy` | string | Field to sort by |
|
|
556
|
+
| `sortDirection` | 'asc' \| 'desc' | Sort direction |
|
|
557
|
+
| `filter` | string | JSON filter string |
|
|
558
|
+
| `limit` | number | Max items to show |
|
|
559
|
+
| `onRowClick` | function | Row click handler |
|
|
560
|
+
| `emptyMessage` | string | Empty state message |
|
|
561
|
+
|
|
562
|
+
### `status_badge_pulse`
|
|
563
|
+
|
|
564
|
+
Status indicator with live data binding.
|
|
565
|
+
|
|
566
|
+
```yaml
|
|
567
|
+
- type: status_badge_pulse
|
|
568
|
+
collection: equipment
|
|
569
|
+
field: items[0].status
|
|
570
|
+
label: 'System Status'
|
|
571
|
+
pulse: true
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Props:
|
|
575
|
+
| Prop | Type | Description |
|
|
576
|
+
|------|------|-------------|
|
|
577
|
+
| `collection` | string | Collection name |
|
|
578
|
+
| `field` | string | Status field path |
|
|
579
|
+
| `label` | string | Display label |
|
|
580
|
+
| `pulse` | boolean | Show pulse animation |
|
|
581
|
+
| `statusMap` | object | Custom value → status mapping |
|
|
582
|
+
|
|
583
|
+
### Hooks
|
|
584
|
+
|
|
585
|
+
For custom component integration:
|
|
586
|
+
|
|
587
|
+
```tsx
|
|
588
|
+
import {
|
|
589
|
+
usePulseCollections, // Full context
|
|
590
|
+
useCollection, // Single collection
|
|
591
|
+
useCollectionField, // Specific field
|
|
592
|
+
useTemplateResolution, // Resolve templates
|
|
593
|
+
resolveTemplate, // Static template resolver
|
|
594
|
+
} from '@stackwright-pro/pulse';
|
|
595
|
+
|
|
596
|
+
// Get full context
|
|
597
|
+
const { collections, isLoading, getField } = usePulseCollections();
|
|
598
|
+
|
|
599
|
+
// Get single collection
|
|
600
|
+
const equipment = useCollection('equipment');
|
|
601
|
+
// Returns: { items, count, meta, ... }
|
|
602
|
+
|
|
603
|
+
// Get specific field
|
|
604
|
+
const count = useCollectionField('equipment', 'items.length');
|
|
605
|
+
|
|
606
|
+
// Resolve template anywhere
|
|
607
|
+
const templateResolution = useTemplateResolution();
|
|
608
|
+
const value = templateResolution('{{ equipment.count }}');
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Template Syntax
|
|
612
|
+
|
|
613
|
+
The `{{ collection.field }}` syntax is automatically resolved:
|
|
614
|
+
|
|
615
|
+
| Pattern | Example | Result |
|
|
616
|
+
| ------------ | ------------------------------- | --------------------- |
|
|
617
|
+
| Count | `{{ equipment.count }}` | Number of items |
|
|
618
|
+
| Array length | `{{ equipment.items.length }}` | Array size |
|
|
619
|
+
| Nested field | `{{ equipment.items[0].name }}` | First item's name |
|
|
620
|
+
| Aggregate | `{{ equipment.status.active }}` | Count of active items |
|
|
621
|
+
|
|
622
|
+
### ISR Intervals
|
|
623
|
+
|
|
624
|
+
Configure refresh intervals based on data freshness needs:
|
|
625
|
+
|
|
626
|
+
| Interval | Use Case | Example |
|
|
627
|
+
| -------- | ------------- | ------------------ |
|
|
628
|
+
| 5000ms | Real-time | Live dashboard |
|
|
629
|
+
| 30000ms | Near-realtime | Status updates |
|
|
630
|
+
| 300000ms | Hourly | Reports, summaries |
|
|
631
|
+
|
|
632
|
+
### Error Handling
|
|
633
|
+
|
|
634
|
+
Pulse components handle errors gracefully:
|
|
635
|
+
|
|
636
|
+
```tsx
|
|
637
|
+
// With error state
|
|
638
|
+
<DataTablePulse
|
|
639
|
+
collection="equipment"
|
|
640
|
+
columns={columns}
|
|
641
|
+
fallback={<ErrorBanner />}
|
|
642
|
+
/>
|
|
643
|
+
|
|
644
|
+
// With stale data (continue showing data during errors)
|
|
645
|
+
<MetricCardPulse
|
|
646
|
+
collection="equipment"
|
|
647
|
+
field="count"
|
|
648
|
+
showStaleData={true}
|
|
649
|
+
/>
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Complete Example
|
|
653
|
+
|
|
654
|
+
See the marine-logistics demo for a full working example:
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
pnpm prebuild # Generate providers
|
|
658
|
+
pnpm dev # Start dev server
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
The dashboard will show live-updating KPI cards and data tables with auto-refresh!
|
|
662
|
+
|
|
663
|
+
### Future: Real-time Providers
|
|
664
|
+
|
|
665
|
+
Coming soon:
|
|
666
|
+
|
|
667
|
+
- `createWebSocketFetcher()` - WebSocket adapter
|
|
668
|
+
- `createSSEFetcher()` - Server-Sent Events adapter
|
|
669
|
+
- `createGraphQLFetcher()` - GraphQL polling adapter
|
|
670
|
+
|
|
346
671
|
## License
|
|
347
672
|
|
|
348
|
-
PROPRIETARY - All rights reserved.
|
|
673
|
+
PROPRIETARY - All rights reserved.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/collection/collectionData.ts
|
|
2
|
+
async function getCollectionData(collection) {
|
|
3
|
+
console.warn(
|
|
4
|
+
`[collectionData] Stub called for collection: ${collection}. Run prebuild to generate real data fetchers.`
|
|
5
|
+
);
|
|
6
|
+
return [];
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
getCollectionData
|
|
10
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -230,4 +230,82 @@ declare class PulseValidationError extends Error {
|
|
|
230
230
|
}[];
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
interface CollectionBinding {
|
|
234
|
+
collection: string;
|
|
235
|
+
endpoint: string;
|
|
236
|
+
slugField?: string;
|
|
237
|
+
refreshInterval?: number;
|
|
238
|
+
schema?: unknown;
|
|
239
|
+
}
|
|
240
|
+
interface CollectionData {
|
|
241
|
+
items: unknown[];
|
|
242
|
+
count: number;
|
|
243
|
+
meta: PulseMeta;
|
|
244
|
+
[key: string]: unknown;
|
|
245
|
+
}
|
|
246
|
+
interface PulseCollectionContextValue {
|
|
247
|
+
collections: Record<string, CollectionData>;
|
|
248
|
+
isLoading: boolean;
|
|
249
|
+
getCollection: (name: string) => CollectionData | null;
|
|
250
|
+
getField: (collection: string, field: string) => unknown;
|
|
251
|
+
}
|
|
252
|
+
declare function resolveTemplate(template: string, collections: Record<string, CollectionData>): unknown;
|
|
253
|
+
declare function PulseCollectionProvider({ collections: collectionConfigs, children, fallback, }: {
|
|
254
|
+
collections: CollectionBinding[];
|
|
255
|
+
children: React.ReactNode;
|
|
256
|
+
fallback?: React.ReactNode;
|
|
257
|
+
}): react_jsx_runtime.JSX.Element;
|
|
258
|
+
declare function usePulseCollections(): PulseCollectionContextValue;
|
|
259
|
+
declare function useCollection(collectionName: string): CollectionData | null;
|
|
260
|
+
declare function useCollectionField(collectionName: string, field: string): unknown;
|
|
261
|
+
declare function useTemplateResolution(): (template: string) => unknown;
|
|
262
|
+
|
|
263
|
+
interface MetricCardPulseProps {
|
|
264
|
+
/** Collection name to bind to */
|
|
265
|
+
collection: string;
|
|
266
|
+
/** Field to display (supports {{ collection.field }} syntax) */
|
|
267
|
+
field: string;
|
|
268
|
+
/** Static label override */
|
|
269
|
+
label?: string;
|
|
270
|
+
/** Icon to show */
|
|
271
|
+
icon?: React.ReactNode;
|
|
272
|
+
/** Color for the card accent */
|
|
273
|
+
color?: string;
|
|
274
|
+
/** Trend direction: 'up' | 'down' | 'stable' */
|
|
275
|
+
trend?: 'up' | 'down' | 'stable';
|
|
276
|
+
/** Static trend value override */
|
|
277
|
+
trendValue?: string;
|
|
278
|
+
/** Aggregate function for array data: 'count' | 'sum' | 'avg' */
|
|
279
|
+
aggregate?: 'count' | 'sum' | 'avg';
|
|
280
|
+
/** Path within items to use for aggregation */
|
|
281
|
+
aggregateField?: string;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* MetricCard with live data binding to collections
|
|
285
|
+
*
|
|
286
|
+
* Examples:
|
|
287
|
+
* ```yaml
|
|
288
|
+
* - type: metric_card_pulse
|
|
289
|
+
* collection: equipment
|
|
290
|
+
* field: items.length # count of equipment
|
|
291
|
+
* label: "Total Equipment"
|
|
292
|
+
* icon: Truck
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
declare function MetricCardPulse({ collection, field, label, icon, color, trend, trendValue, aggregate, aggregateField, }: MetricCardPulseProps): react_jsx_runtime.JSX.Element;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Register Pulse collection binding components
|
|
299
|
+
*
|
|
300
|
+
* Call this AFTER registerDisplayComponents() in _app.tsx:
|
|
301
|
+
* ```ts
|
|
302
|
+
* import { registerDisplayComponents } from '@stackwright-pro/display-components';
|
|
303
|
+
* import { registerPulseComponents } from '@stackwright-pro/pulse';
|
|
304
|
+
*
|
|
305
|
+
* registerDisplayComponents();
|
|
306
|
+
* registerPulseComponents();
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
declare function registerPulseComponents(): void;
|
|
310
|
+
|
|
311
|
+
export { type CollectionBinding, MetricCardPulse, Pulse, type PulseCollectionContextValue, PulseCollectionProvider, PulseEmptyState, PulseErrorState, PulseIndicator, type PulseIndicatorProps, PulseLoadingState, type PulseMeta, type PulseOptions, type PulseProps, PulseStaleState, type PulseState, PulseSyncingState, PulseValidationError, createPulseValidator, registerPulseComponents, resolveTemplate, useCollection, useCollectionField, usePulse, usePulseCollections, useStreaming, useTemplateResolution };
|
package/dist/index.d.ts
CHANGED
|
@@ -230,4 +230,82 @@ declare class PulseValidationError extends Error {
|
|
|
230
230
|
}[];
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
interface CollectionBinding {
|
|
234
|
+
collection: string;
|
|
235
|
+
endpoint: string;
|
|
236
|
+
slugField?: string;
|
|
237
|
+
refreshInterval?: number;
|
|
238
|
+
schema?: unknown;
|
|
239
|
+
}
|
|
240
|
+
interface CollectionData {
|
|
241
|
+
items: unknown[];
|
|
242
|
+
count: number;
|
|
243
|
+
meta: PulseMeta;
|
|
244
|
+
[key: string]: unknown;
|
|
245
|
+
}
|
|
246
|
+
interface PulseCollectionContextValue {
|
|
247
|
+
collections: Record<string, CollectionData>;
|
|
248
|
+
isLoading: boolean;
|
|
249
|
+
getCollection: (name: string) => CollectionData | null;
|
|
250
|
+
getField: (collection: string, field: string) => unknown;
|
|
251
|
+
}
|
|
252
|
+
declare function resolveTemplate(template: string, collections: Record<string, CollectionData>): unknown;
|
|
253
|
+
declare function PulseCollectionProvider({ collections: collectionConfigs, children, fallback, }: {
|
|
254
|
+
collections: CollectionBinding[];
|
|
255
|
+
children: React.ReactNode;
|
|
256
|
+
fallback?: React.ReactNode;
|
|
257
|
+
}): react_jsx_runtime.JSX.Element;
|
|
258
|
+
declare function usePulseCollections(): PulseCollectionContextValue;
|
|
259
|
+
declare function useCollection(collectionName: string): CollectionData | null;
|
|
260
|
+
declare function useCollectionField(collectionName: string, field: string): unknown;
|
|
261
|
+
declare function useTemplateResolution(): (template: string) => unknown;
|
|
262
|
+
|
|
263
|
+
interface MetricCardPulseProps {
|
|
264
|
+
/** Collection name to bind to */
|
|
265
|
+
collection: string;
|
|
266
|
+
/** Field to display (supports {{ collection.field }} syntax) */
|
|
267
|
+
field: string;
|
|
268
|
+
/** Static label override */
|
|
269
|
+
label?: string;
|
|
270
|
+
/** Icon to show */
|
|
271
|
+
icon?: React.ReactNode;
|
|
272
|
+
/** Color for the card accent */
|
|
273
|
+
color?: string;
|
|
274
|
+
/** Trend direction: 'up' | 'down' | 'stable' */
|
|
275
|
+
trend?: 'up' | 'down' | 'stable';
|
|
276
|
+
/** Static trend value override */
|
|
277
|
+
trendValue?: string;
|
|
278
|
+
/** Aggregate function for array data: 'count' | 'sum' | 'avg' */
|
|
279
|
+
aggregate?: 'count' | 'sum' | 'avg';
|
|
280
|
+
/** Path within items to use for aggregation */
|
|
281
|
+
aggregateField?: string;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* MetricCard with live data binding to collections
|
|
285
|
+
*
|
|
286
|
+
* Examples:
|
|
287
|
+
* ```yaml
|
|
288
|
+
* - type: metric_card_pulse
|
|
289
|
+
* collection: equipment
|
|
290
|
+
* field: items.length # count of equipment
|
|
291
|
+
* label: "Total Equipment"
|
|
292
|
+
* icon: Truck
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
declare function MetricCardPulse({ collection, field, label, icon, color, trend, trendValue, aggregate, aggregateField, }: MetricCardPulseProps): react_jsx_runtime.JSX.Element;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Register Pulse collection binding components
|
|
299
|
+
*
|
|
300
|
+
* Call this AFTER registerDisplayComponents() in _app.tsx:
|
|
301
|
+
* ```ts
|
|
302
|
+
* import { registerDisplayComponents } from '@stackwright-pro/display-components';
|
|
303
|
+
* import { registerPulseComponents } from '@stackwright-pro/pulse';
|
|
304
|
+
*
|
|
305
|
+
* registerDisplayComponents();
|
|
306
|
+
* registerPulseComponents();
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
declare function registerPulseComponents(): void;
|
|
310
|
+
|
|
311
|
+
export { type CollectionBinding, MetricCardPulse, Pulse, type PulseCollectionContextValue, PulseCollectionProvider, PulseEmptyState, PulseErrorState, PulseIndicator, type PulseIndicatorProps, PulseLoadingState, type PulseMeta, type PulseOptions, type PulseProps, PulseStaleState, type PulseState, PulseSyncingState, PulseValidationError, createPulseValidator, registerPulseComponents, resolveTemplate, useCollection, useCollectionField, usePulse, usePulseCollections, useStreaming, useTemplateResolution };
|