@lobb-js/studio 0.41.0 → 0.43.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.
Files changed (39) hide show
  1. package/dist/components/confirmationDialog/confirmationDialog.svelte +1 -1
  2. package/dist/components/dataTable/dataTable.svelte +215 -57
  3. package/dist/components/dataTable/header.svelte +5 -2
  4. package/dist/components/dataTable/header.svelte.d.ts +1 -0
  5. package/dist/components/dataTable/listViewChildren.svelte +60 -77
  6. package/dist/components/dataTable/listViewChildren.svelte.d.ts +1 -1
  7. package/dist/components/dataTable/table.svelte +18 -77
  8. package/dist/components/dataTable/table.svelte.d.ts +2 -2
  9. package/dist/components/detailView/changeTreeUtils.d.ts +7 -0
  10. package/dist/components/detailView/changeTreeUtils.js +47 -0
  11. package/dist/components/detailView/create/createDetailView.svelte +49 -3
  12. package/dist/components/detailView/create/createDetailView.svelte.d.ts +1 -0
  13. package/dist/components/detailView/detailView.svelte +7 -2
  14. package/dist/components/detailView/detailView.svelte.d.ts +1 -0
  15. package/dist/components/detailView/fieldInput.svelte +10 -9
  16. package/dist/components/detailView/fieldInput.svelte.d.ts +1 -0
  17. package/dist/components/detailView/update/updateDetailView.svelte +46 -15
  18. package/dist/components/detailView/update/updateDetailViewButton.svelte +7 -0
  19. package/dist/components/detailView/update/updateDetailViewButton.svelte.d.ts +1 -0
  20. package/dist/components/drawer.svelte +16 -2
  21. package/dist/components/foreingKeyInput.svelte +177 -56
  22. package/dist/components/foreingKeyInput.svelte.d.ts +1 -1
  23. package/dist/components/polymorphicInput.svelte +128 -55
  24. package/dist/components/polymorphicInput.svelte.d.ts +1 -0
  25. package/package.json +2 -2
  26. package/src/lib/components/confirmationDialog/confirmationDialog.svelte +1 -1
  27. package/src/lib/components/dataTable/dataTable.svelte +215 -57
  28. package/src/lib/components/dataTable/header.svelte +5 -2
  29. package/src/lib/components/dataTable/listViewChildren.svelte +60 -77
  30. package/src/lib/components/dataTable/table.svelte +18 -77
  31. package/src/lib/components/detailView/changeTreeUtils.ts +39 -0
  32. package/src/lib/components/detailView/create/createDetailView.svelte +49 -3
  33. package/src/lib/components/detailView/detailView.svelte +7 -2
  34. package/src/lib/components/detailView/fieldInput.svelte +10 -9
  35. package/src/lib/components/detailView/update/updateDetailView.svelte +46 -15
  36. package/src/lib/components/detailView/update/updateDetailViewButton.svelte +7 -0
  37. package/src/lib/components/drawer.svelte +16 -2
  38. package/src/lib/components/foreingKeyInput.svelte +177 -56
  39. package/src/lib/components/polymorphicInput.svelte +128 -55
@@ -2,10 +2,12 @@
2
2
  import { onMount } from "svelte";
3
3
  import Input from "./ui/input/input.svelte";
4
4
  import SelectRecord from "./selectRecord.svelte";
5
- import UpdateDetailViewButton from "./detailView/update/updateDetailViewButton.svelte";
5
+ import CreateDetailView from "./detailView/create/createDetailView.svelte";
6
+ import UpdateDetailView from "./detailView/update/updateDetailView.svelte";
6
7
  import { getCollectionPrimaryField } from "./dataTable/utils";
7
8
  import { getStudioContext } from "../context";
8
- import { ExternalLink } from "lucide-svelte";
9
+ import { Plus, Link, Pencil, Unlink, Trash, RotateCcw, RefreshCw } from "lucide-svelte";
10
+ import Button from "./ui/button/button.svelte";
9
11
 
10
12
  const { lobb, ctx } = getStudioContext();
11
13
 
@@ -13,7 +15,7 @@
13
15
  parentCollectionName: string;
14
16
  collectionName: string;
15
17
  fieldName: string;
16
- value?: number | null;
18
+ value?: any;
17
19
  destructive?: boolean;
18
20
  entry: Record<string, any>;
19
21
  }
@@ -27,79 +29,198 @@
27
29
  entry,
