@contractspec/example.saas-boilerplate 3.7.6 → 3.8.2
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/.turbo/turbo-build.log +39 -27
- package/AGENTS.md +50 -27
- package/CHANGELOG.md +36 -0
- package/README.md +65 -144
- package/dist/billing/billing.event.js +1 -1
- package/dist/billing/index.d.ts +6 -6
- package/dist/billing/index.js +1 -1
- package/dist/browser/billing/billing.event.js +1 -1
- package/dist/browser/billing/index.js +1 -1
- package/dist/browser/index.js +1147 -869
- package/dist/browser/project/index.js +209 -209
- package/dist/browser/project/project.event.js +1 -1
- package/dist/browser/saas-boilerplate.feature.js +208 -0
- package/dist/browser/ui/SaasDashboard.js +356 -105
- package/dist/browser/ui/SaasDashboard.visualizations.js +249 -0
- package/dist/browser/ui/SaasProjectList.js +7 -7
- package/dist/browser/ui/SaasSettingsPanel.js +12 -12
- package/dist/browser/ui/hooks/index.js +2 -2
- package/dist/browser/ui/hooks/useProjectList.js +1 -1
- package/dist/browser/ui/hooks/useProjectMutations.js +1 -1
- package/dist/browser/ui/index.js +790 -521
- package/dist/browser/ui/modals/CreateProjectModal.js +10 -10
- package/dist/browser/ui/modals/ProjectActionsModal.js +13 -13
- package/dist/browser/ui/modals/index.js +23 -23
- package/dist/browser/ui/renderers/index.js +341 -115
- package/dist/browser/ui/renderers/project-list.markdown.js +229 -3
- package/dist/browser/ui/renderers/project-list.renderer.js +7 -7
- package/dist/browser/visualizations/catalog.js +155 -0
- package/dist/browser/visualizations/index.js +217 -0
- package/dist/browser/visualizations/selectors.js +210 -0
- package/dist/handlers/index.d.ts +2 -2
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1147 -869
- package/dist/node/billing/billing.event.js +1 -1
- package/dist/node/billing/index.js +1 -1
- package/dist/node/index.js +1147 -869
- package/dist/node/project/index.js +209 -209
- package/dist/node/project/project.event.js +1 -1
- package/dist/node/saas-boilerplate.feature.js +208 -0
- package/dist/node/ui/SaasDashboard.js +356 -105
- package/dist/node/ui/SaasDashboard.visualizations.js +249 -0
- package/dist/node/ui/SaasProjectList.js +7 -7
- package/dist/node/ui/SaasSettingsPanel.js +12 -12
- package/dist/node/ui/hooks/index.js +2 -2
- package/dist/node/ui/hooks/useProjectList.js +1 -1
- package/dist/node/ui/hooks/useProjectMutations.js +1 -1
- package/dist/node/ui/index.js +790 -521
- package/dist/node/ui/modals/CreateProjectModal.js +10 -10
- package/dist/node/ui/modals/ProjectActionsModal.js +13 -13
- package/dist/node/ui/modals/index.js +23 -23
- package/dist/node/ui/renderers/index.js +341 -115
- package/dist/node/ui/renderers/project-list.markdown.js +229 -3
- package/dist/node/ui/renderers/project-list.renderer.js +7 -7
- package/dist/node/visualizations/catalog.js +155 -0
- package/dist/node/visualizations/index.js +217 -0
- package/dist/node/visualizations/selectors.js +210 -0
- package/dist/presentations/index.d.ts +1 -1
- package/dist/project/index.d.ts +7 -7
- package/dist/project/index.js +209 -209
- package/dist/project/project.event.js +1 -1
- package/dist/saas-boilerplate.feature.js +208 -0
- package/dist/settings/index.d.ts +1 -1
- package/dist/ui/SaasDashboard.js +356 -105
- package/dist/ui/SaasDashboard.visualizations.d.ts +5 -0
- package/dist/ui/SaasDashboard.visualizations.js +250 -0
- package/dist/ui/SaasProjectList.js +7 -7
- package/dist/ui/SaasSettingsPanel.js +12 -12
- package/dist/ui/hooks/index.d.ts +2 -2
- package/dist/ui/hooks/index.js +2 -2
- package/dist/ui/hooks/useProjectList.d.ts +5 -0
- package/dist/ui/hooks/useProjectList.js +1 -1
- package/dist/ui/hooks/useProjectMutations.d.ts +8 -0
- package/dist/ui/hooks/useProjectMutations.js +1 -1
- package/dist/ui/index.d.ts +4 -4
- package/dist/ui/index.js +790 -521
- package/dist/ui/modals/CreateProjectModal.js +10 -10
- package/dist/ui/modals/ProjectActionsModal.js +13 -13
- package/dist/ui/modals/index.js +23 -23
- package/dist/ui/renderers/index.d.ts +1 -1
- package/dist/ui/renderers/index.js +341 -115
- package/dist/ui/renderers/project-list.markdown.js +229 -3
- package/dist/ui/renderers/project-list.renderer.d.ts +1 -1
- package/dist/ui/renderers/project-list.renderer.js +7 -7
- package/dist/visualizations/catalog.d.ts +11 -0
- package/dist/visualizations/catalog.js +156 -0
- package/dist/visualizations/index.d.ts +2 -0
- package/dist/visualizations/index.js +218 -0
- package/dist/visualizations/selectors.d.ts +8 -0
- package/dist/visualizations/selectors.js +211 -0
- package/dist/visualizations/selectors.test.d.ts +1 -0
- package/package.json +70 -14
- package/src/billing/billing.entity.ts +132 -132
- package/src/billing/billing.enum.ts +9 -9
- package/src/billing/billing.event.ts +71 -71
- package/src/billing/billing.handler.ts +87 -87
- package/src/billing/billing.operations.ts +158 -158
- package/src/billing/billing.presentation.ts +45 -45
- package/src/billing/billing.schema.ts +76 -76
- package/src/billing/index.ts +43 -48
- package/src/dashboard/dashboard.presentation.ts +45 -45
- package/src/dashboard/index.ts +2 -2
- package/src/docs/saas-boilerplate.docblock.ts +43 -43
- package/src/example.ts +32 -32
- package/src/handlers/index.ts +9 -9
- package/src/handlers/saas.handlers.ts +250 -249
- package/src/index.ts +41 -41
- package/src/presentations/index.ts +18 -20
- package/src/project/index.ts +45 -50
- package/src/project/project.entity.ts +68 -68
- package/src/project/project.enum.ts +8 -8
- package/src/project/project.event.ts +79 -79
- package/src/project/project.handler.ts +103 -103
- package/src/project/project.operations.ts +236 -236
- package/src/project/project.presentation.ts +46 -46
- package/src/project/project.schema.ts +90 -90
- package/src/saas-boilerplate.feature.ts +103 -100
- package/src/seeders/index.ts +20 -20
- package/src/settings/index.ts +2 -3
- package/src/settings/settings.entity.ts +65 -65
- package/src/settings/settings.enum.ts +4 -4
- package/src/shared/mock-data.ts +92 -92
- package/src/shared/overlay-types.ts +23 -23
- package/src/tests/operations.test-spec.ts +96 -96
- package/src/ui/SaasDashboard.tsx +278 -270
- package/src/ui/SaasDashboard.visualizations.tsx +41 -0
- package/src/ui/SaasProjectList.tsx +90 -90
- package/src/ui/SaasSettingsPanel.tsx +84 -84
- package/src/ui/hooks/index.ts +3 -3
- package/src/ui/hooks/useProjectList.ts +69 -68
- package/src/ui/hooks/useProjectMutations.ts +144 -143
- package/src/ui/index.ts +8 -12
- package/src/ui/modals/CreateProjectModal.tsx +154 -154
- package/src/ui/modals/ProjectActionsModal.tsx +321 -321
- package/src/ui/overlays/demo-overlays.ts +49 -49
- package/src/ui/renderers/index.ts +5 -4
- package/src/ui/renderers/project-list.markdown.ts +229 -205
- package/src/ui/renderers/project-list.renderer.tsx +14 -13
- package/src/visualizations/catalog.ts +153 -0
- package/src/visualizations/index.ts +2 -0
- package/src/visualizations/selectors.test.ts +25 -0
- package/src/visualizations/selectors.ts +85 -0
- package/tsconfig.json +7 -8
- package/tsdown.config.js +7 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineVisualization,
|
|
3
|
+
VisualizationRegistry,
|
|
4
|
+
} from '@contractspec/lib.contracts-spec/visualizations';
|
|
5
|
+
|
|
6
|
+
const PROJECT_LIST_REF = {
|
|
7
|
+
key: 'saas.project.list',
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
} as const;
|
|
10
|
+
const META = {
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
domain: 'saas',
|
|
13
|
+
stability: 'experimental' as const,
|
|
14
|
+
owners: ['@example.saas-boilerplate'],
|
|
15
|
+
tags: ['saas', 'visualization', 'projects'],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const SaasProjectUsageVisualization = defineVisualization({
|
|
19
|
+
meta: {
|
|
20
|
+
...META,
|
|
21
|
+
key: 'saas-boilerplate.visualization.project-usage',
|
|
22
|
+
title: 'Project Capacity',
|
|
23
|
+
description: 'Current project count against the current plan limit.',
|
|
24
|
+
goal: 'Show usage against the active plan allowance.',
|
|
25
|
+
context: 'SaaS account overview.',
|
|
26
|
+
},
|
|
27
|
+
source: { primary: PROJECT_LIST_REF, resultPath: 'data' },
|
|
28
|
+
visualization: {
|
|
29
|
+
kind: 'metric',
|
|
30
|
+
measure: 'totalProjects',
|
|
31
|
+
comparisonMeasure: 'projectLimit',
|
|
32
|
+
measures: [
|
|
33
|
+
{
|
|
34
|
+
key: 'totalProjects',
|
|
35
|
+
label: 'Projects',
|
|
36
|
+
dataPath: 'totalProjects',
|
|
37
|
+
format: 'number',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: 'projectLimit',
|
|
41
|
+
label: 'Plan Limit',
|
|
42
|
+
dataPath: 'projectLimit',
|
|
43
|
+
format: 'number',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
table: { caption: 'Current project count and plan limit.' },
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const SaasProjectStatusVisualization = defineVisualization({
|
|
51
|
+
meta: {
|
|
52
|
+
...META,
|
|
53
|
+
key: 'saas-boilerplate.visualization.project-status',
|
|
54
|
+
title: 'Project Status',
|
|
55
|
+
description: 'Distribution of project states.',
|
|
56
|
+
goal: 'Show the mix of active, draft, and archived projects.',
|
|
57
|
+
context: 'Project portfolio overview.',
|
|
58
|
+
},
|
|
59
|
+
source: { primary: PROJECT_LIST_REF, resultPath: 'data' },
|
|
60
|
+
visualization: {
|
|
61
|
+
kind: 'pie',
|
|
62
|
+
nameDimension: 'status',
|
|
63
|
+
valueMeasure: 'projects',
|
|
64
|
+
dimensions: [
|
|
65
|
+
{ key: 'status', label: 'Status', dataPath: 'status', type: 'category' },
|
|
66
|
+
],
|
|
67
|
+
measures: [
|
|
68
|
+
{
|
|
69
|
+
key: 'projects',
|
|
70
|
+
label: 'Projects',
|
|
71
|
+
dataPath: 'projects',
|
|
72
|
+
format: 'number',
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
table: { caption: 'Project counts by status.' },
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const SaasProjectTierVisualization = defineVisualization({
|
|
80
|
+
meta: {
|
|
81
|
+
...META,
|
|
82
|
+
key: 'saas-boilerplate.visualization.project-tiers',
|
|
83
|
+
title: 'Tier Comparison',
|
|
84
|
+
description: 'Distribution of projects across tiers.',
|
|
85
|
+
goal: 'Compare how the current portfolio is distributed by tier.',
|
|
86
|
+
context: 'Plan and packaging overview.',
|
|
87
|
+
},
|
|
88
|
+
source: { primary: PROJECT_LIST_REF, resultPath: 'data' },
|
|
89
|
+
visualization: {
|
|
90
|
+
kind: 'cartesian',
|
|
91
|
+
variant: 'bar',
|
|
92
|
+
xDimension: 'tier',
|
|
93
|
+
yMeasures: ['projects'],
|
|
94
|
+
dimensions: [
|
|
95
|
+
{ key: 'tier', label: 'Tier', dataPath: 'tier', type: 'category' },
|
|
96
|
+
],
|
|
97
|
+
measures: [
|
|
98
|
+
{
|
|
99
|
+
key: 'projects',
|
|
100
|
+
label: 'Projects',
|
|
101
|
+
dataPath: 'projects',
|
|
102
|
+
format: 'number',
|
|
103
|
+
color: '#1d4ed8',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
table: { caption: 'Project counts by tier.' },
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export const SaasProjectActivityVisualization = defineVisualization({
|
|
111
|
+
meta: {
|
|
112
|
+
...META,
|
|
113
|
+
key: 'saas-boilerplate.visualization.project-activity',
|
|
114
|
+
title: 'Recent Project Activity',
|
|
115
|
+
description: 'Daily project creation activity.',
|
|
116
|
+
goal: 'Show recent project activity over time.',
|
|
117
|
+
context: 'Project portfolio trend view.',
|
|
118
|
+
},
|
|
119
|
+
source: { primary: PROJECT_LIST_REF, resultPath: 'data' },
|
|
120
|
+
visualization: {
|
|
121
|
+
kind: 'cartesian',
|
|
122
|
+
variant: 'line',
|
|
123
|
+
xDimension: 'day',
|
|
124
|
+
yMeasures: ['projects'],
|
|
125
|
+
dimensions: [{ key: 'day', label: 'Day', dataPath: 'day', type: 'time' }],
|
|
126
|
+
measures: [
|
|
127
|
+
{
|
|
128
|
+
key: 'projects',
|
|
129
|
+
label: 'Projects',
|
|
130
|
+
dataPath: 'projects',
|
|
131
|
+
format: 'number',
|
|
132
|
+
color: '#0f766e',
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
table: { caption: 'Daily project creation counts.' },
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export const SaasVisualizationSpecs = [
|
|
140
|
+
SaasProjectUsageVisualization,
|
|
141
|
+
SaasProjectStatusVisualization,
|
|
142
|
+
SaasProjectTierVisualization,
|
|
143
|
+
SaasProjectActivityVisualization,
|
|
144
|
+
] as const;
|
|
145
|
+
|
|
146
|
+
export const SaasVisualizationRegistry = new VisualizationRegistry([
|
|
147
|
+
...SaasVisualizationSpecs,
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
export const SaasVisualizationRefs = SaasVisualizationSpecs.map((spec) => ({
|
|
151
|
+
key: spec.meta.key,
|
|
152
|
+
version: spec.meta.version,
|
|
153
|
+
}));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import { createSaasVisualizationItems } from './selectors';
|
|
3
|
+
|
|
4
|
+
describe('saas visualization selectors', () => {
|
|
5
|
+
it('creates dashboard visualization items', () => {
|
|
6
|
+
const items = createSaasVisualizationItems(
|
|
7
|
+
[
|
|
8
|
+
{
|
|
9
|
+
status: 'ACTIVE',
|
|
10
|
+
tier: 'PRO',
|
|
11
|
+
createdAt: '2026-03-18T10:00:00Z',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
status: 'DRAFT',
|
|
15
|
+
tier: 'FREE',
|
|
16
|
+
createdAt: '2026-03-19T10:00:00Z',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
10
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
expect(items).toHaveLength(4);
|
|
23
|
+
expect(items[0]?.title).toBe('Project Capacity');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { VisualizationSurfaceItem } from '@contractspec/lib.design-system';
|
|
2
|
+
import type { Project } from '../handlers/saas.handlers';
|
|
3
|
+
import {
|
|
4
|
+
SaasProjectActivityVisualization,
|
|
5
|
+
SaasProjectStatusVisualization,
|
|
6
|
+
SaasProjectTierVisualization,
|
|
7
|
+
SaasProjectUsageVisualization,
|
|
8
|
+
} from './catalog';
|
|
9
|
+
|
|
10
|
+
type DateLike = Date | string;
|
|
11
|
+
|
|
12
|
+
interface ProjectLike extends Pick<Project, 'status' | 'tier'> {
|
|
13
|
+
createdAt: DateLike;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function toDayKey(value: DateLike): string {
|
|
17
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
18
|
+
return date.toISOString().slice(0, 10);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createSaasVisualizationItems(
|
|
22
|
+
projects: ProjectLike[],
|
|
23
|
+
projectLimit = 10
|
|
24
|
+
): VisualizationSurfaceItem[] {
|
|
25
|
+
const statusCounts = new Map<string, number>();
|
|
26
|
+
const tierCounts = new Map<string, number>();
|
|
27
|
+
const activityCounts = new Map<string, number>();
|
|
28
|
+
|
|
29
|
+
for (const project of projects) {
|
|
30
|
+
statusCounts.set(
|
|
31
|
+
project.status,
|
|
32
|
+
(statusCounts.get(project.status) ?? 0) + 1
|
|
33
|
+
);
|
|
34
|
+
tierCounts.set(project.tier, (tierCounts.get(project.tier) ?? 0) + 1);
|
|
35
|
+
const day = toDayKey(project.createdAt);
|
|
36
|
+
activityCounts.set(day, (activityCounts.get(day) ?? 0) + 1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
key: 'saas-capacity',
|
|
42
|
+
spec: SaasProjectUsageVisualization,
|
|
43
|
+
data: { data: [{ totalProjects: projects.length, projectLimit }] },
|
|
44
|
+
title: 'Project Capacity',
|
|
45
|
+
description: 'Current project count compared to the active limit.',
|
|
46
|
+
height: 220,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: 'saas-status',
|
|
50
|
+
spec: SaasProjectStatusVisualization,
|
|
51
|
+
data: {
|
|
52
|
+
data: Array.from(statusCounts.entries()).map(([status, count]) => ({
|
|
53
|
+
status,
|
|
54
|
+
projects: count,
|
|
55
|
+
})),
|
|
56
|
+
},
|
|
57
|
+
title: 'Project Status',
|
|
58
|
+
description: 'Status mix across the current project portfolio.',
|
|
59
|
+
height: 260,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: 'saas-tier',
|
|
63
|
+
spec: SaasProjectTierVisualization,
|
|
64
|
+
data: {
|
|
65
|
+
data: Array.from(tierCounts.entries()).map(([tier, count]) => ({
|
|
66
|
+
tier,
|
|
67
|
+
projects: count,
|
|
68
|
+
})),
|
|
69
|
+
},
|
|
70
|
+
title: 'Tier Comparison',
|
|
71
|
+
description: 'How projects are distributed across tiers.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
key: 'saas-activity',
|
|
75
|
+
spec: SaasProjectActivityVisualization,
|
|
76
|
+
data: {
|
|
77
|
+
data: Array.from(activityCounts.entries())
|
|
78
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
79
|
+
.map(([day, count]) => ({ day, projects: count })),
|
|
80
|
+
},
|
|
81
|
+
title: 'Recent Project Activity',
|
|
82
|
+
description: 'Daily project creation activity.',
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
"extends": "@contractspec/tool.typescript/react-library.json",
|
|
3
|
+
"include": ["src"],
|
|
4
|
+
"exclude": ["node_modules", "dist"],
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "dist"
|
|
8
|
+
}
|
|
9
9
|
}
|
|
10
|
-
|
package/tsdown.config.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
defineConfig,
|
|
3
|
+
moduleLibrary,
|
|
4
|
+
withDevExports,
|
|
5
|
+
} from '@contractspec/tool.bun';
|
|
2
6
|
|
|
3
7
|
export default defineConfig((options) => ({
|
|
4
|
-
|
|
5
|
-
|
|
8
|
+
...moduleLibrary,
|
|
9
|
+
...withDevExports,
|
|
6
10
|
}));
|