|
30 | 30 | export let viewId: string |
31 | 31 | export let fieldId: string |
32 | 32 | export let field: SelectField |
33 | | - export let option: IOption |
| 33 | + export let option: IOption | null |
34 | 34 | export let readonly = false |
35 | 35 | export let shareId: string |
36 | 36 |
|
|
40 | 40 | shareId, |
41 | 41 | filters: { |
42 | 42 | conjunction: "and", |
43 | | - children: [{ field: fieldId, op: "eq", value: option.id }], |
| 43 | + children: [{ field: fieldId, op: "eq", value: option ? option.id : null }], |
44 | 44 | }, |
45 | 45 | pagination: { |
46 | 46 | page: pageParam, |
|
54 | 54 | viewId, |
55 | 55 | filters: { |
56 | 56 | conjunction: "and", |
57 | | - children: [{ field: fieldId, op: "eq", value: option.id }], |
| 57 | + children: [{ field: fieldId, op: "eq", value: option ? option.id : null }], |
58 | 58 | }, |
59 | 59 | pagination: { |
60 | 60 | page: pageParam, |
|
64 | 64 | } |
65 | 65 |
|
66 | 66 | const query = createInfiniteQuery({ |
67 | | - queryKey: [tableId, fieldId, "getRecords", option.id], |
| 67 | + queryKey: [tableId, fieldId, "getRecords", option?.id], |
68 | 68 | queryFn: getRecords, |
69 | 69 | initialPageParam: 1, |
70 | 70 | getNextPageParam: (lastPage, pages) => { |
|
81 | 81 | const updateRecord = createMutation({ |
82 | 82 | mutationFn: trpc.record.update.mutate, |
83 | 83 | onSuccess: (data, variables, context) => { |
84 | | - recordsStore.setRecordValue(variables.id, fieldId, option.id) |
| 84 | + recordsStore.setRecordValue(variables.id, fieldId, option ? option.id : null) |
85 | 85 | recordsStore.invalidateRecord($table, variables.id) |
86 | 86 | }, |
87 | 87 | }) |
|
108 | 108 | option: { |
109 | 109 | options: field.option |
110 | 110 | .unwrapOrElse(() => ({ options: [] })) |
111 | | - .options.map((o) => (o.id === option.id ? { ...option } : o)), |
| 111 | + .options.map((o) => (o.id === option?.id ? { ...option } : o)), |
112 | 112 | }, |
113 | 113 | }, |
114 | 114 | }) |
|
122 | 122 | type: "select", |
123 | 123 | name: field.name.value, |
124 | 124 | option: { |
125 | | - options: field.option.unwrapOrElse(() => ({ options: [] })).options.filter((o) => o.id !== option.id), |
| 125 | + options: field.option.unwrapOrElse(() => ({ options: [] })).options.filter((o) => o.id !== option?.id), |
126 | 126 | }, |
127 | 127 | }, |
128 | 128 | }) |
129 | 129 | } |
130 | 130 |
|
131 | 131 | onMount(() => { |
132 | | - if (!shareId) { |
| 132 | + if (!shareId && !readonly) { |
133 | 133 | new Sortable(laneElement, { |
134 | 134 | group: "shared", |
135 | 135 | animation: 150, |
|
139 | 139 | onEnd: (evt) => { |
140 | 140 | const recordId = evt.item.dataset.recordId |
141 | 141 | if (!recordId) return |
142 | | - const optionId = evt.to.dataset.optionId |
143 | | - if (!optionId) return |
| 142 | + const optionId = evt.to.dataset.optionId ?? null |
144 | 143 |
|
145 | 144 | $updateRecord.mutate({ |
146 | 145 | tableId, |
|
160 | 159 | recordsStore.upsertRecords(Records.fromJSON($table, records)) |
161 | 160 | } |
162 | 161 |
|
163 | | - $: recordDos = recordsStore.getRecords(Some(new SelectEqual(option.id, new FieldIdVo(fieldId)))) |
| 162 | + $: recordDos = recordsStore.getRecords(Some(new SelectEqual(option?.id ?? null, new FieldIdVo(fieldId)))) |
164 | 163 |
|
165 | 164 | $: fields = $table.getOrderedVisibleFields(viewId) ?? [] |
166 | 165 |
|
|
169 | 168 | </script> |
170 | 169 |
|
171 | 170 | <div |
172 | | - data-option-id={option.id} |
| 171 | + data-option-id={option?.id ?? null} |
173 | 172 | class="kanban-lane flex w-[350px] shrink-0 flex-col space-y-2 rounded-sm px-2 pt-2 transition-all" |
174 | 173 | > |
175 | 174 | <div class="flex w-full items-center justify-between gap-1"> |
176 | 175 | <div class="flex items-center gap-1"> |
177 | | - {#if !shareId} |
| 176 | + {#if !shareId && option && !readonly} |
178 | 177 | <div class="lane-handle cursor-move"> |
179 | 178 | <GripVerticalIcon class="text-muted-foreground h-4 w-4" /> |
180 | 179 | </div> |
181 | 180 | {/if} |
182 | | - <Option {option} /> |
| 181 | + |
| 182 | + {#if option} |
| 183 | + <Option {option} /> |
| 184 | + {:else} |
| 185 | + <Option option={{ id: "", name: "No Option", color: "gray" }} /> |
| 186 | + {/if} |
183 | 187 | </div> |
184 | 188 |
|
185 | | - {#if !shareId && !readonly} |
| 189 | + {#if !shareId && !readonly && option} |
186 | 190 | <DropdownMenu.Root> |
187 | 191 | <DropdownMenu.Trigger asChild let:builder> |
188 | 192 | <Button size="xs" variant="ghost" builders={[builder]}> |
|
208 | 212 | </DropdownMenu.Root> |
209 | 213 | {/if} |
210 | 214 | </div> |
211 | | - <div class="max-w-[350px] flex-1 space-y-2 overflow-auto" data-option-id={option.id}> |
| 215 | + <div class="max-w-[350px] flex-1 space-y-2 overflow-auto" data-option-id={option?.id ?? null}> |
212 | 216 | <div |
213 | 217 | bind:this={laneElement} |
214 | | - data-option-id={option.id} |
| 218 | + data-option-id={option?.id ?? null} |
215 | 219 | class="min-h-[200px] space-y-2 rounded-lg border bg-gray-100 p-2" |
216 | 220 | > |
217 | 221 | {#if !readonly && $hasPermission("record:create")} |
218 | 222 | <Button |
219 | 223 | on:click={() => { |
220 | 224 | $defaultRecordValues = { |
221 | | - [fieldId]: option.id, |
| 225 | + [fieldId]: option ? option.id : null, |
222 | 226 | } |
223 | 227 | toggleModal(CREATE_RECORD_MODAL) |
224 | 228 | }} |
|
253 | 257 | </div> |
254 | 258 | </div> |
255 | 259 |
|
256 | | -<Dialog.Root bind:open={updateOptionDialogOpen}> |
257 | | - <Dialog.Content> |
258 | | - <Dialog.Header> |
259 | | - <Dialog.Title>Update option</Dialog.Title> |
260 | | - </Dialog.Header> |
| 260 | +{#if option} |
| 261 | + <Dialog.Root bind:open={updateOptionDialogOpen}> |
| 262 | + <Dialog.Content> |
| 263 | + <Dialog.Header> |
| 264 | + <Dialog.Title>Update option</Dialog.Title> |
| 265 | + </Dialog.Header> |
261 | 266 |
|
262 | | - <form on:submit|preventDefault={() => updateOption()}> |
263 | | - <OptionEditor bind:name={option.name} bind:color={option.color} /> |
264 | | - <Button type="submit" disabled={$updateFieldMutation.isPending} class="mt-2 w-full">Update</Button> |
265 | | - </form> |
266 | | - </Dialog.Content> |
267 | | -</Dialog.Root> |
| 267 | + <form on:submit|preventDefault={() => updateOption()}> |
| 268 | + <OptionEditor bind:name={option.name} bind:color={option.color} /> |
| 269 | + <Button type="submit" disabled={$updateFieldMutation.isPending} class="mt-2 w-full">Update</Button> |
| 270 | + </form> |
| 271 | + </Dialog.Content> |
| 272 | + </Dialog.Root> |
| 273 | +{/if} |
268 | 274 |
|
269 | | -<AlertDialog.Root bind:open={deleteOptionDialogOpen}> |
270 | | - <AlertDialog.Content> |
271 | | - <AlertDialog.Header> |
272 | | - <AlertDialog.Title>Delete Option <Option {option} /></AlertDialog.Title> |
273 | | - </AlertDialog.Header> |
274 | | - <AlertDialog.Footer> |
275 | | - <AlertDialog.Cancel>Cancel</AlertDialog.Cancel> |
276 | | - <AlertDialog.Action on:click={() => deleteOption()}>Continue</AlertDialog.Action> |
277 | | - </AlertDialog.Footer> |
278 | | - </AlertDialog.Content> |
279 | | -</AlertDialog.Root> |
| 275 | +{#if option} |
| 276 | + <AlertDialog.Root bind:open={deleteOptionDialogOpen}> |
| 277 | + <AlertDialog.Content> |
| 278 | + <AlertDialog.Header> |
| 279 | + <AlertDialog.Title>Delete Option <Option {option} /></AlertDialog.Title> |
| 280 | + </AlertDialog.Header> |
| 281 | + <AlertDialog.Footer> |
| 282 | + <AlertDialog.Cancel>Cancel</AlertDialog.Cancel> |
| 283 | + <AlertDialog.Action on:click={() => deleteOption()}>Continue</AlertDialog.Action> |
| 284 | + </AlertDialog.Footer> |
| 285 | + </AlertDialog.Content> |
| 286 | + </AlertDialog.Root> |
| 287 | +{/if} |
0 commit comments