28
30
  }: LocalProps = $props();
29
31
 
30
- let displayName = $state<string | null>(null);
31
-
32
- onMount(async () => {
33
- if (value == null) return;
34
- try {
35
- const res = await lobb.findOne(collectionName, value);
36
- const record = (await res.json()).data;
37
- const primaryFieldName = getCollectionPrimaryField(ctx, collectionName);
38
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
39
- } catch {
40
- displayName = null;
32
+ let createDrawerOpen = $state(false);
33
+ let editDrawerOpen = $state(false);
34
+ let editValues: Record<string, any> | undefined = $state(undefined);
35
+ let originalId = $state<number | null>(null);
36
+ let initialValue = $state<any>(undefined);
37
+ let unlinked = $state(false);
38
+
39
+ onMount(() => { initialValue = value; });
40
+
41
+ // Derived state from value
42
+ const isPendingCreate = $derived(value && typeof value === 'object' && value.create);
43
+ const isPendingEdit = $derived(value && typeof value === 'object' && value.id && value.update);
44
+ const isStagedDelete = $derived(value && typeof value === 'object' && value.delete === true);
45
+ const isStagedUnlink = $derived(unlinked);
46
+ const hasRealId = $derived(value != null && typeof value === 'number');
47
+ const isNewLink = $derived(hasRealId && initialValue !== undefined && initialValue == null && value !== initialValue);
48
+ const isReplaced = $derived(hasRealId && initialValue !== undefined && initialValue != null && value !== initialValue);
49
+ const isEmpty = $derived((value == null || value === 0) && !unlinked);
50
+ const isZeroPlaceholder = $derived(value === 0);
51
+
52
+ const bgClass = $derived(
53
+ isPendingCreate ? '!bg-green-500/5 border-green-500/40' :
54
+ isNewLink ? '!bg-blue-500/5 border-blue-500/40' :
55
+ isReplaced ? '!bg-orange-500/5 border-orange-500/40' :
56
+ isPendingEdit ? '!bg-orange-500/5 border-orange-500/40' :
57
+ isStagedUnlink ? '!bg-slate-500/5 border-slate-500/40' :
58
+ isStagedDelete ? '!bg-red-500/5 border-red-500/40' :
59
+ ''
60
+ );
61
+
62
+ const displayId = $derived(
63
+ isPendingEdit ? (value as any).id :
64
+ isStagedUnlink ? originalId :
65
+ isStagedDelete ? originalId :
66
+ hasRealId ? value :
67
+ null
68
+ );
69
+
70
+ async function handleCreated(record: any) {
71
+ // dry-run result has no id — store as pending create
72
+ if (!record.id) {
73
+ value = { create: record };
74
+ } else {
75
+ value = record.id;
41
76
  }
42
- });
77
+ }
43
78
 
44
- $effect(() => {
45
- if (value == null) displayName = null;
46
- });
79
+ async function openEdit() {
80
+ const res = await lobb.findAll(collectionName, { filter: { id: value }, limit: 1 });
81
+ const result = await res.json();
82
+ editValues = result.data[0];
83
+ editDrawerOpen = true;
84
+ }
85
+
86
+ function handleEditChanges(changes: import('./detailView/utils').Changes) {
87
+ if (Object.keys(changes.data).length === 0) {
88
+ value = (editValues as any)?.id ?? value;
89
+ } else {
90
+ value = { id: (editValues as any)?.id ?? value, update: changes.data };
91
+ }
92
+ }
47
93
 
48
94
  function handleSelect(selectedEntry: any) {
49
- const primaryFieldName = getCollectionPrimaryField(ctx, collectionName);
50
95
  value = selectedEntry.id;
51
- displayName = primaryFieldName ? String(selectedEntry[primaryFieldName]) : null;
52
96
  }
53
97
 
54
- const idIsZero = $derived(value === 0);
98
+ function handleUnlink() {
99
+ if (hasRealId) {
100
+ originalId = value as number;
101
+ unlinked = true;
102
+ value = null;
103
+ }
104
+ }
105
+
106
+ async function handleDelete() {
107
+ if (hasRealId) {
108
+ originalId = value as number;
109
+ value = { delete: true };
110
+ }
111
+ }
112
+
113
+ function handleRevert() {
114
+ if (originalId != null) {
115
+ value = originalId;
116
+ originalId = null;
117
+ } else {
118
+ value = null;
119
+ }
120
+ unlinked = false;
121
+ }
55
122
  </script>
56
123
 
57
- {#if !idIsZero}
124
+ {#if !isZeroPlaceholder}
58
125
  <div class="relative">
59
- <div class="flex gap-2 absolute right-0 top-0 mr-9 h-full items-center text-xs">
60
- {#if value != null}
61
- <UpdateDetailViewButton
62
- collectionName={collectionName}
63
- recordId={value}
126
+ <!-- Action buttons overlay on the right -->
127
+ <div class="flex gap-1 absolute right-0 top-0 mr-9 h-full items-center text-xs">
128
+ {#if isStagedUnlink || isStagedDelete || isPendingCreate || isPendingEdit}
129
+ <Button
130
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
64
131
  variant="ghost"
65
- class="h-5 w-5 px-0 py-0 text-muted-foreground hover:bg-transparent"
66
- Icon={ExternalLink}
67
- ></UpdateDetailViewButton>
68
- {/if}
69
- {#if displayName}
70
- <div class="flex items-center bg-background rounded-full border h-6 px-3 shadow-sm">
71
- {displayName}
72
- </div>
132
+ Icon={RotateCcw}
133
+ onclick={handleRevert}
134
+ title="Revert"
135
+ ></Button>
136
+ {:else if hasRealId}
137
+ <Button
138
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
139
+ variant="ghost"
140
+ Icon={Trash}
141
+ onclick={handleDelete}
142
+ title="Delete record"
143
+ ></Button>
144
+ <Button
145
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
146
+ variant="ghost"
147
+ Icon={Unlink}
148
+ onclick={handleUnlink}
149
+ title="Unlink"
150
+ ></Button>
151
+ <Button
152
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
153
+ variant="ghost"
154
+ Icon={Pencil}
155
+ onclick={openEdit}
156
+ title="Edit record"
157
+ ></Button>
158
+ <SelectRecord
159
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
160
+ variant="ghost"
161
+ {collectionName}
162
+ onSelect={handleSelect}
163
+ additionalFilter={{ id: { $ne: value } }}
164
+ title="Replace"
165
+ {entry}
166
+ >
167
+ {#snippet children()}<RefreshCw size="13" />{/snippet}
168
+ </SelectRecord>
169
+ {:else if isEmpty}
170
+ <Button
171
+ class="h-6 px-2 font-normal text-xs"
172
+ variant="outline"
173
+ Icon={Plus}
174
+ onclick={() => (createDrawerOpen = true)}
175
+ >
176
+ Create
177
+ </Button>
178
+ <SelectRecord
179
+ class="h-6 px-2 font-normal text-xs"
180
+ variant="outline"
181
+ {parentCollectionName}
182
+ {collectionName}
183
+ {fieldName}
184
+ onSelect={handleSelect}
185
+ text="Link"
186
+ {entry}
187
+ />
73
188
  {/if}
74
- <SelectRecord
75
- class="h-6 px-2 font-normal text-xs"
76
- variant="outline"
77
- {parentCollectionName}
78
- {collectionName}
79
- {fieldName}
80
- onSelect={handleSelect}
81
- {entry}
82
- />
83
189
  </div>
190
+
191
+ <!-- Input field colored by state -->
84
192
  <Input
85
- placeholder={"NULL"}
193
+ placeholder={isEmpty ? "NULL" : ""}
86
194
  type="number"
87
- class="
88
- bg-muted text-xs
89
- {destructive ? 'border-destructive bg-destructive/10' : ''}
90
- "
195
+ class="bg-muted text-xs {bgClass} {destructive ? '!bg-destructive/10 border-destructive' : ''}"
196
+ disabled={isPendingCreate || isPendingEdit}
91
197
  bind:value={
92
- () => value ?? "",
93
- (v) => (value = (v === "" || v == null) ? null : Number(v))
198
+ () => displayId ?? "",
199
+ (v) => { if (hasRealId || isEmpty) value = (v === "" || v == null) ? null : Number(v); }
94
200
  }
95
201
  />
96
202
  </div>
97
203
  {:else}
98
204
  <div class="relative z-10">
99
- <Input
100
- placeholder={"PARENT ID"}
101
- class="bg-muted text-xs"
102
- disabled={true}
103
- />
205
+ <Input placeholder="PARENT ID" class="bg-muted text-xs" disabled={true} />
104
206
  </div>
105
207
  {/if}
208
+
209
+ {#if createDrawerOpen}
210
+ <CreateDetailView
211
+ collectionName={collectionName}
212
+ onCreated={handleCreated}
213
+ onChanges={() => {}}
214
+ onCancel={async () => { createDrawerOpen = false; }}
215
+ />
216
+ {/if}
217
+
218
+ {#if editDrawerOpen && editValues}
219
+ <UpdateDetailView
220
+ collectionName={collectionName}
221
+ recordId={String(editValues.id)}
222
+ values={editValues}
223
+ onChanges={handleEditChanges}
224
+ onCancel={async () => { editDrawerOpen = false; editValues = undefined; }}
225
+ />
226
+ {/if}
@@ -4,15 +4,17 @@
4
4
  import DataTable from "./dataTable/dataTable.svelte";
5
5
  import Drawer from "./drawer.svelte";
6
6
  import * as Popover from "./ui/popover/index";
7
- import { getCollectionPrimaryField } from "./dataTable/utils";
8
7
  import { getStudioContext } from "../context";
9
- import { ArrowLeft, Link, ChevronDown } from "lucide-svelte";
8
+ import { ArrowLeft, Link, ChevronDown, Plus, Pencil, Unlink, Trash, RotateCcw, RefreshCw } from "lucide-svelte";
9
+ import CreateDetailView from "./detailView/create/createDetailView.svelte";
10
+ import UpdateDetailView from "./detailView/update/updateDetailView.svelte";
10
11
 
11
12
  const { ctx, lobb } = getStudioContext();
12
13
 
13
14
  interface Props {
14
15
  collectionField: string;
15
16
  idField: string;
17
+ virtualField: string;
16
18
  targetCollections: string[];
17
19
  entry: Record<string, any>;
18
20
  destructive?: boolean;
@@ -21,38 +23,52 @@
21
23
  let {
22
24
  collectionField,
23
25
  idField,
26
+ virtualField,
24
27
  targetCollections,
25
28
  entry = $bindable(),
26
29
  destructive,
27
30
  }: Props = $props();
28
31
 
32
+
29
33
  const selectedCollection = $derived(entry[collectionField] ?? null);
30
- const selectedId = $derived(entry[idField] ?? null);
34
+ const selectedId = $derived(entry[idField] ?? null);
35
+ const virtualVal = $derived(entry[virtualField] ?? null);
31
36
 
32
- let displayName = $state<string | null>(null);
33
- let collectionPopoverOpen = $state(false);
34
- let recordDrawerOpen = $state(false);
37
+ let initialId = $state<number | null | undefined>(undefined);
38
+ let unlinked = $state(false);
39
+ onMount(() => { initialId = entry[idField] ?? null; });
35
40
 
36
- onMount(async () => {
37
- if (selectedCollection == null || selectedId == null) return;
38
- try {
39
- const res = await lobb.findOne(selectedCollection, selectedId);
40
- const record = await res.json();
41
- const primaryFieldName = getCollectionPrimaryField(ctx, selectedCollection);
42
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
43
- } catch {
44
- displayName = null;
45
- }
46
- });
41
+ // State derived from virtual field and real fields
42
+ const isPendingCreate = $derived(virtualVal && typeof virtualVal === 'object' && virtualVal.create);
43
+ const isPendingEdit = $derived(virtualVal && typeof virtualVal === 'object' && virtualVal.update);
44
+ const isStagedUnlink = $derived(unlinked);
45
+ const isStagedDelete = $derived(virtualVal && typeof virtualVal === 'object' && virtualVal.delete === true);
46
+ const hasRealValue = $derived(selectedId != null && !isPendingCreate && !isPendingEdit && !isStagedUnlink && !isStagedDelete);
47
+ const isNewLink = $derived(hasRealValue && initialId !== undefined && initialId == null && selectedId !== initialId);
48
+ const isReplaced = $derived(hasRealValue && initialId !== undefined && initialId != null && selectedId !== initialId);
49
+ const isEmpty = $derived(!unlinked && (!selectedCollection || (selectedId == null && !isPendingCreate && !isPendingEdit && !isStagedDelete)));
47
50
 
48
- $effect(() => {
49
- if (entry[idField] == null) displayName = null;
50
- });
51
+ const bgClass = $derived(
52
+ isPendingCreate ? '!bg-green-500/5 border-green-500/40' :
53
+ isNewLink ? '!bg-blue-500/5 border-blue-500/40' :
54
+ isReplaced ? '!bg-orange-500/5 border-orange-500/40' :
55
+ isPendingEdit ? '!bg-orange-500/5 border-orange-500/40' :
56
+ isStagedUnlink ? '!bg-slate-500/5 border-slate-500/40' :
57
+ isStagedDelete ? '!bg-red-500/5 border-red-500/40' :
58
+ ''
59
+ );
60
+
61
+ let collectionPopoverOpen = $state(false);
62
+ let recordDrawerOpen = $state(false);
63
+ let createDrawerOpen = $state(false);
64
+ let editDrawerOpen = $state(false);
65
+ let editValues: Record<string, any> | undefined = $state(undefined);
66
+ let originalSnapshot: { collection: string; id: number } | null = $state(null);
51
67
 
52
68
  function onCollectionChange(col: string) {
53
69
  collectionPopoverOpen = false;
54
70
  if (entry[collectionField] !== col) {
55
- entry = { ...entry, [collectionField]: col, [idField]: null };
71
+ entry = { ...entry, [collectionField]: col, [idField]: null, [virtualField]: undefined };
56
72
  }
57
73
  }
58
74
 
@@ -63,14 +79,60 @@
63
79
  }
64
80
 
65
81
  function onRecordSelect(record: any) {
66
- const primaryFieldName = getCollectionPrimaryField(ctx, selectedCollection!);
67
- entry = { ...entry, [idField]: record.id };
68
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
82
+ entry = { ...entry, [idField]: record.id, [virtualField]: undefined };
69
83
  recordDrawerOpen = false;
70
84
  }
85
+
86
+ async function onPolyCreated(record: any) {
87
+ if (!record.id) {
88
+ entry = { ...entry, [virtualField]: { collection: selectedCollection, create: record }, [collectionField]: selectedCollection, [idField]: null };
89
+ } else {
90
+ entry = { ...entry, [idField]: record.id, [virtualField]: undefined };
91
+ }
92
+ }
93
+
94
+ async function openEdit() {
95
+ const res = await lobb.findAll(selectedCollection!, { filter: { id: selectedId }, limit: 1 });
96
+ const result = await res.json();
97
+ editValues = result.data[0];
98
+ editDrawerOpen = true;
99
+ }
100
+
101
+ function handleEditChanges(changes: import('./detailView/utils').Changes) {
102
+ if (Object.keys(changes.data).length === 0) {
103
+ entry = { ...entry, [virtualField]: undefined };
104
+ } else {
105
+ entry = { ...entry, [virtualField]: { collection: selectedCollection, id: selectedId, update: changes.data } };
106
+ }
107
+ }
108
+
109
+ function handleUnlink() {
110
+ if (hasRealValue) {
111
+ originalSnapshot = { collection: selectedCollection!, id: selectedId! };
112
+ unlinked = true;
113
+ entry = { ...entry, [collectionField]: null, [idField]: null, [virtualField]: undefined };
114
+ }
115
+ }
116
+
117
+ async function handleDelete() {
118
+ if (hasRealValue) {
119
+ originalSnapshot = { collection: selectedCollection!, id: selectedId! };
120
+ entry = { ...entry, [virtualField]: { delete: true } };
121
+ }
122
+ }
123
+
124
+ function handleRevert() {
125
+ if (originalSnapshot) {
126
+ entry = { ...entry, [collectionField]: originalSnapshot.collection, [idField]: originalSnapshot.id, [virtualField]: undefined };
127
+ originalSnapshot = null;
128
+ } else {
129
+ entry = { ...entry, [collectionField]: null, [idField]: null, [virtualField]: undefined };
130
+ }
131
+ unlinked = false;
132
+ }
71
133
  </script>
72
134
 
73
- <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' : ''}">
135
+ <div class="flex h-9 w-full items-center gap-1.5 rounded-md border pl-1.5 pr-9 text-xs bg-muted {bgClass} {destructive ? '!bg-destructive/10 border-destructive' : ''}">
74
136
  <!-- Collection picker -->
75
137
  <Popover.Root bind:open={collectionPopoverOpen}>
76
138
  <Popover.Trigger>
@@ -99,31 +161,32 @@
99
161
  </Popover.Content>
100
162
  </Popover.Root>
101
163
 
102
- <!-- Transparent id input -->
164
+ <!-- ID input (only editable when real value or empty) -->
103
165
  <input
104
166
  placeholder="NULL"
105
167
  type="number"
106
168
  class="min-w-0 flex-1 bg-transparent outline-none text-xs placeholder:text-muted-foreground"
107
- value={selectedId ?? ""}
169
+ value={isStagedUnlink || isStagedDelete ? (virtualVal?.id ?? '') : (selectedId ?? "")}
170
+ disabled={isPendingCreate || isPendingEdit}
108
171
  oninput={onIdChange}
109
172
  />
110
173
 
111
- <!-- Primary field badge -->
112
- {#if displayName}
113
- <div class="flex shrink-0 items-center bg-background rounded-full border h-6 px-3 shadow-sm">
114
- {displayName}
115
- </div>
116
- {/if}
117
-
118
- <!-- Select record button -->
119
- {#if selectedCollection}
120
- <Button
121
- class="h-6 shrink-0 px-2 font-normal text-xs"
122
- variant="outline"
123
- onclick={() => (recordDrawerOpen = true)}
124
- >
174
+ <!-- Action buttons -->
175
+ {#if isStagedUnlink || isStagedDelete || isPendingCreate || isPendingEdit}
176
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={RotateCcw} onclick={handleRevert} title="Revert"></Button>
177
+ {:else if hasRealValue}
178
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={Trash} onclick={handleDelete} title="Delete record"></Button>
179
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={Unlink} onclick={handleUnlink} title="Unlink"></Button>
180
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={Pencil} onclick={openEdit} title="Edit record"></Button>
181
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={RefreshCw} onclick={() => (recordDrawerOpen = true)} title="Replace"></Button>
182
+ {:else if selectedCollection && !isPendingCreate}
183
+ <Button class="h-6 shrink-0 px-2 font-normal text-xs" variant="outline" onclick={() => (createDrawerOpen = true)}>
184
+ <Plus size="13" />
185
+ Create
186
+ </Button>
187
+ <Button class="h-6 shrink-0 px-2 font-normal text-xs" variant="outline" onclick={() => (recordDrawerOpen = true)}>
125
188
  <Link size="13" />
126
- Select Record
189
+ Link
127
190
  </Button>
128
191
  {/if}
129
192
  </div>
@@ -131,27 +194,37 @@
131
194
  {#if recordDrawerOpen}
132
195
  <Drawer onHide={async () => { recordDrawerOpen = false }}>
133
196
  <div class="flex h-12 items-center gap-4 border-b px-4">
134
- <Button
135
- variant="outline"
136
- onclick={() => (recordDrawerOpen = false)}
137
- class="h-8 w-8 rounded-full text-xs font-normal"
138
- Icon={ArrowLeft}
139
- />
197
+ <Button variant="outline" onclick={() => (recordDrawerOpen = false)} class="h-8 w-8 rounded-full text-xs font-normal" Icon={ArrowLeft} />
140
198
  <div class="flex items-center gap-2">
141
199
  <div class="text-sm">Select record from</div>
142
- <span class="rounded-md border bg-muted px-2 py-0.5 text-sm">
143
- {selectedCollection}
144
- </span>
200
+ <span class="rounded-md border bg-muted px-2 py-0.5 text-sm">{selectedCollection}</span>
145
201
  </div>
146
202
  </div>
147
203
  <div class="flex-1 overflow-y-auto bg-muted">
148
204
  <DataTable
149
205
  collectionName={selectedCollection!}
150
- tableProps={{
151
- showCheckboxes: false,
152
- select: { onSelect: onRecordSelect },
153
- }}
206
+ filter={selectedId != null ? { id: { $ne: selectedId } } : undefined}
207
+ tableProps={{ showCheckboxes: false, select: { onSelect: onRecordSelect } }}
154
208
  />
155
209
  </div>
156
210
  </Drawer>
157
211
  {/if}
212
+
213
+ {#if createDrawerOpen && selectedCollection}
214
+ <CreateDetailView
215
+ collectionName={selectedCollection}
216
+ onCreated={onPolyCreated}
217
+ onChanges={() => {}}
218
+ onCancel={async () => { createDrawerOpen = false; }}
219
+ />
220
+ {/if}
221
+
222
+ {#if editDrawerOpen && editValues && selectedCollection}
223
+ <UpdateDetailView
224
+ collectionName={selectedCollection}
225
+ recordId={String(editValues.id)}
226
+ values={editValues}
227
+ onChanges={handleEditChanges}
228
+ onCancel={async () => { editDrawerOpen = false; editValues = undefined; }}
229
+ />
230
+ {/if}