@donotdev/cli 0.0.5 → 0.0.7
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 +76 -34
- package/dist/bin/commands/build.js +165 -161
- package/dist/bin/commands/bump.js +172 -160
- package/dist/bin/commands/cacheout.js +163 -157
- package/dist/bin/commands/create-app.js +205 -163
- package/dist/bin/commands/create-project.js +176 -161
- package/dist/bin/commands/deploy.js +480 -472
- package/dist/bin/commands/dev.js +164 -158
- package/dist/bin/commands/emu.js +164 -158
- package/dist/bin/commands/format.js +163 -157
- package/dist/bin/commands/lint.js +166 -157
- package/dist/bin/commands/make-admin.d.ts +11 -0
- package/dist/bin/commands/make-admin.d.ts.map +1 -0
- package/dist/bin/commands/make-admin.js +12 -0
- package/dist/bin/commands/make-admin.js.map +1 -0
- package/dist/bin/commands/preview.js +164 -158
- package/dist/bin/commands/sync-secrets.js +164 -158
- package/dist/bin/commands/wai.d.ts +11 -0
- package/dist/bin/commands/wai.d.ts.map +1 -0
- package/dist/bin/commands/wai.js +12 -0
- package/dist/bin/commands/wai.js.map +1 -0
- package/dist/bin/dndev.js +24 -8
- package/dist/bin/donotdev.js +24 -8
- package/dist/index.js +557 -514
- package/package.json +1 -1
- package/templates/app-demo/index.html.example +4 -0
- package/templates/app-demo/src/App.tsx.example +28 -10
- package/templates/app-demo/src/config/app.ts.example +68 -0
- package/templates/app-next/src/app/ClientLayout.tsx.example +4 -3
- package/templates/app-next/src/app/layout.tsx.example +17 -25
- package/templates/app-next/src/config/app.ts.example +75 -48
- package/templates/app-next/src/globals.css.example +10 -7
- package/templates/app-next/src/locales/dndev_en.json.example +68 -0
- package/templates/app-next/src/pages/locales/example_en.json.example +5 -0
- package/templates/app-vite/index.html.example +71 -34
- package/templates/app-vite/src/config/app.ts.example +75 -47
- package/templates/app-vite/src/globals.css.example +14 -6
- package/templates/app-vite/src/locales/dndev_en.json.example +68 -0
- package/templates/app-vite/src/pages/FormPageExample.tsx.example +152 -0
- package/templates/app-vite/src/pages/HomePage.tsx.example +81 -134
- package/templates/app-vite/src/pages/ListPageExample.tsx.example +88 -0
- package/templates/functions-firebase/README.md.example +25 -0
- package/templates/functions-firebase/build.mjs.example +8 -1
- package/templates/functions-firebase/functions-firebase/build.mjs.example +8 -1
- package/templates/functions-firebase/functions-firebase/src/index.ts.example +19 -25
- package/templates/functions-firebase/functions.config.js.example +35 -0
- package/templates/functions-firebase/tsconfig.json.example +3 -13
- package/templates/functions-vercel/tsconfig.json.example +1 -13
- package/templates/root-consumer/entities/ExampleEntity.ts.example +223 -0
- package/templates/root-consumer/entities/demo.ts.example +562 -0
- package/templates/root-consumer/entities/index.ts.example +15 -0
- package/templates/root-consumer/firebase.json.example +1 -1
- package/templates/root-consumer/guides/{AGENT_START_HERE.md.example → dndev/AGENT_START_HERE.md.example} +22 -0
- package/templates/root-consumer/guides/{COMPONENTS_ADV.md.example → dndev/COMPONENTS_ADV.md.example} +456 -360
- package/templates/root-consumer/guides/{COMPONENTS_ATOMIC.md.example → dndev/COMPONENTS_ATOMIC.md.example} +42 -0
- package/templates/root-consumer/guides/dndev/COMPONENTS_CRUD.md.example +231 -0
- package/templates/root-consumer/guides/{INDEX.md.example → dndev/INDEX.md.example} +3 -0
- package/templates/root-consumer/guides/{SETUP_APP_CONFIG.md.example → dndev/SETUP_APP_CONFIG.md.example} +5 -2
- package/templates/root-consumer/guides/{SETUP_AUTH.md.example → dndev/SETUP_AUTH.md.example} +30 -0
- package/templates/root-consumer/guides/{SETUP_BILLING.md.example → dndev/SETUP_BILLING.md.example} +44 -4
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +473 -0
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +116 -0
- package/templates/root-consumer/guides/{SETUP_PAGES.md.example → dndev/SETUP_PAGES.md.example} +17 -0
- package/templates/root-consumer/guides/dndev/SETUP_PWA.md.example +213 -0
- package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +503 -0
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +404 -0
- package/templates/root-consumer/guides/wai-way/agents/architect.md.example +78 -0
- package/templates/root-consumer/guides/wai-way/agents/builder.md.example +87 -0
- package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +325 -0
- package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +100 -0
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +281 -0
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +77 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +104 -0
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +124 -0
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +165 -0
- package/templates/root-consumer/guides/wai-way/context_map.json.example +95 -0
- package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +840 -0
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +686 -0
- package/templates/root-consumer/guides/wai-way/presets_guide.md.example +217 -0
- package/templates/root-consumer/guides/wai-way/spec_template.md.example +312 -0
- package/templates/root-consumer/vercel.json.example +315 -20
- package/templates/app-demo/src/Routes.tsx.example +0 -20
- package/templates/app-vite/src/Routes.tsx.example +0 -16
- package/templates/app-vite/src/pages/locales/README.md.example +0 -1
- package/templates/functions-firebase/functions-firebase/src/crud/createEntity.ts.example +0 -19
- package/templates/functions-firebase/functions-firebase/src/crud/deleteEntity.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/getEntity.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/index.ts.example +0 -12
- package/templates/functions-firebase/functions-firebase/src/crud/listEntities.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/updateEntity.ts.example +0 -14
- package/templates/root-consumer/guides/COMPONENTS_CRUD.md.example +0 -70
- package/templates/root-consumer/guides/SETUP_FUNCTIONS.md.example +0 -62
- /package/templates/root-consumer/guides/{COMPONENTS_UI.md.example → dndev/COMPONENTS_UI.md.example} +0 -0
- /package/templates/root-consumer/guides/{ENV_SETUP.md.example → dndev/ENV_SETUP.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_I18N.md.example → dndev/SETUP_I18N.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_LAYOUTS.md.example → dndev/SETUP_LAYOUTS.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_OAUTH.md.example → dndev/SETUP_OAUTH.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_THEMES.md.example → dndev/SETUP_THEMES.md.example} +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/APP_CHECK.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/COOKIE_REFERENCE.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/EMULATORS.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/VERSION_CONTROL.md.example +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Example CRUD List Page
|
|
3
|
+
*
|
|
4
|
+
* COPY THIS FILE and rename (e.g., ProductsListPage.tsx, CustomersListPage.tsx)
|
|
5
|
+
*
|
|
6
|
+
* HOW IT WORKS:
|
|
7
|
+
* 1. Import your entity definition
|
|
8
|
+
* 2. Use EntityList component - it handles everything:
|
|
9
|
+
* - Fetching data (optimized via listFields)
|
|
10
|
+
* - Table columns (respects field visibility by role)
|
|
11
|
+
* - Search, sort, pagination
|
|
12
|
+
* - Create/Edit/Delete actions
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { Package } from 'lucide-react';
|
|
16
|
+
|
|
17
|
+
import { EntityList } from '@donotdev/crud';
|
|
18
|
+
import { useAuth } from '@donotdev/auth';
|
|
19
|
+
import type { PageMeta } from '@donotdev/core';
|
|
20
|
+
import { PageContainer } from '@donotdev/ui';
|
|
21
|
+
|
|
22
|
+
// Import your entity from root-level entities folder
|
|
23
|
+
// import { productEntity } from 'entities/Product';
|
|
24
|
+
|
|
25
|
+
// Placeholder - replace with your entity import
|
|
26
|
+
const productEntity = null as any;
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// PAGE METADATA
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
export const NAMESPACE = 'products';
|
|
33
|
+
|
|
34
|
+
export const meta: PageMeta = {
|
|
35
|
+
namespace: NAMESPACE,
|
|
36
|
+
icon: <Package />,
|
|
37
|
+
route: '/products',
|
|
38
|
+
auth: { required: true, role: 'admin' }, // Admin-only page
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// PAGE COMPONENT
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
45
|
+
export default function ProductsListPage() {
|
|
46
|
+
const user = useAuth('user');
|
|
47
|
+
|
|
48
|
+
// Zero-Config: EntityList handles everything automatically:
|
|
49
|
+
// - Fetches data using entity's listFields (optimized query)
|
|
50
|
+
// - Renders columns based on field definitions
|
|
51
|
+
// - Applies visibility rules based on user role
|
|
52
|
+
// - Includes search, sort, pagination
|
|
53
|
+
// - Add/Edit/Delete buttons with proper permissions
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<PageContainer>
|
|
57
|
+
<EntityList
|
|
58
|
+
entity={productEntity}
|
|
59
|
+
userRole={user?.role}
|
|
60
|
+
// Optional overrides:
|
|
61
|
+
// onRowClick={(item) => navigate(`/products/${item.id}`)}
|
|
62
|
+
// createPath="/products/new"
|
|
63
|
+
// hideActions={false}
|
|
64
|
+
// pageSize={25}
|
|
65
|
+
/>
|
|
66
|
+
</PageContainer>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// ALTERNATIVE: Card Grid Layout
|
|
72
|
+
// ============================================================================
|
|
73
|
+
//
|
|
74
|
+
// For a card-based grid instead of table:
|
|
75
|
+
//
|
|
76
|
+
// import { EntityCardList } from '@donotdev/crud';
|
|
77
|
+
//
|
|
78
|
+
// export default function ProductsGridPage() {
|
|
79
|
+
// return (
|
|
80
|
+
// <PageContainer>
|
|
81
|
+
// <EntityCardList
|
|
82
|
+
// entity={productEntity}
|
|
83
|
+
// // Optional: custom card rendering
|
|
84
|
+
// // renderCard={(item) => <CustomProductCard product={item} />}
|
|
85
|
+
// />
|
|
86
|
+
// </PageContainer>
|
|
87
|
+
// );
|
|
88
|
+
// }
|
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
This directory contains the Firebase Functions for the {{APP_NAME}} app, generated using the DoNotDev framework's scaffolding system.
|
|
4
4
|
|
|
5
|
+
## ⚠️ CRITICAL: Import Rules
|
|
6
|
+
|
|
7
|
+
**Functions run on Node.js - you MUST use `/server` imports or your function will crash on deploy.**
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ✅ CORRECT - Functions MUST use /server imports
|
|
11
|
+
import { getFirebaseAdminAuth } from '@donotdev/firebase/server';
|
|
12
|
+
import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
|
|
13
|
+
import { handleError } from '@donotdev/core/server';
|
|
14
|
+
|
|
15
|
+
// ❌ WRONG - This will crash on deploy (pulls in React/client code)
|
|
16
|
+
import { getAuth } from '@donotdev/firebase';
|
|
17
|
+
import { getFirestore } from '@donotdev/firebase';
|
|
18
|
+
import { handleError } from '@donotdev/core';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Why?** Functions run in Node.js, not the browser. Client imports (`@donotdev/firebase`) include React and browser-only code that will crash your function.
|
|
22
|
+
|
|
23
|
+
**Rule:** Always use `/server` suffix for:
|
|
24
|
+
- `@donotdev/firebase/server` (not `@donotdev/firebase`)
|
|
25
|
+
- `@donotdev/core/server` (not `@donotdev/core`)
|
|
26
|
+
- `@donotdev/utils/server` (not `@donotdev/utils`)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
5
30
|
## Structure
|
|
6
31
|
|
|
7
32
|
```
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { build } from 'esbuild';
|
|
8
|
-
import {
|
|
8
|
+
import { writeFileSync } from 'fs';
|
|
9
|
+
import { createAppFunctionsConfig, generateFunctionsYamlWithInfo } from '@donotdev/core/functions';
|
|
10
|
+
import { functionsConfig } from './functions.config.js';
|
|
9
11
|
|
|
10
12
|
async function buildFunctions() {
|
|
11
13
|
console.log('🔨 Building {{APP_NAME}} functions...');
|
|
@@ -33,6 +35,11 @@ async function buildFunctions() {
|
|
|
33
35
|
|
|
34
36
|
console.log('✅ {{APP_NAME}} functions built successfully!');
|
|
35
37
|
console.log('📁 Output directory: lib/');
|
|
38
|
+
|
|
39
|
+
// Generate functions.yaml from config
|
|
40
|
+
const { yaml, staticFunctions, crudFunctions } = generateFunctionsYamlWithInfo(functionsConfig);
|
|
41
|
+
writeFileSync('functions.yaml', yaml);
|
|
42
|
+
console.log(`📄 Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
|
|
36
43
|
|
|
37
44
|
// Log bundle info if metafile is available
|
|
38
45
|
if (result.metafile) {
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { build } from 'esbuild';
|
|
8
|
-
import {
|
|
8
|
+
import { writeFileSync } from 'fs';
|
|
9
|
+
import { createAppFunctionsConfig, generateFunctionsYamlWithInfo } from '@donotdev/core/functions';
|
|
10
|
+
import { functionsConfig } from './functions.config.js';
|
|
9
11
|
|
|
10
12
|
async function buildFunctions() {
|
|
11
13
|
console.log('🔨 Building {{APP_NAME}} functions...');
|
|
@@ -33,6 +35,11 @@ async function buildFunctions() {
|
|
|
33
35
|
|
|
34
36
|
console.log('✅ {{APP_NAME}} functions built successfully!');
|
|
35
37
|
console.log('📁 Output directory: lib/');
|
|
38
|
+
|
|
39
|
+
// Generate functions.yaml from config
|
|
40
|
+
const { yaml, staticFunctions, crudFunctions } = generateFunctionsYamlWithInfo(functionsConfig);
|
|
41
|
+
writeFileSync('functions.yaml', yaml);
|
|
42
|
+
console.log(`📄 Generated functions.yaml: ${staticFunctions.length} static + ${crudFunctions.length} CRUD functions`);
|
|
36
43
|
|
|
37
44
|
// Log bundle info if metafile is available
|
|
38
45
|
if (result.metafile) {
|
|
@@ -2,18 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @fileoverview {{APP_NAME}} Firebase Functions
|
|
5
|
-
* @description
|
|
5
|
+
* @description Auto-registered CRUD + custom functions for {{APP_NAME}}
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { initializeApp } from 'firebase-admin/app';
|
|
9
|
+
import { registerCrudFunctions } from '@donotdev/functions/firebase';
|
|
10
|
+
import * as entities from 'entities';
|
|
9
11
|
|
|
10
|
-
// Initialize Firebase Admin
|
|
12
|
+
// Initialize Firebase Admin
|
|
11
13
|
if (!(globalThis as any).__FIREBASE_ADMIN_INITIALIZED__) {
|
|
12
14
|
initializeApp();
|
|
13
15
|
(globalThis as any).__FIREBASE_ADMIN_INITIALIZED__ = true;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
//
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// CRUD Functions (auto-registered from entities)
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Registers: create_cars, get_cars, list_cars, update_cars, delete_cars
|
|
22
|
+
// create_customers, get_customers, ... for each entity
|
|
23
|
+
registerCrudFunctions(entities);
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Auth Functions
|
|
27
|
+
// ============================================================================
|
|
17
28
|
export {
|
|
18
29
|
setCustomClaims,
|
|
19
30
|
getCustomClaims,
|
|
@@ -21,25 +32,8 @@ export {
|
|
|
21
32
|
getUserAuthStatus,
|
|
22
33
|
} from './auth';
|
|
23
34
|
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from './oauth';
|
|
30
|
-
|
|
31
|
-
// Export CRUD functions
|
|
32
|
-
export {
|
|
33
|
-
createEntity,
|
|
34
|
-
updateEntity,
|
|
35
|
-
deleteEntity,
|
|
36
|
-
getEntity,
|
|
37
|
-
listEntities,
|
|
38
|
-
} from './crud';
|
|
39
|
-
|
|
40
|
-
// Export billing functions
|
|
41
|
-
export {
|
|
42
|
-
processPaymentSuccess,
|
|
43
|
-
refreshSubscriptionStatus,
|
|
44
|
-
stripeWebhook,
|
|
45
|
-
} from './billing';
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Custom Functions (analytics, webhooks, etc.)
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// export { getDashboardMetrics } from './analytics';
|
|
39
|
+
// export { stripeWebhook } from './billing';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// functions/functions.config.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview {{APP_NAME}} Functions Configuration
|
|
5
|
+
* @description Configuration for Firebase Functions deployment
|
|
6
|
+
* @type {import('@donotdev/types').FunctionsConfig}
|
|
7
|
+
*
|
|
8
|
+
* This config file is used to auto-generate functions.yaml during build.
|
|
9
|
+
*
|
|
10
|
+
* - Static functions: List your custom functions here
|
|
11
|
+
* - CRUD functions: List entity names to auto-generate CRUD endpoints
|
|
12
|
+
* (e.g., ['car', 'customer'] generates: create_car, get_car, list_car, update_car, delete_car, etc.)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const functionsConfig = {
|
|
16
|
+
defaults: {
|
|
17
|
+
region: ['us-central1'],
|
|
18
|
+
platform: 'gcfv2',
|
|
19
|
+
labels: { app: '{{APP_NAME}}' },
|
|
20
|
+
},
|
|
21
|
+
functions: {
|
|
22
|
+
// Add your static (non-CRUD) functions here
|
|
23
|
+
// Example:
|
|
24
|
+
// getCustomClaims: { category: 'auth' },
|
|
25
|
+
// setCustomClaims: { category: 'auth' },
|
|
26
|
+
// stripeWebhook: { category: 'billing', trigger: 'http' },
|
|
27
|
+
},
|
|
28
|
+
crud: {
|
|
29
|
+
// List entity names to auto-generate CRUD functions
|
|
30
|
+
// Each entity will generate: create_*, get_*, list_*, update_*, delete_*
|
|
31
|
+
// Example:
|
|
32
|
+
// entities: ['car', 'customer', 'inquiry'],
|
|
33
|
+
entities: [],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "../../../tsconfig.functions.json",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"lib": ["ES2022"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"allowSyntheticDefaultImports": true,
|
|
14
|
-
"noUncheckedIndexedAccess": true,
|
|
15
|
-
"types": ["node"],
|
|
4
|
+
"module": "preserve",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
16
6
|
"outDir": "./lib",
|
|
17
7
|
"rootDir": "./src",
|
|
18
8
|
"declaration": true,
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "../../../tsconfig.functions.json",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"lib": ["ES2022"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"allowSyntheticDefaultImports": true,
|
|
14
|
-
"noUncheckedIndexedAccess": true,
|
|
15
|
-
"types": ["node"],
|
|
16
4
|
"outDir": "./lib",
|
|
17
5
|
"rootDir": "./src",
|
|
18
6
|
"declaration": true,
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Example Entity Definition
|
|
3
|
+
*
|
|
4
|
+
* COPY THIS FILE and rename to your entity (e.g., Product.ts, Task.ts, Customer.ts)
|
|
5
|
+
*
|
|
6
|
+
* HOW ENTITIES WORK:
|
|
7
|
+
* 1. Define fields with types, visibility, validation
|
|
8
|
+
* 2. Set access rules (who can create/read/update/delete)
|
|
9
|
+
* 3. Choose which fields show in list vs card vs form views
|
|
10
|
+
* 4. Framework generates: Firestore queries, forms, lists, cards automatically
|
|
11
|
+
*
|
|
12
|
+
* FIRESTORE PATH: `products/{productId}` (collection name from 'collection' prop)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { defineEntity } from '@donotdev/core';
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// ENTITY DEFINITION
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
export const productEntity = defineEntity({
|
|
22
|
+
// Entity name - used for i18n keys, display labels
|
|
23
|
+
name: 'Product',
|
|
24
|
+
|
|
25
|
+
// Firestore collection path
|
|
26
|
+
collection: 'products',
|
|
27
|
+
|
|
28
|
+
// Fields shown in EntityList table (column order matters)
|
|
29
|
+
listFields: ['name', 'category', 'price', 'status'],
|
|
30
|
+
|
|
31
|
+
// Fields shown in EntityCardList (card layout)
|
|
32
|
+
listCardFields: ['images', 'name', 'price', 'category'],
|
|
33
|
+
|
|
34
|
+
// ==========================================================================
|
|
35
|
+
// ACCESS RULES - Who can do what
|
|
36
|
+
// ==========================================================================
|
|
37
|
+
//
|
|
38
|
+
// 'guest' → Anyone (including not logged in)
|
|
39
|
+
// 'user' → Any logged-in user
|
|
40
|
+
// 'owner' → Only the document owner (createdById matches)
|
|
41
|
+
// 'admin' → Only admin role
|
|
42
|
+
//
|
|
43
|
+
access: {
|
|
44
|
+
create: 'admin', // Only admins can create products
|
|
45
|
+
read: 'guest', // Anyone can view products (public catalog)
|
|
46
|
+
update: 'admin', // Only admins can edit
|
|
47
|
+
delete: 'admin', // Only admins can delete
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// ==========================================================================
|
|
51
|
+
// FIELD DEFINITIONS
|
|
52
|
+
// ==========================================================================
|
|
53
|
+
//
|
|
54
|
+
// FIELD TYPES:
|
|
55
|
+
// 'text' → Single-line text input
|
|
56
|
+
// 'textarea' → Multi-line text
|
|
57
|
+
// 'number' → Numeric input
|
|
58
|
+
// 'email' → Email with validation
|
|
59
|
+
// 'tel' → Phone number with country picker
|
|
60
|
+
// 'select' → Dropdown with options
|
|
61
|
+
// 'combobox' → Searchable dropdown
|
|
62
|
+
// 'switch' → Toggle on/off
|
|
63
|
+
// 'checkbox' → Multiple selections
|
|
64
|
+
// 'date' → Date picker
|
|
65
|
+
// 'timestamp' → Date + time
|
|
66
|
+
// 'images' → Image upload (multiple)
|
|
67
|
+
// 'reference' → Link to another entity
|
|
68
|
+
//
|
|
69
|
+
// VISIBILITY:
|
|
70
|
+
// 'guest' → Everyone can see this field
|
|
71
|
+
// 'user' → Only logged-in users
|
|
72
|
+
// 'owner' → Only document owner
|
|
73
|
+
// 'admin' → Only admins
|
|
74
|
+
//
|
|
75
|
+
// EDITABLE:
|
|
76
|
+
// 'admin' → Only admins can edit
|
|
77
|
+
// 'owner' → Only owner can edit
|
|
78
|
+
// 'create-only' → Set on creation, read-only after
|
|
79
|
+
//
|
|
80
|
+
fields: {
|
|
81
|
+
// ==========================================================================
|
|
82
|
+
// PUBLIC FIELDS - Visible to all, editable by admin
|
|
83
|
+
// ==========================================================================
|
|
84
|
+
|
|
85
|
+
name: {
|
|
86
|
+
name: 'name',
|
|
87
|
+
label: 'name', // i18n key: products.fields.name
|
|
88
|
+
type: 'text',
|
|
89
|
+
visibility: 'guest',
|
|
90
|
+
editable: 'admin',
|
|
91
|
+
validation: { required: true },
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
description: {
|
|
95
|
+
name: 'description',
|
|
96
|
+
label: 'description',
|
|
97
|
+
type: 'textarea',
|
|
98
|
+
visibility: 'guest',
|
|
99
|
+
editable: 'admin',
|
|
100
|
+
validation: { required: false },
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
category: {
|
|
104
|
+
name: 'category',
|
|
105
|
+
label: 'category',
|
|
106
|
+
type: 'select',
|
|
107
|
+
visibility: 'guest',
|
|
108
|
+
editable: 'admin',
|
|
109
|
+
validation: {
|
|
110
|
+
required: true,
|
|
111
|
+
options: [
|
|
112
|
+
{ value: 'electronics', label: 'category.electronics' },
|
|
113
|
+
{ value: 'clothing', label: 'category.clothing' },
|
|
114
|
+
{ value: 'home', label: 'category.home' },
|
|
115
|
+
{ value: 'other', label: 'category.other' },
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
price: {
|
|
121
|
+
name: 'price',
|
|
122
|
+
label: 'price',
|
|
123
|
+
type: 'number',
|
|
124
|
+
visibility: 'guest',
|
|
125
|
+
editable: 'admin',
|
|
126
|
+
validation: { required: true },
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
images: {
|
|
130
|
+
name: 'images',
|
|
131
|
+
label: 'images',
|
|
132
|
+
type: 'images',
|
|
133
|
+
visibility: 'guest',
|
|
134
|
+
editable: 'admin',
|
|
135
|
+
validation: { required: false },
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
// ==========================================================================
|
|
139
|
+
// ADMIN-ONLY FIELDS - Hidden from public, visible to admins
|
|
140
|
+
// ==========================================================================
|
|
141
|
+
|
|
142
|
+
cost: {
|
|
143
|
+
name: 'cost',
|
|
144
|
+
label: 'cost',
|
|
145
|
+
type: 'number',
|
|
146
|
+
visibility: 'admin', // Only admins see this
|
|
147
|
+
editable: 'admin',
|
|
148
|
+
validation: { required: false },
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
supplier: {
|
|
152
|
+
name: 'supplier',
|
|
153
|
+
label: 'supplier',
|
|
154
|
+
type: 'text',
|
|
155
|
+
visibility: 'admin',
|
|
156
|
+
editable: 'admin',
|
|
157
|
+
validation: { required: false },
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// ==========================================================================
|
|
161
|
+
// STATUS FIELD - Framework provides draft/available/deleted by default
|
|
162
|
+
// ==========================================================================
|
|
163
|
+
// Add custom status options that extend framework defaults:
|
|
164
|
+
|
|
165
|
+
status: {
|
|
166
|
+
name: 'status',
|
|
167
|
+
label: 'status',
|
|
168
|
+
type: 'select',
|
|
169
|
+
visibility: 'admin',
|
|
170
|
+
validation: {
|
|
171
|
+
options: [
|
|
172
|
+
// Framework adds: draft, available, deleted
|
|
173
|
+
// Add your custom statuses:
|
|
174
|
+
{ value: 'featured', label: 'status.featured' },
|
|
175
|
+
{ value: 'clearance', label: 'status.clearance' },
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// USAGE EXAMPLES
|
|
184
|
+
// ============================================================================
|
|
185
|
+
//
|
|
186
|
+
// In a List Page:
|
|
187
|
+
// ```tsx
|
|
188
|
+
// import { EntityList } from '@donotdev/crud';
|
|
189
|
+
// import { productEntity } from '../entities/ExampleEntity';
|
|
190
|
+
//
|
|
191
|
+
// export default function ProductsListPage() {
|
|
192
|
+
// return (
|
|
193
|
+
// <PageContainer>
|
|
194
|
+
// <EntityList entity={productEntity} />
|
|
195
|
+
// </PageContainer>
|
|
196
|
+
// );
|
|
197
|
+
// }
|
|
198
|
+
// ```
|
|
199
|
+
//
|
|
200
|
+
// In a Form Page:
|
|
201
|
+
// ```tsx
|
|
202
|
+
// import { EntityFormRenderer, useCrud } from '@donotdev/crud';
|
|
203
|
+
// import { productEntity } from '../entities/ExampleEntity';
|
|
204
|
+
//
|
|
205
|
+
// export default function ProductPage() {
|
|
206
|
+
// const { get, add, update } = useCrud(productEntity);
|
|
207
|
+
// // ... see ExampleFormPage.tsx for full pattern
|
|
208
|
+
// }
|
|
209
|
+
// ```
|
|
210
|
+
//
|
|
211
|
+
// In a Card Grid:
|
|
212
|
+
// ```tsx
|
|
213
|
+
// import { EntityCardList } from '@donotdev/crud';
|
|
214
|
+
// import { productEntity } from '../entities/ExampleEntity';
|
|
215
|
+
//
|
|
216
|
+
// export default function ProductsGridPage() {
|
|
217
|
+
// return (
|
|
218
|
+
// <PageContainer>
|
|
219
|
+
// <EntityCardList entity={productEntity} />
|
|
220
|
+
// </PageContainer>
|
|
221
|
+
// );
|
|
222
|
+
// }
|
|
223
|
+
// ```
|