|
11 | 11 | let activeSection: "general" | "agents" | "slack" = "general"; |
12 | 12 | let pendingSlackAppToken = ""; |
13 | 13 | let pendingSlackBotToken = ""; |
| 14 | + let isAddWorkspaceDialogOpen = false; |
14 | 15 |
|
15 | 16 | $: pathname = $page.url.pathname; |
16 | 17 | $: normalizedPathname = pathname.endsWith("/") && pathname.length > 1 ? pathname.slice(0, -1) : pathname; |
|
31 | 32 | if (!workspace) return; |
32 | 33 | pendingSlackAppToken = ""; |
33 | 34 | pendingSlackBotToken = ""; |
| 35 | + isAddWorkspaceDialogOpen = false; |
34 | 36 | await goto(getWorkspacePath(workspace)); |
35 | 37 | } |
36 | 38 |
|
| 39 | + function openAddWorkspaceDialog(): void { |
| 40 | + isAddWorkspaceDialogOpen = true; |
| 41 | + } |
| 42 | +
|
| 43 | + function closeAddWorkspaceDialog(): void { |
| 44 | + isAddWorkspaceDialogOpen = false; |
| 45 | + } |
| 46 | +
|
37 | 47 | function onPendingSlackAppTokenInput(event: Event): void { |
38 | 48 | pendingSlackAppToken = (event.currentTarget as HTMLInputElement).value; |
39 | 49 | } |
|
104 | 114 | <span class="empty-tip">No workspaces</span> |
105 | 115 | {:else} |
106 | 116 | {#each $localSettingStore.config.workspaces as workspace} |
107 | | - <div class="workspace-row"> |
108 | | - <button |
109 | | - class="nav-item {selectedWorkspace?.id === workspace.id && activeSection === 'slack' ? 'active' : ''}" |
110 | | - on:click={() => goto(getWorkspacePath(workspace))} |
111 | | - > |
112 | | - {workspace.name || workspace.id} |
113 | | - </button> |
114 | | - <button |
115 | | - class="workspace-remove" |
116 | | - type="button" |
117 | | - on:click={() => removeWorkspace(workspace.id)} |
118 | | - disabled={$localSettingStore.isLoading || $localSettingStore.isSaving || $localSettingStore.isSyncingSlack || $localSettingStore.isAddingWorkspace || $localSettingStore.isCheckingCli} |
119 | | - > |
120 | | - Remove |
121 | | - </button> |
122 | | - </div> |
| 117 | + <button |
| 118 | + class="nav-item {selectedWorkspace?.id === workspace.id && activeSection === 'slack' ? 'active' : ''}" |
| 119 | + on:click={() => goto(getWorkspacePath(workspace))} |
| 120 | + > |
| 121 | + {workspace.name || workspace.id} |
| 122 | + </button> |
123 | 123 | {/each} |
124 | 124 | {/if} |
125 | 125 |
|
126 | | - <label for="new-workspace-app-token">Slack App Token</label> |
127 | | - <input |
128 | | - id="new-workspace-app-token" |
129 | | - type="text" |
130 | | - value={pendingSlackAppToken} |
131 | | - on:input={onPendingSlackAppTokenInput} |
132 | | - placeholder="xapp-..." |
133 | | - /> |
134 | | - |
135 | | - <label for="new-workspace-bot-token">Slack Bot Token</label> |
136 | | - <input |
137 | | - id="new-workspace-bot-token" |
138 | | - type="text" |
139 | | - value={pendingSlackBotToken} |
140 | | - on:input={onPendingSlackBotTokenInput} |
141 | | - placeholder="xoxb-..." |
142 | | - /> |
143 | | - |
144 | 126 | <button |
145 | 127 | class="nav-item add-workspace" |
146 | 128 | type="button" |
147 | | - on:click={() => void addWorkspace()} |
| 129 | + on:click={openAddWorkspaceDialog} |
148 | 130 | disabled={$localSettingStore.isLoading || $localSettingStore.isSaving || $localSettingStore.isSyncingSlack || $localSettingStore.isAddingWorkspace || $localSettingStore.isCheckingCli} |
149 | 131 | > |
150 | | - {$localSettingStore.isAddingWorkspace ? "Adding..." : "Add workspace"} |
| 132 | + Add Workspace |
151 | 133 | </button> |
152 | 134 | </div> |
153 | 135 | </aside> |
|
156 | 138 | <slot /> |
157 | 139 |
|
158 | 140 | <footer class="actions"> |
| 141 | + {#if activeSection === "slack" && selectedWorkspace} |
| 142 | + <button |
| 143 | + class="danger-action" |
| 144 | + type="button" |
| 145 | + on:click={() => removeWorkspace(selectedWorkspace.id)} |
| 146 | + disabled={$localSettingStore.isLoading || $localSettingStore.isSaving || $localSettingStore.isSyncingSlack || $localSettingStore.isAddingWorkspace || $localSettingStore.isCheckingCli} |
| 147 | + > |
| 148 | + Remove Workspace |
| 149 | + </button> |
| 150 | + {/if} |
159 | 151 | <button |
160 | 152 | on:click={() => void localSettingStore.saveConfig()} |
161 | 153 | disabled={$localSettingStore.isLoading || $localSettingStore.isSaving || $localSettingStore.isSyncingSlack || $localSettingStore.isAddingWorkspace || $localSettingStore.isCheckingCli} |
|
172 | 164 | </div> |
173 | 165 | </main> |
174 | 166 |
|
| 167 | +{#if isAddWorkspaceDialogOpen} |
| 168 | + <div class="dialog-backdrop" role="presentation" on:click={closeAddWorkspaceDialog}> |
| 169 | + <div class="dialog card" role="dialog" aria-modal="true" aria-labelledby="add-workspace-title" on:click|stopPropagation> |
| 170 | + <h2 id="add-workspace-title">Add Workspace</h2> |
| 171 | + |
| 172 | + <label for="new-workspace-app-token">Slack App Token</label> |
| 173 | + <input |
| 174 | + id="new-workspace-app-token" |
| 175 | + type="text" |
| 176 | + value={pendingSlackAppToken} |
| 177 | + on:input={onPendingSlackAppTokenInput} |
| 178 | + placeholder="xapp-..." |
| 179 | + /> |
| 180 | + |
| 181 | + <label for="new-workspace-bot-token">Slack Bot Token</label> |
| 182 | + <input |
| 183 | + id="new-workspace-bot-token" |
| 184 | + type="text" |
| 185 | + value={pendingSlackBotToken} |
| 186 | + on:input={onPendingSlackBotTokenInput} |
| 187 | + placeholder="xoxb-..." |
| 188 | + /> |
| 189 | + |
| 190 | + <div class="dialog-actions"> |
| 191 | + <button type="button" on:click={closeAddWorkspaceDialog}>Cancel</button> |
| 192 | + <button |
| 193 | + type="button" |
| 194 | + on:click={() => void addWorkspace()} |
| 195 | + disabled={$localSettingStore.isLoading || $localSettingStore.isSaving || $localSettingStore.isSyncingSlack || $localSettingStore.isAddingWorkspace || $localSettingStore.isCheckingCli} |
| 196 | + > |
| 197 | + {$localSettingStore.isAddingWorkspace ? "Adding..." : "Add Workspace"} |
| 198 | + </button> |
| 199 | + </div> |
| 200 | + </div> |
| 201 | + </div> |
| 202 | +{/if} |
| 203 | + |
175 | 204 | <style> |
176 | 205 | :global(body) { |
177 | 206 | background: var(--bg); |
|
248 | 277 | color: var(--ink-soft); |
249 | 278 | } |
250 | 279 |
|
251 | | - .workspace-row { |
252 | | - display: grid; |
253 | | - grid-template-columns: minmax(0, 1fr) auto; |
254 | | - gap: 8px; |
255 | | - } |
256 | | -
|
257 | | - .workspace-remove { |
258 | | - border-color: var(--line); |
259 | | - color: var(--ink-soft); |
260 | | - background: var(--bg-soft); |
261 | | - padding: 9px 8px; |
262 | | - } |
263 | | -
|
264 | 280 | .nav-item { |
265 | 281 | width: 100%; |
266 | 282 | text-align: left; |
|
298 | 314 | justify-content: flex-end; |
299 | 315 | } |
300 | 316 |
|
| 317 | + .danger-action { |
| 318 | + border-color: #bf3a2b; |
| 319 | + color: #bf3a2b; |
| 320 | + } |
| 321 | +
|
| 322 | + .dialog-backdrop { |
| 323 | + position: fixed; |
| 324 | + inset: 0; |
| 325 | + background: color-mix(in srgb, var(--ink) 24%, transparent); |
| 326 | + display: grid; |
| 327 | + place-items: center; |
| 328 | + z-index: 50; |
| 329 | + padding: 16px; |
| 330 | + } |
| 331 | +
|
| 332 | + .dialog { |
| 333 | + width: min(520px, 100%); |
| 334 | + margin: 0; |
| 335 | + } |
| 336 | +
|
| 337 | + .dialog-actions { |
| 338 | + display: flex; |
| 339 | + justify-content: flex-end; |
| 340 | + gap: 8px; |
| 341 | + } |
| 342 | +
|
301 | 343 | .message, |
302 | 344 | .empty-tip { |
303 | 345 | margin: 0; |
|
0 commit comments