@meeovi/directus-client 1.0.2 → 1.0.3
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/package.json +1 -1
- package/src/generators/form-engine.ts +123 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meeovi/directus-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Directus Client Library with auto generating forms and tables, Directus SDK and Types, and vue/react components for Directus Visual Editing.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { DirectusField } from '../schema/types';
|
|
2
2
|
import { widgetRegistry } from './widget-registry';
|
|
3
3
|
|
|
4
|
+
export interface FormEngineOptions {
|
|
5
|
+
clearOnSuccess?: boolean;
|
|
6
|
+
onSuccess?: () => void;
|
|
7
|
+
onError?: (msg: string) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
export interface GeneratedFormField {
|
|
5
11
|
key: string;
|
|
6
12
|
widget: string;
|
|
@@ -12,6 +18,9 @@ export interface GeneratedFormField {
|
|
|
12
18
|
isRelational?: boolean;
|
|
13
19
|
}
|
|
14
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Convert a Directus field into a UI-ready form field schema.
|
|
23
|
+
*/
|
|
15
24
|
export function generateFormField(field: DirectusField): GeneratedFormField {
|
|
16
25
|
const widget = widgetRegistry[field.interface || 'input'];
|
|
17
26
|
|
|
@@ -25,15 +34,127 @@ export function generateFormField(field: DirectusField): GeneratedFormField {
|
|
|
25
34
|
isRelational: widget.isRelational
|
|
26
35
|
};
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
// Repeater or group fields contain nested fields
|
|
38
|
+
if (
|
|
39
|
+
(field.interface === 'repeater' || field.interface === 'group') &&
|
|
40
|
+
Array.isArray(field.options?.fields)
|
|
41
|
+
) {
|
|
42
|
+
base.fields = field.options.fields.map((sub: any) =>
|
|
43
|
+
generateFormField(sub)
|
|
44
|
+
);
|
|
30
45
|
}
|
|
31
46
|
|
|
32
47
|
return base;
|
|
33
48
|
}
|
|
34
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Convert an entire collection's fields into a form schema.
|
|
52
|
+
*/
|
|
35
53
|
export function generateFormSchema(fields: DirectusField[]): GeneratedFormField[] {
|
|
36
54
|
return fields
|
|
37
55
|
.filter(f => f.interface !== 'presentation' && f.interface !== 'divider')
|
|
38
56
|
.map(generateFormField);
|
|
39
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Framework-agnostic form engine for submitting Directus items.
|
|
61
|
+
*/
|
|
62
|
+
export function createFormEngine(
|
|
63
|
+
collectionName: string,
|
|
64
|
+
fields: DirectusField[],
|
|
65
|
+
directusClient: any,
|
|
66
|
+
opts?: FormEngineOptions
|
|
67
|
+
) {
|
|
68
|
+
const form: Record<string, any> = {};
|
|
69
|
+
let error: string | null = null;
|
|
70
|
+
let success: string | null = null;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Validate a single field using Directus validation metadata.
|
|
74
|
+
*/
|
|
75
|
+
const validateField = (field: DirectusField): string | null => {
|
|
76
|
+
if (!field.validation) return null;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const validation = field.validation;
|
|
80
|
+
|
|
81
|
+
if (validation._and) {
|
|
82
|
+
for (const rule of validation._and) {
|
|
83
|
+
const fieldName = Object.keys(rule)[0];
|
|
84
|
+
if (!fieldName) continue;
|
|
85
|
+
|
|
86
|
+
const ruleDef = (rule as any)[fieldName];
|
|
87
|
+
|
|
88
|
+
if (ruleDef?._regex) {
|
|
89
|
+
const regex = new RegExp(ruleDef._regex);
|
|
90
|
+
const value = String(form[field.field] ?? '');
|
|
91
|
+
|
|
92
|
+
if (!regex.test(value)) {
|
|
93
|
+
return field.validation_message || `${field.field} failed validation`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
return `Validation error for ${field.field}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return null;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Validate all fields before submission.
|
|
107
|
+
*/
|
|
108
|
+
const validate = () => {
|
|
109
|
+
error = null;
|
|
110
|
+
|
|
111
|
+
for (const field of fields) {
|
|
112
|
+
const result = validateField(field);
|
|
113
|
+
if (result) {
|
|
114
|
+
error = result;
|
|
115
|
+
opts?.onError?.(result);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return true;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Submit the form to Directus.
|
|
125
|
+
*/
|
|
126
|
+
const submit = async () => {
|
|
127
|
+
if (!validate()) return { error, success };
|
|
128
|
+
|
|
129
|
+
const result = await directusClient.request(
|
|
130
|
+
directusClient.createItem(collectionName, form)
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
if (result?.error) {
|
|
134
|
+
error = result.error.message;
|
|
135
|
+
opts?.onError?.(error as any);
|
|
136
|
+
return { error, success };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
success = `${collectionName} created successfully`;
|
|
140
|
+
|
|
141
|
+
if (opts?.clearOnSuccess) {
|
|
142
|
+
for (const key of Object.keys(form)) delete form[key];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
opts?.onSuccess?.();
|
|
146
|
+
|
|
147
|
+
return { error, success };
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
form,
|
|
152
|
+
submit,
|
|
153
|
+
get error() {
|
|
154
|
+
return error;
|
|
155
|
+
},
|
|
156
|
+
get success() {
|
|
157
|
+
return success;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|