|
2 | 2 | import { t } from '../stores/i18n.svelte.js'; |
3 | 3 | import MilkdownEditor from '../editors/LazyMilkdownEditor.svelte'; |
4 | 4 | import Input from '../components/Input.svelte'; |
| 5 | + import ChipPicker from '../pickers/ChipPicker.svelte'; |
| 6 | + import Spinner from '../components/Spinner.svelte'; |
| 7 | + import { LayoutTemplate } from '@lucide/svelte'; |
5 | 8 |
|
6 | 9 | let { |
7 | 10 | formData = $bindable({ |
8 | 11 | name: '', |
9 | 12 | key: '', |
10 | | - description: '' |
| 13 | + description: '', |
| 14 | + template_workspace_id: null |
11 | 15 | }), |
| 16 | + templates = [], |
| 17 | + templatesLoading = false, |
| 18 | + templatesError = null, |
12 | 19 | nameInputRef = $bindable(null) |
13 | 20 | } = $props(); |
14 | 21 |
|
|
34 | 41 | formData.key = e.target.value.toUpperCase(); |
35 | 42 | } |
36 | 43 |
|
| 44 | + let templatePickerItems = $derived.by(() => { |
| 45 | + if (templates.length === 0) return []; |
| 46 | + return [ |
| 47 | + { id: null, name: t('createModal.workspaceTemplateBlank') }, |
| 48 | + ...templates |
| 49 | + ]; |
| 50 | + }); |
| 51 | +
|
37 | 52 | export function validate() { |
38 | 53 | return formData.name.trim() !== '' && formData.key.trim() !== ''; |
39 | 54 | } |
|
43 | 58 | name: formData.name, |
44 | 59 | key: formData.key, |
45 | 60 | description: formData.description || '', |
46 | | - active: true |
| 61 | + active: true, |
| 62 | + template_workspace_id: formData.template_workspace_id ?? null |
47 | 63 | }; |
48 | 64 | } |
49 | 65 |
|
50 | 66 | export function reset() { |
51 | 67 | formData = { |
52 | 68 | name: '', |
53 | 69 | key: '', |
54 | | - description: '' |
| 70 | + description: '', |
| 71 | + template_workspace_id: null |
55 | 72 | }; |
56 | 73 | keyManuallyEdited = false; |
57 | 74 | } |
|
87 | 104 | placeholder={t('createModal.workspaceKeyPlaceholder')} |
88 | 105 | /> |
89 | 106 |
|
| 107 | + <!-- Template picker: blank workspace is the default and preserves the |
| 108 | + legacy creation flow. --> |
| 109 | + {#if templatesLoading} |
| 110 | + <div |
| 111 | + data-testid="workspace-template-loading" |
| 112 | + class="flex items-center gap-2 text-sm px-2 py-1.5 rounded" |
| 113 | + style="color: var(--ds-text-subtle);" |
| 114 | + > |
| 115 | + <Spinner size="sm" /> |
| 116 | + <span>{t('createModal.workspaceTemplateLoading')}</span> |
| 117 | + </div> |
| 118 | + {:else if templatesError} |
| 119 | + <div |
| 120 | + data-testid="workspace-template-error" |
| 121 | + class="text-sm px-2 py-1.5 rounded" |
| 122 | + style="color: var(--ds-text-danger, #dc2626);" |
| 123 | + > |
| 124 | + {t('createModal.workspaceTemplateError')} |
| 125 | + </div> |
| 126 | + {:else if templatePickerItems.length > 0} |
| 127 | + <div data-testid="workspace-template-section" class="pt-1"> |
| 128 | + <ChipPicker |
| 129 | + value={formData.template_workspace_id} |
| 130 | + items={templatePickerItems} |
| 131 | + getValue={(tpl) => tpl.id} |
| 132 | + getLabel={(tpl) => tpl.name} |
| 133 | + icon={LayoutTemplate} |
| 134 | + placeholder={t('createModal.workspaceTemplate')} |
| 135 | + searchable={true} |
| 136 | + searchFields={['name']} |
| 137 | + testId="workspace-template-picker" |
| 138 | + onSelect={(tpl) => { |
| 139 | + formData.template_workspace_id = tpl?.id ?? null; |
| 140 | + }} |
| 141 | + > |
| 142 | + {#snippet itemSnippet({ item })} |
| 143 | + <LayoutTemplate size={14} style="color: var(--ds-text-subtle); flex-shrink: 0;" /> |
| 144 | + <span class="truncate">{item.name}</span> |
| 145 | + {#if item.id !== null && item.id !== undefined} |
| 146 | + <span |
| 147 | + class="text-xs ml-auto pl-2 flex-shrink-0" |
| 148 | + style="color: var(--ds-text-subtle);" |
| 149 | + > |
| 150 | + {t('createModal.workspaceTemplateMeta', { |
| 151 | + templates: item.template_count ?? 0, |
| 152 | + items: item.item_count ?? 0 |
| 153 | + })} |
| 154 | + </span> |
| 155 | + {/if} |
| 156 | + {/snippet} |
| 157 | + </ChipPicker> |
| 158 | + </div> |
| 159 | + {/if} |
| 160 | +
|
90 | 161 | <!-- Description --> |
91 | 162 | <div class="min-h-[60px]"> |
92 | 163 | <MilkdownEditor |
|
0 commit comments