@cat-factory/app 0.9.0 → 0.10.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/app/components/board/AddTaskModal.vue +209 -21
- package/app/components/board/nodes/BlockNode.vue +2 -2
- package/app/components/focus/BlockFocusView.vue +2 -2
- package/app/components/layout/CommandBar.vue +7 -33
- package/app/components/layout/IntegrationsHub.vue +230 -0
- package/app/components/layout/SideBar.vue +8 -170
- package/app/components/panels/GenericStructuredResultView.vue +131 -0
- package/app/components/panels/InspectorPanel.vue +6 -2
- package/app/components/panels/StepResultViewHost.vue +4 -0
- package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +148 -0
- package/app/components/settings/IssueTrackerWritebackPanel.vue +45 -57
- package/app/components/settings/MergeThresholdsPanel.vue +189 -226
- package/app/components/settings/ObservabilityConnectionPanel.vue +151 -0
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +46 -61
- package/app/components/settings/WorkspaceSettingsPanel.vue +136 -63
- package/app/composables/api/releaseHealth.ts +11 -10
- package/app/pages/index.vue +4 -8
- package/app/stores/agents.ts +27 -2
- package/app/stores/releaseHealth.ts +48 -12
- package/app/stores/ui.ts +34 -42
- package/app/stores/workspace.ts +4 -0
- package/app/types/domain.ts +33 -1
- package/app/types/execution.ts +6 -0
- package/app/types/releaseHealth.ts +19 -11
- package/app/utils/catalog.spec.ts +10 -0
- package/app/utils/catalog.ts +20 -6
- package/package.json +2 -2
- package/app/components/board/ContextPicker.vue +0 -367
- package/app/components/settings/DatadogPanel.vue +0 -213
|
@@ -15,15 +15,9 @@ const CONCERN_LEVELS: { value: RequirementConcernLevel; label: string }[] = [
|
|
|
15
15
|
{ value: 'high', label: 'High (never stop)' },
|
|
16
16
|
]
|
|
17
17
|
|
|
18
|
-
const ui = useUiStore()
|
|
19
18
|
const store = useMergePresetsStore()
|
|
20
19
|
const toast = useToast()
|
|
21
20
|
|
|
22
|
-
const open = computed({
|
|
23
|
-
get: () => ui.mergeThresholdsOpen,
|
|
24
|
-
set: (v: boolean) => (v ? ui.openMergeThresholds() : ui.closeMergeThresholds()),
|
|
25
|
-
})
|
|
26
|
-
|
|
27
21
|
// Local editable copy per preset, kept in sync with the store. Percentages are
|
|
28
22
|
// edited 0..100 and stored 0..1.
|
|
29
23
|
interface Draft {
|
|
@@ -149,230 +143,199 @@ async function create() {
|
|
|
149
143
|
</script>
|
|
150
144
|
|
|
151
145
|
<template>
|
|
152
|
-
<
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
that picks none.
|
|
161
|
-
</p>
|
|
146
|
+
<div class="space-y-4">
|
|
147
|
+
<p class="text-xs text-slate-400">
|
|
148
|
+
Named auto-merge policies a task can choose. After CI passes, the
|
|
149
|
+
<span class="text-slate-300">merger</span> agent scores the PR on complexity, risk and impact
|
|
150
|
+
(0–100%); the PR auto-merges only when every score is at or below the preset's ceilings —
|
|
151
|
+
otherwise a review notification is raised. The default preset governs any task that picks
|
|
152
|
+
none.
|
|
153
|
+
</p>
|
|
162
154
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
155
|
+
<div
|
|
156
|
+
v-for="p in store.presets"
|
|
157
|
+
:key="p.id"
|
|
158
|
+
class="rounded-lg border border-slate-700 bg-slate-800/40 p-3"
|
|
159
|
+
>
|
|
160
|
+
<div class="mb-3 flex items-center gap-2">
|
|
161
|
+
<UInput v-model="drafts[p.id]!.name" size="sm" class="flex-1" placeholder="Preset name" />
|
|
162
|
+
<UBadge v-if="p.isDefault" color="primary" variant="subtle" size="sm">Default</UBadge>
|
|
163
|
+
<UButton
|
|
164
|
+
v-else
|
|
165
|
+
color="neutral"
|
|
166
|
+
variant="ghost"
|
|
167
|
+
size="xs"
|
|
168
|
+
icon="i-lucide-star"
|
|
169
|
+
:loading="busy === p.id"
|
|
170
|
+
@click="makeDefault(p)"
|
|
167
171
|
>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
size="xs"
|
|
181
|
-
icon="i-lucide-star"
|
|
182
|
-
:loading="busy === p.id"
|
|
183
|
-
@click="makeDefault(p)"
|
|
184
|
-
>
|
|
185
|
-
Make default
|
|
186
|
-
</UButton>
|
|
187
|
-
<UButton
|
|
188
|
-
color="error"
|
|
189
|
-
variant="ghost"
|
|
190
|
-
size="xs"
|
|
191
|
-
icon="i-lucide-trash-2"
|
|
192
|
-
:disabled="p.isDefault || busy === p.id"
|
|
193
|
-
:title="p.isDefault ? 'The default preset cannot be deleted' : 'Delete preset'"
|
|
194
|
-
@click="remove(p)"
|
|
195
|
-
/>
|
|
196
|
-
</div>
|
|
172
|
+
Make default
|
|
173
|
+
</UButton>
|
|
174
|
+
<UButton
|
|
175
|
+
color="error"
|
|
176
|
+
variant="ghost"
|
|
177
|
+
size="xs"
|
|
178
|
+
icon="i-lucide-trash-2"
|
|
179
|
+
:disabled="p.isDefault || busy === p.id"
|
|
180
|
+
:title="p.isDefault ? 'The default preset cannot be deleted' : 'Delete preset'"
|
|
181
|
+
@click="remove(p)"
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
197
184
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
185
|
+
<div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
|
186
|
+
<label class="block">
|
|
187
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
188
|
+
Max complexity %
|
|
189
|
+
</span>
|
|
190
|
+
<UInput
|
|
191
|
+
v-model.number="drafts[p.id]!.maxComplexity"
|
|
192
|
+
type="number"
|
|
193
|
+
:min="0"
|
|
194
|
+
:max="100"
|
|
195
|
+
size="sm"
|
|
196
|
+
/>
|
|
197
|
+
</label>
|
|
198
|
+
<label class="block">
|
|
199
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
200
|
+
Max risk %
|
|
201
|
+
</span>
|
|
202
|
+
<UInput
|
|
203
|
+
v-model.number="drafts[p.id]!.maxRisk"
|
|
204
|
+
type="number"
|
|
205
|
+
:min="0"
|
|
206
|
+
:max="100"
|
|
207
|
+
size="sm"
|
|
208
|
+
/>
|
|
209
|
+
</label>
|
|
210
|
+
<label class="block">
|
|
211
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
212
|
+
Max impact %
|
|
213
|
+
</span>
|
|
214
|
+
<UInput
|
|
215
|
+
v-model.number="drafts[p.id]!.maxImpact"
|
|
216
|
+
type="number"
|
|
217
|
+
:min="0"
|
|
218
|
+
:max="100"
|
|
219
|
+
size="sm"
|
|
220
|
+
/>
|
|
221
|
+
</label>
|
|
222
|
+
<label class="block">
|
|
223
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
224
|
+
CI-fix attempts
|
|
225
|
+
</span>
|
|
226
|
+
<UInput
|
|
227
|
+
v-model.number="drafts[p.id]!.ciMaxAttempts"
|
|
228
|
+
type="number"
|
|
229
|
+
:min="0"
|
|
230
|
+
:max="50"
|
|
231
|
+
size="sm"
|
|
232
|
+
/>
|
|
233
|
+
</label>
|
|
234
|
+
<label class="block">
|
|
235
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
236
|
+
Requirement iterations
|
|
237
|
+
</span>
|
|
238
|
+
<UInput
|
|
239
|
+
v-model.number="drafts[p.id]!.maxRequirementIterations"
|
|
240
|
+
type="number"
|
|
241
|
+
:min="1"
|
|
242
|
+
:max="20"
|
|
243
|
+
size="sm"
|
|
244
|
+
/>
|
|
245
|
+
</label>
|
|
246
|
+
<label class="block">
|
|
247
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
248
|
+
Auto-pass concerns ≤
|
|
249
|
+
</span>
|
|
250
|
+
<USelect
|
|
251
|
+
v-model="drafts[p.id]!.maxRequirementConcernAllowed"
|
|
252
|
+
:items="CONCERN_LEVELS"
|
|
253
|
+
value-key="value"
|
|
254
|
+
size="sm"
|
|
255
|
+
/>
|
|
256
|
+
</label>
|
|
257
|
+
</div>
|
|
271
258
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
259
|
+
<div class="mt-3 flex justify-end">
|
|
260
|
+
<UButton
|
|
261
|
+
color="primary"
|
|
262
|
+
variant="soft"
|
|
263
|
+
size="xs"
|
|
264
|
+
icon="i-lucide-save"
|
|
265
|
+
:loading="busy === p.id"
|
|
266
|
+
@click="save(p)"
|
|
267
|
+
>
|
|
268
|
+
Save
|
|
269
|
+
</UButton>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
285
272
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
</label>
|
|
352
|
-
<label class="block w-32">
|
|
353
|
-
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500"
|
|
354
|
-
>Auto-pass ≤</span
|
|
355
|
-
>
|
|
356
|
-
<USelect
|
|
357
|
-
v-model="draft.maxRequirementConcernAllowed"
|
|
358
|
-
:items="CONCERN_LEVELS"
|
|
359
|
-
value-key="value"
|
|
360
|
-
size="sm"
|
|
361
|
-
/>
|
|
362
|
-
</label>
|
|
363
|
-
<UButton
|
|
364
|
-
color="primary"
|
|
365
|
-
size="sm"
|
|
366
|
-
icon="i-lucide-plus"
|
|
367
|
-
:loading="creating"
|
|
368
|
-
:disabled="!draft.name.trim()"
|
|
369
|
-
@click="create"
|
|
370
|
-
>
|
|
371
|
-
Add
|
|
372
|
-
</UButton>
|
|
373
|
-
</div>
|
|
374
|
-
</div>
|
|
273
|
+
<!-- create -->
|
|
274
|
+
<div class="rounded-lg border border-dashed border-slate-700 p-3">
|
|
275
|
+
<p class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
276
|
+
New preset
|
|
277
|
+
</p>
|
|
278
|
+
<div class="flex flex-wrap items-end gap-3">
|
|
279
|
+
<label class="block min-w-40 flex-1">
|
|
280
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">Name</span>
|
|
281
|
+
<UInput v-model="draft.name" size="sm" placeholder="e.g. Cautious" />
|
|
282
|
+
</label>
|
|
283
|
+
<label class="block w-20">
|
|
284
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">Cmplx%</span>
|
|
285
|
+
<UInput
|
|
286
|
+
v-model.number="draft.maxComplexity"
|
|
287
|
+
type="number"
|
|
288
|
+
:min="0"
|
|
289
|
+
:max="100"
|
|
290
|
+
size="sm"
|
|
291
|
+
/>
|
|
292
|
+
</label>
|
|
293
|
+
<label class="block w-20">
|
|
294
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">Risk%</span>
|
|
295
|
+
<UInput v-model.number="draft.maxRisk" type="number" :min="0" :max="100" size="sm" />
|
|
296
|
+
</label>
|
|
297
|
+
<label class="block w-20">
|
|
298
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">Impact%</span>
|
|
299
|
+
<UInput v-model.number="draft.maxImpact" type="number" :min="0" :max="100" size="sm" />
|
|
300
|
+
</label>
|
|
301
|
+
<label class="block w-20">
|
|
302
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">CI-fix</span>
|
|
303
|
+
<UInput v-model.number="draft.ciMaxAttempts" type="number" :min="0" :max="50" size="sm" />
|
|
304
|
+
</label>
|
|
305
|
+
<label class="block w-20">
|
|
306
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500"
|
|
307
|
+
>Req iter</span
|
|
308
|
+
>
|
|
309
|
+
<UInput
|
|
310
|
+
v-model.number="draft.maxRequirementIterations"
|
|
311
|
+
type="number"
|
|
312
|
+
:min="1"
|
|
313
|
+
:max="20"
|
|
314
|
+
size="sm"
|
|
315
|
+
/>
|
|
316
|
+
</label>
|
|
317
|
+
<label class="block w-32">
|
|
318
|
+
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500"
|
|
319
|
+
>Auto-pass ≤</span
|
|
320
|
+
>
|
|
321
|
+
<USelect
|
|
322
|
+
v-model="draft.maxRequirementConcernAllowed"
|
|
323
|
+
:items="CONCERN_LEVELS"
|
|
324
|
+
value-key="value"
|
|
325
|
+
size="sm"
|
|
326
|
+
/>
|
|
327
|
+
</label>
|
|
328
|
+
<UButton
|
|
329
|
+
color="primary"
|
|
330
|
+
size="sm"
|
|
331
|
+
icon="i-lucide-plus"
|
|
332
|
+
:loading="creating"
|
|
333
|
+
:disabled="!draft.name.trim()"
|
|
334
|
+
@click="create"
|
|
335
|
+
>
|
|
336
|
+
Add
|
|
337
|
+
</UButton>
|
|
375
338
|
</div>
|
|
376
|
-
</
|
|
377
|
-
</
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
378
341
|
</template>
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// The observability connection — the post-release-health gate reads a pluggable
|
|
3
|
+
// observability provider (Datadog today). This panel owns ONLY the per-workspace
|
|
4
|
+
// connection (provider + credentials, write-only). The per-service monitor/SLO mapping
|
|
5
|
+
// lives in the service inspector (ServiceReleaseHealthConfig), so there is no manual
|
|
6
|
+
// block-id entry here. Opened from the Integrations hub.
|
|
7
|
+
import { computed, reactive, ref, watch } from 'vue'
|
|
8
|
+
import type { ObservabilityProviderKind } from '~/types/releaseHealth'
|
|
9
|
+
|
|
10
|
+
const ui = useUiStore()
|
|
11
|
+
const store = useReleaseHealthStore()
|
|
12
|
+
const toast = useToast()
|
|
13
|
+
|
|
14
|
+
const open = computed({
|
|
15
|
+
get: () => ui.observabilityConnectionOpen,
|
|
16
|
+
set: (v: boolean) => (v ? ui.openObservabilityConnection() : ui.closeObservabilityConnection()),
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
// The providers a user can connect. Datadog only today; the picker is ready for more.
|
|
20
|
+
const PROVIDERS: { value: ObservabilityProviderKind; label: string }[] = [
|
|
21
|
+
{ value: 'datadog', label: 'Datadog' },
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const provider = ref<ObservabilityProviderKind>('datadog')
|
|
25
|
+
const datadog = reactive({ site: 'datadoghq.com', apiKey: '', appKey: '' })
|
|
26
|
+
const busy = ref(false)
|
|
27
|
+
|
|
28
|
+
function notifyError(title: string, e: unknown) {
|
|
29
|
+
toast.add({
|
|
30
|
+
title,
|
|
31
|
+
description: e instanceof Error ? e.message : String(e),
|
|
32
|
+
icon: 'i-lucide-triangle-alert',
|
|
33
|
+
color: 'error',
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
watch(open, async (isOpen) => {
|
|
38
|
+
if (!isOpen) return
|
|
39
|
+
try {
|
|
40
|
+
await store.ensureLoaded()
|
|
41
|
+
if (store.connection.provider) provider.value = store.connection.provider
|
|
42
|
+
const site = store.connection.summary?.site
|
|
43
|
+
if (site) datadog.site = site
|
|
44
|
+
} catch (e) {
|
|
45
|
+
notifyError('Could not load observability settings', e)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
async function saveConnection() {
|
|
50
|
+
busy.value = true
|
|
51
|
+
try {
|
|
52
|
+
await store.saveConnection({
|
|
53
|
+
provider: provider.value,
|
|
54
|
+
credentials: { site: datadog.site, apiKey: datadog.apiKey, appKey: datadog.appKey },
|
|
55
|
+
})
|
|
56
|
+
datadog.apiKey = ''
|
|
57
|
+
datadog.appKey = ''
|
|
58
|
+
toast.add({ title: 'Observability connected', icon: 'i-lucide-check', color: 'success' })
|
|
59
|
+
} catch (e) {
|
|
60
|
+
notifyError('Could not save the connection', e)
|
|
61
|
+
} finally {
|
|
62
|
+
busy.value = false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function disconnect() {
|
|
67
|
+
busy.value = true
|
|
68
|
+
try {
|
|
69
|
+
await store.removeConnection()
|
|
70
|
+
} catch (e) {
|
|
71
|
+
notifyError('Could not disconnect', e)
|
|
72
|
+
} finally {
|
|
73
|
+
busy.value = false
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const connectedLabel = computed(() => {
|
|
78
|
+
if (!store.connection.connected) return 'Not connected'
|
|
79
|
+
const site = store.connection.summary?.site
|
|
80
|
+
return site ? `Connected (${site})` : 'Connected'
|
|
81
|
+
})
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<UModal v-model:open="open" title="Post-release health" :ui="{ content: 'max-w-lg' }">
|
|
86
|
+
<template #body>
|
|
87
|
+
<div class="space-y-4">
|
|
88
|
+
<p class="text-sm text-slate-400">
|
|
89
|
+
After a release ships, the <code>post-release-health</code> gate watches the configured
|
|
90
|
+
observability monitors/SLOs. On a regression it spawns an on-call agent to investigate (a
|
|
91
|
+
human decides whether to revert). Map which monitors/SLOs a service watches from that
|
|
92
|
+
service's inspector.
|
|
93
|
+
</p>
|
|
94
|
+
|
|
95
|
+
<section class="space-y-3 rounded-lg border border-slate-700 p-3">
|
|
96
|
+
<div class="flex items-center justify-between">
|
|
97
|
+
<h3 class="text-sm font-semibold">Connection</h3>
|
|
98
|
+
<UBadge :color="store.connection.connected ? 'success' : 'neutral'" variant="soft">
|
|
99
|
+
{{ connectedLabel }}
|
|
100
|
+
</UBadge>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<UFormField label="Provider">
|
|
104
|
+
<USelect v-model="provider" :items="PROVIDERS" value-key="value" class="w-full" />
|
|
105
|
+
</UFormField>
|
|
106
|
+
|
|
107
|
+
<template v-if="provider === 'datadog'">
|
|
108
|
+
<UFormField label="Datadog site">
|
|
109
|
+
<UInput v-model="datadog.site" placeholder="datadoghq.com" class="w-full" />
|
|
110
|
+
</UFormField>
|
|
111
|
+
<UFormField label="API key">
|
|
112
|
+
<UInput
|
|
113
|
+
v-model="datadog.apiKey"
|
|
114
|
+
type="password"
|
|
115
|
+
placeholder="DD-API-KEY"
|
|
116
|
+
class="w-full"
|
|
117
|
+
/>
|
|
118
|
+
</UFormField>
|
|
119
|
+
<UFormField label="Application key">
|
|
120
|
+
<UInput
|
|
121
|
+
v-model="datadog.appKey"
|
|
122
|
+
type="password"
|
|
123
|
+
placeholder="DD-APPLICATION-KEY"
|
|
124
|
+
class="w-full"
|
|
125
|
+
/>
|
|
126
|
+
</UFormField>
|
|
127
|
+
</template>
|
|
128
|
+
|
|
129
|
+
<div class="flex gap-2">
|
|
130
|
+
<UButton
|
|
131
|
+
:loading="busy"
|
|
132
|
+
:disabled="!datadog.apiKey || !datadog.appKey"
|
|
133
|
+
@click="saveConnection"
|
|
134
|
+
>
|
|
135
|
+
Save connection
|
|
136
|
+
</UButton>
|
|
137
|
+
<UButton
|
|
138
|
+
v-if="store.connection.connected"
|
|
139
|
+
color="error"
|
|
140
|
+
variant="soft"
|
|
141
|
+
:loading="busy"
|
|
142
|
+
@click="disconnect"
|
|
143
|
+
>
|
|
144
|
+
Disconnect
|
|
145
|
+
</UButton>
|
|
146
|
+
</div>
|
|
147
|
+
</section>
|
|
148
|
+
</div>
|
|
149
|
+
</template>
|
|
150
|
+
</UModal>
|
|
151
|
+
</template>
|