@svgrid/enterprise 2.2.0 → 2.3.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 +95 -81
- package/dist/cdn/svgrid-enterprise.svelte-external.js +22479 -10466
- package/dist/node/studio.js +11590 -2907
- package/package.json +31 -10
- package/src/SvAlertRuleEditor.svelte +294 -0
- package/src/SvAlertsManager.svelte +210 -0
- package/src/SvAlertsPanel.svelte +129 -0
- package/src/SvBoard.svelte +3 -1
- package/src/SvExpressionEditor.svelte +341 -0
- package/src/SvGridAlerts.dom.test.ts +113 -0
- package/src/SvGridAlerts.svelte +265 -0
- package/src/SvGridBoard.svelte +2355 -0
- package/src/SvGridEditPanel.svelte +849 -794
- package/src/SvGridScheduler.svelte +5334 -4410
- package/src/SvPivotDesigner.svelte +3 -3
- package/src/SvRecordDetail.svelte +6 -2
- package/src/SvSchedule.svelte +3 -1
- package/src/{ai-export-pdf.test.ts → ai-export-pdf.dom.test.ts} +4 -1
- package/src/{ai-export-xlsx.test.ts → ai-export-xlsx.dom.test.ts} +4 -1
- package/src/{ai-export.test.ts → ai-export.dom.test.ts} +5 -1
- package/src/alerts/alert-engine-attach.ts +165 -0
- package/src/alerts/alert-engine.test.ts +135 -0
- package/src/alerts/alert-engine.ts +260 -0
- package/src/alerts/alert-formats.test.ts +87 -0
- package/src/alerts/alert-formats.ts +77 -0
- package/src/alerts/alert-observer.test.ts +189 -0
- package/src/alerts/alert-observer.ts +208 -0
- package/src/alerts/alert-scheduler.ts +96 -0
- package/src/alerts/alert-storage.test.ts +54 -0
- package/src/alerts/alert-storage.ts +116 -0
- package/src/alerts/alert-store.svelte.ts +80 -0
- package/src/alerts/alert-types.ts +94 -0
- package/src/alerts.ts +28 -0
- package/src/board.dom.test.ts +941 -0
- package/src/board.ts +36 -0
- package/src/export.ts +13 -1
- package/src/expressions/evaluate.test.ts +111 -0
- package/src/expressions/evaluate.ts +228 -0
- package/src/expressions/expression-columns.ts +133 -0
- package/src/expressions/expression-types.ts +84 -0
- package/src/expressions/parse.test.ts +106 -0
- package/src/expressions/parse.ts +610 -0
- package/src/import.ts +2 -0
- package/src/index.ts +180 -46
- package/src/install.ts +12 -2
- package/src/pivot-enable.ts +44 -0
- package/src/scheduler-assignments.test.ts +97 -0
- package/src/scheduler-assignments.ts +134 -0
- package/src/scheduler-axis.test.ts +108 -0
- package/src/scheduler-axis.ts +238 -0
- package/src/scheduler-booking.test.ts +57 -0
- package/src/scheduler-booking.ts +63 -0
- package/src/scheduler-config.ts +179 -0
- package/src/scheduler-dependencies.test.ts +155 -0
- package/src/scheduler-dependencies.ts +223 -0
- package/src/scheduler-freebusy.test.ts +41 -0
- package/src/scheduler-freebusy.ts +36 -0
- package/src/scheduler-heatmap.test.ts +39 -0
- package/src/scheduler-heatmap.ts +55 -0
- package/src/scheduler-resource-tree.test.ts +84 -0
- package/src/scheduler-resource-tree.ts +107 -0
- package/src/scheduler-slots.test.ts +53 -0
- package/src/scheduler-slots.ts +94 -0
- package/src/scheduler-summary.test.ts +47 -0
- package/src/scheduler-summary.ts +81 -0
- package/src/sources/index.ts +1 -1
- package/src/sources/introspect-supabase.test.ts +13 -1
- package/src/sources/introspect-supabase.ts +20 -0
- package/src/studio/copilot-core.test.ts +45 -0
- package/src/studio/copilot-core.ts +65 -0
- package/src/studio/deploy-cli.test.ts +56 -0
- package/src/studio/deploy-cli.ts +100 -0
- package/src/studio/emit-project.test.ts +503 -18
- package/src/studio/emit-project.ts +829 -111
- package/src/studio/emit-schema.test.ts +17 -0
- package/src/studio/emit-schema.ts +166 -35
- package/src/studio/index.ts +25 -1
- package/src/studio/introspect-openapi.test.ts +84 -0
- package/src/studio/introspect-openapi.ts +252 -0
- package/src/studio/project.test.ts +57 -0
- package/src/studio/project.ts +193 -6
- package/src/studio/samples/crm.ts +282 -258
- package/src/studio/samples/fleet.ts +213 -186
- package/src/studio/samples/insurance.ts +223 -195
- package/src/studio/samples/inventory.ts +213 -182
- package/src/studio/samples/live-data.test.ts +99 -98
- package/src/studio/samples/live-data.ts +8 -10
- package/src/studio/samples/projects.ts +212 -190
- package/src/studio/samples/samples.test.ts +52 -0
- package/src/studio/samples/shared.ts +26 -6
- package/src/studio/samples/starter.ts +251 -0
- package/src/studio/samples/support.ts +209 -184
- package/src/studio/ui-components-surface.test.ts +185 -0
- package/src/studio/ui-components.generated.ts +5617 -0
- package/src/studio/ui-components.ts +641 -472
- package/src/sveltekit/sql-source.test.ts +13 -0
- package/src/sveltekit/sql-source.ts +11 -6
- package/src/upgrade-prompt.ts +2 -2
- package/src/watermark.ts +2 -2
- package/src/ai.test.ts +0 -522
- package/src/ai.ts +0 -1388
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project a fresh `svgrid-studio designer` session opens with: not a bare stub,
|
|
3
|
+
* but a complete, enterprise-ready multi-page CRM that shows off the grid's range on
|
|
4
|
+
* first paint - a KPI/chart **Overview**, the rich **Customers** CRUD grid (status
|
|
5
|
+
* pills, health bars, export, popup form), a drag-and-drop **Pipeline** board, a
|
|
6
|
+
* **Deals** grid, a **Calendar** of close dates, and a **Forecast** analytics page.
|
|
7
|
+
* Every generated Studio app already wires `@svgrid/enterprise` (data layer, columns,
|
|
8
|
+
* validation); the rich grids + export make that enterprise surface visible.
|
|
9
|
+
*/
|
|
10
|
+
import { project, dashScreen, boardScreen, calendarScreen } from './shared.js'
|
|
11
|
+
import { gridColumns, defaultBlockConfig, buildDockLayout, type StudioProject, type Screen, type Block, type GridConfig, type GridColumnConfig } from '../project.js'
|
|
12
|
+
import type { EntitySchema } from '../../schema.js'
|
|
13
|
+
|
|
14
|
+
/** A realistic B2B customer/account: company + contact, region, industry, plan,
|
|
15
|
+
* seats, MRR, a health score, and lifecycle dates. */
|
|
16
|
+
const customers: EntitySchema = {
|
|
17
|
+
name: 'customers',
|
|
18
|
+
label: 'Customer',
|
|
19
|
+
idField: 'id',
|
|
20
|
+
fields: [
|
|
21
|
+
{ field: 'id', label: 'ID', type: 'number', primaryKey: true, readonly: true },
|
|
22
|
+
{ field: 'company', label: 'Company', type: 'text', required: true },
|
|
23
|
+
{ field: 'contact', label: 'Contact', type: 'text', required: true },
|
|
24
|
+
{ field: 'email', label: 'Email', type: 'text', format: 'email' },
|
|
25
|
+
{ field: 'country', label: 'Country', type: 'text' },
|
|
26
|
+
{ field: 'industry', label: 'Industry', type: 'enum', input: { editorType: 'list' }, options: [
|
|
27
|
+
{ value: 'saas', label: 'SaaS', color: '#6366f1' },
|
|
28
|
+
{ value: 'fintech', label: 'Fintech', color: '#0ea5e9' },
|
|
29
|
+
{ value: 'healthcare', label: 'Healthcare', color: '#10b981' },
|
|
30
|
+
{ value: 'retail', label: 'Retail', color: '#f59e0b' },
|
|
31
|
+
{ value: 'manufacturing', label: 'Manufacturing', color: '#64748b' },
|
|
32
|
+
{ value: 'media', label: 'Media', color: '#ec4899' },
|
|
33
|
+
{ value: 'education', label: 'Education', color: '#14b8a6' },
|
|
34
|
+
{ value: 'logistics', label: 'Logistics', color: '#a855f7' },
|
|
35
|
+
] },
|
|
36
|
+
{ field: 'status', label: 'Status', type: 'enum', required: true, input: { editorType: 'list' }, options: [
|
|
37
|
+
{ value: 'active', label: 'Active', color: '#10b981' },
|
|
38
|
+
{ value: 'trial', label: 'Trial', color: '#f59e0b' },
|
|
39
|
+
{ value: 'paused', label: 'Paused', color: '#64748b' },
|
|
40
|
+
{ value: 'churned', label: 'Churned', color: '#ef4444' },
|
|
41
|
+
] },
|
|
42
|
+
{ field: 'plan', label: 'Plan', type: 'enum', input: { editorType: 'list' }, options: [
|
|
43
|
+
{ value: 'starter', label: 'Starter', color: '#94a3b8' },
|
|
44
|
+
{ value: 'growth', label: 'Growth', color: '#6366f1' },
|
|
45
|
+
{ value: 'scale', label: 'Scale', color: '#0ea5e9' },
|
|
46
|
+
{ value: 'enterprise', label: 'Enterprise', color: '#8b5cf6' },
|
|
47
|
+
] },
|
|
48
|
+
{ field: 'seats', label: 'Seats', type: 'number' },
|
|
49
|
+
{ field: 'mrr', label: 'MRR', type: 'number' },
|
|
50
|
+
{ field: 'health', label: 'Health', type: 'number', min: 0, max: 100 },
|
|
51
|
+
{ field: 'signupDate', label: 'Signed up', type: 'date' },
|
|
52
|
+
{ field: 'lastContact', label: 'Last contact', type: 'date' },
|
|
53
|
+
],
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Sales opportunities against accounts - the Pipeline board / Calendar / Forecast. */
|
|
57
|
+
const deals: EntitySchema = {
|
|
58
|
+
name: 'deals',
|
|
59
|
+
label: 'Deal',
|
|
60
|
+
idField: 'id',
|
|
61
|
+
fields: [
|
|
62
|
+
{ field: 'id', label: 'ID', type: 'number', primaryKey: true, readonly: true },
|
|
63
|
+
{ field: 'name', label: 'Deal', type: 'text', required: true },
|
|
64
|
+
{ field: 'customerId', label: 'Account', type: 'relation', relation: { entity: 'customers', labelField: 'company' } },
|
|
65
|
+
{ field: 'stage', label: 'Stage', type: 'enum', required: true, input: { editorType: 'list' }, options: [
|
|
66
|
+
{ value: 'lead', label: 'Lead', color: '#94a3b8' },
|
|
67
|
+
{ value: 'qualified', label: 'Qualified', color: '#38bdf8' },
|
|
68
|
+
{ value: 'proposal', label: 'Proposal', color: '#6366f1' },
|
|
69
|
+
{ value: 'negotiation', label: 'Negotiation', color: '#f59e0b' },
|
|
70
|
+
{ value: 'won', label: 'Won', color: '#10b981' },
|
|
71
|
+
{ value: 'lost', label: 'Lost', color: '#ef4444' },
|
|
72
|
+
] },
|
|
73
|
+
{ field: 'owner', label: 'Owner', type: 'enum', input: { editorType: 'list' }, options: [
|
|
74
|
+
{ value: 'Sarah Chen', label: 'Sarah Chen', color: '#6366f1' },
|
|
75
|
+
{ value: 'Marcus Lee', label: 'Marcus Lee', color: '#10b981' },
|
|
76
|
+
{ value: 'Elena Vidal', label: 'Elena Vidal', color: '#f59e0b' },
|
|
77
|
+
{ value: 'Tom Baker', label: 'Tom Baker', color: '#ec4899' },
|
|
78
|
+
] },
|
|
79
|
+
{ field: 'amount', label: 'Amount', type: 'number' },
|
|
80
|
+
{ field: 'probability', label: 'Probability', type: 'number', min: 0, max: 100 },
|
|
81
|
+
{ field: 'closeDate', label: 'Close date', type: 'date' },
|
|
82
|
+
],
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** ~20 seeded accounts with a realistic spread of industries, regions, plans and
|
|
86
|
+
* lifecycle states (active/paused carry MRR; trials + churned sit at 0). */
|
|
87
|
+
const customerSeed: Record<string, unknown>[] = [
|
|
88
|
+
{ id: 1, company: 'Meridian Software', contact: 'Sarah Chen', email: 'sarah.chen@meridiansoft.com', country: 'United States', industry: 'saas', status: 'active', plan: 'scale', seats: 42, mrr: 1490, health: 88, signupDate: '2024-03-12', lastContact: '2026-07-28' },
|
|
89
|
+
{ id: 2, company: 'Cedar Analytics', contact: 'Michael Rodriguez', email: 'm.rodriguez@cedaranalytics.io', country: 'United States', industry: 'fintech', status: 'active', plan: 'enterprise', seats: 180, mrr: 4200, health: 94, signupDate: '2023-11-05', lastContact: '2026-08-04' },
|
|
90
|
+
{ id: 3, company: 'BlueSky Labs', contact: 'Emma Thompson', email: 'emma@blueskylabs.co.uk', country: 'United Kingdom', industry: 'saas', status: 'trial', plan: 'starter', seats: 3, mrr: 0, health: 65, signupDate: '2026-06-20', lastContact: '2026-08-06' },
|
|
91
|
+
{ id: 4, company: 'Northgate Systems', contact: 'David Kim', email: 'dkim@northgate.com', country: 'Canada', industry: 'manufacturing', status: 'active', plan: 'growth', seats: 15, mrr: 499, health: 79, signupDate: '2025-01-18', lastContact: '2026-07-15' },
|
|
92
|
+
{ id: 5, company: 'Vantage Digital', contact: 'Olivia Martins', email: 'olivia.martins@vantage.digital', country: 'Australia', industry: 'media', status: 'active', plan: 'growth', seats: 12, mrr: 399, health: 82, signupDate: '2024-09-30', lastContact: '2026-07-22' },
|
|
93
|
+
{ id: 6, company: 'Harbor Health', contact: "James O'Brien", email: 'j.obrien@harborhealth.org', country: 'United States', industry: 'healthcare', status: 'active', plan: 'enterprise', seats: 240, mrr: 5400, health: 91, signupDate: '2023-06-14', lastContact: '2026-08-01' },
|
|
94
|
+
{ id: 7, company: 'Riverstone Media', contact: 'Priya Sharma', email: 'priya@riverstone.media', country: 'India', industry: 'media', status: 'churned', plan: 'scale', seats: 0, mrr: 0, health: 22, signupDate: '2024-02-08', lastContact: '2026-03-19' },
|
|
95
|
+
{ id: 8, company: 'Lumen Retail', contact: 'Lucas Müller', email: 'lucas.mueller@lumenretail.de', country: 'Germany', industry: 'retail', status: 'active', plan: 'scale', seats: 55, mrr: 1890, health: 85, signupDate: '2024-12-02', lastContact: '2026-07-30' },
|
|
96
|
+
{ id: 9, company: 'Pinewood Financial', contact: 'Aisha Bello', email: 'aisha.bello@pinewoodfin.com', country: 'United States', industry: 'fintech', status: 'paused', plan: 'growth', seats: 8, mrr: 0, health: 48, signupDate: '2025-04-27', lastContact: '2026-05-11' },
|
|
97
|
+
{ id: 10, company: 'Orchard Foods', contact: 'Carlos Mendez', email: 'carlos@orchardfoods.mx', country: 'Brazil', industry: 'retail', status: 'active', plan: 'starter', seats: 4, mrr: 99, health: 73, signupDate: '2025-08-09', lastContact: '2026-07-19' },
|
|
98
|
+
{ id: 11, company: 'Ironclad Security', contact: 'Nina Petrova', email: 'nina.petrova@ironcladsec.com', country: 'Netherlands', industry: 'saas', status: 'active', plan: 'enterprise', seats: 130, mrr: 3600, health: 96, signupDate: '2023-09-21', lastContact: '2026-08-05' },
|
|
99
|
+
{ id: 12, company: 'Brightpath Education', contact: 'Tomás Silva', email: 'tomas.silva@brightpath.edu', country: 'Portugal', industry: 'education', status: 'trial', plan: 'starter', seats: 2, mrr: 0, health: 61, signupDate: '2026-07-01', lastContact: '2026-08-07' },
|
|
100
|
+
{ id: 13, company: 'Quantum Ledger', contact: 'Grace Okafor', email: 'grace@quantumledger.io', country: 'United Kingdom', industry: 'fintech', status: 'active', plan: 'scale', seats: 38, mrr: 1290, health: 87, signupDate: '2024-05-16', lastContact: '2026-07-26' },
|
|
101
|
+
{ id: 14, company: 'Evergreen Energy', contact: 'Hiroshi Tanaka', email: 'h.tanaka@evergreen-energy.jp', country: 'Japan', industry: 'manufacturing', status: 'active', plan: 'growth', seats: 20, mrr: 549, health: 80, signupDate: '2025-02-11', lastContact: '2026-06-28' },
|
|
102
|
+
{ id: 15, company: 'Summit Logistics', contact: 'Fatima Al-Farsi', email: 'fatima@summitlogistics.com', country: 'United States', industry: 'logistics', status: 'active', plan: 'scale', seats: 47, mrr: 1590, health: 89, signupDate: '2024-07-03', lastContact: '2026-08-02' },
|
|
103
|
+
{ id: 16, company: 'Fabrikam Retail', contact: 'Erik Larsson', email: 'erik.larsson@fabrikam.se', country: 'Sweden', industry: 'retail', status: 'churned', plan: 'starter', seats: 0, mrr: 0, health: 18, signupDate: '2025-03-22', lastContact: '2026-01-30' },
|
|
104
|
+
{ id: 17, company: 'Beacon Analytics', contact: 'Sofia Rossi', email: 'sofia.rossi@beaconanalytics.com', country: 'Italy', industry: 'saas', status: 'active', plan: 'growth', seats: 11, mrr: 449, health: 76, signupDate: '2025-05-19', lastContact: '2026-07-24' },
|
|
105
|
+
{ id: 18, company: 'Cobalt Cloud', contact: 'Daniel Okoye', email: 'daniel@cobaltcloud.com', country: 'United States', industry: 'saas', status: 'trial', plan: 'growth', seats: 6, mrr: 0, health: 68, signupDate: '2026-06-28', lastContact: '2026-08-08' },
|
|
106
|
+
{ id: 19, company: 'Willow Health', contact: 'Mei Lin', email: 'mei.lin@willowhealth.sg', country: 'Singapore', industry: 'healthcare', status: 'active', plan: 'enterprise', seats: 95, mrr: 2800, health: 92, signupDate: '2023-12-08', lastContact: '2026-07-31' },
|
|
107
|
+
{ id: 20, company: 'Atlas Manufacturing', contact: 'Pierre Dubois', email: 'p.dubois@atlasmfg.fr', country: 'France', industry: 'manufacturing', status: 'paused', plan: 'scale', seats: 30, mrr: 0, health: 44, signupDate: '2024-10-15', lastContact: '2026-04-22' },
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
/** ~24 open + closed opportunities across the accounts, spread over stages, owners
|
|
111
|
+
* and close dates - so the board, calendar, and forecast are all alive. */
|
|
112
|
+
const dealSeed: Record<string, unknown>[] = [
|
|
113
|
+
{ id: 1, name: 'Enterprise rollout', customerId: 2, stage: 'negotiation', owner: 'Sarah Chen', amount: 84000, probability: 70, closeDate: '2026-09-15' },
|
|
114
|
+
{ id: 2, name: 'Platform upgrade', customerId: 6, stage: 'proposal', owner: 'Marcus Lee', amount: 62000, probability: 55, closeDate: '2026-10-02' },
|
|
115
|
+
{ id: 3, name: 'Seat expansion', customerId: 1, stage: 'won', owner: 'Elena Vidal', amount: 24000, probability: 100, closeDate: '2026-07-20' },
|
|
116
|
+
{ id: 4, name: 'Pilot program', customerId: 3, stage: 'qualified', owner: 'Tom Baker', amount: 12000, probability: 35, closeDate: '2026-11-10' },
|
|
117
|
+
{ id: 5, name: 'Annual renewal', customerId: 11, stage: 'negotiation', owner: 'Sarah Chen', amount: 58000, probability: 65, closeDate: '2026-09-30' },
|
|
118
|
+
{ id: 6, name: 'Security add-on', customerId: 19, stage: 'proposal', owner: 'Marcus Lee', amount: 33000, probability: 45, closeDate: '2026-10-18' },
|
|
119
|
+
{ id: 7, name: 'Data migration', customerId: 8, stage: 'lead', owner: 'Elena Vidal', amount: 21000, probability: 20, closeDate: '2026-12-05' },
|
|
120
|
+
{ id: 8, name: 'Multi-region', customerId: 13, stage: 'won', owner: 'Tom Baker', amount: 47000, probability: 100, closeDate: '2026-06-28' },
|
|
121
|
+
{ id: 9, name: 'Onboarding package', customerId: 5, stage: 'qualified', owner: 'Sarah Chen', amount: 9000, probability: 40, closeDate: '2026-11-22' },
|
|
122
|
+
{ id: 10, name: 'Analytics tier', customerId: 15, stage: 'proposal', owner: 'Marcus Lee', amount: 38000, probability: 50, closeDate: '2026-10-08' },
|
|
123
|
+
{ id: 11, name: 'Compliance module', customerId: 6, stage: 'negotiation', owner: 'Elena Vidal', amount: 72000, probability: 75, closeDate: '2026-09-12' },
|
|
124
|
+
{ id: 12, name: 'Trial conversion', customerId: 3, stage: 'lead', owner: 'Tom Baker', amount: 6000, probability: 15, closeDate: '2026-12-20' },
|
|
125
|
+
{ id: 13, name: 'Enterprise SSO', customerId: 2, stage: 'won', owner: 'Sarah Chen', amount: 30000, probability: 100, closeDate: '2026-07-05' },
|
|
126
|
+
{ id: 14, name: 'Capacity boost', customerId: 14, stage: 'qualified', owner: 'Marcus Lee', amount: 15000, probability: 30, closeDate: '2026-11-15' },
|
|
127
|
+
{ id: 15, name: 'Premium support', customerId: 17, stage: 'proposal', owner: 'Elena Vidal', amount: 18000, probability: 45, closeDate: '2026-10-25' },
|
|
128
|
+
{ id: 16, name: 'Global expansion', customerId: 11, stage: 'lost', owner: 'Tom Baker', amount: 90000, probability: 0, closeDate: '2026-05-30' },
|
|
129
|
+
{ id: 17, name: 'API integration', customerId: 10, stage: 'qualified', owner: 'Sarah Chen', amount: 8000, probability: 35, closeDate: '2026-11-28' },
|
|
130
|
+
{ id: 18, name: 'Renewal + upsell', customerId: 19, stage: 'negotiation', owner: 'Marcus Lee', amount: 66000, probability: 70, closeDate: '2026-09-22' },
|
|
131
|
+
{ id: 19, name: 'Sandbox pilot', customerId: 18, stage: 'lead', owner: 'Elena Vidal', amount: 7000, probability: 20, closeDate: '2026-12-12' },
|
|
132
|
+
{ id: 20, name: 'Custom reporting', customerId: 15, stage: 'won', owner: 'Tom Baker', amount: 26000, probability: 100, closeDate: '2026-06-18' },
|
|
133
|
+
{ id: 21, name: 'Migration service', customerId: 4, stage: 'proposal', owner: 'Sarah Chen', amount: 22000, probability: 50, closeDate: '2026-10-14' },
|
|
134
|
+
{ id: 22, name: 'Team plan', customerId: 5, stage: 'lost', owner: 'Marcus Lee', amount: 11000, probability: 0, closeDate: '2026-04-16' },
|
|
135
|
+
{ id: 23, name: 'Platform renewal', customerId: 1, stage: 'negotiation', owner: 'Elena Vidal', amount: 44000, probability: 60, closeDate: '2026-09-08' },
|
|
136
|
+
{ id: 24, name: 'Advanced tier', customerId: 13, stage: 'qualified', owner: 'Tom Baker', amount: 19000, probability: 40, closeDate: '2026-11-05' },
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
/** The hero grid: the no-code default plus the enterprise surface (filtering, export
|
|
140
|
+
* toolbar, totals, status pills, row actions) and custom cells - MRR as currency,
|
|
141
|
+
* health as a progress bar, email as a link, dates formatted, larger comfortable rows. */
|
|
142
|
+
function crudGrid(): Block {
|
|
143
|
+
const base = defaultBlockConfig('grid', customers) as GridConfig
|
|
144
|
+
const columns: GridColumnConfig[] = gridColumns(customers).map((c) =>
|
|
145
|
+
c.field === 'mrr' ? { ...c, header: 'MRR', format: { type: 'currency', currency: 'USD' }, align: 'right', aggregate: 'sum' }
|
|
146
|
+
: c.field === 'seats' ? { ...c, align: 'right', aggregate: 'sum' }
|
|
147
|
+
: c.field === 'health' ? { ...c, header: 'Health', width: 140, cellType: { kind: 'progress', max: 100 } }
|
|
148
|
+
: c.field === 'signupDate' || c.field === 'lastContact' ? { ...c, format: { type: 'date' } }
|
|
149
|
+
: c.field === 'email' ? { ...c, cellType: { kind: 'link', as: 'email' } }
|
|
150
|
+
: c,
|
|
151
|
+
)
|
|
152
|
+
const config: GridConfig = {
|
|
153
|
+
...base,
|
|
154
|
+
columns,
|
|
155
|
+
filterable: true,
|
|
156
|
+
filterUi: { global: true, row: false, menu: true },
|
|
157
|
+
export: { csv: true, json: true, copy: true },
|
|
158
|
+
rowSummaries: true,
|
|
159
|
+
pageSize: 10,
|
|
160
|
+
density: 'comfortable',
|
|
161
|
+
rowActions: [{ kind: 'edit' }, { kind: 'delete' }],
|
|
162
|
+
props: { headerHeight: 48 },
|
|
163
|
+
}
|
|
164
|
+
return { id: 'grid-1', span: 3, height: 440, config }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The Deals grid: stage/owner chips, currency amount (summed), a probability bar. */
|
|
168
|
+
function dealsGrid(): Block {
|
|
169
|
+
const base = defaultBlockConfig('grid', deals) as GridConfig
|
|
170
|
+
const columns: GridColumnConfig[] = gridColumns(deals).map((c) =>
|
|
171
|
+
c.field === 'amount' ? { ...c, format: { type: 'currency', currency: 'USD' }, align: 'right', aggregate: 'sum' }
|
|
172
|
+
: c.field === 'probability' ? { ...c, header: 'Win %', width: 130, cellType: { kind: 'progress', max: 100 } }
|
|
173
|
+
: c.field === 'closeDate' ? { ...c, format: { type: 'date' } }
|
|
174
|
+
: c,
|
|
175
|
+
)
|
|
176
|
+
const config: GridConfig = {
|
|
177
|
+
...base,
|
|
178
|
+
columns,
|
|
179
|
+
filterable: true,
|
|
180
|
+
filterUi: { global: true, row: false, menu: true },
|
|
181
|
+
export: { csv: true, json: true, copy: true },
|
|
182
|
+
rowSummaries: true,
|
|
183
|
+
pageSize: 10,
|
|
184
|
+
density: 'comfortable',
|
|
185
|
+
rowActions: [{ kind: 'edit' }, { kind: 'delete' }],
|
|
186
|
+
props: { headerHeight: 48 },
|
|
187
|
+
}
|
|
188
|
+
return { id: 'grid-1', span: 3, height: 440, config }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** A docking-workspace console: a facet filter, the rich grid, and a record panel laid
|
|
192
|
+
* out in a live SvDockManager (drag to float / pin / re-dock) - the signature "wow"
|
|
193
|
+
* layout. `buildDockLayout` seeds filter-left, grid-centre, record-right. */
|
|
194
|
+
function dockConsole(entity: EntitySchema, id: string, title: string, order: number, gridBlock: Block, filterFields: string[]): Screen {
|
|
195
|
+
const blocks: Block[] = [
|
|
196
|
+
{ id: 'filter-1', span: 3, config: { kind: 'filter', fields: filterFields } },
|
|
197
|
+
gridBlock,
|
|
198
|
+
{ id: 'record-1', span: 3, config: { kind: 'record', editable: true } },
|
|
199
|
+
]
|
|
200
|
+
const base: Screen = { id, entity: entity.name, title, route: id, blocks, nav: { show: true, label: title, order }, layout: 'dock' }
|
|
201
|
+
return { ...base, dock: buildDockLayout(base) }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** The Overview: the hero Customers grid FIRST (so opening the app lands on a real
|
|
205
|
+
* data grid, not a chart), with KPI cards + charts below it as supporting context. */
|
|
206
|
+
function overviewScreen(): Screen {
|
|
207
|
+
const dash = dashScreen(customers, { id: 'overview', title: 'Overview', order: 0 }, [
|
|
208
|
+
{ kpi: 'Recurring revenue', measure: 'mrr', reduce: 'sum', format: 'currency', span: 1 },
|
|
209
|
+
{ kpi: 'Accounts', reduce: 'count', span: 1 },
|
|
210
|
+
{ kpi: 'Seats', measure: 'seats', reduce: 'sum', format: 'compact', span: 1 },
|
|
211
|
+
{ gauge: 'Avg health', measure: 'health', reduce: 'avg', min: 0, max: 100, span: 1 },
|
|
212
|
+
{ chart: 'industry', measure: 'mrr', reduce: 'sum', type: 'bar', span: 2 },
|
|
213
|
+
{ chart: 'status', reduce: 'count', type: 'pie', span: 1 },
|
|
214
|
+
])
|
|
215
|
+
return { ...dash, blocks: [crudGrid(), ...dash.blocks] }
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** The default first-run project: a complete, enterprise-ready multi-page CRM whose
|
|
219
|
+
* hero is the CRUD grid (Overview + two SvDockManager consoles). */
|
|
220
|
+
export function starterProject(): StudioProject {
|
|
221
|
+
return project({
|
|
222
|
+
title: 'Acme CRM',
|
|
223
|
+
brand: 'Acme CRM',
|
|
224
|
+
accent: '#6366f1',
|
|
225
|
+
footer: 'Built with SvGrid Studio',
|
|
226
|
+
entities: [customers, deals],
|
|
227
|
+
screens: [
|
|
228
|
+
// Overview: KPIs + charts ABOVE the hero Customers grid.
|
|
229
|
+
overviewScreen(),
|
|
230
|
+
// Customers: a dockable console - filter + hero grid + record panel (drag to float / pin).
|
|
231
|
+
dockConsole(customers, 'customers', 'Customers', 1, crudGrid(), ['status', 'industry', 'plan']),
|
|
232
|
+
// Pipeline: deals as draggable cards in stage columns (drag to change stage).
|
|
233
|
+
boardScreen(deals, { id: 'pipeline', title: 'Pipeline', order: 2 }, { groupBy: 'stage', titleField: 'name', badgeField: 'amount', subtitleField: 'owner', filter: ['owner', 'stage'] }),
|
|
234
|
+
// Deals: a second docking console over the opportunity grid.
|
|
235
|
+
dockConsole(deals, 'deals', 'Deals', 3, dealsGrid(), ['stage', 'owner']),
|
|
236
|
+
// Calendar: deals placed on a month calendar by their close date, tinted by stage.
|
|
237
|
+
calendarScreen(deals, { id: 'calendar', title: 'Calendar', order: 4 }, { dateField: 'closeDate', titleField: 'name', colorField: 'stage', filter: ['owner'] }),
|
|
238
|
+
// Forecast: pipeline KPIs, value by stage/owner, and a pivot of amount by owner x stage.
|
|
239
|
+
dashScreen(deals, { id: 'forecast', title: 'Forecast', order: 5 }, [
|
|
240
|
+
{ kpi: 'Pipeline value', measure: 'amount', reduce: 'sum', format: 'currency', span: 1 },
|
|
241
|
+
{ kpi: 'Open deals', reduce: 'count', span: 1 },
|
|
242
|
+
{ kpi: 'Avg deal size', measure: 'amount', reduce: 'avg', format: 'currency', span: 1 },
|
|
243
|
+
{ kpi: 'Largest deal', measure: 'amount', reduce: 'max', format: 'currency', span: 1 },
|
|
244
|
+
{ chart: 'stage', measure: 'amount', reduce: 'sum', type: 'bar', span: 2 },
|
|
245
|
+
{ chart: 'owner', measure: 'amount', reduce: 'sum', type: 'bar', span: 1 },
|
|
246
|
+
{ pivot: { rows: ['owner'], cols: ['stage'], measure: 'amount', aggregate: 'sum' }, span: 3 },
|
|
247
|
+
]),
|
|
248
|
+
],
|
|
249
|
+
seed: { customers: customerSeed, deals: dealSeed },
|
|
250
|
+
})
|
|
251
|
+
}
|