@stacksjs/defaults 0.70.366 → 0.70.368
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/ai/skills/stacks-browse/SKILL.md +9 -1
- package/ai/skills/stacks-dashboard/SKILL.md +49 -1
- package/ai/skills/stacks-deploy/SKILL.md +18 -0
- package/ai/skills/stacks-desktop/SKILL.md +11 -2
- package/ai/skills/stacks-stx/SKILL.md +25 -0
- package/app/Actions/Dashboard/Deployments/CreateDeployment.ts +64 -44
- package/app/Actions/Dashboard/Deployments/CreateDeploymentRollback.ts +26 -0
- package/app/Actions/Dashboard/Deployments/PreviewDeployment.ts +39 -0
- package/app/Actions/Dashboard/Deployments/PreviewDeploymentRollback.ts +22 -0
- package/app/Actions/Dashboard/Deployments/deployment-input.test.ts +12 -2
- package/app/Actions/Dashboard/Deployments/deployment-input.ts +5 -3
- package/app/Actions/Dashboard/Deployments/deployment-preview.test.ts +29 -0
- package/app/Actions/Dashboard/Deployments/deployment-preview.ts +41 -0
- package/app/Actions/Dashboard/Deployments/deployment-rollback.test.ts +16 -0
- package/app/Actions/Dashboard/Deployments/deployment-rollback.ts +89 -0
- package/app/Actions/Dashboard/Operations/AuditIndexAction.ts +25 -0
- package/app/Actions/Dashboard/Operations/ChangeApprovalAction.ts +28 -0
- package/app/Actions/Dashboard/Operations/ChangeIndexAction.ts +32 -0
- package/app/Actions/Dashboard/Operations/IncidentIndexAction.ts +32 -0
- package/app/Actions/Dashboard/Operations/IncidentUpdateAction.ts +34 -0
- package/app/Actions/Dashboard/Operations/MigrationApplyAction.ts +30 -0
- package/app/Actions/Dashboard/Operations/MigrationIndexAction.ts +24 -0
- package/app/Actions/Dashboard/Operations/MigrationReconcileAction.ts +23 -0
- package/app/Actions/Dashboard/Operations/RecoveryDestinationStoreAction.ts +91 -0
- package/app/Actions/Dashboard/Operations/RecoveryDestinationTestAction.ts +34 -0
- package/app/Actions/Dashboard/Operations/RecoveryIndexAction.ts +58 -0
- package/app/Actions/Dashboard/Operations/RecoveryPolicyStoreAction.ts +90 -0
- package/app/Actions/Dashboard/Operations/RecoveryProtectAction.ts +32 -0
- package/app/Actions/Dashboard/Operations/RecoveryRestoreAction.ts +72 -0
- package/app/Actions/Dashboard/Operations/RecoveryRetentionAction.ts +17 -0
- package/app/Actions/Dashboard/Operations/RecoveryRunAction.ts +25 -0
- package/app/Actions/Dashboard/Operations/RecoveryVerifyAction.ts +24 -0
- package/app/Actions/Dashboard/Operations/SchedulerIndexAction.ts +34 -0
- package/app/Actions/Dashboard/Operations/SchedulerRunAction.ts +33 -0
- package/app/Actions/Dashboard/Operations/SchedulerToggleAction.ts +36 -0
- package/app/Actions/Dashboard/Operations/control-plane.ts +150 -0
- package/app/Actions/Dashboard/Operations/migration-operations.ts +80 -0
- package/app/Actions/Dashboard/Operations/operations-runtime.ts +11 -0
- package/app/Actions/Dashboard/Operations/recovery-input.test.ts +22 -0
- package/app/Actions/Dashboard/Operations/recovery-input.ts +33 -0
- package/app/Actions/Dashboard/Operations/recovery-runtime.ts +99 -0
- package/app/Actions/Dashboard/Operations/scheduler-operations.test.ts +23 -0
- package/app/Actions/Dashboard/Operations/scheduler-operations.ts +138 -0
- package/functions/deployments.ts +18 -0
- package/functions/operations.ts +361 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +1 -1
- package/resources/components/Dashboard/Ci/CiDashboard.stx +4 -4
- package/resources/components/Dashboard/Deployments/DeploymentList.stx +147 -14
- package/resources/components/Dashboard/Deployments/DeploymentPreviewDialog.stx +118 -0
- package/resources/components/Dashboard/GlobalSearch.stx +87 -91
- package/resources/components/Dashboard/Operations/AuditDashboard.stx +16 -0
- package/resources/components/Dashboard/Operations/ChangeDashboard.stx +66 -0
- package/resources/components/Dashboard/Operations/IncidentDashboard.stx +39 -0
- package/resources/components/Dashboard/Operations/MigrationDashboard.stx +146 -0
- package/resources/components/Dashboard/Operations/OperationHistory.stx +61 -0
- package/resources/components/Dashboard/Operations/OperationsNavigation.stx +32 -0
- package/resources/components/Dashboard/Operations/RecoveryDashboard.stx +229 -0
- package/resources/components/Dashboard/Operations/RecoveryDestinationDialog.stx +126 -0
- package/resources/components/Dashboard/Operations/RecoveryJobList.stx +32 -0
- package/resources/components/Dashboard/Operations/RecoveryPointTable.stx +82 -0
- package/resources/components/Dashboard/Operations/RecoveryPolicyDialog.stx +155 -0
- package/resources/components/Dashboard/Operations/RecoveryRestoreDialog.stx +90 -0
- package/resources/components/Dashboard/Operations/SchedulerDashboard.stx +144 -0
- package/resources/components/Dashboard/Operations/SchedulerTaskTable.stx +81 -0
- package/resources/components/Dashboard/Settings/SettingsDashboard.stx +45 -3
- package/resources/components/Dashboard/UI/Modal.stx +33 -8
- package/resources/functions/dashboard/sidebar.ts +1 -0
- package/routes/dashboard-api.ts +23 -0
- package/routes/dashboard.ts +1 -0
- package/vcs/github/workflows/ci.yml +3 -3
- package/vcs/github/workflows/release.yml +1 -1
- package/views/dashboard/operations/audit.stx +5 -0
- package/views/dashboard/operations/changes.stx +5 -0
- package/views/dashboard/operations/incidents.stx +5 -0
- package/views/dashboard/operations/migrations.stx +8 -0
- package/views/dashboard/operations/recovery.stx +8 -0
- package/views/dashboard/operations/scheduler.stx +8 -0
- package/views/dashboard/stores/ci.ts +2 -2
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script client>
|
|
2
|
+
import type { SchedulerTask } from '../../../../functions/operations'
|
|
3
|
+
|
|
4
|
+
const tasks = useReactiveProp('tasks', [])
|
|
5
|
+
const loading = useReactiveProp('loading', false)
|
|
6
|
+
const busyTask = useReactiveProp('busyTask', '')
|
|
7
|
+
const emit = defineEmits()
|
|
8
|
+
|
|
9
|
+
function rows(): SchedulerTask[] {
|
|
10
|
+
return tasks() as SchedulerTask[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function formatDate(value: string | null): string {
|
|
14
|
+
if (!value)
|
|
15
|
+
return 'Not scheduled'
|
|
16
|
+
const date = new Date(value)
|
|
17
|
+
return Number.isNaN(date.getTime())
|
|
18
|
+
? value
|
|
19
|
+
: new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' }).format(date)
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 border border-gray-200 rounded-xl dark:border-neutral-700">
|
|
24
|
+
<div :if="loading()" class="px-5 py-14 text-center text-gray-500 text-sm dark:text-neutral-400">
|
|
25
|
+
Loading scheduled tasks
|
|
26
|
+
</div>
|
|
27
|
+
<div :if="!loading() && rows().length === 0" class="px-5 py-14 text-center">
|
|
28
|
+
<span aria-hidden="true" class="block mb-3 mx-auto h-9 w-9 text-gray-400 i-hugeicons-calendar-03"></span>
|
|
29
|
+
<p class="font-semibold text-gray-900 dark:text-white">No scheduled tasks registered</p>
|
|
30
|
+
<p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Add a rate to an app job or register a task in app/Scheduler.ts.</p>
|
|
31
|
+
</div>
|
|
32
|
+
<div :if="rows().length > 0" class="overflow-x-auto">
|
|
33
|
+
<table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
|
|
34
|
+
<thead class="bg-gray-50 dark:bg-neutral-700/50">
|
|
35
|
+
<tr>
|
|
36
|
+
<th class="px-4 py-3 font-medium text-gray-500 text-left text-xs uppercase dark:text-neutral-300">Task</th>
|
|
37
|
+
<th class="px-4 py-3 font-medium text-gray-500 text-left text-xs uppercase dark:text-neutral-300">Schedule</th>
|
|
38
|
+
<th class="px-4 py-3 font-medium text-gray-500 text-left text-xs uppercase dark:text-neutral-300">Next run</th>
|
|
39
|
+
<th class="px-4 py-3 font-medium text-gray-500 text-left text-xs uppercase dark:text-neutral-300">Status</th>
|
|
40
|
+
<th class="px-4 py-3"><span class="sr-only">Actions</span></th>
|
|
41
|
+
</tr>
|
|
42
|
+
</thead>
|
|
43
|
+
<tbody class="divide-gray-200 divide-y dark:divide-neutral-700">
|
|
44
|
+
<template :for="task in rows()">
|
|
45
|
+
<tr>
|
|
46
|
+
<td class="px-4 py-3">
|
|
47
|
+
<p class="font-medium text-gray-900 text-sm dark:text-white">{{ task.name }}</p>
|
|
48
|
+
<p class="mt-0.5 text-gray-500 text-xs dark:text-neutral-400">{{ task.timezone }}</p>
|
|
49
|
+
</td>
|
|
50
|
+
<td class="px-4 py-3 font-mono text-gray-600 text-sm whitespace-nowrap dark:text-neutral-300">{{ task.pattern || 'Not configured' }}</td>
|
|
51
|
+
<td class="px-4 py-3 text-gray-600 text-sm whitespace-nowrap dark:text-neutral-300">{{ formatDate(task.nextRun) }}</td>
|
|
52
|
+
<td class="px-4 py-3">
|
|
53
|
+
<Badge :variant="task.enabled ? 'success' : 'warning'" dot>{{ task.enabled ? 'Active' : 'Paused' }}</Badge>
|
|
54
|
+
</td>
|
|
55
|
+
<td class="px-4 py-3 text-right whitespace-nowrap">
|
|
56
|
+
<div class="inline-flex gap-2 items-center">
|
|
57
|
+
<Button
|
|
58
|
+
size="sm"
|
|
59
|
+
:disabled="busyTask() !== '' || !task.enabled"
|
|
60
|
+
:loading="busyTask() === task.name + ':run'"
|
|
61
|
+
@click="emit('run', task.name)"
|
|
62
|
+
>
|
|
63
|
+
Run now
|
|
64
|
+
</Button>
|
|
65
|
+
<Button
|
|
66
|
+
size="sm"
|
|
67
|
+
variant="outline"
|
|
68
|
+
:disabled="busyTask() !== ''"
|
|
69
|
+
:loading="busyTask() === task.name + ':toggle'"
|
|
70
|
+
@click="emit('toggle', { name: task.name, enabled: !task.enabled })"
|
|
71
|
+
>
|
|
72
|
+
{{ task.enabled ? 'Pause' : 'Resume' }}
|
|
73
|
+
</Button>
|
|
74
|
+
</div>
|
|
75
|
+
</td>
|
|
76
|
+
</tr>
|
|
77
|
+
</template>
|
|
78
|
+
</tbody>
|
|
79
|
+
</table>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
@@ -42,6 +42,7 @@ const files = state<ConfigFile[]>([])
|
|
|
42
42
|
const fields = state<ConfigField[]>([])
|
|
43
43
|
const drafts = reactive<Record<string, string | number | boolean>>({})
|
|
44
44
|
const selected = state('')
|
|
45
|
+
const pendingSelection = state('')
|
|
45
46
|
const query = state('')
|
|
46
47
|
const loading = state(true)
|
|
47
48
|
const saving = state(false)
|
|
@@ -58,6 +59,7 @@ const filteredFiles = derived(() => {
|
|
|
58
59
|
|
|
59
60
|
const selectedFile = derived(() => files().find(file => file.name === selected()))
|
|
60
61
|
const editableCount = derived(() => fields().filter(field => field.editable).length)
|
|
62
|
+
const isDirty = derived(() => fields().some(field => field.editable && drafts[field.key] !== field.value))
|
|
61
63
|
|
|
62
64
|
function displayValue(field: ConfigField): string | number {
|
|
63
65
|
if (field.editable)
|
|
@@ -101,7 +103,6 @@ async function selectFile(name: string): Promise<void> {
|
|
|
101
103
|
if (!body.ok)
|
|
102
104
|
throw new Error(body.error || `Unable to read config/${name}.ts`)
|
|
103
105
|
|
|
104
|
-
fields.set(body.fields)
|
|
105
106
|
for (const key of Object.keys(drafts))
|
|
106
107
|
delete drafts[key]
|
|
107
108
|
Object.assign(
|
|
@@ -112,6 +113,7 @@ async function selectFile(name: string): Promise<void> {
|
|
|
112
113
|
.map((field: ConfigField) => [field.key, field.value]),
|
|
113
114
|
),
|
|
114
115
|
)
|
|
116
|
+
fields.set(body.fields)
|
|
115
117
|
}
|
|
116
118
|
catch (cause) {
|
|
117
119
|
error.set(cause instanceof Error ? cause.message : `Unable to read config/${name}.ts`)
|
|
@@ -121,6 +123,34 @@ async function selectFile(name: string): Promise<void> {
|
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
function requestSelectFile(name: string): void {
|
|
127
|
+
if (name === selected())
|
|
128
|
+
return
|
|
129
|
+
if (isDirty()) {
|
|
130
|
+
pendingSelection.set(name)
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
void selectFile(name)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function cancelPendingSelection(): void {
|
|
137
|
+
pendingSelection.set('')
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function discardAndSelect(): void {
|
|
141
|
+
const name = pendingSelection()
|
|
142
|
+
pendingSelection.set('')
|
|
143
|
+
if (name)
|
|
144
|
+
void selectFile(name)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function handleBeforeUnload(event: BeforeUnloadEvent): void {
|
|
148
|
+
if (!isDirty())
|
|
149
|
+
return
|
|
150
|
+
event.preventDefault()
|
|
151
|
+
event.returnValue = ''
|
|
152
|
+
}
|
|
153
|
+
|
|
124
154
|
async function save(): Promise<void> {
|
|
125
155
|
const file = selected()
|
|
126
156
|
if (!file || saving())
|
|
@@ -154,6 +184,7 @@ async function save(): Promise<void> {
|
|
|
154
184
|
}
|
|
155
185
|
}
|
|
156
186
|
|
|
187
|
+
useEventListener('beforeunload', handleBeforeUnload)
|
|
157
188
|
void loadFiles()
|
|
158
189
|
</script>
|
|
159
190
|
|
|
@@ -185,7 +216,7 @@ void loadFiles()
|
|
|
185
216
|
<button
|
|
186
217
|
type="button"
|
|
187
218
|
:class="selected() === file.name ? 'flex items-center gap-3 px-3 py-2.5 w-full text-left text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-500/10 rounded-lg' : 'flex items-center gap-3 px-3 py-2.5 w-full text-left text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-white/5 rounded-lg'"
|
|
188
|
-
@click="
|
|
219
|
+
@click="requestSelectFile(file.name)"
|
|
189
220
|
>
|
|
190
221
|
<span class="flex-none h-4 w-4 i-hugeicons-settings-02"></span>
|
|
191
222
|
<span class="flex-1 font-medium text-sm truncate">{{ file.title }}</span>
|
|
@@ -220,8 +251,9 @@ void loadFiles()
|
|
|
220
251
|
<p class="mt-1 font-mono text-neutral-500 text-xs dark:text-neutral-400">config/{{ selectedFile().name }}.ts</p>
|
|
221
252
|
</div>
|
|
222
253
|
<div class="flex gap-2 items-center">
|
|
254
|
+
<Badge :if="isDirty()" variant="warning" size="sm">Unsaved changes</Badge>
|
|
223
255
|
<Badge variant="default" size="sm">{{ editableCount() }} editable</Badge>
|
|
224
|
-
<Button variant="primary" size="sm" :disabled="saving() || editableCount() === 0" @click="save()">
|
|
256
|
+
<Button variant="primary" size="sm" :disabled="saving() || editableCount() === 0 || !isDirty()" @click="save()">
|
|
225
257
|
{{ saving() ? 'Saving...' : 'Save changes' }}
|
|
226
258
|
</Button>
|
|
227
259
|
</div>
|
|
@@ -284,5 +316,15 @@ void loadFiles()
|
|
|
284
316
|
@endif
|
|
285
317
|
</Card>
|
|
286
318
|
</div>
|
|
319
|
+
|
|
320
|
+
<ConfirmDialog
|
|
321
|
+
:isOpen="Boolean(pendingSelection())"
|
|
322
|
+
title="Discard unsaved changes?"
|
|
323
|
+
description="Switching configuration files will discard the edits in this file."
|
|
324
|
+
confirmLabel="Discard changes"
|
|
325
|
+
variant="warning"
|
|
326
|
+
@close="cancelPendingSelection"
|
|
327
|
+
@confirm="discardAndSelect"
|
|
328
|
+
/>
|
|
287
329
|
</div>
|
|
288
330
|
</template>
|
|
@@ -5,11 +5,27 @@ interface ModalProps {
|
|
|
5
5
|
description?: string
|
|
6
6
|
ariaLabel?: string
|
|
7
7
|
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
|
|
8
|
+
position?: 'center' | 'top'
|
|
9
|
+
panelClassName?: string
|
|
10
|
+
contentClassName?: string
|
|
11
|
+
showCloseButton?: boolean
|
|
8
12
|
closable?: boolean
|
|
9
13
|
role?: 'dialog' | 'alertdialog'
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
isOpen = false,
|
|
18
|
+
title = '',
|
|
19
|
+
description = '',
|
|
20
|
+
ariaLabel = '',
|
|
21
|
+
size = 'md',
|
|
22
|
+
position = 'center',
|
|
23
|
+
panelClassName = '',
|
|
24
|
+
contentClassName = 'p-6',
|
|
25
|
+
showCloseButton = true,
|
|
26
|
+
closable = true,
|
|
27
|
+
role = 'dialog',
|
|
28
|
+
} = defineProps<ModalProps>()
|
|
13
29
|
|
|
14
30
|
const sizeClasses = {
|
|
15
31
|
sm: 'max-w-sm',
|
|
@@ -18,6 +34,11 @@ const sizeClasses = {
|
|
|
18
34
|
xl: 'max-w-4xl',
|
|
19
35
|
full: 'max-w-[calc(100vw-2rem)] max-h-[calc(100vh-2rem)]'
|
|
20
36
|
}
|
|
37
|
+
|
|
38
|
+
const positionClasses = {
|
|
39
|
+
center: 'items-center justify-center p-4',
|
|
40
|
+
top: 'items-start justify-center px-4 pb-4 pt-[15vh]',
|
|
41
|
+
}
|
|
21
42
|
</script>
|
|
22
43
|
<script client>
|
|
23
44
|
const open = useReactiveProp('isOpen', false)
|
|
@@ -26,6 +47,7 @@ const liveTitle = useReactiveProp('title', '')
|
|
|
26
47
|
const liveDescription = useReactiveProp('description', '')
|
|
27
48
|
const liveAriaLabel = useReactiveProp('ariaLabel', '')
|
|
28
49
|
const liveRole = useReactiveProp('role', 'dialog')
|
|
50
|
+
const liveShowCloseButton = useReactiveProp('showCloseButton', true)
|
|
29
51
|
const dialog = useRef<HTMLDialogElement>('dashboardModalDialog')
|
|
30
52
|
const activeElement = useActiveElement()
|
|
31
53
|
const scrollLocked = useScrollLock()
|
|
@@ -65,8 +87,11 @@ effect(() => {
|
|
|
65
87
|
const autofocusTarget = element.querySelector<HTMLElement>('[autofocus]:not([disabled])')
|
|
66
88
|
if (autofocusTarget)
|
|
67
89
|
autofocusTarget.focus()
|
|
68
|
-
else
|
|
69
|
-
|
|
90
|
+
else {
|
|
91
|
+
const currentFocus = peek(() => activeElement.value)
|
|
92
|
+
if (!(currentFocus instanceof HTMLElement && element.contains(currentFocus)))
|
|
93
|
+
element.focus()
|
|
94
|
+
}
|
|
70
95
|
})
|
|
71
96
|
return
|
|
72
97
|
}
|
|
@@ -89,12 +114,12 @@ effect(() => {
|
|
|
89
114
|
@cancel="handleCancel"
|
|
90
115
|
>
|
|
91
116
|
<!-- Modal container -->
|
|
92
|
-
<div class="flex
|
|
117
|
+
<div class="flex min-h-full {{ positionClasses[position] }}" @click="handleBackdropClick">
|
|
93
118
|
<div
|
|
94
|
-
class="relative w-full rounded-xl bg-white dark:bg-neutral-900 shadow-2xl {{ sizeClasses[size] }}"
|
|
119
|
+
class="relative w-full rounded-xl bg-white dark:bg-neutral-900 shadow-2xl {{ sizeClasses[size] }} {{ panelClassName }}"
|
|
95
120
|
>
|
|
96
121
|
<!-- Header -->
|
|
97
|
-
<div :if="liveTitle() || liveClosable()" class="flex gap-4 items-start justify-between p-6 border-b border-neutral-200 dark:border-neutral-700">
|
|
122
|
+
<div :if="liveTitle() || (liveClosable() && liveShowCloseButton())" class="flex gap-4 items-start justify-between p-6 border-b border-neutral-200 dark:border-neutral-700">
|
|
98
123
|
<div class="flex gap-3 items-start min-w-0">
|
|
99
124
|
<slot name="header-leading" />
|
|
100
125
|
<div class="min-w-0">
|
|
@@ -110,7 +135,7 @@ effect(() => {
|
|
|
110
135
|
<div class="flex flex-shrink-0 gap-2 items-center">
|
|
111
136
|
<slot name="header-trailing" />
|
|
112
137
|
<Button
|
|
113
|
-
:if="liveClosable()"
|
|
138
|
+
:if="liveClosable() && liveShowCloseButton()"
|
|
114
139
|
variant="ghost"
|
|
115
140
|
size="sm"
|
|
116
141
|
iconOnly
|
|
@@ -124,7 +149,7 @@ effect(() => {
|
|
|
124
149
|
|
|
125
150
|
<!-- Body -->
|
|
126
151
|
@if($slots.default)
|
|
127
|
-
<div class="
|
|
152
|
+
<div class="{{ contentClassName }}">
|
|
128
153
|
<slot />
|
|
129
154
|
</div>
|
|
130
155
|
@endif
|
|
@@ -281,6 +281,7 @@ export function buildNavSections(
|
|
|
281
281
|
// (`/notifications/dashboard`); the bare `/notifications` redirects.
|
|
282
282
|
sections.push(['app', 'app', [
|
|
283
283
|
{ to: '/deployments', icon: 'rocket', text: 'Deployments' },
|
|
284
|
+
{ to: '/operations/scheduler', icon: 'calendar-03', text: 'Operations' },
|
|
284
285
|
{ to: '/requests', icon: 'api', text: 'Requests' },
|
|
285
286
|
{ to: '/realtime', icon: 'link', text: 'Realtime' },
|
|
286
287
|
{ to: '/actions', icon: 'bolt', text: 'Actions' },
|
package/routes/dashboard-api.ts
CHANGED
|
@@ -161,6 +161,9 @@ route.group({ prefix: '/api/dashboard', apiResponse: true }, () => {
|
|
|
161
161
|
guard(route.delete('/commerce/print-logs/{id}', 'Actions/Commerce/ReceiptDestroyAction'))
|
|
162
162
|
guard(route.get('/deployments', 'Actions/Dashboard/Deployments/GetDeployments'))
|
|
163
163
|
guard(route.post('/deployments', 'Actions/Dashboard/Deployments/CreateDeployment'))
|
|
164
|
+
guard(route.post('/deployments/preview', 'Actions/Dashboard/Deployments/PreviewDeployment'))
|
|
165
|
+
guard(route.post('/deployments/rollback/preview', 'Actions/Dashboard/Deployments/PreviewDeploymentRollback'))
|
|
166
|
+
guard(route.post('/deployments/rollback', 'Actions/Dashboard/Deployments/CreateDeploymentRollback'))
|
|
164
167
|
guard(route.get('/deployments/count', 'Actions/Dashboard/Deployments/GetDeploymentCount'))
|
|
165
168
|
guard(route.get('/deployments/recent', 'Actions/Dashboard/Deployments/GetRecentDeployments'))
|
|
166
169
|
guard(route.get('/deployments/avg-time', 'Actions/Dashboard/Deployments/GetAverageDeploymentTime'))
|
|
@@ -168,6 +171,26 @@ route.group({ prefix: '/api/dashboard', apiResponse: true }, () => {
|
|
|
168
171
|
guard(route.put('/deployments/script', 'Actions/Dashboard/Deployments/UpdateDeployScript'))
|
|
169
172
|
guard(route.get('/deployments/terminal', 'Actions/Dashboard/Deployments/GetDeploymentLiveTerminalOutput'))
|
|
170
173
|
guard(route.get('/deployments/{id}', 'Actions/Dashboard/Deployments/GetDeployment'))
|
|
174
|
+
guard(route.get('/operations/scheduler', 'Actions/Dashboard/Operations/SchedulerIndexAction'))
|
|
175
|
+
guard(route.post('/operations/scheduler/{name}/run', 'Actions/Dashboard/Operations/SchedulerRunAction'))
|
|
176
|
+
guard(route.patch('/operations/scheduler/{name}', 'Actions/Dashboard/Operations/SchedulerToggleAction'))
|
|
177
|
+
guard(route.get('/operations/recovery', 'Actions/Dashboard/Operations/RecoveryIndexAction'))
|
|
178
|
+
guard(route.post('/operations/recovery/destinations', 'Actions/Dashboard/Operations/RecoveryDestinationStoreAction'))
|
|
179
|
+
guard(route.post('/operations/recovery/destinations/{id}/test', 'Actions/Dashboard/Operations/RecoveryDestinationTestAction'))
|
|
180
|
+
guard(route.post('/operations/recovery/policies', 'Actions/Dashboard/Operations/RecoveryPolicyStoreAction'))
|
|
181
|
+
guard(route.post('/operations/recovery/policies/{id}/run', 'Actions/Dashboard/Operations/RecoveryRunAction'))
|
|
182
|
+
guard(route.post('/operations/recovery/points/{id}/verify', 'Actions/Dashboard/Operations/RecoveryVerifyAction'))
|
|
183
|
+
guard(route.post('/operations/recovery/points/{id}/restore', 'Actions/Dashboard/Operations/RecoveryRestoreAction'))
|
|
184
|
+
guard(route.patch('/operations/recovery/points/{id}/protection', 'Actions/Dashboard/Operations/RecoveryProtectAction'))
|
|
185
|
+
guard(route.post('/operations/recovery/retention', 'Actions/Dashboard/Operations/RecoveryRetentionAction'))
|
|
186
|
+
guard(route.get('/operations/migrations', 'Actions/Dashboard/Operations/MigrationIndexAction'))
|
|
187
|
+
guard(route.post('/operations/migrations/apply', 'Actions/Dashboard/Operations/MigrationApplyAction'))
|
|
188
|
+
guard(route.post('/operations/migrations/reconcile', 'Actions/Dashboard/Operations/MigrationReconcileAction'))
|
|
189
|
+
guard(route.get('/operations/changes', 'Actions/Dashboard/Operations/ChangeIndexAction'))
|
|
190
|
+
guard(route.post('/operations/changes/releases/{id}/decision', 'Actions/Dashboard/Operations/ChangeApprovalAction'))
|
|
191
|
+
guard(route.get('/operations/incidents', 'Actions/Dashboard/Operations/IncidentIndexAction'))
|
|
192
|
+
guard(route.patch('/operations/incidents/{id}', 'Actions/Dashboard/Operations/IncidentUpdateAction'))
|
|
193
|
+
guard(route.get('/operations/audit', 'Actions/Dashboard/Operations/AuditIndexAction'))
|
|
171
194
|
guard(route.get('/data/activity', 'Actions/Dashboard/Data/ActivityIndexAction'))
|
|
172
195
|
guard(route.get('/data/users', 'Actions/Dashboard/Data/UserIndexAction'))
|
|
173
196
|
guard(route.get('/data/teams', 'Actions/Dashboard/Data/TeamIndexAction'))
|
package/routes/dashboard.ts
CHANGED
|
@@ -647,6 +647,7 @@ route.group({ prefix: '/deployments', middleware: 'auth' }, () => {
|
|
|
647
647
|
route.get('/recent', 'Actions/Dashboard/Deployments/GetRecentDeployments')
|
|
648
648
|
route.get('/avg-time', 'Actions/Dashboard/Deployments/GetAverageDeploymentTime')
|
|
649
649
|
route.post('/', 'Actions/Dashboard/Deployments/CreateDeployment')
|
|
650
|
+
route.post('/preview', 'Actions/Dashboard/Deployments/PreviewDeployment')
|
|
650
651
|
route.get('/script', 'Actions/Dashboard/Deployments/GetDeployScript')
|
|
651
652
|
route.put('/script', 'Actions/Dashboard/Deployments/UpdateDeployScript')
|
|
652
653
|
route.get('/terminal', 'Actions/Dashboard/Deployments/GetDeploymentLiveTerminalOutput')
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
uses: actions/checkout@v4
|
|
28
28
|
|
|
29
29
|
- name: Setup Pantry
|
|
30
|
-
uses: pantry-pm/pantry/packages/action@
|
|
30
|
+
uses: pantry-pm/pantry/packages/action@c1417d98f5613290bc3b1f96d35086b834684659 # v0.10.47 + the socket-hang-up retry fix
|
|
31
31
|
with:
|
|
32
32
|
install: 'false'
|
|
33
33
|
|
|
@@ -58,7 +58,7 @@ jobs:
|
|
|
58
58
|
uses: actions/checkout@v4
|
|
59
59
|
|
|
60
60
|
- name: Setup Pantry
|
|
61
|
-
uses: pantry-pm/pantry/packages/action@
|
|
61
|
+
uses: pantry-pm/pantry/packages/action@c1417d98f5613290bc3b1f96d35086b834684659 # v0.10.47 + the socket-hang-up retry fix
|
|
62
62
|
with:
|
|
63
63
|
install: 'false'
|
|
64
64
|
|
|
@@ -92,7 +92,7 @@ jobs:
|
|
|
92
92
|
uses: actions/checkout@v4
|
|
93
93
|
|
|
94
94
|
- name: Setup Pantry
|
|
95
|
-
uses: pantry-pm/pantry/packages/action@
|
|
95
|
+
uses: pantry-pm/pantry/packages/action@c1417d98f5613290bc3b1f96d35086b834684659 # v0.10.47 + the socket-hang-up retry fix
|
|
96
96
|
with:
|
|
97
97
|
install: 'false'
|
|
98
98
|
|
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
fetch-depth: 0
|
|
22
22
|
|
|
23
23
|
- name: Setup Pantry
|
|
24
|
-
uses: pantry-pm/pantry/packages/action@
|
|
24
|
+
uses: pantry-pm/pantry/packages/action@c1417d98f5613290bc3b1f96d35086b834684659 # v0.10.47 + the socket-hang-up retry fix
|
|
25
25
|
with:
|
|
26
26
|
install: 'false'
|
|
27
27
|
|
|
@@ -24,8 +24,8 @@ interface RepoStatus {
|
|
|
24
24
|
updatedAt: string | null
|
|
25
25
|
runUrl: string | null
|
|
26
26
|
failedJobs: FailedJob[]
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
buddyBotPRs: number
|
|
28
|
+
buddyBotPRsUrl: string | null
|
|
29
29
|
actionsPRs: number
|
|
30
30
|
actionsPRsUrl: string | null
|
|
31
31
|
}
|