@donotdev/cli 0.0.19 → 0.0.21
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 +31 -0
- package/dependencies-matrix.json +205 -50
- package/dist/bin/commands/agent-setup.js +2 -2
- package/dist/bin/commands/build.js +6 -6
- package/dist/bin/commands/bump.js +495 -70
- package/dist/bin/commands/cacheout.js +6 -6
- package/dist/bin/commands/coach.js +6 -6
- package/dist/bin/commands/create-app.js +24 -16
- package/dist/bin/commands/create-project.js +114 -18
- package/dist/bin/commands/db.js +142136 -0
- package/dist/bin/commands/deploy.js +354 -126
- package/dist/bin/commands/dev.js +6 -6
- package/dist/bin/commands/doctor.js +140 -33
- package/dist/bin/commands/emu.js +6 -6
- package/dist/bin/commands/format.js +6 -6
- package/dist/bin/commands/get-demo.js +11 -6
- package/dist/bin/commands/make-admin.js +14210 -13770
- package/dist/bin/commands/preview.js +6 -6
- package/dist/bin/commands/seed.js +142426 -0
- package/dist/bin/commands/setup-cicd.js +8904 -0
- package/dist/bin/commands/setup.js +259 -212
- package/dist/bin/commands/staging.js +361 -127
- package/dist/bin/commands/sync-secrets.js +55 -33
- package/dist/bin/commands/type-check.js +16 -10
- package/dist/bin/commands/wai.js +6 -6
- package/dist/bin/dndev.js +194 -188
- package/dist/bin/donotdev.js +139 -189
- package/dist/index.js +468 -144
- package/package.json +1 -1
- package/templates/app-demo/.env.example +1 -0
- package/templates/{root-consumer → app-demo}/entities/ExampleEntity.ts.example +15 -9
- package/templates/app-demo/index.html.example +1 -1
- package/templates/app-demo/public/apple-touch-icon.png.example +0 -0
- package/templates/app-demo/public/favicon.svg.example +1 -0
- package/templates/app-demo/public/icon-192x192.png.example +0 -0
- package/templates/app-demo/public/icon-512x512.png.example +0 -0
- package/templates/app-demo/src/App.tsx.example +3 -1
- package/templates/app-demo/src/config/app.ts.example +1 -0
- package/templates/app-demo/src/entities/booking.ts.example +75 -0
- package/templates/app-demo/src/entities/onboarding.ts.example +160 -0
- package/templates/app-demo/src/entities/product.ts.example +12 -0
- package/templates/app-demo/src/entities/quote.ts.example +70 -0
- package/templates/app-demo/src/pages/ChangelogPage.tsx.example +28 -1
- package/templates/app-demo/src/pages/ConditionalFormPage.tsx.example +88 -0
- package/templates/app-demo/src/pages/DashboardPage.tsx.example +2 -0
- package/templates/app-demo/src/pages/HomePage.tsx.example +355 -2
- package/templates/app-demo/src/pages/OnboardingPage.tsx.example +47 -0
- package/templates/app-demo/src/pages/PricingPage.tsx.example +28 -1
- package/templates/app-demo/src/pages/ProductsPage.tsx.example +2 -0
- package/templates/app-demo/src/pages/ProfilePage.tsx.example +2 -0
- package/templates/app-demo/src/pages/SettingsPage.tsx.example +2 -0
- package/templates/app-demo/src/pages/ShowcaseDetailPage.tsx.example +22 -16
- package/templates/app-demo/src/pages/ShowcasePage.tsx.example +3 -1
- package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +147 -51
- package/templates/app-demo/src/pages/components/ComponentsData.tsx.example +103 -21
- package/templates/app-demo/src/pages/components/componentConfig.ts.example +139 -59
- package/templates/app-demo/src/pages/legal/LegalPage.tsx.example +12 -1
- package/templates/app-demo/src/pages/legal/PrivacyPage.tsx.example +10 -1
- package/templates/app-demo/src/pages/legal/TermsPage.tsx.example +10 -1
- package/templates/app-demo/src/themes.css.example +289 -77
- package/templates/app-demo/stats.html.example +4949 -0
- package/templates/app-dndev/index.html.example +164 -0
- package/templates/app-dndev/public/logo.svg.example +1 -0
- package/templates/app-dndev/public/manifest.json.example +10 -0
- package/templates/app-dndev/src/App.tsx.example +35 -0
- package/templates/app-dndev/src/components/CockpitLayout.css.example +181 -0
- package/templates/app-dndev/src/components/CockpitLayout.tsx.example +209 -0
- package/templates/app-dndev/src/components/Kanban.css.example +385 -0
- package/templates/app-dndev/src/components/ModeToggle.tsx.example +32 -0
- package/templates/app-dndev/src/components/OverlaySlot.tsx.example +68 -0
- package/templates/app-dndev/src/components/TerminalPanel.css.example +228 -0
- package/templates/app-dndev/src/components/TerminalPanel.tsx.example +714 -0
- package/templates/app-dndev/src/components/markdown-prose.css.example +49 -0
- package/templates/app-dndev/src/components/phases/CaptainLog.tsx.example +107 -0
- package/templates/app-dndev/src/components/phases/ContextTabs.tsx.example +352 -0
- package/templates/app-dndev/src/components/phases/PhaseCard.tsx.example +126 -0
- package/templates/app-dndev/src/components/phases/PhaseDetail.tsx.example +147 -0
- package/templates/app-dndev/src/components/phases/ReviewPanel.tsx.example +115 -0
- package/templates/app-dndev/src/components/phases/phaseData.ts.example +366 -0
- package/templates/app-dndev/src/config/app.ts.example +103 -0
- package/templates/app-dndev/src/config/commands.ts.example +171 -0
- package/templates/app-dndev/src/config/legal.ts.example +170 -0
- package/templates/app-dndev/src/config/providers.ts.example +7 -0
- package/templates/app-dndev/src/globals.css.example +10 -0
- package/templates/app-dndev/src/hooks/useDndevFile.ts.example +144 -0
- package/templates/app-dndev/src/main.tsx.example +21 -0
- package/templates/app-dndev/src/pages/BoardPage.tsx.example +640 -0
- package/templates/app-dndev/src/pages/GrillPage.tsx.example +658 -0
- package/templates/app-dndev/src/pages/HomePage.tsx.example +347 -0
- package/templates/app-dndev/src/pages/NotFoundPage.tsx.example +33 -0
- package/templates/app-dndev/src/pages/PhasesPage.tsx.example +137 -0
- package/templates/app-dndev/src/pages/SettingsPage.tsx.example +64 -0
- package/templates/app-dndev/src/pages/legal/LegalNoticePage.tsx.example +75 -0
- package/templates/app-dndev/src/pages/legal/PrivacyPage.tsx.example +69 -0
- package/templates/app-dndev/src/pages/legal/TermsPage.tsx.example +71 -0
- package/templates/app-dndev/src/stores/dndevStore.ts.example +386 -0
- package/templates/app-dndev/src/themes.css.example +161 -0
- package/templates/app-dndev/terminal-sidecar.cjs.example +341 -0
- package/templates/app-dndev/tsconfig.json.example +9 -0
- package/templates/app-dndev/vite.config.ts.example +24 -0
- package/templates/app-vite/index.html.example +1 -1
- package/templates/functions-supabase/supabase/functions/.env.example +0 -2
- package/templates/root-consumer/.claude/commands/grill.md.example +86 -8
- package/templates/root-consumer/.dndev.secrets.example +32 -0
- package/templates/root-consumer/.gitignore.example +3 -0
- package/templates/root-consumer/AI.md.example +4 -0
- package/templates/root-consumer/entities/index.ts.example +2 -5
- package/templates/root-consumer/guides/dndev/COMPONENTS_ATOMIC.md.example +4 -0
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +23 -20
- package/templates/root-consumer/guides/dndev/INDEX.md.example +1 -0
- package/templates/root-consumer/guides/dndev/SETUP_BILLING.md.example +3 -7
- package/templates/root-consumer/guides/dndev/SETUP_CICD.md.example +115 -0
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +41 -0
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +13 -18
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +17 -12
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +185 -251
- package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +26 -8
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +66 -49
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +6 -5
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +9 -9
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +1 -1
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +7 -6
- package/templates/root-consumer/guides/wai-way/context_map.json.example +51 -20
- package/templates/root-consumer/guides/wai-way/hld_template.md.example +138 -0
- package/templates/root-consumer/guides/wai-way/lld_template.md.example +103 -0
- package/templates/root-consumer/guides/wai-way/prd_template.md.example +140 -0
- /package/templates/{root-consumer → app-demo}/entities/Contact.ts.example +0 -0
- /package/templates/{root-consumer → app-demo}/entities/demo.ts.example +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VITE_AUTH_PARTNERS=password, google, github, apple, discord, facebook, linkedin, reddit, twitch, twitter, microsoft, spotify, yahoo
|
|
@@ -32,13 +32,16 @@ export const productEntity = defineEntity({
|
|
|
32
32
|
listCardFields: ['images', 'name', 'price', 'category'],
|
|
33
33
|
|
|
34
34
|
// ==========================================================================
|
|
35
|
-
// ACCESS RULES - Who can do what
|
|
35
|
+
// ACCESS RULES - Who can do what (maps to Supabase RLS policies)
|
|
36
36
|
// ==========================================================================
|
|
37
37
|
//
|
|
38
38
|
// 'guest' → Anyone (including not logged in)
|
|
39
39
|
// 'user' → Any logged-in user
|
|
40
|
-
// 'owner' → Only the document owner (createdById matches)
|
|
41
40
|
// 'admin' → Only admin role
|
|
41
|
+
// 'super' → Only super admin
|
|
42
|
+
//
|
|
43
|
+
// NOTE: These are DB-level roles. For owner-based logic, use field-level
|
|
44
|
+
// 'editable' / 'visibility' settings (see FIELD DEFINITIONS below).
|
|
42
45
|
//
|
|
43
46
|
access: {
|
|
44
47
|
create: 'admin', // Only admins can create products
|
|
@@ -67,16 +70,19 @@ export const productEntity = defineEntity({
|
|
|
67
70
|
// 'images' → Image upload (multiple)
|
|
68
71
|
// 'reference' → Link to another entity
|
|
69
72
|
//
|
|
70
|
-
// VISIBILITY:
|
|
71
|
-
// 'guest'
|
|
72
|
-
// 'user'
|
|
73
|
-
// '
|
|
74
|
-
// '
|
|
73
|
+
// VISIBILITY (field-level, UI only):
|
|
74
|
+
// 'guest' → Everyone can see this field
|
|
75
|
+
// 'user' → Only logged-in users
|
|
76
|
+
// 'admin' → Only admins
|
|
77
|
+
// 'super' → Only super admins
|
|
78
|
+
// 'hidden' → Never sent to client (server-only)
|
|
75
79
|
//
|
|
76
|
-
// EDITABLE:
|
|
80
|
+
// EDITABLE (field-level, UI only):
|
|
77
81
|
// 'admin' → Only admins can edit
|
|
78
|
-
// 'owner' → Only
|
|
82
|
+
// 'owner' → Only document creator can edit
|
|
83
|
+
// 'user' → Any authenticated user can edit
|
|
79
84
|
// 'create-only' → Set on creation, read-only after
|
|
85
|
+
// false → Never editable (read-only)
|
|
80
86
|
//
|
|
81
87
|
fields: {
|
|
82
88
|
// ==========================================================================
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
box-sizing: border-box;
|
|
21
21
|
}
|
|
22
22
|
body {
|
|
23
|
-
font-family:
|
|
23
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
|
24
24
|
line-height: 1.5;
|
|
25
25
|
-webkit-font-smoothing: antialiased;
|
|
26
26
|
-moz-osx-font-smoothing: grayscale;
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" xmlns:v="https://vecta.io/nano"><path d="M11.995 68.133c-.747.14-2.114 1.276-2.986 2.409l-1.557 2.199-.062 104.273.684 251.717c.935 2.835 3.423 4.749 6.347 4.89 2.366.142 3.61-.566 10.767-5.599l42.311-30.054L112.3 366.14l16.366-11.768c3.234-2.268 6.098-4.749 6.346-5.599 1.369-3.828 9.271-32.679 9.023-32.891-.124-.213-1.743.78-3.547 2.198-1.803 1.347-8.773 6.309-15.432 10.916L87.1 355.862l-24.891 17.65-23.831 16.729c-5.413 3.898-10.143 7.017-10.454 7.017-.685 0-.809-291.837-.063-292.334.249-.141 1.619.497 3.049 1.559l51.521 37.711 18.668 13.61 20.222 14.674 13.69 9.996 9.333 6.734 12.756 9.215c10.455 7.798 15.992 11.767 16.553 11.908.374.073 1.99-4.889 3.609-11.058l3.048-11.202-5.537-4.038-10.641-7.799c-2.863-1.984-10.391-7.584-16.8-12.405l-23.21-17.154-20.721-15.24L89.4 121.157c-2.613-1.986-7.653-5.671-11.2-8.223L23.506 73.096c-6.471-4.679-8.774-5.671-11.512-4.962l.001-.001zm235.829 4.466c-1.057.708-2.302 2.055-2.737 2.977-.622 1.276-.809 14.673-.746 62.733l.062 61.104 4.915 8.01 10.206 16.871 5.225 8.861.187-62.308 1.057-61.812c.56.212 6.098 4.111 12.321 8.648l43.806 31.97c1.307.991 1.431.708 5.973-9.641l4.667-10.705-1.618-1.346-14.747-10.845-20.844-15.313-36.65-26.864c-5.788-4.182-7.841-4.608-11.077-2.34zm-34.784 196.85l-7.279 15.807-11.511 25.166c.123.141 5.351-3.474 11.697-7.939l18.356-13.042 8.027-5.813c1.057-.922.685-1.701-6.347-13.469l-7.466-12.546-5.477 11.838v-.002z" fill="var(--primary,#dc143c)"/><path d="M376.752 57.145l-4.977 11.2c-1.432 2.907-4.792 10.066-7.468 15.95l-9.955 21.619-25.388 54.583-11.2 24.101-20.658 43.949-11.7 24.81-7.84 16.304c-.809 1.347-.621 1.631-15.679-23.747l-26.072-43.949-22.213-37.71c-8.587-14.815-10.267-16.73-12.322-14.319-.435.566-2.676 8.009-4.978 16.586l-22.711 82.228-13.378 47.494-8.153 29.064-18.232 64.86-12.133 43.382-4.355 16.162c.186 0 3.671-7.443 14.871-31.898l10.578-22.684 8.088-17.013 8.774-18.43 9.771-20.556 7.901-16.659 9.333-19.848 9.957-21.267 10.765-23.038c6.844-14.957 9.397-20.061 10.08-20.273.374-.142 3.485 4.606 6.968 10.562l24.828 41.255 31.981 52.809c5.289 8.932 6.846 11.06 8.153 11.2.87.142 1.929-.212 2.302-.779.685-.851 19.6-65.499 44.054-150.421l25.823-88.889 17.798-62.168c-.125-.141-1.308 2.34-2.615 5.53h.002z" fill="var(--accent,#ffd700)"/><path d="M359.081 153.904l-3.111 11.555c-1.369 4.89-2.302 9.074-2.053 9.287s5.041 3.757 10.703 7.869l33.289 24.314 37.645 27.505 19.601 14.318 6.409 4.536c2.489 1.49 5.538-.991-32.542 26.369l-38.269 27.432-31.236 22.402-33.913 24.456-28.187 20.273-12.134 8.648c-10.019 7.16-19.413 13.681-19.848 13.681-.188 0-.374-14.248-.374-31.757v-31.686l-4.419-7.088-10.019-16.518c-3.111-5.102-5.849-9.356-6.098-9.356s-.375 11.909-.249 26.37l.249 64.223v37.711l2.054 2.623c1.866 2.268 2.489 2.553 4.914 2.553 3.237 0 4.169-.568 18.855-11.202l76.535-55.291 21.78-15.807 120.403-86.411c3.67-2.552 5.102-4.748 5.475-8.434.188-2.409 0-3.971-.746-5.599-1.244-2.623-2.677-3.686-48.908-37.711l-51.023-37.642-14.624-10.774-12.88-9.427c-2.986-2.199-5.724-4.041-6.035-4.041-.374 0-.934 1.206-1.245 2.622l.001-.003z" fill="var(--primary,#dc143c)"/></svg>
|
|
Binary file
|
|
Binary file
|
|
@@ -26,5 +26,7 @@ import { appConfig } from './config/app';
|
|
|
26
26
|
* @author AMBROISE PARK Consulting
|
|
27
27
|
*/
|
|
28
28
|
export function App() {
|
|
29
|
-
return
|
|
29
|
+
return (
|
|
30
|
+
<ViteAppProviders config={appConfig} layout={{ breadcrumbs: 'smart' }} />
|
|
31
|
+
);
|
|
30
32
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// apps/demo/src/entities/booking.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity, when } from '@donotdev/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Booking entity — demonstrates complex conditional logic.
|
|
7
|
+
*
|
|
8
|
+
* - groupSize: visible only for group bookings
|
|
9
|
+
* - companyName: visible only for corporate bookings
|
|
10
|
+
* - invoiceAddress: visible for corporate OR group with 10+ people
|
|
11
|
+
*/
|
|
12
|
+
export const bookingEntity = defineEntity({
|
|
13
|
+
name: 'Booking',
|
|
14
|
+
collection: 'bookings',
|
|
15
|
+
fields: {
|
|
16
|
+
bookingType: {
|
|
17
|
+
name: 'bookingType',
|
|
18
|
+
type: 'select',
|
|
19
|
+
label: 'Booking Type',
|
|
20
|
+
visibility: 'user',
|
|
21
|
+
validation: {
|
|
22
|
+
required: true,
|
|
23
|
+
options: [
|
|
24
|
+
{ value: 'individual', label: 'Individual' },
|
|
25
|
+
{ value: 'group', label: 'Group (5+)' },
|
|
26
|
+
{ value: 'corporate', label: 'Corporate' },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
groupSize: {
|
|
31
|
+
name: 'groupSize',
|
|
32
|
+
type: 'number',
|
|
33
|
+
label: 'Number of People',
|
|
34
|
+
visibility: 'user',
|
|
35
|
+
conditions: {
|
|
36
|
+
visible: when('bookingType').equals('group'),
|
|
37
|
+
required: when('bookingType').equals('group'),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
companyName: {
|
|
41
|
+
name: 'companyName',
|
|
42
|
+
type: 'text',
|
|
43
|
+
label: 'Company Name',
|
|
44
|
+
visibility: 'user',
|
|
45
|
+
conditions: {
|
|
46
|
+
visible: when('bookingType').equals('corporate'),
|
|
47
|
+
required: when('bookingType').equals('corporate'),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
invoiceAddress: {
|
|
51
|
+
name: 'invoiceAddress',
|
|
52
|
+
type: 'address',
|
|
53
|
+
label: 'Invoice Address',
|
|
54
|
+
visibility: 'user',
|
|
55
|
+
conditions: {
|
|
56
|
+
visible: when('bookingType')
|
|
57
|
+
.equals('corporate')
|
|
58
|
+
.or(when('groupSize').greaterThan(10)),
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
date: {
|
|
62
|
+
name: 'date',
|
|
63
|
+
type: 'date',
|
|
64
|
+
label: 'Booking Date',
|
|
65
|
+
visibility: 'user',
|
|
66
|
+
validation: { required: true },
|
|
67
|
+
},
|
|
68
|
+
notes: {
|
|
69
|
+
name: 'notes',
|
|
70
|
+
type: 'textarea',
|
|
71
|
+
label: 'Special Requests',
|
|
72
|
+
visibility: 'user',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// apps/demo/src/entities/onboarding.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity, when } from '@donotdev/core';
|
|
4
|
+
import { defineWorkflow } from '@donotdev/crud';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Entities for the Customer Onboarding workflow demo.
|
|
8
|
+
* Each entity represents one step in the wizard.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const companyEntity = defineEntity({
|
|
12
|
+
name: 'Company',
|
|
13
|
+
collection: 'companies',
|
|
14
|
+
fields: {
|
|
15
|
+
name: {
|
|
16
|
+
name: 'name',
|
|
17
|
+
type: 'text',
|
|
18
|
+
label: 'Company Name',
|
|
19
|
+
visibility: 'user',
|
|
20
|
+
validation: { required: true, minLength: 2 },
|
|
21
|
+
},
|
|
22
|
+
industry: {
|
|
23
|
+
name: 'industry',
|
|
24
|
+
type: 'select',
|
|
25
|
+
label: 'Industry',
|
|
26
|
+
visibility: 'user',
|
|
27
|
+
validation: {
|
|
28
|
+
required: true,
|
|
29
|
+
options: [
|
|
30
|
+
{ value: 'tech', label: 'Technology' },
|
|
31
|
+
{ value: 'finance', label: 'Finance' },
|
|
32
|
+
{ value: 'healthcare', label: 'Healthcare' },
|
|
33
|
+
{ value: 'retail', label: 'Retail' },
|
|
34
|
+
{ value: 'other', label: 'Other' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
size: {
|
|
39
|
+
name: 'size',
|
|
40
|
+
type: 'number',
|
|
41
|
+
label: 'Number of Employees',
|
|
42
|
+
visibility: 'user',
|
|
43
|
+
validation: { required: true, min: 1 },
|
|
44
|
+
},
|
|
45
|
+
website: {
|
|
46
|
+
name: 'website',
|
|
47
|
+
type: 'url',
|
|
48
|
+
label: 'Website',
|
|
49
|
+
visibility: 'user',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const contactEntity = defineEntity({
|
|
55
|
+
name: 'Contact',
|
|
56
|
+
collection: 'contacts',
|
|
57
|
+
fields: {
|
|
58
|
+
firstName: {
|
|
59
|
+
name: 'firstName',
|
|
60
|
+
type: 'text',
|
|
61
|
+
label: 'First Name',
|
|
62
|
+
visibility: 'user',
|
|
63
|
+
validation: { required: true },
|
|
64
|
+
},
|
|
65
|
+
lastName: {
|
|
66
|
+
name: 'lastName',
|
|
67
|
+
type: 'text',
|
|
68
|
+
label: 'Last Name',
|
|
69
|
+
visibility: 'user',
|
|
70
|
+
validation: { required: true },
|
|
71
|
+
},
|
|
72
|
+
email: {
|
|
73
|
+
name: 'email',
|
|
74
|
+
type: 'email',
|
|
75
|
+
label: 'Email',
|
|
76
|
+
visibility: 'user',
|
|
77
|
+
validation: { required: true },
|
|
78
|
+
},
|
|
79
|
+
phone: {
|
|
80
|
+
name: 'phone',
|
|
81
|
+
type: 'tel',
|
|
82
|
+
label: 'Phone',
|
|
83
|
+
visibility: 'user',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export const preferencesEntity = defineEntity({
|
|
89
|
+
name: 'Preferences',
|
|
90
|
+
collection: 'preferences',
|
|
91
|
+
fields: {
|
|
92
|
+
language: {
|
|
93
|
+
name: 'language',
|
|
94
|
+
type: 'select',
|
|
95
|
+
label: 'Language',
|
|
96
|
+
visibility: 'user',
|
|
97
|
+
validation: {
|
|
98
|
+
options: [
|
|
99
|
+
{ value: 'en', label: 'English' },
|
|
100
|
+
{ value: 'fr', label: 'French' },
|
|
101
|
+
{ value: 'de', label: 'German' },
|
|
102
|
+
{ value: 'es', label: 'Spanish' },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
notifications: {
|
|
107
|
+
name: 'notifications',
|
|
108
|
+
type: 'switch',
|
|
109
|
+
label: 'Enable Email Notifications',
|
|
110
|
+
visibility: 'user',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Customer Onboarding Workflow
|
|
117
|
+
*
|
|
118
|
+
* 4 steps:
|
|
119
|
+
* 1. Company Info (required)
|
|
120
|
+
* 2. Primary Contact (required)
|
|
121
|
+
* 3. Preferences (skippable)
|
|
122
|
+
* 4. Billing — only shown if company size > 10
|
|
123
|
+
*/
|
|
124
|
+
export const onboardingWorkflow = defineWorkflow({
|
|
125
|
+
id: 'customer-onboarding',
|
|
126
|
+
name: 'Customer Onboarding',
|
|
127
|
+
persist: true,
|
|
128
|
+
|
|
129
|
+
steps: [
|
|
130
|
+
{
|
|
131
|
+
id: 'company',
|
|
132
|
+
title: 'Company Info',
|
|
133
|
+
entity: companyEntity,
|
|
134
|
+
fields: ['name', 'industry', 'size', 'website'],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'contact',
|
|
138
|
+
title: 'Primary Contact',
|
|
139
|
+
entity: contactEntity,
|
|
140
|
+
fields: ['firstName', 'lastName', 'email', 'phone'],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'preferences',
|
|
144
|
+
title: 'Preferences',
|
|
145
|
+
entity: preferencesEntity,
|
|
146
|
+
fields: ['language', 'notifications'],
|
|
147
|
+
allowSkip: true,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'billing',
|
|
151
|
+
title: 'Billing',
|
|
152
|
+
description: 'Required for companies with more than 10 employees',
|
|
153
|
+
entity: companyEntity,
|
|
154
|
+
fields: ['website'], // placeholder — real app would have billing entity
|
|
155
|
+
conditions: {
|
|
156
|
+
visible: when('size').greaterThan(10),
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// apps/demo/src/entities/product.ts
|
|
2
|
+
|
|
1
3
|
import { defineEntity } from '@donotdev/core';
|
|
2
4
|
|
|
3
5
|
export const productEntity = defineEntity({
|
|
@@ -5,20 +7,28 @@ export const productEntity = defineEntity({
|
|
|
5
7
|
collection: 'products',
|
|
6
8
|
fields: {
|
|
7
9
|
name: {
|
|
10
|
+
name: 'name',
|
|
11
|
+
label: 'Name',
|
|
8
12
|
type: 'text',
|
|
9
13
|
visibility: 'user',
|
|
10
14
|
validation: { required: true, minLength: 3 },
|
|
11
15
|
},
|
|
12
16
|
description: {
|
|
17
|
+
name: 'description',
|
|
18
|
+
label: 'Description',
|
|
13
19
|
type: 'textarea',
|
|
14
20
|
visibility: 'user',
|
|
15
21
|
},
|
|
16
22
|
price: {
|
|
23
|
+
name: 'price',
|
|
24
|
+
label: 'Price',
|
|
17
25
|
type: 'number',
|
|
18
26
|
visibility: 'user',
|
|
19
27
|
validation: { required: true, min: 0 },
|
|
20
28
|
},
|
|
21
29
|
category: {
|
|
30
|
+
name: 'category',
|
|
31
|
+
label: 'Category',
|
|
22
32
|
type: 'select',
|
|
23
33
|
visibility: 'user',
|
|
24
34
|
validation: {
|
|
@@ -31,6 +41,8 @@ export const productEntity = defineEntity({
|
|
|
31
41
|
},
|
|
32
42
|
},
|
|
33
43
|
image: {
|
|
44
|
+
name: 'image',
|
|
45
|
+
label: 'Image',
|
|
34
46
|
type: 'image',
|
|
35
47
|
visibility: 'user',
|
|
36
48
|
},
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// apps/demo/src/entities/quote.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity, when } from '@donotdev/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Insurance Quote entity — demonstrates conditional field visibility.
|
|
7
|
+
*
|
|
8
|
+
* - licensePlate: only visible when productType === 'car'
|
|
9
|
+
* - propertyAddress: only visible when productType === 'home'
|
|
10
|
+
* - estimatedValue: visible for car OR home (not health)
|
|
11
|
+
* - notes: disabled until productType is selected
|
|
12
|
+
*/
|
|
13
|
+
export const quoteEntity = defineEntity({
|
|
14
|
+
name: 'Quote',
|
|
15
|
+
collection: 'quotes',
|
|
16
|
+
fields: {
|
|
17
|
+
productType: {
|
|
18
|
+
name: 'productType',
|
|
19
|
+
type: 'select',
|
|
20
|
+
label: 'Product',
|
|
21
|
+
visibility: 'user',
|
|
22
|
+
validation: {
|
|
23
|
+
required: true,
|
|
24
|
+
options: [
|
|
25
|
+
{ value: 'health', label: 'Health Insurance' },
|
|
26
|
+
{ value: 'car', label: 'Car Insurance' },
|
|
27
|
+
{ value: 'home', label: 'Home Insurance' },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
licensePlate: {
|
|
32
|
+
name: 'licensePlate',
|
|
33
|
+
type: 'text',
|
|
34
|
+
label: 'License Plate',
|
|
35
|
+
visibility: 'user',
|
|
36
|
+
conditions: {
|
|
37
|
+
visible: when('productType').equals('car'),
|
|
38
|
+
required: when('productType').equals('car'),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
propertyAddress: {
|
|
42
|
+
name: 'propertyAddress',
|
|
43
|
+
type: 'address',
|
|
44
|
+
label: 'Property Address',
|
|
45
|
+
visibility: 'user',
|
|
46
|
+
conditions: {
|
|
47
|
+
visible: when('productType').equals('home'),
|
|
48
|
+
required: when('productType').equals('home'),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
estimatedValue: {
|
|
52
|
+
name: 'estimatedValue',
|
|
53
|
+
type: 'number',
|
|
54
|
+
label: 'Estimated Value',
|
|
55
|
+
visibility: 'user',
|
|
56
|
+
conditions: {
|
|
57
|
+
visible: when('productType').in(['car', 'home']),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
notes: {
|
|
61
|
+
name: 'notes',
|
|
62
|
+
type: 'textarea',
|
|
63
|
+
label: 'Additional Notes',
|
|
64
|
+
visibility: 'user',
|
|
65
|
+
conditions: {
|
|
66
|
+
disabled: when('productType').notExists(),
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// apps/demo/src/pages/ChangelogPage.tsx
|
|
2
|
+
|
|
1
3
|
import { History } from 'lucide-react';
|
|
2
4
|
|
|
3
5
|
import { WhatsNewTemplate } from '@donotdev/templates';
|
|
@@ -10,5 +12,30 @@ export const meta: PageMeta = {
|
|
|
10
12
|
};
|
|
11
13
|
|
|
12
14
|
export default function ChangelogPage() {
|
|
13
|
-
return
|
|
15
|
+
return (
|
|
16
|
+
<WhatsNewTemplate
|
|
17
|
+
changelog={[
|
|
18
|
+
{
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
date: '2026-01-15',
|
|
21
|
+
type: 'major',
|
|
22
|
+
title: 'Initial Release',
|
|
23
|
+
description: 'First public release of the demo app.',
|
|
24
|
+
changes: [
|
|
25
|
+
{
|
|
26
|
+
type: 'added',
|
|
27
|
+
items: [
|
|
28
|
+
'Condition builder with when() API',
|
|
29
|
+
'Multi-step workflow engine',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'changed',
|
|
34
|
+
items: ['Entity form renderer supports dynamic fields'],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
]}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
14
41
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// apps/demo/src/pages/ConditionalFormPage.tsx
|
|
2
|
+
|
|
3
|
+
import { SlidersHorizontal } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
import { Card, Tabs } from '@donotdev/components';
|
|
6
|
+
import { EntityFormRenderer } from '@donotdev/ui';
|
|
7
|
+
|
|
8
|
+
import { quoteEntity } from '../entities/quote';
|
|
9
|
+
import { bookingEntity } from '../entities/booking';
|
|
10
|
+
|
|
11
|
+
import type { PageMeta } from '@donotdev/core';
|
|
12
|
+
|
|
13
|
+
export const meta: PageMeta = {
|
|
14
|
+
icon: <SlidersHorizontal />,
|
|
15
|
+
title: 'Conditional Forms',
|
|
16
|
+
preset: 'admin',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Conditional Forms Demo — shows field visibility driven by `when()` conditions.
|
|
21
|
+
*
|
|
22
|
+
* Two examples:
|
|
23
|
+
* 1. Insurance Quote — fields appear/disappear based on product type
|
|
24
|
+
* 2. Booking — complex conditions with .or() combinator
|
|
25
|
+
*/
|
|
26
|
+
export default function ConditionalFormPage() {
|
|
27
|
+
return (
|
|
28
|
+
<div style={{ maxWidth: 640, margin: '0 auto' }}>
|
|
29
|
+
<Card
|
|
30
|
+
title="Conditional Forms"
|
|
31
|
+
content="Fields appear, hide, or become required based on other field values. Powered by when() condition builder."
|
|
32
|
+
>
|
|
33
|
+
<Tabs
|
|
34
|
+
items={[
|
|
35
|
+
{
|
|
36
|
+
value: 'quote',
|
|
37
|
+
label: 'Insurance Quote',
|
|
38
|
+
content: (
|
|
39
|
+
<Card
|
|
40
|
+
title="Insurance Quote"
|
|
41
|
+
content='Select a product type to see conditional fields appear. "Car" shows license plate, "Home" shows address, both show estimated value.'
|
|
42
|
+
>
|
|
43
|
+
<EntityFormRenderer
|
|
44
|
+
entity={quoteEntity}
|
|
45
|
+
operation="create"
|
|
46
|
+
onSubmit={async (data) => {
|
|
47
|
+
alert(
|
|
48
|
+
`Quote submitted: ${JSON.stringify(data, null, 2)}`
|
|
49
|
+
);
|
|
50
|
+
}}
|
|
51
|
+
submitText="Get Quote"
|
|
52
|
+
cancelText={null}
|
|
53
|
+
warnOnUnsavedChanges={false}
|
|
54
|
+
hideVisibilityInfo
|
|
55
|
+
/>
|
|
56
|
+
</Card>
|
|
57
|
+
),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
value: 'booking',
|
|
61
|
+
label: 'Booking',
|
|
62
|
+
content: (
|
|
63
|
+
<Card
|
|
64
|
+
title="Booking Form"
|
|
65
|
+
content='"Group" shows group size, "Corporate" shows company name. Invoice address appears for corporate OR groups with 10+ people.'
|
|
66
|
+
>
|
|
67
|
+
<EntityFormRenderer
|
|
68
|
+
entity={bookingEntity}
|
|
69
|
+
operation="create"
|
|
70
|
+
onSubmit={async (data) => {
|
|
71
|
+
alert(
|
|
72
|
+
`Booking submitted: ${JSON.stringify(data, null, 2)}`
|
|
73
|
+
);
|
|
74
|
+
}}
|
|
75
|
+
submitText="Book Now"
|
|
76
|
+
cancelText={null}
|
|
77
|
+
warnOnUnsavedChanges={false}
|
|
78
|
+
hideVisibilityInfo
|
|
79
|
+
/>
|
|
80
|
+
</Card>
|
|
81
|
+
),
|
|
82
|
+
},
|
|
83
|
+
]}
|
|
84
|
+
/>
|
|
85
|
+
</Card>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|