@lobb-js/studio 0.40.0 → 0.42.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/confirmationDialog/confirmationDialog.svelte +1 -1
- package/dist/components/dataTable/dataTable.svelte +182 -50
- package/dist/components/dataTable/header.svelte +5 -2
- package/dist/components/dataTable/header.svelte.d.ts +1 -0
- package/dist/components/dataTable/sort.svelte +5 -9
- package/dist/components/dataTable/sortButton.svelte +0 -1
- package/dist/components/dataTable/table.svelte +10 -21
- package/dist/components/dataTable/table.svelte.d.ts +1 -0
- package/dist/components/detailView/create/createDetailView.svelte +43 -1
- package/dist/components/detailView/create/createDetailView.svelte.d.ts +1 -0
- package/dist/components/detailView/update/updateDetailView.svelte +39 -12
- package/dist/components/detailView/update/updateDetailViewButton.svelte +7 -0
- package/dist/components/detailView/update/updateDetailViewButton.svelte.d.ts +1 -0
- package/dist/components/drawer.svelte +1 -0
- package/dist/components/foreingKeyInput.svelte +27 -1
- package/dist/components/polymorphicInput.svelte +27 -3
- package/package.json +2 -2
- package/src/lib/components/confirmationDialog/confirmationDialog.svelte +1 -1
- package/src/lib/components/dataTable/dataTable.svelte +182 -50
- package/src/lib/components/dataTable/header.svelte +5 -2
- package/src/lib/components/dataTable/sort.svelte +5 -9
- package/src/lib/components/dataTable/sortButton.svelte +0 -1
- package/src/lib/components/dataTable/table.svelte +10 -21
- package/src/lib/components/detailView/create/createDetailView.svelte +43 -1
- package/src/lib/components/detailView/update/updateDetailView.svelte +39 -12
- package/src/lib/components/detailView/update/updateDetailViewButton.svelte +7 -0
- package/src/lib/components/drawer.svelte +1 -0
- package/src/lib/components/foreingKeyInput.svelte +27 -1
- package/src/lib/components/polymorphicInput.svelte +27 -3
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import * as Popover from "../ui/popover/index.js";
|
|
5
5
|
import * as Select from "../ui/select/index.js";
|
|
6
6
|
import { GripVertical, Plus, X } from "lucide-svelte";
|
|
7
|
-
import Button
|
|
7
|
+
import Button from "../ui/button/button.svelte";
|
|
8
8
|
import { getStudioContext } from "../../context";
|
|
9
9
|
import { getFieldIcon } from "./utils";
|
|
10
10
|
import { dndzone } from "svelte-dnd-action";
|
|
@@ -205,17 +205,13 @@
|
|
|
205
205
|
</div>
|
|
206
206
|
{/if}
|
|
207
207
|
</div>
|
|
208
|
-
<div class="flex justify-between
|
|
208
|
+
<div class="flex justify-between px-3 pb-3">
|
|
209
209
|
{#if getFieldNames().length}
|
|
210
210
|
<Popover.Root bind:open={popoverOpen}>
|
|
211
211
|
<Popover.Trigger
|
|
212
|
-
class=
|
|
213
|
-
variant: "ghost",
|
|
214
|
-
size: "sm",
|
|
215
|
-
class: "text-muted-foreground",
|
|
216
|
-
})}
|
|
212
|
+
class="inline-flex w-fit items-center gap-1.5 rounded-md px-2 py-1 text-xs text-muted-foreground hover:text-foreground"
|
|
217
213
|
>
|
|
218
|
-
<Plus />
|
|
214
|
+
<Plus size="14" />
|
|
219
215
|
Add a sort rule
|
|
220
216
|
</Popover.Trigger>
|
|
221
217
|
<Popover.Content class="w-64 p-2">
|
|
@@ -231,7 +227,7 @@
|
|
|
231
227
|
</Popover.Content>
|
|
232
228
|
</Popover.Root>
|
|
233
229
|
{:else}
|
|
234
|
-
<div class="
|
|
230
|
+
<div class="px-2 py-1 text-xs text-muted-foreground">
|
|
235
231
|
All columns have been added
|
|
236
232
|
</div>
|
|
237
233
|
{/if}
|
|
@@ -41,6 +41,9 @@
|
|
|
41
41
|
parentWidth?: number;
|
|
42
42
|
select?: Select;
|
|
43
43
|
tableWidth?: number;
|
|
44
|
+
|
|
45
|
+
// recording mode row visuals — cellIndex 0 = tools cell, 1+ = data/action cells
|
|
46
|
+
onCellClass?: (entry: Entry, cellIndex: number) => string;
|
|
44
47
|
}
|
|
45
48
|
</script>
|
|
46
49
|
|
|
@@ -79,6 +82,7 @@
|
|
|
79
82
|
collapsible,
|
|
80
83
|
select,
|
|
81
84
|
tableWidth = $bindable(),
|
|
85
|
+
onCellClass,
|
|
82
86
|
}: TableProps = $props();
|
|
83
87
|
|
|
84
88
|
let expandedRows: boolean[] = $state(new Array(data.length).fill(false));
|
|
@@ -183,7 +187,7 @@
|
|
|
183
187
|
flex items-center p-2.5 text-xs h-10
|
|
184
188
|
border-r border-b gap-2
|
|
185
189
|
{headerBorderTop ? 'border-t' : ''}
|
|
186
|
-
bg-muted
|
|
190
|
+
bg-muted/50
|
|
187
191
|
"
|
|
188
192
|
>
|
|
189
193
|
<!-- collapsable toggle -->
|
|
@@ -208,7 +212,7 @@
|
|
|
208
212
|
class="
|
|
209
213
|
sticky top-0 z-10
|
|
210
214
|
flex items-center p-2.5 text-xs h-10
|
|
211
|
-
bg-muted
|
|
215
|
+
bg-muted/50
|
|
212
216
|
{lastColumn && !showLastColumnBorder ? '' : 'border-r'}
|
|
213
217
|
border-b gap-2
|
|
214
218
|
{headerBorderTop ? 'border-t' : ''}
|
|
@@ -235,7 +239,7 @@
|
|
|
235
239
|
class="
|
|
236
240
|
sticky top-0 right-0 z-20
|
|
237
241
|
flex items-center p-2.5 h-10
|
|
238
|
-
bg-muted
|
|
242
|
+
bg-muted/50
|
|
239
243
|
border-l border-b
|
|
240
244
|
{headerBorderTop ? 'border-t' : ''}
|
|
241
245
|
"
|
|
@@ -247,12 +251,7 @@
|
|
|
247
251
|
{@const lastRow = data.length - 1 === index}
|
|
248
252
|
{#if selectedRecords || tools}
|
|
249
253
|
<div
|
|
250
|
-
class="
|
|
251
|
-
sticky left-0
|
|
252
|
-
flex items-center p-2.5 text-xs h-10
|
|
253
|
-
bg-card
|
|
254
|
-
border-r gap-2
|
|
255
|
-
"
|
|
254
|
+
class="sticky left-0 flex items-center p-2.5 text-xs h-10 bg-card border-r gap-2 {onCellClass?.(entry, 0) ?? ''}"
|
|
256
255
|
>
|
|
257
256
|
<!-- collapsable toggle -->
|
|
258
257
|
{#if showCollapsible}
|
|
@@ -294,12 +293,7 @@
|
|
|
294
293
|
onclick={() => {
|
|
295
294
|
select?.onSelect(entry);
|
|
296
295
|
}}
|
|
297
|
-
class="
|
|
298
|
-
flex items-center p-2.5 text-xs h-10 text-nowrap overflow-clip
|
|
299
|
-
{select ? 'cursor-pointer hover:bg-accent' : ''}
|
|
300
|
-
bg-card
|
|
301
|
-
{lastColumn && !showLastColumnBorder ? '' : 'border-r'}
|
|
302
|
-
"
|
|
296
|
+
class="flex items-center p-2.5 text-xs h-10 text-nowrap overflow-clip bg-card {select ? 'cursor-pointer hover:bg-accent' : ''} {lastColumn && !showLastColumnBorder ? '' : 'border-r'} {onCellClass?.(entry, index + 1) ?? ''}"
|
|
303
297
|
>
|
|
304
298
|
{#if overrideCell}
|
|
305
299
|
{@render overrideCell(fieldValue, column, entry)}
|
|
@@ -310,12 +304,7 @@
|
|
|
310
304
|
{/each}
|
|
311
305
|
{#if rowActions}
|
|
312
306
|
<div
|
|
313
|
-
class="
|
|
314
|
-
sticky right-0 z-10
|
|
315
|
-
flex items-center p-2.5 text-xs h-10
|
|
316
|
-
border-l gap-2
|
|
317
|
-
bg-card
|
|
318
|
-
"
|
|
307
|
+
class="sticky right-0 z-10 flex items-center p-2.5 text-xs h-10 border-l gap-2 bg-card {onCellClass?.(entry, columns.length + 1) ?? ''}"
|
|
319
308
|
>
|
|
320
309
|
{@render rowActions?.(entry, index)}
|
|
321
310
|
</div>
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
submitButton?: SubmitButton;
|
|
15
15
|
title?: Snippet<[string]>;
|
|
16
16
|
onSuccessfullSave?: (entry: any) => Promise<void>;
|
|
17
|
+
onCreated?: (record: any) => Promise<void>;
|
|
17
18
|
onCancel?: () => Promise<void>;
|
|
18
19
|
onChanges?: (changes: Changes) => void;
|
|
19
20
|
}
|
|
@@ -25,6 +26,8 @@
|
|
|
25
26
|
import { getStudioContext } from "../../../context";
|
|
26
27
|
import { toast } from "svelte-sonner";
|
|
27
28
|
import { untrack } from "svelte";
|
|
29
|
+
import type { ChildrenChanges } from "../utils";
|
|
30
|
+
import { showDialog } from "../../../actions";
|
|
28
31
|
|
|
29
32
|
const { lobb, ctx } = getStudioContext();
|
|
30
33
|
import CreateDetailViewChildren from "./createDetailViewChildren.svelte";
|
|
@@ -38,6 +41,7 @@
|
|
|
38
41
|
showRelatedRecords = true,
|
|
39
42
|
onCancel,
|
|
40
43
|
onSuccessfullSave,
|
|
44
|
+
onCreated,
|
|
41
45
|
title,
|
|
42
46
|
submitButton,
|
|
43
47
|
onChanges,
|
|
@@ -46,6 +50,31 @@
|
|
|
46
50
|
const isRecordingMode = onChanges !== undefined;
|
|
47
51
|
let changes = $state<Changes>({ data: {}, children: {} });
|
|
48
52
|
|
|
53
|
+
const totalChangeCount = $derived.by(() => {
|
|
54
|
+
let count = Object.keys(changes.data).length;
|
|
55
|
+
for (const ch of Object.values(changes.children) as ChildrenChanges[]) {
|
|
56
|
+
count += ch.created.length + ch.updated.length + ch.deleted.length + ch.linked.length + ch.unlinked.length;
|
|
57
|
+
}
|
|
58
|
+
return count;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const hasChildChanges = $derived(
|
|
62
|
+
Object.values(changes.children).some((ch: ChildrenChanges) =>
|
|
63
|
+
ch.created.length || ch.linked.length
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const changeSummaryLines = $derived.by(() => {
|
|
68
|
+
const lines: string[] = [];
|
|
69
|
+
const fieldCount = Object.keys(changes.data).length;
|
|
70
|
+
if (fieldCount > 0) lines.push(`${fieldCount} field${fieldCount > 1 ? 's' : ''} filled`);
|
|
71
|
+
for (const [col, ch] of Object.entries(changes.children) as [string, ChildrenChanges][]) {
|
|
72
|
+
if (ch.created.length) lines.push(`${ch.created.length} created in ${col}`);
|
|
73
|
+
if (ch.linked.length) lines.push(`${ch.linked.length} linked in ${col}`);
|
|
74
|
+
}
|
|
75
|
+
return lines;
|
|
76
|
+
});
|
|
77
|
+
|
|
49
78
|
const fieldNames = Object.keys(ctx.meta.collections[collectionName].fields);
|
|
50
79
|
let values = $state(getDefaultEntry(ctx, fieldNames, collectionName, passedValues));
|
|
51
80
|
let fieldsErrors: Record<string, any> = $state({});
|
|
@@ -82,17 +111,27 @@
|
|
|
82
111
|
}
|
|
83
112
|
|
|
84
113
|
async function handleSave() {
|
|
114
|
+
if (!isRecordingMode && hasChildChanges && changeSummaryLines.length > 0) {
|
|
115
|
+
const confirmed = await showDialog(
|
|
116
|
+
"Confirm changes",
|
|
117
|
+
changeSummaryLines.map(l => `• ${l}`).join('\n')
|
|
118
|
+
);
|
|
119
|
+
if (!confirmed) return;
|
|
120
|
+
}
|
|
121
|
+
|
|
85
122
|
const snap = $state.snapshot(changes);
|
|
86
123
|
const response = await lobb.createOne(collectionName, buildPayload(snap), undefined, isRecordingMode);
|
|
87
124
|
|
|
88
125
|
if (response.status === 204) {
|
|
89
126
|
onChanges?.(snap);
|
|
90
127
|
if (onSuccessfullSave) await onSuccessfullSave(snap);
|
|
128
|
+
await onCreated?.(snap.data);
|
|
91
129
|
toast.success(`The record was successfully created`);
|
|
92
130
|
handleCancel();
|
|
93
131
|
return;
|
|
94
132
|
}
|
|
95
133
|
|
|
134
|
+
let createdRecord: any = null;
|
|
96
135
|
if (!response.bodyUsed) {
|
|
97
136
|
const result = await response.json();
|
|
98
137
|
if (response.status >= 400) {
|
|
@@ -104,10 +143,12 @@
|
|
|
104
143
|
return;
|
|
105
144
|
}
|
|
106
145
|
}
|
|
146
|
+
createdRecord = result.data ?? result;
|
|
107
147
|
}
|
|
108
148
|
|
|
109
149
|
onChanges?.(snap);
|
|
110
150
|
if (onSuccessfullSave) await onSuccessfullSave(snap);
|
|
151
|
+
await onCreated?.(createdRecord ?? snap.data);
|
|
111
152
|
toast.success(`The record was successfully created`);
|
|
112
153
|
onCancel?.();
|
|
113
154
|
}
|
|
@@ -152,9 +193,10 @@
|
|
|
152
193
|
variant="default"
|
|
153
194
|
size="sm"
|
|
154
195
|
Icon={submitButton?.icon ? submitButton.icon : Plus}
|
|
196
|
+
aria-label={submitButton?.text ?? "Create record"}
|
|
155
197
|
onclick={handleSave}
|
|
156
198
|
>
|
|
157
|
-
{submitButton?.text ?
|
|
199
|
+
{submitButton?.text ?? "Create"}{totalChangeCount > 0 ? ` (${totalChangeCount})` : ''}
|
|
158
200
|
</Button>
|
|
159
201
|
</div>
|
|
160
202
|
</div>
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import { getStudioContext } from "../../../context";
|
|
28
28
|
import { toast } from "svelte-sonner";
|
|
29
29
|
import { untrack } from "svelte";
|
|
30
|
+
import { showDialog } from "../../../actions";
|
|
30
31
|
|
|
31
32
|
const { lobb, ctx } = getStudioContext();
|
|
32
33
|
import { getChangedProperties } from "../../../utils";
|
|
@@ -69,6 +70,34 @@
|
|
|
69
70
|
),
|
|
70
71
|
);
|
|
71
72
|
|
|
73
|
+
const totalChangeCount = $derived.by(() => {
|
|
74
|
+
let count = Object.keys(localChanges.data).length;
|
|
75
|
+
for (const ch of Object.values(localChanges.children) as ChildrenChanges[]) {
|
|
76
|
+
count += ch.created.length + ch.updated.length + ch.deleted.length + ch.linked.length + ch.unlinked.length;
|
|
77
|
+
}
|
|
78
|
+
return count;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const hasChildChanges = $derived(
|
|
82
|
+
Object.values(localChanges.children).some((ch: ChildrenChanges) =>
|
|
83
|
+
ch.created.length || ch.updated.length || ch.deleted.length || ch.linked.length || ch.unlinked.length
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const changeSummaryLines = $derived.by(() => {
|
|
88
|
+
const lines: string[] = [];
|
|
89
|
+
const fieldCount = Object.keys(localChanges.data).length;
|
|
90
|
+
if (fieldCount > 0) lines.push(`${fieldCount} field${fieldCount > 1 ? 's' : ''} changed`);
|
|
91
|
+
for (const [col, ch] of Object.entries(localChanges.children) as [string, ChildrenChanges][]) {
|
|
92
|
+
if (ch.created.length) lines.push(`${ch.created.length} created in ${col}`);
|
|
93
|
+
if (ch.linked.length) lines.push(`${ch.linked.length} linked in ${col}`);
|
|
94
|
+
if (ch.updated.length) lines.push(`${ch.updated.length} edited in ${col}`);
|
|
95
|
+
if (ch.deleted.length) lines.push(`${ch.deleted.length} deleted from ${col}`);
|
|
96
|
+
if (ch.unlinked.length) lines.push(`${ch.unlinked.length} unlinked from ${col}`);
|
|
97
|
+
}
|
|
98
|
+
return lines;
|
|
99
|
+
});
|
|
100
|
+
|
|
72
101
|
$effect(() => {
|
|
73
102
|
const currentEntrySnap = $state.snapshot(values);
|
|
74
103
|
|
|
@@ -77,17 +106,6 @@
|
|
|
77
106
|
});
|
|
78
107
|
});
|
|
79
108
|
|
|
80
|
-
$effect(() => {
|
|
81
|
-
const snap = $state.snapshot(localChanges);
|
|
82
|
-
if (isRecordingMode) {
|
|
83
|
-
const hasAny = Object.keys(snap.data).length > 0 ||
|
|
84
|
-
Object.values(snap.children).some((c: ChildrenChanges) =>
|
|
85
|
-
c.created.length || c.updated.length || c.deleted.length || c.linked.length || c.unlinked.length
|
|
86
|
-
);
|
|
87
|
-
if (hasAny) untrack(() => onChanges?.(snap));
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
109
|
function buildPayload(changes: Changes): { data: Record<string, any>; children?: Record<string, any> } {
|
|
92
110
|
const { id: _id, ...data } = changes.data;
|
|
93
111
|
const children = buildChildren(changes.children);
|
|
@@ -119,6 +137,14 @@
|
|
|
119
137
|
}
|
|
120
138
|
|
|
121
139
|
async function handleSave() {
|
|
140
|
+
if (!isRecordingMode && hasChildChanges && changeSummaryLines.length > 0) {
|
|
141
|
+
const confirmed = await showDialog(
|
|
142
|
+
"Confirm changes",
|
|
143
|
+
changeSummaryLines.map(l => `• ${l}`).join('\n')
|
|
144
|
+
);
|
|
145
|
+
if (!confirmed) return;
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
const snap = $state.snapshot(localChanges);
|
|
123
149
|
const response = await lobb.updateOne(collectionName, recordId, buildPayload(snap), isRecordingMode);
|
|
124
150
|
|
|
@@ -189,10 +215,11 @@
|
|
|
189
215
|
variant="default"
|
|
190
216
|
size="sm"
|
|
191
217
|
Icon={submitButton?.icon ? submitButton.icon : Pencil}
|
|
218
|
+
aria-label={submitButton?.text ?? "Update"}
|
|
192
219
|
onclick={handleSave}
|
|
193
220
|
disabled={!hasChanges}
|
|
194
221
|
>
|
|
195
|
-
{submitButton?.text ?
|
|
222
|
+
{submitButton?.text ?? "Update"}{totalChangeCount > 0 ? ` (${totalChangeCount})` : ''}
|
|
196
223
|
</Button>
|
|
197
224
|
</div>
|
|
198
225
|
</div>
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
class?: ButtonProps["class"];
|
|
12
12
|
Icon?: ButtonProps["Icon"];
|
|
13
13
|
children?: ButtonProps["children"];
|
|
14
|
+
"aria-label"?: string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
let props: LocalProp = $props();
|
|
@@ -20,6 +21,11 @@
|
|
|
20
21
|
const { lobb } = getStudioContext();
|
|
21
22
|
|
|
22
23
|
async function openView() {
|
|
24
|
+
if (props.values) {
|
|
25
|
+
values = props.values;
|
|
26
|
+
open = true;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
23
29
|
const params = {
|
|
24
30
|
fields: "*",
|
|
25
31
|
filter: { id: props.recordId },
|
|
@@ -37,6 +43,7 @@
|
|
|
37
43
|
size={props.size}
|
|
38
44
|
class={props.class}
|
|
39
45
|
Icon={props.Icon}
|
|
46
|
+
aria-label={props["aria-label"]}
|
|
40
47
|
onclick={openView}
|
|
41
48
|
>
|
|
42
49
|
{#if props.children}
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
import Input from "./ui/input/input.svelte";
|
|
4
4
|
import SelectRecord from "./selectRecord.svelte";
|
|
5
5
|
import UpdateDetailViewButton from "./detailView/update/updateDetailViewButton.svelte";
|
|
6
|
+
import CreateDetailView from "./detailView/create/createDetailView.svelte";
|
|
6
7
|
import { getCollectionPrimaryField } from "./dataTable/utils";
|
|
7
8
|
import { getStudioContext } from "../context";
|
|
8
|
-
import { ExternalLink } from "lucide-svelte";
|
|
9
|
+
import { ExternalLink, Plus } from "lucide-svelte";
|
|
10
|
+
import Button from "./ui/button/button.svelte";
|
|
9
11
|
|
|
10
12
|
const { lobb, ctx } = getStudioContext();
|
|
11
13
|
|
|
@@ -28,6 +30,7 @@
|
|
|
28
30
|
}: LocalProps = $props();
|
|
29
31
|
|
|
30
32
|
let displayName = $state<string | null>(null);
|
|
33
|
+
let createDrawerOpen = $state(false);
|
|
31
34
|
|
|
32
35
|
onMount(async () => {
|
|
33
36
|
if (value == null) return;
|
|
@@ -51,6 +54,12 @@
|
|
|
51
54
|
displayName = primaryFieldName ? String(selectedEntry[primaryFieldName]) : null;
|
|
52
55
|
}
|
|
53
56
|
|
|
57
|
+
async function handleCreated(record: any) {
|
|
58
|
+
const primaryFieldName = getCollectionPrimaryField(ctx, collectionName);
|
|
59
|
+
value = record.id;
|
|
60
|
+
displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
const idIsZero = $derived(value === 0);
|
|
55
64
|
</script>
|
|
56
65
|
|
|
@@ -71,6 +80,14 @@
|
|
|
71
80
|
{displayName}
|
|
72
81
|
</div>
|
|
73
82
|
{/if}
|
|
83
|
+
<Button
|
|
84
|
+
class="h-6 px-2 font-normal text-xs"
|
|
85
|
+
variant="outline"
|
|
86
|
+
Icon={Plus}
|
|
87
|
+
onclick={() => (createDrawerOpen = true)}
|
|
88
|
+
>
|
|
89
|
+
Create
|
|
90
|
+
</Button>
|
|
74
91
|
<SelectRecord
|
|
75
92
|
class="h-6 px-2 font-normal text-xs"
|
|
76
93
|
variant="outline"
|
|
@@ -78,6 +95,7 @@
|
|
|
78
95
|
{collectionName}
|
|
79
96
|
{fieldName}
|
|
80
97
|
onSelect={handleSelect}
|
|
98
|
+
text="Select"
|
|
81
99
|
{entry}
|
|
82
100
|
/>
|
|
83
101
|
</div>
|
|
@@ -103,3 +121,11 @@
|
|
|
103
121
|
/>
|
|
104
122
|
</div>
|
|
105
123
|
{/if}
|
|
124
|
+
|
|
125
|
+
{#if createDrawerOpen}
|
|
126
|
+
<CreateDetailView
|
|
127
|
+
collectionName={collectionName}
|
|
128
|
+
onCreated={handleCreated}
|
|
129
|
+
onCancel={async () => { createDrawerOpen = false; }}
|
|
130
|
+
/>
|
|
131
|
+
{/if}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import * as Popover from "./ui/popover/index";
|
|
7
7
|
import { getCollectionPrimaryField } from "./dataTable/utils";
|
|
8
8
|
import { getStudioContext } from "../context";
|
|
9
|
-
import { ArrowLeft, Link, ChevronDown } from "lucide-svelte";
|
|
9
|
+
import { ArrowLeft, Link, ChevronDown, Plus } from "lucide-svelte";
|
|
10
|
+
import CreateDetailView from "./detailView/create/createDetailView.svelte";
|
|
10
11
|
|
|
11
12
|
const { ctx, lobb } = getStudioContext();
|
|
12
13
|
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
let displayName = $state<string | null>(null);
|
|
33
34
|
let collectionPopoverOpen = $state(false);
|
|
34
35
|
let recordDrawerOpen = $state(false);
|
|
36
|
+
let createDrawerOpen = $state(false);
|
|
35
37
|
|
|
36
38
|
onMount(async () => {
|
|
37
39
|
if (selectedCollection == null || selectedId == null) return;
|
|
@@ -68,6 +70,12 @@
|
|
|
68
70
|
displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
|
|
69
71
|
recordDrawerOpen = false;
|
|
70
72
|
}
|
|
73
|
+
|
|
74
|
+
async function onPolyCreated(record: any) {
|
|
75
|
+
const primaryFieldName = getCollectionPrimaryField(ctx, selectedCollection!);
|
|
76
|
+
entry = { ...entry, [idField]: record.id };
|
|
77
|
+
displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
|
|
78
|
+
}
|
|
71
79
|
</script>
|
|
72
80
|
|
|
73
81
|
<div class="flex h-9 w-full items-center gap-1.5 rounded-md border pl-1.5 pr-9 text-xs bg-muted {destructive ? 'border-destructive bg-destructive/10' : ''}">
|
|
@@ -115,15 +123,23 @@
|
|
|
115
123
|
</div>
|
|
116
124
|
{/if}
|
|
117
125
|
|
|
118
|
-
<!-- Select record
|
|
126
|
+
<!-- Create / Select record buttons -->
|
|
119
127
|
{#if selectedCollection}
|
|
128
|
+
<Button
|
|
129
|
+
class="h-6 shrink-0 px-2 font-normal text-xs"
|
|
130
|
+
variant="outline"
|
|
131
|
+
onclick={() => (createDrawerOpen = true)}
|
|
132
|
+
>
|
|
133
|
+
<Plus size="13" />
|
|
134
|
+
Create
|
|
135
|
+
</Button>
|
|
120
136
|
<Button
|
|
121
137
|
class="h-6 shrink-0 px-2 font-normal text-xs"
|
|
122
138
|
variant="outline"
|
|
123
139
|
onclick={() => (recordDrawerOpen = true)}
|
|
124
140
|
>
|
|
125
141
|
<Link size="13" />
|
|
126
|
-
Select
|
|
142
|
+
Select
|
|
127
143
|
</Button>
|
|
128
144
|
{/if}
|
|
129
145
|
</div>
|
|
@@ -155,3 +171,11 @@
|
|
|
155
171
|
</div>
|
|
156
172
|
</Drawer>
|
|
157
173
|
{/if}
|
|
174
|
+
|
|
175
|
+
{#if createDrawerOpen && selectedCollection}
|
|
176
|
+
<CreateDetailView
|
|
177
|
+
collectionName={selectedCollection}
|
|
178
|
+
onCreated={onPolyCreated}
|
|
179
|
+
onCancel={async () => { createDrawerOpen = false; }}
|
|
180
|
+
/>
|
|
181
|
+
{/if}
|