@meeovi/directus-client 1.0.3 → 1.0.5

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.
@@ -1,4 +1,9 @@
1
1
  import type { DirectusField } from '../schema/types';
2
+ export interface FormEngineOptions {
3
+ clearOnSuccess?: boolean;
4
+ onSuccess?: () => void;
5
+ onError?: (msg: string) => void;
6
+ }
2
7
  export interface GeneratedFormField {
3
8
  key: string;
4
9
  widget: string;
@@ -9,5 +14,23 @@ export interface GeneratedFormField {
9
14
  isFile?: boolean;
10
15
  isRelational?: boolean;
11
16
  }
17
+ /**
18
+ * Convert a Directus field into a UI-ready form field schema.
19
+ */
12
20
  export declare function generateFormField(field: DirectusField): GeneratedFormField;
21
+ /**
22
+ * Convert an entire collection's fields into a form schema.
23
+ */
13
24
  export declare function generateFormSchema(fields: DirectusField[]): GeneratedFormField[];
25
+ /**
26
+ * Framework-agnostic form engine for submitting Directus items.
27
+ */
28
+ export declare function createFormEngine(collectionName: string, fields: DirectusField[], directusClient: any, opts?: FormEngineOptions): {
29
+ form: Record<string, any>;
30
+ submit: () => Promise<{
31
+ error: string | null;
32
+ success: string | null;
33
+ }>;
34
+ readonly error: string | null;
35
+ readonly success: string | null;
36
+ };
@@ -1,4 +1,7 @@
1
1
  import { widgetRegistry } from './widget-registry';
2
+ /**
3
+ * Convert a Directus field into a UI-ready form field schema.
4
+ */
2
5
  export function generateFormField(field) {
3
6
  const widget = widgetRegistry[field.interface || 'input'];
4
7
  const base = {
@@ -10,13 +13,100 @@ export function generateFormField(field) {
10
13
  isFile: widget.isFile,
11
14
  isRelational: widget.isRelational
12
15
  };
13
- if ((field.interface === 'repeater' || field.interface === 'group') && field.options?.fields) {
16
+ // Repeater or group fields contain nested fields
17
+ if ((field.interface === 'repeater' || field.interface === 'group') &&
18
+ Array.isArray(field.options?.fields)) {
14
19
  base.fields = field.options.fields.map((sub) => generateFormField(sub));
15
20
  }
16
21
  return base;
17
22
  }
23
+ /**
24
+ * Convert an entire collection's fields into a form schema.
25
+ */
18
26
  export function generateFormSchema(fields) {
19
27
  return fields
20
28
  .filter(f => f.interface !== 'presentation' && f.interface !== 'divider')
21
29
  .map(generateFormField);
22
30
  }
31
+ /**
32
+ * Framework-agnostic form engine for submitting Directus items.
33
+ */
34
+ export function createFormEngine(collectionName, fields, directusClient, opts) {
35
+ const form = {};
36
+ let error = null;
37
+ let success = null;
38
+ /**
39
+ * Validate a single field using Directus validation metadata.
40
+ */
41
+ const validateField = (field) => {
42
+ if (!field.validation)
43
+ return null;
44
+ try {
45
+ const validation = field.validation;
46
+ if (validation._and) {
47
+ for (const rule of validation._and) {
48
+ const fieldName = Object.keys(rule)[0];
49
+ if (!fieldName)
50
+ continue;
51
+ const ruleDef = rule[fieldName];
52
+ if (ruleDef?._regex) {
53
+ const regex = new RegExp(ruleDef._regex);
54
+ const value = String(form[field.field] ?? '');
55
+ if (!regex.test(value)) {
56
+ return field.validation_message || `${field.field} failed validation`;
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ catch {
63
+ return `Validation error for ${field.field}`;
64
+ }
65
+ return null;
66
+ };
67
+ /**
68
+ * Validate all fields before submission.
69
+ */
70
+ const validate = () => {
71
+ error = null;
72
+ for (const field of fields) {
73
+ const result = validateField(field);
74
+ if (result) {
75
+ error = result;
76
+ opts?.onError?.(result);
77
+ return false;
78
+ }
79
+ }
80
+ return true;
81
+ };
82
+ /**
83
+ * Submit the form to Directus.
84
+ */
85
+ const submit = async () => {
86
+ if (!validate())
87
+ return { error, success };
88
+ const result = await directusClient.request(directusClient.createItem(collectionName, form));
89
+ if (result?.error) {
90
+ error = result.error.message;
91
+ opts?.onError?.(error);
92
+ return { error, success };
93
+ }
94
+ success = `${collectionName} created successfully`;
95
+ if (opts?.clearOnSuccess) {
96
+ for (const key of Object.keys(form))
97
+ delete form[key];
98
+ }
99
+ opts?.onSuccess?.();
100
+ return { error, success };
101
+ };
102
+ return {
103
+ form,
104
+ submit,
105
+ get error() {
106
+ return error;
107
+ },
108
+ get success() {
109
+ return success;
110
+ }
111
+ };
112
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meeovi/directus-client",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
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",
@@ -9,13 +9,13 @@ import {
9
9
  deleteItem,
10
10
  uploadFiles,
11
11
  readSingleton,
12
- readFieldsByCollection,
13
- type DirectusClient
12
+ readFieldsByCollection
14
13
  } from '@directus/sdk';
14
+ import type { RestClient } from '@directus/sdk';
15
15
 
16
16
  export interface MeeoviDirectusClient<Schema> {
17
- client: DirectusClient<Schema>;
18
- request: any;
17
+ client: RestClient<Schema>;
18
+ request: RestClient<Schema>['request'];
19
19
  readItem: typeof readItem;
20
20
  readItems: typeof readItems;
21
21
  createItem: typeof createItem;
@@ -43,4 +43,4 @@ export function createMeeoviDirectusClient<Schema>(url: string): MeeoviDirectusC
43
43
  readSingleton,
44
44
  readFieldsByCollection
45
45
  };
46
- }
46
+ }
@@ -1,11 +1,45 @@
1
1
  import type { DirectusField } from '../schema/types';
2
2
 
3
- export function generateTableSchema(fields: DirectusField[]) {
3
+ export interface TableColumn {
4
+ key: string;
5
+ label: string;
6
+ type: string;
7
+ sortable?: boolean;
8
+ hidden?: boolean;
9
+ }
10
+
11
+ /**
12
+ * Convert Directus fields into a table schema.
13
+ */
14
+ export function generateTableSchema(fields: DirectusField[]): TableColumn[] {
4
15
  return fields
5
- .filter(f => !f.hidden)
6
- .map(f => ({
16
+ .filter((f) => !f.hidden)
17
+ .map((f) => ({
7
18
  key: f.field,
8
- label: f.field.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
9
- type: f.type
19
+ label: prettifyLabel(f.field),
20
+ type: f.type,
21
+ sortable: true,
22
+ hidden: false
10
23
  }));
11
24
  }
25
+
26
+ /**
27
+ * Convert "product_name" → "Product Name"
28
+ */
29
+ function prettifyLabel(str: string): string {
30
+ return str
31
+ .replace(/_/g, ' ')
32
+ .replace(/\b\w/g, (c) => c.toUpperCase());
33
+ }
34
+
35
+ /**
36
+ * Fetch table rows from Directus.
37
+ */
38
+ export async function fetchTableRows(
39
+ directus: any,
40
+ collection: string
41
+ ): Promise<any[]> {
42
+ return await directus.request(
43
+ directus.readItems(collection)
44
+ );
45
+ }