@donotdev/cli 0.0.19 → 0.0.20
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/dependencies-matrix.json +135 -47
- package/dist/bin/commands/bump.js +5 -2
- package/dist/bin/commands/create-app.js +1 -1
- package/dist/bin/commands/create-project.js +13 -2
- package/dist/bin/commands/deploy.js +18 -0
- package/dist/bin/commands/setup.js +3 -0
- package/dist/bin/commands/staging.js +18 -0
- package/dist/bin/commands/type-check.js +10 -4
- package/dist/bin/dndev.js +120 -179
- package/dist/bin/donotdev.js +120 -179
- package/dist/index.js +31 -2
- package/package.json +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-next/src/locales/home_en.json.example +6 -6
- package/templates/app-vite/src/locales/home_en.json.example +6 -6
- package/templates/root-consumer/guides/dndev/advanced/COOKIE_REFERENCE.md.example +252 -252
- package/templates/root-consumer/guides/dndev/advanced/VERSION_CONTROL.md.example +174 -174
|
@@ -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
|
+
}
|