@aphexcms/cms-core 0.1.17 → 0.2.1
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/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +7 -1
- package/dist/api/types.d.ts +2 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/cli/generate-types.js +59 -16
- package/dist/cli/index.js +1 -1
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +0 -1
- package/dist/components/AdminApp.svelte +278 -45
- package/dist/components/AdminApp.svelte.d.ts +2 -0
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentEditor.svelte +60 -13
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/ObjectModal.svelte +15 -4
- package/dist/components/admin/ObjectModal.svelte.d.ts +1 -0
- package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
- package/dist/components/admin/SchemaField.svelte +64 -5
- package/dist/components/admin/SchemaField.svelte.d.ts +1 -0
- package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ArrayField.svelte +72 -17
- package/dist/components/admin/fields/ArrayField.svelte.d.ts +1 -0
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/DateField.svelte +145 -0
- package/dist/components/admin/fields/DateField.svelte.d.ts +14 -0
- package/dist/components/admin/fields/DateField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/DateTimeField.svelte +225 -0
- package/dist/components/admin/fields/DateTimeField.svelte.d.ts +14 -0
- package/dist/components/admin/fields/DateTimeField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/ImageField.svelte +20 -7
- package/dist/components/admin/fields/ImageField.svelte.d.ts +1 -0
- package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ReferenceField.svelte +1 -1
- package/dist/components/admin/fields/SlugField.svelte +1 -3
- package/dist/components/admin/fields/SlugField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/StringField.svelte +156 -12
- package/dist/components/admin/fields/StringField.svelte.d.ts +3 -2
- package/dist/components/admin/fields/StringField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/URLField.svelte +41 -0
- package/dist/components/admin/fields/URLField.svelte.d.ts +14 -0
- package/dist/components/admin/fields/URLField.svelte.d.ts.map +1 -0
- package/dist/components/index.d.ts +0 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +0 -1
- package/dist/db/interfaces/document.d.ts +0 -2
- package/dist/db/interfaces/document.d.ts.map +1 -1
- package/dist/db/interfaces/index.d.ts +2 -1
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/user.d.ts +2 -0
- package/dist/db/interfaces/user.d.ts.map +1 -1
- package/dist/db/utils/reference-resolver.js +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +3 -0
- package/dist/field-validation/date-utils.d.ts +30 -0
- package/dist/field-validation/date-utils.d.ts.map +1 -0
- package/dist/field-validation/date-utils.js +147 -0
- package/dist/field-validation/rule.d.ts +4 -0
- package/dist/field-validation/rule.d.ts.map +1 -1
- package/dist/field-validation/rule.js +170 -4
- package/dist/field-validation/utils.d.ts +7 -3
- package/dist/field-validation/utils.d.ts.map +1 -1
- package/dist/field-validation/utils.js +129 -35
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +38 -21
- package/dist/lib/field-validation/date-utils.js +147 -0
- package/dist/lib/field-validation/rule.js +170 -4
- package/dist/lib/field-validation/utils.js +129 -35
- package/dist/local-api/collection-api.d.ts +16 -4
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +51 -17
- package/dist/local-api/index.d.ts +1 -1
- package/dist/local-api/index.d.ts.map +1 -1
- package/dist/routes/assets-cdn.d.ts.map +1 -1
- package/dist/routes/assets-cdn.js +14 -7
- package/dist/routes/assets.d.ts.map +1 -1
- package/dist/routes/assets.js +6 -1
- package/dist/routes/documents-by-id.d.ts.map +1 -1
- package/dist/routes/documents-by-id.js +18 -7
- package/dist/routes/documents-publish.js +2 -2
- package/dist/routes/documents-query.d.ts +3 -1
- package/dist/routes/documents-query.d.ts.map +1 -1
- package/dist/routes/documents-query.js +6 -2
- package/dist/routes/documents.d.ts.map +1 -1
- package/dist/routes/documents.js +20 -4
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +2 -0
- package/dist/routes/user-preferences.d.ts +4 -0
- package/dist/routes/user-preferences.d.ts.map +1 -0
- package/dist/routes/user-preferences.js +77 -0
- package/dist/schema-utils/utils.d.ts +4 -0
- package/dist/schema-utils/utils.d.ts.map +1 -1
- package/dist/schema-utils/utils.js +23 -2
- package/dist/schema-utils/validator.d.ts +4 -0
- package/dist/schema-utils/validator.d.ts.map +1 -1
- package/dist/schema-utils/validator.js +120 -0
- package/dist/types/filters.d.ts +13 -0
- package/dist/types/filters.d.ts.map +1 -1
- package/dist/types/organization.d.ts +3 -0
- package/dist/types/organization.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +67 -7
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/utils/default-orderings.d.ts +10 -0
- package/dist/utils/default-orderings.d.ts.map +1 -0
- package/dist/utils/default-orderings.js +63 -0
- package/dist/utils/field-defaults.d.ts +8 -0
- package/dist/utils/field-defaults.d.ts.map +1 -0
- package/dist/utils/field-defaults.js +20 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/initial-value-helpers.d.ts +50 -0
- package/dist/utils/initial-value-helpers.d.ts.map +1 -0
- package/dist/utils/initial-value-helpers.js +70 -0
- package/package.json +6 -4
- package/dist/components/admin/DocumentTypesList.svelte +0 -97
- package/dist/components/admin/DocumentTypesList.svelte.d.ts +0 -14
- package/dist/components/admin/DocumentTypesList.svelte.d.ts.map +0 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
4
4
|
import type { SchemaType } from 'src/types/schemas.js';
|
|
5
5
|
import SchemaField from './SchemaField.svelte';
|
|
6
|
+
import { getDefaultValueForFieldType } from '../../utils/field-defaults';
|
|
6
7
|
|
|
7
8
|
interface Props {
|
|
8
9
|
open: boolean;
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
onUpdate?: (value: Record<string, any>) => void; // For real-time updates
|
|
14
15
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
15
16
|
readonly?: boolean;
|
|
17
|
+
organizationId?: string; // For asset uploads to org-specific storage
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
// TODO: add onUpdate to auto save
|
|
@@ -24,7 +26,8 @@
|
|
|
24
26
|
onSave,
|
|
25
27
|
onUpdate,
|
|
26
28
|
onOpenReference,
|
|
27
|
-
readonly = false
|
|
29
|
+
readonly = false,
|
|
30
|
+
organizationId
|
|
28
31
|
}: Props = $props();
|
|
29
32
|
|
|
30
33
|
// Initialize editing data with defaults and existing values
|
|
@@ -33,10 +36,17 @@
|
|
|
33
36
|
|
|
34
37
|
if (schema?.fields) {
|
|
35
38
|
schema.fields.forEach((field) => {
|
|
36
|
-
if (
|
|
37
|
-
|
|
39
|
+
if ('initialValue' in field && field.initialValue !== undefined) {
|
|
40
|
+
// Only use literal initialValue (skip functions to keep this synchronous)
|
|
41
|
+
if (typeof field.initialValue !== 'function') {
|
|
42
|
+
initialData[field.name] = field.initialValue;
|
|
43
|
+
} else {
|
|
44
|
+
// Function-based initialValues are skipped for nested items
|
|
45
|
+
// They will use field type defaults instead
|
|
46
|
+
initialData[field.name] = getDefaultValueForFieldType(field.type);
|
|
47
|
+
}
|
|
38
48
|
} else {
|
|
39
|
-
initialData[field.name] =
|
|
49
|
+
initialData[field.name] = getDefaultValueForFieldType(field.type);
|
|
40
50
|
}
|
|
41
51
|
});
|
|
42
52
|
}
|
|
@@ -116,6 +126,7 @@
|
|
|
116
126
|
}}
|
|
117
127
|
{onOpenReference}
|
|
118
128
|
{readonly}
|
|
129
|
+
{organizationId}
|
|
119
130
|
/>
|
|
120
131
|
{/each}
|
|
121
132
|
{/if}
|
|
@@ -8,6 +8,7 @@ interface Props {
|
|
|
8
8
|
onUpdate?: (value: Record<string, any>) => void;
|
|
9
9
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
10
10
|
readonly?: boolean;
|
|
11
|
+
organizationId?: string;
|
|
11
12
|
}
|
|
12
13
|
declare const ObjectModal: import("svelte").Component<Props, {}, "">;
|
|
13
14
|
type ObjectModal = ReturnType<typeof ObjectModal>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectModal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/ObjectModal.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"ObjectModal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/ObjectModal.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKtD,UAAU,KAAK;IACd,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAChD,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAwHF,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -2,22 +2,33 @@
|
|
|
2
2
|
import { Label } from '@aphexcms/ui/shadcn/label';
|
|
3
3
|
import { Badge } from '@aphexcms/ui/shadcn/badge';
|
|
4
4
|
import * as Alert from '@aphexcms/ui/shadcn/alert';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
Field,
|
|
7
|
+
DateField as DateFieldType,
|
|
8
|
+
DateTimeField as DateTimeFieldType
|
|
9
|
+
} from 'src/types/schemas.js';
|
|
6
10
|
import {
|
|
7
11
|
isFieldRequired,
|
|
8
12
|
validateField,
|
|
9
13
|
getValidationClasses,
|
|
10
14
|
type ValidationError
|
|
11
15
|
} from '../../field-validation/utils';
|
|
16
|
+
import {
|
|
17
|
+
convertDateToUserFormat,
|
|
18
|
+
convertDateTimeToUserFormat
|
|
19
|
+
} from '../../field-validation/date-utils';
|
|
12
20
|
|
|
13
21
|
// Import individual field components
|
|
14
22
|
import StringField from './fields/StringField.svelte';
|
|
15
23
|
import SlugField from './fields/SlugField.svelte';
|
|
24
|
+
import URLField from './fields/URLField.svelte';
|
|
16
25
|
import TextareaField from './fields/TextareaField.svelte';
|
|
17
26
|
import NumberField from './fields/NumberField.svelte';
|
|
18
27
|
import BooleanField from './fields/BooleanField.svelte';
|
|
19
28
|
import ImageField from './fields/ImageField.svelte';
|
|
20
29
|
import ArrayField from './fields/ArrayField.svelte';
|
|
30
|
+
import DateField from './fields/DateField.svelte';
|
|
31
|
+
import DateTimeField from './fields/DateTimeField.svelte';
|
|
21
32
|
import ReferenceField from './fields/ReferenceField.svelte';
|
|
22
33
|
import SchemaField from './SchemaField.svelte';
|
|
23
34
|
|
|
@@ -31,6 +42,7 @@
|
|
|
31
42
|
schemaType?: string; // Document type
|
|
32
43
|
parentPath?: string; // Parent field path for nested fields
|
|
33
44
|
readonly?: boolean; // Read-only mode for viewers
|
|
45
|
+
organizationId?: string; // Document's organization ID for asset uploads
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
let {
|
|
@@ -42,7 +54,8 @@
|
|
|
42
54
|
doValidation,
|
|
43
55
|
schemaType,
|
|
44
56
|
parentPath,
|
|
45
|
-
readonly = false
|
|
57
|
+
readonly = false,
|
|
58
|
+
organizationId
|
|
46
59
|
}: Props = $props();
|
|
47
60
|
|
|
48
61
|
// Build full field path
|
|
@@ -54,9 +67,47 @@
|
|
|
54
67
|
// Real-time validation for wrapper display
|
|
55
68
|
export async function performValidation(currentValue: any, context: any = {}) {
|
|
56
69
|
validationErrors = []; // Clear previous errors
|
|
57
|
-
|
|
70
|
+
|
|
71
|
+
console.log(`[SchemaField.performValidation] Field "${field.name}" type="${field.type}"`, {
|
|
72
|
+
currentValue,
|
|
73
|
+
context
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Convert date/datetime values from ISO to user format for validation
|
|
77
|
+
let valueForValidation = currentValue;
|
|
78
|
+
if (field.type === 'date' && currentValue && typeof currentValue === 'string') {
|
|
79
|
+
const dateField = field as DateFieldType;
|
|
80
|
+
const userFormat = dateField.options?.dateFormat || 'YYYY-MM-DD';
|
|
81
|
+
console.log(`[SchemaField.performValidation] Converting DATE field "${field.name}"`, {
|
|
82
|
+
currentValue,
|
|
83
|
+
userFormat
|
|
84
|
+
});
|
|
85
|
+
valueForValidation = convertDateToUserFormat(currentValue, userFormat);
|
|
86
|
+
console.log(`[SchemaField.performValidation] DATE converted`, {
|
|
87
|
+
valueForValidation
|
|
88
|
+
});
|
|
89
|
+
} else if (field.type === 'datetime' && currentValue && typeof currentValue === 'string') {
|
|
90
|
+
const dateTimeField = field as DateTimeFieldType;
|
|
91
|
+
const dateFormat = dateTimeField.options?.dateFormat || 'YYYY-MM-DD';
|
|
92
|
+
const timeFormat = dateTimeField.options?.timeFormat || 'HH:mm';
|
|
93
|
+
console.log(`[SchemaField.performValidation] Converting DATETIME field "${field.name}"`, {
|
|
94
|
+
currentValue,
|
|
95
|
+
dateFormat,
|
|
96
|
+
timeFormat
|
|
97
|
+
});
|
|
98
|
+
valueForValidation = convertDateTimeToUserFormat(currentValue, dateFormat, timeFormat);
|
|
99
|
+
console.log(`[SchemaField.performValidation] DATETIME converted`, {
|
|
100
|
+
valueForValidation
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const result = await validateField(field, valueForValidation, context);
|
|
105
|
+
console.log(`[SchemaField.performValidation] Validation result for "${field.name}"`, {
|
|
106
|
+
errors: result.errors
|
|
107
|
+
});
|
|
58
108
|
validationErrors = result.errors;
|
|
59
109
|
}
|
|
110
|
+
|
|
60
111
|
// Computed values
|
|
61
112
|
const hasErrors = $derived(validationErrors.filter((e) => e.level === 'error').length > 0);
|
|
62
113
|
const validationClasses = $derived(getValidationClasses(hasErrors));
|
|
@@ -109,15 +160,21 @@
|
|
|
109
160
|
|
|
110
161
|
<!-- Field type routing to individual components -->
|
|
111
162
|
{#if field.type === 'string'}
|
|
112
|
-
<StringField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
163
|
+
<StringField {field} {value} {documentData} {onUpdate} {validationClasses} {readonly} />
|
|
113
164
|
{:else if field.type === 'text'}
|
|
114
165
|
<TextareaField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
115
166
|
{:else if field.type === 'slug'}
|
|
116
167
|
<SlugField {field} {value} {documentData} {onUpdate} {validationClasses} {readonly} />
|
|
168
|
+
{:else if field.type === 'url'}
|
|
169
|
+
<URLField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
117
170
|
{:else if field.type === 'number'}
|
|
118
171
|
<NumberField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
119
172
|
{:else if field.type === 'boolean'}
|
|
120
173
|
<BooleanField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
174
|
+
{:else if field.type === 'date'}
|
|
175
|
+
<DateField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
176
|
+
{:else if field.type === 'datetime'}
|
|
177
|
+
<DateTimeField {field} {value} {onUpdate} {validationClasses} {readonly} />
|
|
121
178
|
|
|
122
179
|
<!-- Image Field -->
|
|
123
180
|
{:else if field.type === 'image'}
|
|
@@ -129,6 +186,7 @@
|
|
|
129
186
|
{schemaType}
|
|
130
187
|
{fieldPath}
|
|
131
188
|
{readonly}
|
|
189
|
+
{organizationId}
|
|
132
190
|
/>
|
|
133
191
|
|
|
134
192
|
<!-- Object Field -->
|
|
@@ -145,13 +203,14 @@
|
|
|
145
203
|
{schemaType}
|
|
146
204
|
parentPath={fieldPath}
|
|
147
205
|
{readonly}
|
|
206
|
+
{organizationId}
|
|
148
207
|
/>
|
|
149
208
|
{/each}
|
|
150
209
|
</div>
|
|
151
210
|
|
|
152
211
|
<!-- Array Field -->
|
|
153
212
|
{:else if field.type === 'array' && field.of}
|
|
154
|
-
<ArrayField {field} {value} {onUpdate} {onOpenReference} {readonly} />
|
|
213
|
+
<ArrayField {field} {value} {onUpdate} {onOpenReference} {readonly} {organizationId} />
|
|
155
214
|
|
|
156
215
|
<!-- Reference Field -->
|
|
157
216
|
{:else if field.type === 'reference' && field.to}
|
|
@@ -10,6 +10,7 @@ interface Props {
|
|
|
10
10
|
schemaType?: string;
|
|
11
11
|
parentPath?: string;
|
|
12
12
|
readonly?: boolean;
|
|
13
|
+
organizationId?: string;
|
|
13
14
|
}
|
|
14
15
|
declare const SchemaField: import("svelte").Component<Props, {
|
|
15
16
|
performValidation: (currentValue: any, context?: any) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaField.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/SchemaField.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"SchemaField.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/SchemaField.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,KAAK,EAGL,MAAM,sBAAsB,CAAC;AAuB/B,OAAO,WAAW,MAAM,sBAAsB,CAAC;AAG9C,UAAU,KAAK;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AA6LF,QAAA,MAAM,WAAW;sCAjJgC,GAAG,YAAW,GAAG;MAiJT,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { getSchemaContext } from '../../../schema-context.svelte';
|
|
11
11
|
import ObjectModal from '../ObjectModal.svelte';
|
|
12
12
|
import ImageField from './ImageField.svelte';
|
|
13
|
+
import { getDefaultValueForFieldType } from '../../../utils/field-defaults';
|
|
13
14
|
|
|
14
15
|
interface Props {
|
|
15
16
|
field: ArrayFieldType;
|
|
@@ -17,17 +18,51 @@
|
|
|
17
18
|
onUpdate: (value: any) => void;
|
|
18
19
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
19
20
|
readonly?: boolean;
|
|
21
|
+
organizationId?: string; // For asset uploads to org-specific storage
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
let {
|
|
24
|
+
let {
|
|
25
|
+
field,
|
|
26
|
+
value,
|
|
27
|
+
onUpdate,
|
|
28
|
+
onOpenReference,
|
|
29
|
+
readonly = false,
|
|
30
|
+
organizationId
|
|
31
|
+
}: Props = $props();
|
|
23
32
|
|
|
24
33
|
// Get schemas from context
|
|
25
34
|
const schemas = getSchemaContext();
|
|
26
35
|
|
|
36
|
+
// Get schema for a type - either from inline definition or registry
|
|
37
|
+
function getSchemaForType(typeName: string): SchemaType | null {
|
|
38
|
+
// First check if this type has an inline definition in field.of
|
|
39
|
+
// Match by name OR type (since inline objects might use either)
|
|
40
|
+
const inlineDef = field.of?.find(
|
|
41
|
+
(ref) => (ref.name && ref.name === typeName) || ref.type === typeName
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (inlineDef && inlineDef.fields) {
|
|
45
|
+
// Create a temporary SchemaType from inline definition
|
|
46
|
+
return {
|
|
47
|
+
type: 'object',
|
|
48
|
+
name: inlineDef.name || typeName,
|
|
49
|
+
title: inlineDef.title || typeName,
|
|
50
|
+
fields: inlineDef.fields
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Otherwise look it up in the schema registry
|
|
55
|
+
return getSchemaByName(schemas, typeName);
|
|
56
|
+
}
|
|
57
|
+
|
|
27
58
|
// Determine if this is a primitive array or object array
|
|
28
|
-
// If the type is not found in schemas, it's a primitive type
|
|
59
|
+
// If the type is not found in schemas AND has no inline fields, it's a primitive type
|
|
29
60
|
const isPrimitiveArray = $derived(
|
|
30
|
-
field.of &&
|
|
61
|
+
field.of &&
|
|
62
|
+
field.of.length > 0 &&
|
|
63
|
+
field.of[0]?.type &&
|
|
64
|
+
!field.of[0].fields && // Not an inline object
|
|
65
|
+
!getSchemaByName(schemas, field.of[0].type) // Not in registry
|
|
31
66
|
);
|
|
32
67
|
const primitiveType = $derived(isPrimitiveArray ? field.of?.[0]?.type : null);
|
|
33
68
|
|
|
@@ -93,8 +128,8 @@
|
|
|
93
128
|
function handleTypeSelected(selectedType: string) {
|
|
94
129
|
if (readonly || !selectedType) return;
|
|
95
130
|
|
|
96
|
-
// Get the schema for the selected type
|
|
97
|
-
const schema =
|
|
131
|
+
// Get the schema for the selected type (inline or from registry)
|
|
132
|
+
const schema = getSchemaForType(selectedType);
|
|
98
133
|
if (!schema) return;
|
|
99
134
|
|
|
100
135
|
// Initialize empty object with default values
|
|
@@ -102,10 +137,17 @@
|
|
|
102
137
|
|
|
103
138
|
if (schema.fields) {
|
|
104
139
|
schema.fields.forEach((field) => {
|
|
105
|
-
if (
|
|
106
|
-
|
|
140
|
+
if ('initialValue' in field && field.initialValue !== undefined) {
|
|
141
|
+
// Only use literal initialValue (skip functions to keep this synchronous)
|
|
142
|
+
if (typeof field.initialValue !== 'function') {
|
|
143
|
+
newItem[field.name] = field.initialValue;
|
|
144
|
+
} else {
|
|
145
|
+
// Function-based initialValues are skipped for nested items
|
|
146
|
+
// They will use field type defaults instead
|
|
147
|
+
newItem[field.name] = getDefaultValueForFieldType(field.type);
|
|
148
|
+
}
|
|
107
149
|
} else {
|
|
108
|
-
newItem[field.name] =
|
|
150
|
+
newItem[field.name] = getDefaultValueForFieldType(field.type);
|
|
109
151
|
}
|
|
110
152
|
});
|
|
111
153
|
}
|
|
@@ -122,7 +164,7 @@
|
|
|
122
164
|
const item = arrayValue[index];
|
|
123
165
|
if (!item._type) return;
|
|
124
166
|
|
|
125
|
-
const schema =
|
|
167
|
+
const schema = getSchemaForType(item._type);
|
|
126
168
|
if (!schema) return;
|
|
127
169
|
|
|
128
170
|
editingIndex = index;
|
|
@@ -197,7 +239,9 @@
|
|
|
197
239
|
<!-- Primitive array UI -->
|
|
198
240
|
{#if arrayValue.length === 0}
|
|
199
241
|
<!-- Empty state -->
|
|
200
|
-
<div
|
|
242
|
+
<div
|
|
243
|
+
class="border-border/50 bg-muted/30 flex items-center justify-center rounded border border-dashed p-6"
|
|
244
|
+
>
|
|
201
245
|
<p class="text-muted-foreground text-sm">No items</p>
|
|
202
246
|
</div>
|
|
203
247
|
{:else}
|
|
@@ -225,6 +269,7 @@
|
|
|
225
269
|
}}
|
|
226
270
|
{readonly}
|
|
227
271
|
compact={true}
|
|
272
|
+
{organizationId}
|
|
228
273
|
/>
|
|
229
274
|
{:else}
|
|
230
275
|
<!-- Always-editable primitive with options menu -->
|
|
@@ -243,7 +288,7 @@
|
|
|
243
288
|
<Textarea
|
|
244
289
|
value={item}
|
|
245
290
|
oninput={(e) => handleUpdatePrimitive(index, e.currentTarget.value)}
|
|
246
|
-
|
|
291
|
+
{readonly}
|
|
247
292
|
class="flex-1"
|
|
248
293
|
rows={3}
|
|
249
294
|
placeholder="Enter text..."
|
|
@@ -252,8 +297,9 @@
|
|
|
252
297
|
<Input
|
|
253
298
|
type="number"
|
|
254
299
|
value={item}
|
|
255
|
-
oninput={(e) =>
|
|
256
|
-
|
|
300
|
+
oninput={(e) =>
|
|
301
|
+
handleUpdatePrimitive(index, parseFloat(e.currentTarget.value) || 0)}
|
|
302
|
+
{readonly}
|
|
257
303
|
class="flex-1"
|
|
258
304
|
placeholder="Enter number..."
|
|
259
305
|
/>
|
|
@@ -261,7 +307,7 @@
|
|
|
261
307
|
<Input
|
|
262
308
|
value={item}
|
|
263
309
|
oninput={(e) => handleUpdatePrimitive(index, e.currentTarget.value)}
|
|
264
|
-
|
|
310
|
+
{readonly}
|
|
265
311
|
class="flex-1"
|
|
266
312
|
placeholder="Enter value..."
|
|
267
313
|
/>
|
|
@@ -282,7 +328,12 @@
|
|
|
282
328
|
</DropdownMenu.Trigger>
|
|
283
329
|
<DropdownMenu.Content align="end">
|
|
284
330
|
<DropdownMenu.Item onclick={() => handleRemoveItem(index)}>
|
|
285
|
-
<svg
|
|
331
|
+
<svg
|
|
332
|
+
class="mr-2 h-4 w-4"
|
|
333
|
+
fill="none"
|
|
334
|
+
viewBox="0 0 24 24"
|
|
335
|
+
stroke="currentColor"
|
|
336
|
+
>
|
|
286
337
|
<path
|
|
287
338
|
stroke-linecap="round"
|
|
288
339
|
stroke-linejoin="round"
|
|
@@ -319,7 +370,9 @@
|
|
|
319
370
|
<!-- Object array UI (existing code) -->
|
|
320
371
|
{#if arrayValue.length === 0}
|
|
321
372
|
<!-- Empty state -->
|
|
322
|
-
<div
|
|
373
|
+
<div
|
|
374
|
+
class="border-border/50 bg-muted/30 flex items-center justify-center rounded border border-dashed p-6"
|
|
375
|
+
>
|
|
323
376
|
<p class="text-muted-foreground text-sm">No items</p>
|
|
324
377
|
</div>
|
|
325
378
|
{:else}
|
|
@@ -449,13 +502,14 @@
|
|
|
449
502
|
onSave={handleModalSave}
|
|
450
503
|
{onOpenReference}
|
|
451
504
|
{readonly}
|
|
505
|
+
{organizationId}
|
|
452
506
|
/>
|
|
453
507
|
{/if}
|
|
454
508
|
|
|
455
509
|
<!-- Image upload modal -->
|
|
456
510
|
{#if imageModalOpen}
|
|
457
511
|
<div
|
|
458
|
-
class="bg-background/80 fixed bottom-0 left-0 right-0 top-12 z-[100] flex items-center justify-center p-6
|
|
512
|
+
class="bg-background/80 backdrop-blur-xs fixed bottom-0 left-0 right-0 top-12 z-[100] flex items-center justify-center p-6 sm:absolute sm:top-0 sm:p-4"
|
|
459
513
|
onclick={(e) => {
|
|
460
514
|
if (e.target === e.currentTarget) handleImageModalClose();
|
|
461
515
|
}}
|
|
@@ -495,6 +549,7 @@
|
|
|
495
549
|
}}
|
|
496
550
|
value={imageModalValue}
|
|
497
551
|
onUpdate={handleImageUpload}
|
|
552
|
+
{organizationId}
|
|
498
553
|
/>
|
|
499
554
|
</Card.Content>
|
|
500
555
|
</Card.Root>
|
|
@@ -5,6 +5,7 @@ interface Props {
|
|
|
5
5
|
onUpdate: (value: any) => void;
|
|
6
6
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
7
7
|
readonly?: boolean;
|
|
8
|
+
organizationId?: string;
|
|
8
9
|
}
|
|
9
10
|
declare const ArrayField: import("svelte").Component<Props, {}, "">;
|
|
10
11
|
type ArrayField = ReturnType<typeof ArrayField>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrayField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ArrayField.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAc,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"ArrayField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ArrayField.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAc,MAAM,wBAAwB,CAAC;AAQtF,UAAU,KAAK;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAobF,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CalendarIcon from '@lucide/svelte/icons/calendar';
|
|
3
|
+
import { type DateValue, parseDate } from '@internationalized/date';
|
|
4
|
+
import { Input } from '@aphexcms/ui/shadcn/input';
|
|
5
|
+
import { Calendar } from '@aphexcms/ui/shadcn/calendar';
|
|
6
|
+
import * as Popover from '@aphexcms/ui/shadcn/popover';
|
|
7
|
+
import type { DateField } from '../../../types/schemas';
|
|
8
|
+
import dayjs from 'dayjs';
|
|
9
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
10
|
+
|
|
11
|
+
// Enable strict parsing
|
|
12
|
+
dayjs.extend(customParseFormat);
|
|
13
|
+
|
|
14
|
+
interface Props {
|
|
15
|
+
field: DateField;
|
|
16
|
+
value: string | null; // Always stored as ISO YYYY-MM-DD
|
|
17
|
+
onUpdate: (value: string | null) => void;
|
|
18
|
+
validationClasses?: string;
|
|
19
|
+
onBlur?: (event: any) => void;
|
|
20
|
+
onFocus?: (event: any) => void;
|
|
21
|
+
readonly?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
field,
|
|
26
|
+
value,
|
|
27
|
+
onUpdate,
|
|
28
|
+
validationClasses,
|
|
29
|
+
onBlur,
|
|
30
|
+
onFocus,
|
|
31
|
+
readonly = false
|
|
32
|
+
}: Props = $props();
|
|
33
|
+
|
|
34
|
+
// Get date format from options or use default
|
|
35
|
+
const dateFormat = $derived(field.options?.dateFormat || 'YYYY-MM-DD');
|
|
36
|
+
|
|
37
|
+
// Track local input value for display
|
|
38
|
+
let inputValue = $state('');
|
|
39
|
+
|
|
40
|
+
// Convert stored ISO value to display format
|
|
41
|
+
// Only update if the formatted value is different to avoid overwriting user input
|
|
42
|
+
$effect(() => {
|
|
43
|
+
if (!value || value === '') {
|
|
44
|
+
if (inputValue !== '') {
|
|
45
|
+
inputValue = '';
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// Convert ISO (YYYY-MM-DD) to display format
|
|
49
|
+
const date = dayjs(value, 'YYYY-MM-DD', true);
|
|
50
|
+
if (date.isValid()) {
|
|
51
|
+
const formatted = date.format(dateFormat);
|
|
52
|
+
// Only update if different to avoid overwriting user's in-progress typing
|
|
53
|
+
if (inputValue !== formatted) {
|
|
54
|
+
inputValue = formatted;
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
// Value is not ISO (might be user's in-progress input or invalid)
|
|
58
|
+
if (inputValue !== value) {
|
|
59
|
+
inputValue = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Convert string value to DateValue for calendar
|
|
66
|
+
const dateValue = $derived.by(() => {
|
|
67
|
+
if (!value || value === '') return undefined;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
// Value is stored as ISO date string (YYYY-MM-DD)
|
|
71
|
+
return parseDate(value);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.error('Failed to parse date:', value, err);
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Handle date selection from calendar
|
|
79
|
+
function handleDateChange(newValue: DateValue | undefined) {
|
|
80
|
+
if (!newValue) {
|
|
81
|
+
onUpdate(null);
|
|
82
|
+
} else {
|
|
83
|
+
// Convert DateValue to ISO string (YYYY-MM-DD) for storage
|
|
84
|
+
const isoString = newValue.toString();
|
|
85
|
+
onUpdate(isoString);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Handle manual input changes
|
|
90
|
+
function handleInputChange(event: Event) {
|
|
91
|
+
const target = event.target as HTMLInputElement;
|
|
92
|
+
const displayValue = target.value;
|
|
93
|
+
inputValue = displayValue;
|
|
94
|
+
|
|
95
|
+
if (displayValue === '') {
|
|
96
|
+
onUpdate(null);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Parse according to the chosen format
|
|
101
|
+
const parsed = dayjs(displayValue, dateFormat, true);
|
|
102
|
+
|
|
103
|
+
if (parsed.isValid()) {
|
|
104
|
+
// Convert to ISO for storage
|
|
105
|
+
const isoString = parsed.format('YYYY-MM-DD');
|
|
106
|
+
onUpdate(isoString);
|
|
107
|
+
} else {
|
|
108
|
+
// Still update with the invalid value so autosave triggers
|
|
109
|
+
// Validation will catch the error
|
|
110
|
+
onUpdate(displayValue);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<div class="space-y-2">
|
|
116
|
+
<div class="flex w-full gap-2">
|
|
117
|
+
<Input
|
|
118
|
+
id={field.name}
|
|
119
|
+
type="text"
|
|
120
|
+
placeholder={dateFormat}
|
|
121
|
+
value={inputValue}
|
|
122
|
+
oninput={handleInputChange}
|
|
123
|
+
onblur={onBlur}
|
|
124
|
+
onfocus={onFocus}
|
|
125
|
+
class="flex-1 {validationClasses}"
|
|
126
|
+
disabled={readonly}
|
|
127
|
+
/>
|
|
128
|
+
<Popover.Root>
|
|
129
|
+
<Popover.Trigger
|
|
130
|
+
class="border-input bg-background ring-offset-background hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring inline-flex h-10 w-10 items-center justify-center whitespace-nowrap rounded-md border text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
|
131
|
+
disabled={readonly}
|
|
132
|
+
>
|
|
133
|
+
<CalendarIcon class="h-4 w-4" />
|
|
134
|
+
</Popover.Trigger>
|
|
135
|
+
<Popover.Content class="w-auto p-0">
|
|
136
|
+
<Calendar
|
|
137
|
+
type="single"
|
|
138
|
+
value={dateValue}
|
|
139
|
+
onValueChange={handleDateChange}
|
|
140
|
+
captionLayout="dropdown"
|
|
141
|
+
/>
|
|
142
|
+
</Popover.Content>
|
|
143
|
+
</Popover.Root>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DateField } from '../../../types/schemas.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
field: DateField;
|
|
4
|
+
value: string | null;
|
|
5
|
+
onUpdate: (value: string | null) => void;
|
|
6
|
+
validationClasses?: string;
|
|
7
|
+
onBlur?: (event: any) => void;
|
|
8
|
+
onFocus?: (event: any) => void;
|
|
9
|
+
readonly?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const DateField: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type DateField = ReturnType<typeof DateField>;
|
|
13
|
+
export default DateField;
|
|
14
|
+
//# sourceMappingURL=DateField.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/DateField.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKvD,UAAU,KAAK;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AA0HF,QAAA,MAAM,SAAS,2CAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|