@cat-factory/app 0.46.9 → 0.46.11
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 +106 -88
- package/app/components/board/AgentFailureCard.vue +8 -5
- package/app/components/board/AgentStopButton.vue +8 -5
- package/app/components/board/BoardCanvas.vue +13 -9
- package/app/components/board/RecurringPipelineModal.vue +33 -23
- package/app/components/board/nodes/BlockNode.vue +50 -34
- package/app/components/board/nodes/DecisionBadge.vue +6 -3
- package/app/components/board/nodes/DraggableTask.vue +2 -1
- package/app/components/board/nodes/EpicNode.vue +10 -3
- package/app/components/board/nodes/ModuleFrame.vue +6 -5
- package/app/components/board/nodes/TaskCard.vue +40 -22
- package/app/components/board/nodes/TaskPipelineMini.vue +4 -3
- package/app/components/layout/BoardToolbar.vue +26 -19
- package/app/components/observability/StepMetricsBar.vue +31 -11
- package/app/components/observability/StepModelActivity.vue +3 -2
- package/app/components/panels/AgentStepDetail.vue +52 -39
- package/app/components/panels/DecisionModal.vue +12 -5
- package/app/components/panels/GenericStructuredResultView.vue +16 -6
- package/app/components/panels/InspectorPanel.vue +35 -28
- package/app/components/panels/ObservabilityPanel.vue +92 -49
- package/app/components/panels/StepMetadataCard.vue +87 -30
- package/app/components/panels/StepRestartControl.vue +4 -3
- package/app/components/panels/StepRunMeta.vue +23 -10
- package/app/components/panels/StepTestReport.vue +14 -11
- package/app/components/panels/inspector/ContainerSummary.vue +25 -14
- package/app/components/panels/inspector/EpicChildren.vue +7 -4
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +60 -19
- package/app/components/panels/inspector/ServiceFragments.vue +3 -2
- package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +18 -13
- package/app/components/panels/inspector/ServiceTestConfig.vue +50 -39
- package/app/components/panels/inspector/TaskAgentConfig.vue +6 -5
- package/app/components/panels/inspector/TaskDependencies.vue +9 -4
- package/app/components/panels/inspector/TaskEstimateBadge.vue +14 -13
- package/app/components/panels/inspector/TaskExecution.vue +65 -31
- package/app/components/panels/inspector/TaskRunSettings.vue +93 -56
- package/app/components/panels/inspector/TaskStructure.vue +5 -4
- package/i18n/locales/en.json +606 -0
- package/i18n/locales/es.json +596 -2
- package/i18n/locales/fr.json +596 -2
- package/i18n/locales/pl.json +596 -2
- package/i18n/locales/uk.json +596 -2
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ const accounts = useAccountsStore()
|
|
|
15
15
|
const tracker = useTrackerStore()
|
|
16
16
|
const ui = useUiStore()
|
|
17
17
|
const { ready, unavailableInPreset } = useAiReadiness()
|
|
18
|
+
const { t, n } = useI18n()
|
|
18
19
|
|
|
19
20
|
// ---- responsible product person --------------------------------------------
|
|
20
21
|
// The account member (a `product` role-holder) accountable for this task; they are
|
|
@@ -34,7 +35,11 @@ const responsibleLabel = computed(() => {
|
|
|
34
35
|
})
|
|
35
36
|
const responsibleMenu = computed(() => [
|
|
36
37
|
[
|
|
37
|
-
{
|
|
38
|
+
{
|
|
39
|
+
label: t('inspector.runSettings.unassigned'),
|
|
40
|
+
icon: 'i-lucide-user-x',
|
|
41
|
+
onSelect: () => setResponsible(''),
|
|
42
|
+
},
|
|
38
43
|
...productMembers.value.map((m) => ({
|
|
39
44
|
label: m.name || m.email || m.userId,
|
|
40
45
|
icon: 'i-lucide-user',
|
|
@@ -62,8 +67,11 @@ const presetMenu = computed(() => [
|
|
|
62
67
|
[
|
|
63
68
|
{
|
|
64
69
|
label: mergePresets.defaultPreset
|
|
65
|
-
?
|
|
66
|
-
|
|
70
|
+
? t('inspector.runSettings.defaultPresetThresholds', {
|
|
71
|
+
name: mergePresets.defaultPreset.name,
|
|
72
|
+
thresholds: mergePresetThresholds(mergePresets.defaultPreset),
|
|
73
|
+
})
|
|
74
|
+
: t('inspector.runSettings.workspaceDefault'),
|
|
67
75
|
icon: 'i-lucide-rotate-ccw',
|
|
68
76
|
onSelect: () => setPreset(''),
|
|
69
77
|
},
|
|
@@ -99,8 +107,8 @@ const modelPresetMenu = computed(() => [
|
|
|
99
107
|
[
|
|
100
108
|
{
|
|
101
109
|
label: modelPresets.defaultPreset
|
|
102
|
-
?
|
|
103
|
-
: '
|
|
110
|
+
? t('inspector.runSettings.defaultPreset', { name: modelPresets.defaultPreset.name })
|
|
111
|
+
: t('inspector.runSettings.workspaceDefault'),
|
|
104
112
|
icon: 'i-lucide-rotate-ccw',
|
|
105
113
|
onSelect: () => setModelPreset(''),
|
|
106
114
|
},
|
|
@@ -124,7 +132,7 @@ const selectedPipeline = computed(() =>
|
|
|
124
132
|
const pipelineMenu = computed(() => [
|
|
125
133
|
[
|
|
126
134
|
{
|
|
127
|
-
label: '
|
|
135
|
+
label: t('inspector.runSettings.noDefault'),
|
|
128
136
|
icon: 'i-lucide-rotate-ccw',
|
|
129
137
|
onSelect: () => setPipeline(''),
|
|
130
138
|
},
|
|
@@ -151,9 +159,13 @@ function setResolveOnMerge(value: WritebackOverride | null) {
|
|
|
151
159
|
function writebackMenu(set: (value: WritebackOverride | null) => void) {
|
|
152
160
|
return [
|
|
153
161
|
[
|
|
154
|
-
{
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
{
|
|
163
|
+
label: t('inspector.runSettings.inheritWorkspace'),
|
|
164
|
+
icon: 'i-lucide-rotate-ccw',
|
|
165
|
+
onSelect: () => set(null),
|
|
166
|
+
},
|
|
167
|
+
{ label: t('inspector.runSettings.on'), icon: 'i-lucide-check', onSelect: () => set('on') },
|
|
168
|
+
{ label: t('inspector.runSettings.off'), icon: 'i-lucide-x', onSelect: () => set('off') },
|
|
157
169
|
],
|
|
158
170
|
]
|
|
159
171
|
}
|
|
@@ -162,9 +174,9 @@ function writebackLabel(
|
|
|
162
174
|
override: WritebackOverride | null | undefined,
|
|
163
175
|
wsDefault: boolean,
|
|
164
176
|
): string {
|
|
165
|
-
if (override === 'on') return '
|
|
166
|
-
if (override === 'off') return '
|
|
167
|
-
return
|
|
177
|
+
if (override === 'on') return t('inspector.runSettings.on')
|
|
178
|
+
if (override === 'off') return t('inspector.runSettings.off')
|
|
179
|
+
return wsDefault ? t('inspector.runSettings.inheritOn') : t('inspector.runSettings.inheritOff')
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
const commentOnPrOpenLabel = computed(() =>
|
|
@@ -182,21 +194,29 @@ const resolveOnMergeLabel = computed(() =>
|
|
|
182
194
|
function setTechnical(value: boolean | null) {
|
|
183
195
|
board.updateBlock(props.block.id, { technical: value })
|
|
184
196
|
}
|
|
185
|
-
const technicalMenu = [
|
|
197
|
+
const technicalMenu = computed(() => [
|
|
186
198
|
[
|
|
187
199
|
{
|
|
188
|
-
label: '
|
|
200
|
+
label: t('inspector.runSettings.technical.unset'),
|
|
189
201
|
icon: 'i-lucide-rotate-ccw',
|
|
190
202
|
onSelect: () => setTechnical(null),
|
|
191
203
|
},
|
|
192
|
-
{
|
|
193
|
-
|
|
204
|
+
{
|
|
205
|
+
label: t('inspector.runSettings.technical.technical'),
|
|
206
|
+
icon: 'i-lucide-wrench',
|
|
207
|
+
onSelect: () => setTechnical(true),
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
label: t('inspector.runSettings.technical.business'),
|
|
211
|
+
icon: 'i-lucide-briefcase',
|
|
212
|
+
onSelect: () => setTechnical(false),
|
|
213
|
+
},
|
|
194
214
|
],
|
|
195
|
-
]
|
|
215
|
+
])
|
|
196
216
|
const technicalLabel = computed(() => {
|
|
197
|
-
if (props.block.technical === true) return '
|
|
198
|
-
if (props.block.technical === false) return '
|
|
199
|
-
return '
|
|
217
|
+
if (props.block.technical === true) return t('inspector.runSettings.technical.technical')
|
|
218
|
+
if (props.block.technical === false) return t('inspector.runSettings.technical.business')
|
|
219
|
+
return t('inspector.runSettings.technical.unset')
|
|
200
220
|
})
|
|
201
221
|
</script>
|
|
202
222
|
|
|
@@ -206,7 +226,7 @@ const technicalLabel = computed(() => {
|
|
|
206
226
|
<div>
|
|
207
227
|
<div class="mb-1 flex items-center justify-between">
|
|
208
228
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
209
|
-
|
|
229
|
+
{{ t('inspector.runSettings.pipeline') }}
|
|
210
230
|
</span>
|
|
211
231
|
<UDropdownMenu :items="pipelineMenu">
|
|
212
232
|
<UButton
|
|
@@ -230,7 +250,7 @@ const technicalLabel = computed(() => {
|
|
|
230
250
|
</UBadge>
|
|
231
251
|
</div>
|
|
232
252
|
<div v-else class="text-[11px] text-slate-500">
|
|
233
|
-
|
|
253
|
+
{{ t('inspector.runSettings.pipelineEmpty') }}
|
|
234
254
|
</div>
|
|
235
255
|
</div>
|
|
236
256
|
|
|
@@ -238,7 +258,7 @@ const technicalLabel = computed(() => {
|
|
|
238
258
|
<div>
|
|
239
259
|
<div class="mb-1 flex items-center justify-between">
|
|
240
260
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
241
|
-
|
|
261
|
+
{{ t('inspector.runSettings.mergePolicy') }}
|
|
242
262
|
</span>
|
|
243
263
|
<UDropdownMenu :items="presetMenu">
|
|
244
264
|
<UButton
|
|
@@ -251,15 +271,21 @@ const technicalLabel = computed(() => {
|
|
|
251
271
|
</UDropdownMenu>
|
|
252
272
|
</div>
|
|
253
273
|
<div v-if="selectedPreset" class="text-[11px] text-slate-400">
|
|
254
|
-
<
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
274
|
+
<i18n-t keypath="inspector.runSettings.mergePresetDetail" tag="span" scope="global">
|
|
275
|
+
<template #name>
|
|
276
|
+
<span class="text-slate-300">{{ selectedPreset.name }}</span>
|
|
277
|
+
</template>
|
|
278
|
+
<template #complexity>{{ n(selectedPreset.maxComplexity, { key: 'percent' }) }}</template>
|
|
279
|
+
<template #risk>{{ n(selectedPreset.maxRisk, { key: 'percent' }) }}</template>
|
|
280
|
+
<template #impact>{{ n(selectedPreset.maxImpact, { key: 'percent' }) }}</template>
|
|
281
|
+
<template #attempts>{{ selectedPreset.ciMaxAttempts }}</template>
|
|
282
|
+
</i18n-t>
|
|
283
|
+
<span v-if="!block.mergePresetId" class="text-slate-500">{{
|
|
284
|
+
t('inspector.runSettings.workspaceDefaultParen')
|
|
285
|
+
}}</span>
|
|
260
286
|
</div>
|
|
261
287
|
<div v-else class="text-[11px] text-slate-500">
|
|
262
|
-
|
|
288
|
+
{{ t('inspector.runSettings.mergePresetEmpty') }}
|
|
263
289
|
</div>
|
|
264
290
|
</div>
|
|
265
291
|
|
|
@@ -267,7 +293,7 @@ const technicalLabel = computed(() => {
|
|
|
267
293
|
<div>
|
|
268
294
|
<div class="mb-1 flex items-center justify-between">
|
|
269
295
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
270
|
-
|
|
296
|
+
{{ t('inspector.runSettings.modelPreset') }}
|
|
271
297
|
</span>
|
|
272
298
|
<UDropdownMenu :items="modelPresetMenu">
|
|
273
299
|
<UButton
|
|
@@ -281,14 +307,21 @@ const technicalLabel = computed(() => {
|
|
|
281
307
|
</div>
|
|
282
308
|
<div v-if="selectedModelPreset" class="text-[11px] text-slate-400">
|
|
283
309
|
<span class="text-slate-300">{{ selectedModelPreset.name }}</span>
|
|
284
|
-
|
|
285
|
-
}}<span v-if="Object.keys(selectedModelPreset.overrides).length">
|
|
286
|
-
|
|
310
|
+
{{ t('inspector.runSettings.modelPresetBase', { model: selectedModelPreset.baseModelId })
|
|
311
|
+
}}<span v-if="Object.keys(selectedModelPreset.overrides).length">{{
|
|
312
|
+
t(
|
|
313
|
+
'inspector.runSettings.modelPresetOverrides',
|
|
314
|
+
{ count: Object.keys(selectedModelPreset.overrides).length },
|
|
315
|
+
Object.keys(selectedModelPreset.overrides).length,
|
|
316
|
+
)
|
|
317
|
+
}}</span
|
|
287
318
|
>.
|
|
288
|
-
<span v-if="!block.modelPresetId" class="text-slate-500">
|
|
319
|
+
<span v-if="!block.modelPresetId" class="text-slate-500">{{
|
|
320
|
+
t('inspector.runSettings.workspaceDefaultParen')
|
|
321
|
+
}}</span>
|
|
289
322
|
</div>
|
|
290
323
|
<div v-else class="text-[11px] text-slate-500">
|
|
291
|
-
|
|
324
|
+
{{ t('inspector.runSettings.modelPresetEmpty') }}
|
|
292
325
|
</div>
|
|
293
326
|
<div
|
|
294
327
|
v-if="unavailablePresetModels.length"
|
|
@@ -301,29 +334,31 @@ const technicalLabel = computed(() => {
|
|
|
301
334
|
/>
|
|
302
335
|
<div class="min-w-0">
|
|
303
336
|
<p>
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
337
|
+
<i18n-t keypath="inspector.runSettings.unavailableModels" tag="span" scope="global">
|
|
338
|
+
<template #models>
|
|
339
|
+
<span class="text-amber-100">{{ unavailablePresetModels.join(', ') }}</span>
|
|
340
|
+
</template>
|
|
341
|
+
</i18n-t>
|
|
307
342
|
</p>
|
|
308
343
|
<div class="mt-1.5 flex flex-wrap gap-2">
|
|
309
344
|
<button
|
|
310
345
|
class="font-medium text-amber-100 underline-offset-2 hover:underline"
|
|
311
346
|
@click="ui.openModelConfig()"
|
|
312
347
|
>
|
|
313
|
-
|
|
348
|
+
{{ t('inspector.runSettings.editPresets') }}
|
|
314
349
|
</button>
|
|
315
350
|
<button
|
|
316
351
|
class="font-medium text-amber-100 underline-offset-2 hover:underline"
|
|
317
352
|
@click="ui.openVendorCredentials()"
|
|
318
353
|
>
|
|
319
|
-
|
|
354
|
+
{{ t('inspector.runSettings.configureVendors') }}
|
|
320
355
|
</button>
|
|
321
356
|
</div>
|
|
322
357
|
</div>
|
|
323
358
|
</div>
|
|
324
359
|
</div>
|
|
325
360
|
<p class="mt-1 text-[11px] text-slate-500">
|
|
326
|
-
|
|
361
|
+
{{ t('inspector.runSettings.modelPresetChangeHint') }}
|
|
327
362
|
</p>
|
|
328
363
|
</div>
|
|
329
364
|
|
|
@@ -331,7 +366,7 @@ const technicalLabel = computed(() => {
|
|
|
331
366
|
<div>
|
|
332
367
|
<div class="mb-1 flex items-center justify-between">
|
|
333
368
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
334
|
-
|
|
369
|
+
{{ t('inspector.runSettings.taskKind') }}
|
|
335
370
|
</span>
|
|
336
371
|
<UDropdownMenu :items="technicalMenu">
|
|
337
372
|
<UButton
|
|
@@ -347,14 +382,13 @@ const technicalLabel = computed(() => {
|
|
|
347
382
|
</div>
|
|
348
383
|
<div class="text-[11px] text-slate-500">
|
|
349
384
|
<template v-if="block.technical === true">
|
|
350
|
-
|
|
351
|
-
regression reference; the spec-writer may produce no business specs.
|
|
385
|
+
{{ t('inspector.runSettings.technicalHint.technical') }}
|
|
352
386
|
</template>
|
|
353
387
|
<template v-else-if="block.technical === false">
|
|
354
|
-
|
|
388
|
+
{{ t('inspector.runSettings.technicalHint.business') }}
|
|
355
389
|
</template>
|
|
356
390
|
<template v-else>
|
|
357
|
-
|
|
391
|
+
{{ t('inspector.runSettings.technicalHint.unset') }}
|
|
358
392
|
</template>
|
|
359
393
|
</div>
|
|
360
394
|
</div>
|
|
@@ -363,12 +397,14 @@ const technicalLabel = computed(() => {
|
|
|
363
397
|
<div>
|
|
364
398
|
<div class="mb-1 flex items-center justify-between">
|
|
365
399
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
366
|
-
|
|
400
|
+
{{ t('inspector.runSettings.issueWriteback') }}
|
|
367
401
|
</span>
|
|
368
402
|
</div>
|
|
369
403
|
<div class="space-y-1.5">
|
|
370
404
|
<div class="flex items-center justify-between">
|
|
371
|
-
<span class="text-[11px] text-slate-400">
|
|
405
|
+
<span class="text-[11px] text-slate-400">{{
|
|
406
|
+
t('inspector.runSettings.commentOnPrOpen')
|
|
407
|
+
}}</span>
|
|
372
408
|
<UDropdownMenu :items="writebackMenu(setCommentOnPrOpen)">
|
|
373
409
|
<UButton
|
|
374
410
|
size="xs"
|
|
@@ -381,7 +417,9 @@ const technicalLabel = computed(() => {
|
|
|
381
417
|
</UDropdownMenu>
|
|
382
418
|
</div>
|
|
383
419
|
<div class="flex items-center justify-between">
|
|
384
|
-
<span class="text-[11px] text-slate-400">
|
|
420
|
+
<span class="text-[11px] text-slate-400">{{
|
|
421
|
+
t('inspector.runSettings.closeOnMerge')
|
|
422
|
+
}}</span>
|
|
385
423
|
<UDropdownMenu :items="writebackMenu(setResolveOnMerge)">
|
|
386
424
|
<UButton
|
|
387
425
|
size="xs"
|
|
@@ -395,7 +433,7 @@ const technicalLabel = computed(() => {
|
|
|
395
433
|
</div>
|
|
396
434
|
</div>
|
|
397
435
|
<div class="mt-1 text-[11px] text-slate-500">
|
|
398
|
-
|
|
436
|
+
{{ t('inspector.runSettings.writebackHint') }}
|
|
399
437
|
</div>
|
|
400
438
|
</div>
|
|
401
439
|
|
|
@@ -403,7 +441,7 @@ const technicalLabel = computed(() => {
|
|
|
403
441
|
<div>
|
|
404
442
|
<div class="mb-1 flex items-center justify-between">
|
|
405
443
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
406
|
-
|
|
444
|
+
{{ t('inspector.runSettings.responsibleProduct') }}
|
|
407
445
|
</span>
|
|
408
446
|
<UDropdownMenu :items="responsibleMenu">
|
|
409
447
|
<UButton
|
|
@@ -427,7 +465,7 @@ const technicalLabel = computed(() => {
|
|
|
427
465
|
</UBadge>
|
|
428
466
|
</div>
|
|
429
467
|
<div v-else class="text-[11px] text-slate-500">
|
|
430
|
-
|
|
468
|
+
{{ t('inspector.runSettings.responsibleEmpty') }}
|
|
431
469
|
</div>
|
|
432
470
|
</div>
|
|
433
471
|
|
|
@@ -435,7 +473,7 @@ const technicalLabel = computed(() => {
|
|
|
435
473
|
<div>
|
|
436
474
|
<div class="flex items-center justify-between gap-2">
|
|
437
475
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
438
|
-
|
|
476
|
+
{{ t('inspector.runSettings.autoStartDependents') }}
|
|
439
477
|
</span>
|
|
440
478
|
<USwitch
|
|
441
479
|
size="sm"
|
|
@@ -444,8 +482,7 @@ const technicalLabel = computed(() => {
|
|
|
444
482
|
/>
|
|
445
483
|
</div>
|
|
446
484
|
<div class="mt-1 text-[11px] text-slate-500">
|
|
447
|
-
|
|
448
|
-
dependencies are also done).
|
|
485
|
+
{{ t('inspector.runSettings.autoStartHint') }}
|
|
449
486
|
</div>
|
|
450
487
|
</div>
|
|
451
488
|
</div>
|
|
@@ -5,6 +5,7 @@ const props = defineProps<{ block: Block }>()
|
|
|
5
5
|
|
|
6
6
|
const board = useBoardStore()
|
|
7
7
|
const fragments = useFragmentsStore()
|
|
8
|
+
const { t } = useI18n()
|
|
8
9
|
|
|
9
10
|
// ---- best-practice prompt fragments ----------------------------------------
|
|
10
11
|
// Selected fragments (resolved against the catalog; unknown ids are dropped).
|
|
@@ -47,13 +48,13 @@ function removeFragment(id: string) {
|
|
|
47
48
|
<!-- module assignment -->
|
|
48
49
|
<div>
|
|
49
50
|
<div class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
50
|
-
|
|
51
|
+
{{ t('inspector.structure.module') }}
|
|
51
52
|
</div>
|
|
52
53
|
<UInput
|
|
53
54
|
v-model="block.moduleName"
|
|
54
55
|
size="sm"
|
|
55
56
|
class="w-full"
|
|
56
|
-
placeholder="
|
|
57
|
+
:placeholder="t('inspector.structure.modulePlaceholder')"
|
|
57
58
|
icon="i-lucide-package"
|
|
58
59
|
/>
|
|
59
60
|
</div>
|
|
@@ -62,7 +63,7 @@ function removeFragment(id: string) {
|
|
|
62
63
|
<div>
|
|
63
64
|
<div class="mb-1 flex items-center justify-between">
|
|
64
65
|
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
65
|
-
|
|
66
|
+
{{ t('inspector.structure.bestPractices') }}
|
|
66
67
|
</span>
|
|
67
68
|
<UDropdownMenu v-if="fragmentMenu.length" :items="fragmentMenu">
|
|
68
69
|
<UButton
|
|
@@ -89,7 +90,7 @@ function removeFragment(id: string) {
|
|
|
89
90
|
</UBadge>
|
|
90
91
|
</div>
|
|
91
92
|
<div v-else class="text-[11px] text-slate-500">
|
|
92
|
-
|
|
93
|
+
{{ t('inspector.structure.bestPracticesEmpty') }}
|
|
93
94
|
</div>
|
|
94
95
|
</div>
|
|
95
96
|
</div>
|