@lobb-js/studio 0.48.0 → 0.49.0
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/components/detailView/detailView.svelte +12 -62
- package/dist/components/detailView/detailView.svelte.d.ts +1 -1
- package/dist/components/detailView/fieldInput.svelte +161 -288
- package/dist/components/detailView/fieldInput.svelte.d.ts +1 -1
- package/dist/components/detailView/fields/BoolField.svelte +42 -0
- package/dist/components/detailView/fields/BoolField.svelte.d.ts +13 -0
- package/dist/components/detailView/fields/CodeField.svelte +30 -0
- package/dist/components/detailView/fields/CodeField.svelte.d.ts +13 -0
- package/dist/components/detailView/fields/CustomInputField.svelte +50 -0
- package/dist/components/detailView/fields/CustomInputField.svelte.d.ts +18 -0
- package/dist/components/detailView/fields/DateField.svelte +47 -0
- package/dist/components/detailView/fields/DateField.svelte.d.ts +14 -0
- package/dist/components/detailView/fields/EmbeddedField.svelte +139 -0
- package/dist/components/detailView/fields/EmbeddedField.svelte.d.ts +13 -0
- package/dist/components/detailView/fields/EmbeddedPolymorphicField.svelte +197 -0
- package/dist/components/detailView/fields/EmbeddedPolymorphicField.svelte.d.ts +13 -0
- package/dist/components/detailView/fields/EnumField.svelte +70 -0
- package/dist/components/detailView/fields/EnumField.svelte.d.ts +17 -0
- package/dist/components/detailView/fields/FieldWrapper.svelte +68 -0
- package/dist/components/detailView/fields/FieldWrapper.svelte.d.ts +18 -0
- package/dist/components/detailView/fields/ForeignKeyField.svelte +78 -0
- package/dist/components/detailView/fields/ForeignKeyField.svelte.d.ts +17 -0
- package/dist/components/detailView/fields/IdField.svelte +21 -0
- package/dist/components/detailView/fields/IdField.svelte.d.ts +12 -0
- package/dist/components/detailView/fields/NumberField.svelte +38 -0
- package/dist/components/detailView/fields/NumberField.svelte.d.ts +16 -0
- package/dist/components/detailView/fields/PasswordField.svelte +29 -0
- package/dist/components/detailView/fields/PasswordField.svelte.d.ts +12 -0
- package/dist/components/detailView/fields/PolymorphicField.svelte +51 -0
- package/dist/components/detailView/fields/PolymorphicField.svelte.d.ts +16 -0
- package/dist/components/detailView/fields/RichTextField.svelte +30 -0
- package/dist/components/detailView/fields/RichTextField.svelte.d.ts +13 -0
- package/dist/components/detailView/fields/StringField.svelte +35 -0
- package/dist/components/detailView/fields/StringField.svelte.d.ts +14 -0
- package/dist/components/detailView/fields/TextField.svelte +35 -0
- package/dist/components/detailView/fields/TextField.svelte.d.ts +14 -0
- package/dist/components/foreingKeyInput.svelte +1 -1
- package/dist/components/polymorphicInput.svelte +1 -1
- package/dist/extensions/extension.types.d.ts +3 -1
- package/dist/extensions/extensionUtils.js +2 -0
- package/package.json +7 -6
- package/src/lib/components/detailView/detailView.svelte +12 -62
- package/src/lib/components/detailView/fieldInput.svelte +161 -288
- package/src/lib/components/detailView/fields/BoolField.svelte +42 -0
- package/src/lib/components/detailView/fields/CodeField.svelte +30 -0
- package/src/lib/components/detailView/fields/CustomInputField.svelte +50 -0
- package/src/lib/components/detailView/fields/DateField.svelte +47 -0
- package/src/lib/components/detailView/fields/EmbeddedField.svelte +139 -0
- package/src/lib/components/detailView/fields/EmbeddedPolymorphicField.svelte +197 -0
- package/src/lib/components/detailView/fields/EnumField.svelte +70 -0
- package/src/lib/components/detailView/fields/FieldWrapper.svelte +68 -0
- package/src/lib/components/detailView/fields/ForeignKeyField.svelte +78 -0
- package/src/lib/components/detailView/fields/IdField.svelte +21 -0
- package/src/lib/components/detailView/fields/NumberField.svelte +38 -0
- package/src/lib/components/detailView/fields/PasswordField.svelte +29 -0
- package/src/lib/components/detailView/fields/PolymorphicField.svelte +51 -0
- package/src/lib/components/detailView/fields/RichTextField.svelte +30 -0
- package/src/lib/components/detailView/fields/StringField.svelte +35 -0
- package/src/lib/components/detailView/fields/TextField.svelte +35 -0
- package/src/lib/components/foreingKeyInput.svelte +1 -1
- package/src/lib/components/polymorphicInput.svelte +1 -1
- package/src/lib/extensions/extension.types.ts +2 -1
- package/src/lib/extensions/extensionUtils.ts +2 -0
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { CircleHelp } from "lucide-svelte";
|
|
3
|
-
import * as Tooltip from "../ui/tooltip";
|
|
4
2
|
import { getStudioContext } from "../../context";
|
|
5
|
-
import ExtensionsComponents from "../extensionsComponents.svelte";
|
|
6
|
-
import { getExtensionUtils } from "../../extensions/extensionUtils";
|
|
7
|
-
import { getField, getFieldIcon } from "../dataTable/utils";
|
|
8
3
|
import FieldInput from "./fieldInput.svelte";
|
|
9
|
-
import { getFieldTypeLabel } from "../../utils";
|
|
10
4
|
|
|
11
5
|
interface Props {
|
|
12
6
|
collectionName: string;
|
|
13
7
|
entry: Record<string, any>;
|
|
14
|
-
fieldsErrors?: Record<string,
|
|
8
|
+
fieldsErrors?: Record<string, any>;
|
|
15
9
|
changedFields?: string[];
|
|
16
10
|
}
|
|
17
11
|
|
|
@@ -22,9 +16,7 @@
|
|
|
22
16
|
changedFields = [],
|
|
23
17
|
}: Props = $props();
|
|
24
18
|
|
|
25
|
-
const {
|
|
26
|
-
// Singleton collections only ever have one row, and `id` is auto-
|
|
27
|
-
// generated for that row — there's no value to showing it in the form.
|
|
19
|
+
const { ctx } = getStudioContext();
|
|
28
20
|
const fieldNames = $derived(
|
|
29
21
|
Object.keys(ctx.meta.collections[collectionName].fields).filter(
|
|
30
22
|
(fieldName) =>
|
|
@@ -35,58 +27,16 @@
|
|
|
35
27
|
|
|
36
28
|
<div class="grid grid-cols-2 gap-4 p-4">
|
|
37
29
|
{#each fieldNames as fieldName}
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
name="detailView.field.label"
|
|
49
|
-
utils={getExtensionUtils(lobb, ctx)}
|
|
50
|
-
{collectionName}
|
|
51
|
-
{fieldName}
|
|
52
|
-
bind:value={entry[fieldName]}
|
|
53
|
-
>
|
|
54
|
-
<div class="flex items-center gap-1.5">
|
|
55
|
-
<div class="h-fit">{field.label}</div>
|
|
56
|
-
<div class="flex h-fit items-center gap-1 text-[0.7rem] text-muted-foreground">
|
|
57
|
-
<FieldIcon size="12" />
|
|
58
|
-
{getFieldTypeLabel(field.type)}
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
</ExtensionsComponents>
|
|
62
|
-
{#if description}
|
|
63
|
-
<Tooltip.Root>
|
|
64
|
-
<Tooltip.Trigger>
|
|
65
|
-
<CircleHelp size="12" class="text-muted-foreground" />
|
|
66
|
-
</Tooltip.Trigger>
|
|
67
|
-
<Tooltip.Content class="max-w-64 text-xs">
|
|
68
|
-
{description}
|
|
69
|
-
</Tooltip.Content>
|
|
70
|
-
</Tooltip.Root>
|
|
71
|
-
{/if}
|
|
72
|
-
</div>
|
|
73
|
-
<div>
|
|
74
|
-
<ExtensionsComponents
|
|
75
|
-
name="dvFields.topRight.{collectionName}.{fieldName}"
|
|
76
|
-
utils={getExtensionUtils(lobb, ctx)}
|
|
77
|
-
bind:value={entry[fieldName]}
|
|
78
|
-
/>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
<FieldInput
|
|
82
|
-
{collectionName}
|
|
83
|
-
{fieldName}
|
|
84
|
-
bind:value={entry[fieldName]}
|
|
85
|
-
bind:entry
|
|
86
|
-
errorMessages={fieldsErrors[fieldName]}
|
|
87
|
-
changed={changedFields.includes(fieldName)}
|
|
88
|
-
/>
|
|
89
|
-
</div>
|
|
30
|
+
{@const fieldDef = ctx.meta.collections[collectionName].fields[fieldName]}
|
|
31
|
+
{#if !(fieldDef?.ui?.hidden) || (fieldDef as any)?.embedded}
|
|
32
|
+
<FieldInput
|
|
33
|
+
{collectionName}
|
|
34
|
+
{fieldName}
|
|
35
|
+
bind:value={entry[fieldName]}
|
|
36
|
+
bind:entry
|
|
37
|
+
errorMessages={fieldsErrors[fieldName]}
|
|
38
|
+
changed={changedFields.includes(fieldName)}
|
|
39
|
+
/>
|
|
90
40
|
{/if}
|
|
91
41
|
{/each}
|
|
92
42
|
</div>
|
|
@@ -1,296 +1,169 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import NumberInput from "../ui/input/numberInput.svelte";
|
|
10
|
-
import * as Select from "../ui/select/index";
|
|
11
|
-
import EnumBadge from "../dataTable/enumBadge.svelte";
|
|
12
|
-
import type { EnumOption } from "@lobb-js/core";
|
|
13
|
-
import Textarea from "../ui/textarea/textarea.svelte";
|
|
14
|
-
import ForeingKeyInput from "../foreingKeyInput.svelte";
|
|
15
|
-
import PolymorphicInput from "../polymorphicInput.svelte";
|
|
16
|
-
import ExtensionsComponents from "../extensionsComponents.svelte";
|
|
17
|
-
import { getExtensionUtils } from "../../extensions/extensionUtils";
|
|
2
|
+
import { getStudioContext } from "../../context";
|
|
3
|
+
import { getFieldRelationTarget, getPolymorphicRelation } from "../../relations";
|
|
4
|
+
import { Ban } from "lucide-svelte";
|
|
5
|
+
import { getField, getFieldIcon } from "../dataTable/utils";
|
|
6
|
+
import { getFieldTypeLabel } from "../../utils";
|
|
7
|
+
import Button from "../ui/button/button.svelte";
|
|
8
|
+
import type { EnumOption } from "@lobb-js/core";
|
|
18
9
|
|
|
19
|
-
|
|
10
|
+
import ForeignKeyField from "./fields/ForeignKeyField.svelte";
|
|
11
|
+
import PolymorphicField from "./fields/PolymorphicField.svelte";
|
|
12
|
+
import EmbeddedField from "./fields/EmbeddedField.svelte";
|
|
13
|
+
import EmbeddedPolymorphicField from "./fields/EmbeddedPolymorphicField.svelte";
|
|
14
|
+
import RichTextField from "./fields/RichTextField.svelte";
|
|
15
|
+
import CodeField from "./fields/CodeField.svelte";
|
|
16
|
+
import PasswordField from "./fields/PasswordField.svelte";
|
|
17
|
+
import IdField from "./fields/IdField.svelte";
|
|
18
|
+
import StringField from "./fields/StringField.svelte";
|
|
19
|
+
import TextField from "./fields/TextField.svelte";
|
|
20
|
+
import NumberField from "./fields/NumberField.svelte";
|
|
21
|
+
import DateField from "./fields/DateField.svelte";
|
|
22
|
+
import BoolField from "./fields/BoolField.svelte";
|
|
23
|
+
import EnumField from "./fields/EnumField.svelte";
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
collectionName: string;
|
|
23
|
-
fieldName: string;
|
|
24
|
-
value: any;
|
|
25
|
-
errorMessages?: string[];
|
|
26
|
-
entry?: Record<string, any>;
|
|
27
|
-
changed?: boolean;
|
|
28
|
-
}
|
|
25
|
+
const { ctx } = getStudioContext();
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
interface Props {
|
|
28
|
+
collectionName: string;
|
|
29
|
+
fieldName: string;
|
|
30
|
+
value: any;
|
|
31
|
+
errorMessages?: any;
|
|
32
|
+
entry?: Record<string, any>;
|
|
33
|
+
changed?: boolean;
|
|
34
|
+
}
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const disabledClasses = "pointer-events-none opacity-50";
|
|
48
|
-
const destructive: boolean = $derived(!isDisabled && Boolean(errorMessages.length));
|
|
49
|
-
const changedClass = $derived(changed && !destructive ? '!bg-orange-500/5' : '');
|
|
36
|
+
let {
|
|
37
|
+
collectionName,
|
|
38
|
+
fieldName,
|
|
39
|
+
value = $bindable(),
|
|
40
|
+
errorMessages = [],
|
|
41
|
+
entry = $bindable(),
|
|
42
|
+
changed = false,
|
|
43
|
+
}: Props = $props();
|
|
50
44
|
|
|
45
|
+
const fieldDef = ctx.meta.collections[collectionName].fields[fieldName];
|
|
46
|
+
const ui_input = fieldDef?.ui?.input;
|
|
47
|
+
const ui = fieldDef?.ui;
|
|
48
|
+
const field = getField(ctx, fieldName, collectionName);
|
|
49
|
+
const fieldRelationTarget = getFieldRelationTarget(ctx, collectionName, fieldName);
|
|
50
|
+
const polymorphicRelation = getPolymorphicRelation(ctx, collectionName, fieldName);
|
|
51
|
+
const isDisabled = field.key === 'id' || Boolean(ui?.disabled);
|
|
52
|
+
const destructive: boolean = $derived(Array.isArray(errorMessages) && errorMessages.length > 0);
|
|
53
|
+
const changedClass = $derived(changed && !destructive ? '!bg-orange-500/5' : '');
|
|
54
|
+
const isEmbedded = !!(fieldRelationTarget && entry && (fieldDef as any)?.embedded);
|
|
55
|
+
const isEmbeddedPolymorphic = !!(polymorphicRelation && entry && (fieldDef as any)?.embedded);
|
|
56
|
+
|
|
57
|
+
const FieldIcon = getFieldIcon(ctx, fieldName, collectionName);
|
|
58
|
+
const labelData = {
|
|
59
|
+
text: field.label,
|
|
60
|
+
icon: FieldIcon,
|
|
61
|
+
typeText: getFieldTypeLabel(field.type),
|
|
62
|
+
description: fieldDef?.description as string | undefined,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function handleClear(e: MouseEvent) {
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
value = null;
|
|
68
|
+
if (polymorphicRelation && entry) {
|
|
69
|
+
entry[polymorphicRelation.from.collection_field] = null;
|
|
70
|
+
entry[polymorphicRelation.from.id_field] = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
51
73
|
</script>
|
|
52
74
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{#if enumOptions}
|
|
149
|
-
<EnumBadge value={optionValue} enum={enumOptions} />
|
|
150
|
-
{:else}
|
|
151
|
-
{optionValue}
|
|
152
|
-
{/if}
|
|
153
|
-
</Select.Item>
|
|
154
|
-
{/each}
|
|
155
|
-
</Select.Group>
|
|
156
|
-
</Select.Content>
|
|
157
|
-
</Select.Root>
|
|
158
|
-
{:else if field.type === "string"}
|
|
159
|
-
<Input
|
|
160
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
161
|
-
type="text"
|
|
162
|
-
class="
|
|
163
|
-
bg-muted text-xs {changedClass}
|
|
164
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
165
|
-
"
|
|
166
|
-
bind:value
|
|
167
|
-
/>
|
|
168
|
-
{:else if field.type === "text"}
|
|
169
|
-
<Textarea
|
|
170
|
-
placeholder={ui?.placeholder ? ui.placeholder : value === "" ? "EMPTY STRING" : "NULL"}
|
|
171
|
-
rows={5}
|
|
172
|
-
class="
|
|
173
|
-
bg-muted text-xs {changedClass}
|
|
174
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
175
|
-
"
|
|
176
|
-
bind:value
|
|
177
|
-
/>
|
|
178
|
-
{:else if field.type === "date"}
|
|
179
|
-
<Input
|
|
180
|
-
type="date"
|
|
181
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
182
|
-
class="
|
|
183
|
-
dateInput block w-full bg-muted pr-9 text-xs
|
|
184
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
185
|
-
"
|
|
186
|
-
bind:value={
|
|
187
|
-
() => {
|
|
188
|
-
if (!value) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const date = new Date(value);
|
|
192
|
-
return date.toISOString().split("T")[0];
|
|
193
|
-
},
|
|
194
|
-
(v) => (value = v)
|
|
195
|
-
}
|
|
196
|
-
/>
|
|
197
|
-
{:else if field.type === "time"}
|
|
198
|
-
<Input
|
|
199
|
-
type="time"
|
|
200
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
201
|
-
class="
|
|
202
|
-
dateInput block w-full bg-muted pr-9 text-xs
|
|
203
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
204
|
-
"
|
|
205
|
-
bind:value={
|
|
206
|
-
() => {
|
|
207
|
-
if (!value) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
return value;
|
|
211
|
-
},
|
|
212
|
-
(v) => (value = v)
|
|
213
|
-
}
|
|
214
|
-
/>
|
|
215
|
-
{:else if field.type === "datetime"}
|
|
216
|
-
<Input
|
|
217
|
-
type="datetime-local"
|
|
218
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
219
|
-
class="
|
|
220
|
-
dateInput block w-full bg-muted pr-9 text-xs
|
|
221
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
222
|
-
"
|
|
223
|
-
bind:value={
|
|
224
|
-
() => {
|
|
225
|
-
if (!value) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
const date = new Date(value);
|
|
229
|
-
return date.toISOString().slice(0, 16);
|
|
230
|
-
},
|
|
231
|
-
(v) => {
|
|
232
|
-
value = v;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
/>
|
|
236
|
-
{:else if field.type === "bool"}
|
|
237
|
-
<Select.Root type="single" bind:value>
|
|
238
|
-
<Select.Trigger
|
|
239
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
240
|
-
class="
|
|
241
|
-
bg-muted pr-9
|
|
242
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
243
|
-
"
|
|
244
|
-
>
|
|
245
|
-
{String(value).toUpperCase()}
|
|
246
|
-
</Select.Trigger>
|
|
247
|
-
<Select.Content>
|
|
248
|
-
<Select.Item value={"true"} class="flex gap-1.5">
|
|
249
|
-
<Check size="15" />
|
|
250
|
-
TRUE
|
|
251
|
-
</Select.Item>
|
|
252
|
-
<Select.Item value={"false"} class="flex gap-1.5">
|
|
253
|
-
<X size="15" />
|
|
254
|
-
FALSE
|
|
255
|
-
</Select.Item>
|
|
256
|
-
<Select.Item value={"null"} class="flex gap-1.5">
|
|
257
|
-
<Ban size="15" />
|
|
258
|
-
NULL
|
|
259
|
-
</Select.Item>
|
|
260
|
-
</Select.Content>
|
|
261
|
-
</Select.Root>
|
|
262
|
-
{:else if field.type === "decimal" || field.type === "float" || field.type === "integer" || field.type === "long"}
|
|
263
|
-
{@const isFloat = field.type === "decimal" || field.type === "float"}
|
|
264
|
-
<NumberInput
|
|
265
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
266
|
-
scale={isFloat ? 20 : 0}
|
|
267
|
-
groupDigits={ui?.groupDigits ?? false}
|
|
268
|
-
class="
|
|
269
|
-
bg-muted text-xs {changedClass}
|
|
270
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
271
|
-
"
|
|
272
|
-
bind:value
|
|
273
|
-
/>
|
|
274
|
-
{:else}
|
|
275
|
-
<Input
|
|
276
|
-
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
277
|
-
type="text"
|
|
278
|
-
class="
|
|
279
|
-
bg-muted text-xs {changedClass}
|
|
280
|
-
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
281
|
-
"
|
|
282
|
-
bind:value
|
|
283
|
-
/>
|
|
284
|
-
{/if}
|
|
285
|
-
{#if !isDisabled && errorMessages}
|
|
286
|
-
{#each errorMessages as message}
|
|
287
|
-
<div class="flex gap-1 text-destructive">
|
|
288
|
-
<CircleAlert size="15" class="translate-y-[0.025rem]" />
|
|
289
|
-
<div class="text-[0.7rem]">
|
|
290
|
-
{message}
|
|
291
|
-
</div>
|
|
292
|
-
</div>
|
|
293
|
-
{/each}
|
|
294
|
-
{/if}
|
|
295
|
-
</div>
|
|
296
|
-
</div>
|
|
75
|
+
{#snippet clearBtn()}
|
|
76
|
+
{#if !isDisabled}
|
|
77
|
+
<Button
|
|
78
|
+
onclick={handleClear}
|
|
79
|
+
variant="outline"
|
|
80
|
+
class="aspect-square h-6 w-6 shrink-0 p-0"
|
|
81
|
+
Icon={Ban}
|
|
82
|
+
tabindex={-1}
|
|
83
|
+
/>
|
|
84
|
+
{/if}
|
|
85
|
+
{/snippet}
|
|
86
|
+
|
|
87
|
+
{#if isEmbeddedPolymorphic && entry}
|
|
88
|
+
<EmbeddedPolymorphicField
|
|
89
|
+
virtualField={polymorphicRelation!.from.virtual_field ?? fieldName}
|
|
90
|
+
collectionField={polymorphicRelation!.from.collection_field}
|
|
91
|
+
idField={polymorphicRelation!.from.id_field}
|
|
92
|
+
targetCollections={polymorphicRelation!.to}
|
|
93
|
+
bind:entry
|
|
94
|
+
{isDisabled}
|
|
95
|
+
{errorMessages}
|
|
96
|
+
header={labelData}
|
|
97
|
+
/>
|
|
98
|
+
{:else if polymorphicRelation && entry}
|
|
99
|
+
<PolymorphicField
|
|
100
|
+
collectionField={polymorphicRelation.from.collection_field}
|
|
101
|
+
idField={polymorphicRelation.from.id_field}
|
|
102
|
+
virtualField={polymorphicRelation.from.virtual_field ?? ''}
|
|
103
|
+
targetCollections={polymorphicRelation.to}
|
|
104
|
+
bind:entry
|
|
105
|
+
{destructive}
|
|
106
|
+
{isDisabled}
|
|
107
|
+
{errorMessages}
|
|
108
|
+
header={labelData}
|
|
109
|
+
{clearBtn}
|
|
110
|
+
/>
|
|
111
|
+
{:else if isEmbedded}
|
|
112
|
+
<EmbeddedField
|
|
113
|
+
collectionName={fieldRelationTarget!}
|
|
114
|
+
{fieldName}
|
|
115
|
+
bind:value
|
|
116
|
+
entry={entry!}
|
|
117
|
+
{isDisabled}
|
|
118
|
+
{errorMessages}
|
|
119
|
+
header={labelData}
|
|
120
|
+
onClear={handleClear}
|
|
121
|
+
/>
|
|
122
|
+
{:else if ui_input?.type === 'richtext'}
|
|
123
|
+
<RichTextField bind:value {field} {destructive} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
124
|
+
{:else if ui_input?.type === 'code'}
|
|
125
|
+
<CodeField bind:value {field} args={ui_input.args} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
126
|
+
{:else if ui_input?.type === 'password'}
|
|
127
|
+
<PasswordField bind:value {destructive} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
128
|
+
{:else if fieldRelationTarget && entry}
|
|
129
|
+
<ForeignKeyField
|
|
130
|
+
parentCollectionName={collectionName}
|
|
131
|
+
collectionName={fieldRelationTarget}
|
|
132
|
+
{fieldName}
|
|
133
|
+
bind:value
|
|
134
|
+
bind:entry
|
|
135
|
+
{destructive}
|
|
136
|
+
{isDisabled}
|
|
137
|
+
{errorMessages}
|
|
138
|
+
header={labelData}
|
|
139
|
+
{clearBtn}
|
|
140
|
+
/>
|
|
141
|
+
{:else if field.label === "id"}
|
|
142
|
+
<IdField bind:value {changedClass} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
143
|
+
{:else if field.enum}
|
|
144
|
+
<EnumField
|
|
145
|
+
bind:value
|
|
146
|
+
rawEnum={field.enum as (string | number | EnumOption)[]}
|
|
147
|
+
isNumeric={field.type === "integer" || field.type === "long" || field.type === "decimal" || field.type === "float"}
|
|
148
|
+
placeholder={ui?.placeholder}
|
|
149
|
+
{destructive} {changedClass} {isDisabled} {errorMessages} header={labelData} {clearBtn}
|
|
150
|
+
/>
|
|
151
|
+
{:else if field.type === "string"}
|
|
152
|
+
<StringField bind:value placeholder={ui?.placeholder} {destructive} {changedClass} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
153
|
+
{:else if field.type === "text"}
|
|
154
|
+
<TextField bind:value placeholder={ui?.placeholder ?? (value === "" ? "EMPTY STRING" : "NULL")} {destructive} {changedClass} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
155
|
+
{:else if field.type === "date" || field.type === "time" || field.type === "datetime"}
|
|
156
|
+
<DateField bind:value type={field.type} placeholder={ui?.placeholder} {destructive} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
157
|
+
{:else if field.type === "bool"}
|
|
158
|
+
<BoolField bind:value placeholder={ui?.placeholder} {destructive} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
159
|
+
{:else if field.type === "decimal" || field.type === "float" || field.type === "integer" || field.type === "long"}
|
|
160
|
+
<NumberField
|
|
161
|
+
bind:value
|
|
162
|
+
scale={field.type === "decimal" || field.type === "float" ? 20 : 0}
|
|
163
|
+
groupDigits={ui?.groupDigits ?? false}
|
|
164
|
+
placeholder={ui?.placeholder}
|
|
165
|
+
{destructive} {changedClass} {isDisabled} {errorMessages} header={labelData} {clearBtn}
|
|
166
|
+
/>
|
|
167
|
+
{:else}
|
|
168
|
+
<StringField bind:value placeholder={ui?.placeholder} {destructive} {changedClass} {isDisabled} {errorMessages} header={labelData} {clearBtn} />
|
|
169
|
+
{/if}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import { Ban, Check, X } from "lucide-svelte";
|
|
4
|
+
import * as Select from "../../ui/select/index";
|
|
5
|
+
import FieldWrapper from "./FieldWrapper.svelte";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
value?: any;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
destructive?: boolean;
|
|
11
|
+
isDisabled?: boolean;
|
|
12
|
+
errorMessages?: any;
|
|
13
|
+
header?: any;
|
|
14
|
+
clearBtn?: Snippet<[]>;
|
|
15
|
+
}
|
|
16
|
+
let { value = $bindable(), placeholder = "NULL", destructive = false, isDisabled = false, errorMessages = [], header, clearBtn }: Props = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<FieldWrapper span={1} {isDisabled} {errorMessages} {header}>
|
|
20
|
+
{#snippet children()}
|
|
21
|
+
<div class="relative">
|
|
22
|
+
{#if clearBtn}
|
|
23
|
+
<div class="absolute right-1 inset-y-0 z-10 flex items-center">
|
|
24
|
+
{@render clearBtn()}
|
|
25
|
+
</div>
|
|
26
|
+
{/if}
|
|
27
|
+
<Select.Root type="single" bind:value>
|
|
28
|
+
<Select.Trigger
|
|
29
|
+
{placeholder}
|
|
30
|
+
class="bg-muted pr-9 {destructive ? 'border-destructive' : ''}"
|
|
31
|
+
>
|
|
32
|
+
{String(value).toUpperCase()}
|
|
33
|
+
</Select.Trigger>
|
|
34
|
+
<Select.Content>
|
|
35
|
+
<Select.Item value={"true"} class="flex gap-1.5"><Check size="15" />TRUE</Select.Item>
|
|
36
|
+
<Select.Item value={"false"} class="flex gap-1.5"><X size="15" />FALSE</Select.Item>
|
|
37
|
+
<Select.Item value={"null"} class="flex gap-1.5"><Ban size="15" />NULL</Select.Item>
|
|
38
|
+
</Select.Content>
|
|
39
|
+
</Select.Root>
|
|
40
|
+
</div>
|
|
41
|
+
{/snippet}
|
|
42
|
+
</FieldWrapper>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface Props {
|
|
3
|
+
value?: any;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
destructive?: boolean;
|
|
6
|
+
isDisabled?: boolean;
|
|
7
|
+
errorMessages?: any;
|
|
8
|
+
header?: any;
|
|
9
|
+
clearBtn?: Snippet<[]>;
|
|
10
|
+
}
|
|
11
|
+
declare const BoolField: import("svelte").Component<Props, {}, "value">;
|
|
12
|
+
type BoolField = ReturnType<typeof BoolField>;
|
|
13
|
+
export default BoolField;
|