@stacksjs/ts-cloud 0.11.5 → 0.11.6
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/dist/bin/{chunk-fdrbeb7p.js → chunk-5nsqz5n3.js} +46 -46
- package/dist/bin/{chunk-ayhqt80q.js → chunk-j447p8t4.js} +1 -1
- package/dist/bin/{chunk-6wxxe560.js → chunk-yw6f160x.js} +1 -1
- package/dist/bin/cli.js +4 -4
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-t2a6r38z.js → chunk-aw0spg20.js} +64 -64
- package/dist/{chunk-9pa96r7f.js → chunk-ywjkyg8p.js} +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/deploy-script.d.ts +49 -0
- package/dist/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +5 -5
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +5 -5
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +6 -6
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +5 -5
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +5 -5
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +1 -1
- package/dist/ui/serverless/alarms.html +5 -5
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +1 -1
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +1 -1
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +5 -5
- package/dist/ui/serverless/metrics.html +1 -1
- package/dist/ui/serverless/queues.html +5 -5
- package/dist/ui/serverless/secrets.html +5 -5
- package/dist/ui/serverless/traces.html +5 -5
- package/dist/ui/serverless.html +6 -6
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="
|
|
2
|
-
function
|
|
1
|
+
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mt61jpq58ij9e5"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.c696d17a.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Deployment queue</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
|
|
2
|
+
function __stx_setup_1787503695064_9() {
|
|
3
3
|
const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
4
4
|
|
|
5
5
|
const operations = state([]);
|
|
@@ -135,9 +135,9 @@ onMount(() => {
|
|
|
135
135
|
|
|
136
136
|
return { operations, concurrency, selectedId, logs, filter, loading, message, confirmLimits, confirmClear, source, selected, visible, duration, statusTone, setFilter, refresh, appendLog, openDetail, closeDetail, mutate, cancelSelected, retrySelected, saveLimits, clearHistory };
|
|
137
137
|
}
|
|
138
|
-
window.__stx_latestSetup=
|
|
139
|
-
if(window.stx)window.stx._latestSetup=
|
|
140
|
-
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="
|
|
138
|
+
window.__stx_latestSetup=__stx_setup_1787503695064_9;
|
|
139
|
+
if(window.stx)window.stx._latestSetup=__stx_setup_1787503695064_9;
|
|
140
|
+
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1787503695064_9"><a data-stx-scope="stx_scope_nav_12" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="active" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment & secrets</a><a class="" href="/data/backups?env=production">Backups & recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
|
|
141
141
|
(function() {
|
|
142
142
|
var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
143
143
|
var __destroyHooks = [];
|
|
@@ -488,6 +488,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1787415905689_11;
|
|
|
488
488
|
|
|
489
489
|
|
|
490
490
|
try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
|
|
491
|
-
window.stx._scopes['
|
|
491
|
+
window.stx._scopes['stx_scope_nav_12'] = __scopeRegistration;
|
|
492
492
|
})();
|
|
493
493
|
</script> <div class="queue-wrap wrap"><div class="crumbs">Operations <span class="sep">/</span> Deployment queue</div><header class="page"><div><h1>Deployment queue</h1><p>Durable deployments and mutations, with ordered progress, resource locks, cancellation, and safe retries.</p></div><div class="queue-limits" x-cloak><span x-cloak>Project <b x-cloak>{{ concurrency().project }}</b></span><span x-cloak>Environment <b x-cloak>{{ concurrency().environment }}</b></span><span x-cloak>Provider <b x-cloak>{{ concurrency().provider }}</b></span><span x-cloak>Builds <b x-cloak>{{ concurrency().builds }}</b></span></div></header><div class="bad notice" @show="!!message()" x-cloak>{{ message() }}</div><div class="queue-layout" :class="{ inspecting: !!selectedId() }"><main class="panel queue-main"><div class="filters queue-filters"><div class="segmented" role="group" aria-label="Filter queue state"><button type="button" :class="{ active: filter() === 'active' }" @click="setFilter('active')">Active</button><button type="button" :class="{ active: filter() === 'all' }" @click="setFilter('all')">All</button><button type="button" :class="{ active: filter() === 'failed' }" @click="setFilter('failed')">Failed</button><button type="button" :class="{ active: filter() === 'cancelled' }" @click="setFilter('cancelled')">Cancelled</button></div><button class="btn sm" type="button" @click="refresh()">Refresh</button></div><div class="queue-table-wrap"><table class="queue-table"><thead><tr><th scope="col">Status</th><th scope="col">Target</th><th scope="col">Operation</th><th scope="col">Actor / trigger</th><th scope="col">Commit</th><th scope="col">Progress</th><th scope="col">Attempt</th><th scope="col">Timing</th></tr></thead><tbody><template :for="item in visible()"><tr class="queue-row" :class="{ selected: item.operation.id === selectedId() }" @click="openDetail(item)" tabindex="0"><td x-cloak><span class="pill" :class="statusTone(item.operation.state)" x-cloak>{{ item.operation.state }}</span></td><td x-cloak><b x-cloak>{{ item.target.name }}</b><small x-cloak>{{ item.target.kind }} · {{ item.target.slug }}</small></td><td class="mono" x-cloak>{{ item.operation.kind }}<small x-cloak>{{ item.operation.id.slice(0, 8) }}</small></td><td x-cloak>{{ item.actor?.name || 'System' }}<small x-cloak>{{ item.actor?.kind || 'automation' }}</small></td><td class="mono" x-cloak>{{ item.commit ? String(item.commit).slice(0, 12) : '—' }}</td><td x-cloak><span @show="!!item.job.currentStep" x-cloak>{{ item.job.currentStep }}</span><span class="blocked" @show="!!item.job.blockedReason" x-cloak>{{ item.job.blockedReason }}</span><small @show="!!item.approximatePosition && item.operation.state === 'queued'" x-cloak>About {{ item.approximatePosition.ahead }} ahead</small></td><td class="mono" x-cloak>{{ item.operation.attempt }} / {{ item.job.maxAttempts }}</td><td x-cloak>{{ duration(item.operation) }}<small x-cloak>{{ new Date(item.operation.createdAt).toLocaleString() }}</small></td></tr></template></tbody></table></div><div class="empty" @show="!loading() && visible().length === 0" x-cloak><strong>No matching work</strong><span>Queued deployments and other long-lived mutations will appear here.</span></div></main><aside class="panel queue-detail" @show="!!selected()" x-cloak><button class="detail-close" type="button" aria-label="Close operation detail" @click="closeDetail()">×</button><template :if="selected()" x-cloak><div class="eyebrow" x-cloak>{{ selected().operation.kind }}</div><h2 x-cloak>{{ selected().target.name }}</h2><div class="detail-meta" x-cloak><span class="pill" :class="statusTone(selected().operation.state)" x-cloak>{{ selected().operation.state }}</span><span x-cloak>Attempt {{ selected().operation.attempt }} of {{ selected().job.maxAttempts }}</span><span x-cloak>{{ duration(selected().operation) }}</span></div><div class="blocked-card" @show="!!selected().job.blockedReason" x-cloak><b>Waiting</b><span x-cloak>{{ selected().job.blockedReason }}</span><small>Position is an estimate because earlier work may unblock or retry.</small></div><div class="detail-actions"></div><h3>Structured progress</h3><div class="step-list"><template :for="entry in logs().filter(item => item.stream === 'step')"><div><span></span><b x-cloak>{{ entry.step || 'Step' }}</b><small x-cloak>{{ entry.message }}</small></div></template></div><details class="raw-logs" open><summary x-cloak>Raw logs · {{ logs().length }} chunks</summary><pre x-cloak><template :for="entry in logs()"><span :class="entry.stream" x-cloak>{{ entry.sequence }} {{ entry.stream.toUpperCase() }}{{ entry.redacted ? ' [REDACTED]' : '' }}{{ entry.truncated ? ' [TRUNCATED]' : '' }} {{ entry.message }} </span></template></pre></details><div class="detail-foot mono" x-cloak>{{ selected().operation.id }}</div></template></aside></div></div><style> .queue-wrap{max-width:1500px}.queue-limits{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}.queue-limits span{border:1px solid var(--line);background:var(--bg2);border-radius:8px;padding:8px 10px;color:var(--txt3);font-size:12px}.queue-limits b{color:var(--txt);margin-left:5px}.queue-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}.queue-layout.inspecting{grid-template-columns:minmax(620px,1.4fr) minmax(340px,.6fr)}.queue-main{padding:0;overflow:hidden}.queue-filters{padding:14px 16px;margin:0;border-bottom:1px solid var(--line);display:flex;justify-content:space-between}.queue-table-wrap{overflow:auto}.queue-table{min-width:1060px}.queue-row{cursor:pointer}.queue-row.selected{background:color-mix(in srgb,var(--accent) 9%,transparent)}.queue-row td small{display:block;margin-top:4px;color:var(--txt3);font-size:11px}.blocked{color:var(--yellow);font-size:12px}.queue-detail{position:sticky;top:16px;align-self:start;max-height:calc(100vh - 32px);overflow:auto;padding:22px}.detail-close{float:right;border:0;background:transparent;color:var(--txt3);font-size:24px;cursor:pointer}.eyebrow{text-transform:uppercase;letter-spacing:.08em;color:var(--accent);font-size:11px}.queue-detail h2{margin:5px 0 10px}.detail-meta,.detail-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap;color:var(--txt3);font-size:12px}.blocked-card{display:grid;gap:5px;margin:16px 0;padding:12px;border:1px solid color-mix(in srgb,var(--yellow) 35%,var(--line));border-radius:8px;background:color-mix(in srgb,var(--yellow) 6%,transparent)}.blocked-card small{color:var(--txt3)}.detail-actions{margin:16px 0}.step-list>div{display:grid;grid-template-columns:12px 1fr;gap:0 8px;margin:10px 0}.step-list span{width:8px;height:8px;margin-top:5px;border-radius:50%;background:var(--accent)}.step-list small{grid-column:2;color:var(--txt3)}.raw-logs{margin-top:14px}.raw-logs pre{max-height:330px;overflow:auto;background:#090c12;border:1px solid var(--line);border-radius:8px;padding:12px;font-size:11px;white-space:pre-wrap}.raw-logs .stderr{color:#ff9b9b}.raw-logs .step{color:#8dd6ff}.detail-foot{margin-top:16px;color:var(--txt3);font-size:10px}.queue-admin{margin-top:16px;display:grid;grid-template-columns:1fr 1fr;gap:14px 24px}.limit-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.limit-grid label{font-size:11px;color:var(--txt3)}.limit-grid input,.confirm-row input{width:100%;margin-top:5px}.confirm-row{display:flex;gap:8px;align-items:end}.confirm-row input{margin:0}.notice{margin-bottom:12px}.notice.bad{padding:10px 12px} @media(max-width:1050px){.queue-layout.inspecting{grid-template-columns:1fr}.queue-detail{position:static;max-height:none}.queue-admin{grid-template-columns:1fr}} @media(max-width:680px){.queue-limits{justify-content:flex-start}.queue-table{min-width:0}.queue-table thead{display:none}.queue-table tbody,.queue-row{display:block}.queue-row{padding:14px;border-bottom:1px solid var(--line)}.queue-row td{display:grid;grid-template-columns:100px 1fr;padding:4px 0;border:0}.queue-row td:before{color:var(--txt3);font-size:11px}.queue-row td:nth-child(1):before{content:'Status'}.queue-row td:nth-child(2):before{content:'Target'}.queue-row td:nth-child(3):before{content:'Operation'}.queue-row td:nth-child(4):before{content:'Actor'}.queue-row td:nth-child(5):before{content:'Commit'}.queue-row td:nth-child(6):before{content:'Progress'}.queue-row td:nth-child(7):before{content:'Attempt'}.queue-row td:nth-child(8):before{content:'Timing'}.limit-grid{grid-template-columns:repeat(2,1fr)}.confirm-row{flex-direction:column;align-items:stretch}} </style></body></html>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="
|
|
2
|
-
function
|
|
1
|
+
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mt61jpq58ij9e5"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.c696d17a.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud · Regions & failover</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
|
|
2
|
+
function __stx_setup_1787503695151_15() {
|
|
3
3
|
const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
4
4
|
|
|
5
5
|
const items = state([]), selected = state(null), adding = state(false), busy = state(false), error = state(""), notice = state("");
|
|
@@ -72,9 +72,9 @@ function sync(item) {
|
|
|
72
72
|
|
|
73
73
|
return { items, api, load, pollingState, pollingError, lastUpdatedAt, refresh, post, create, action, tone, sync };
|
|
74
74
|
}
|
|
75
|
-
window.__stx_latestSetup=
|
|
76
|
-
if(window.stx)window.stx._latestSetup=
|
|
77
|
-
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="
|
|
75
|
+
window.__stx_latestSetup=__stx_setup_1787503695151_15;
|
|
76
|
+
if(window.stx)window.stx._latestSetup=__stx_setup_1787503695151_15;
|
|
77
|
+
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1787503695151_15"><a data-stx-scope="stx_scope_nav_19" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="active" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment & secrets</a><a class="" href="/data/backups?env=production">Backups & recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
|
|
78
78
|
(function() {
|
|
79
79
|
var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
80
80
|
var __destroyHooks = [];
|
|
@@ -425,6 +425,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1787415905835_16;
|
|
|
425
425
|
|
|
426
426
|
|
|
427
427
|
try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
|
|
428
|
-
window.stx._scopes['
|
|
428
|
+
window.stx._scopes['stx_scope_nav_19'] = __scopeRegistration;
|
|
429
429
|
})();
|
|
430
430
|
</script> <main class="wrap" id="main-content"><div class="crumbs">Operations <span class="sep">/</span> Regions & failover</div><header class="page"><div><h1>Regions & failover</h1><p>Stage immutable stacks, replication, edge traffic, failover, failback, and retained-data teardown from one durable timeline.</p></div><div class="actions" x-cloak><span class="pill" :class="pollingState()==='live'?'ok':'warn'" x-cloak>{{ pollingState() }}</span><small x-cloak>{{ lastUpdatedAt()?.toLocaleTimeString()||'connecting' }}</small><button class="btn sm" @click="adding.set(!adding())" x-cloak>{{ adding()?'Close':'New topology' }}</button></div></header><p class="notice" role="status" @show="!!notice()" x-cloak>{{ notice() }}</p><p class="bad notice" role="alert" @show="!!error()||!!pollingError()" x-cloak>{{ error()||pollingError() }}</p><form class="create panel" @show="adding()" @submit="create($event)" x-cloak><div class="wide"><h2>New regional topology</h2><p>List the primary first. Replication is configured in both directions so failback has a fresh path.</p></div><label>Name<input name="name" required pattern="[a-z0-9][a-z0-9-]{1,62}"></label><label>Hostname<input name="hostname" required placeholder="api.example.com"></label><label>Regions<input name="regions" required placeholder="us-west-2,us-east-1"></label><label>Traffic policy<select name="trafficPolicy"><option value="active_passive">Active / passive</option><option value="weighted">Weighted</option><option value="latency">Latency</option></select></label><label>Maximum replication lag<input name="maxLagSeconds" type="number" min="0" value="30"></label><label class="check"><input name="cdnEnabled" type="checkbox"> CloudFront</label><label class="check"><input name="wafEnabled" type="checkbox"> WAF</label><button class="btn" type="submit">Save topology</button></form><section class="layout" x-cloak><div class="cards" x-cloak><template :for="item in items()"><article class="card panel" x-cloak><div x-cloak><span class="pill" :class="tone(item.topology.status)" x-cloak>{{ item.topology.status }}</span><h2 x-cloak>{{ item.topology.name }}</h2><p x-cloak>{{ item.topology.hostname }} · active {{ item.topology.activeRegion }}</p></div><div class="facts" x-cloak><span x-cloak>{{ item.topology.regions.length }} regions</span><span x-cloak>{{ sync(item) }} replication paths in sync</span><span x-cloak>{{ item.route?.dnsProvider }} · {{ item.route?.cdnEnabled?'CloudFront · ':'' }}{{ item.route?.wafEnabled?'WAF':'' }}</span></div><button class="btn ghost sm" @click="selected.set(item)">Inspect</button></article></template></div><aside class="detail panel" @show="!!selected()" x-cloak><div class="actions" x-cloak><h2 x-cloak>{{ selected()?.topology.name }}</h2><button class="btn ghost sm" @click="selected.set(null)">Close</button></div><div class="actions"><button class="btn sm" @click="action('rollout')" :disabled="busy()">Roll out</button><button class="btn sm warn" @click="action('failover')" :disabled="busy()">Fail over</button><button class="btn ghost sm" @click="action('failback')" :disabled="busy()">Fail back</button><button class="btn danger sm" @click="action('destroy')" :disabled="busy()">Drain & destroy</button></div><h3>Regional stacks</h3><template :for="target in selected()?.targets||[]"><p class="row" x-cloak><b x-cloak>{{ target.region }}</b><span x-cloak>{{ target.role }} · {{ target.status }}</span></p></template><h3>Replication</h3><template :for="channel in selected()?.channels||[]"><p class="row" x-cloak><b x-cloak>{{ channel.kind }} → {{ channel.targetRegion }}</b><span x-cloak>{{ channel.status }} · {{ channel.lagSeconds??'—' }}s</span></p></template><h3>Traffic</h3><pre x-cloak>{{ JSON.stringify(selected()?.route?.weights||{},null,2) }}</pre><h3>Execution timeline</h3><template :for="execution in selected()?.executions||[]"><div class="execution" x-cloak><span class="pill" :class="tone(execution.status)" x-cloak>{{ execution.status }}</span><b x-cloak>{{ execution.kind }}</b><small x-cloak>{{ execution.currentStep||execution.completedSteps.at(-1)||'queued' }}</small><p @show="!!execution.error" x-cloak>{{ execution.error }}</p></div></template></aside></section></main><style>.actions{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap}.actions h2{margin-right:auto}.create{display:grid;grid-template-columns:repeat(4,1fr);gap:1rem;margin-bottom:1rem}.create label{display:grid;gap:.3rem}.create .check{display:flex;align-items:center}.wide{grid-column:1/-1}.layout{display:grid;grid-template-columns:1fr 430px;gap:1rem}.cards{display:grid;gap:1rem}.card{display:grid;grid-template-columns:1fr 1fr auto;align-items:center;gap:1rem}.facts{display:grid;gap:.3rem}.detail{position:sticky;top:1rem;align-self:start}.row{display:flex;justify-content:space-between;border-bottom:1px solid var(--border);padding:.5rem 0}.execution{display:grid;grid-template-columns:auto 1fr auto;gap:.5rem;align-items:center;border-bottom:1px solid var(--border);padding:.6rem 0}.execution p{grid-column:1/-1;color:var(--danger)}@media(max-width:1000px){.layout{grid-template-columns:1fr}.detail{position:static}.create{grid-template-columns:1fr 1fr}.card{grid-template-columns:1fr}}@media(max-width:600px){.create{grid-template-columns:1fr}.wide{grid-column:auto}}</style></body></html>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="
|
|
2
|
-
function
|
|
1
|
+
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mt61jpq58ij9e5"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.c696d17a.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Releases & promotion</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
|
|
2
|
+
function __stx_setup_1787503695064_10() {
|
|
3
3
|
const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
4
4
|
|
|
5
5
|
const data = state({ releases: [], resources: [], environments: [] });
|
|
@@ -116,9 +116,9 @@ onMount(() => {
|
|
|
116
116
|
|
|
117
117
|
return { data, selected, message, filters, promote, request, refresh, current, visible, tone, short, duration, configObject, act, approve, rollback, promoteRelease };
|
|
118
118
|
}
|
|
119
|
-
window.__stx_latestSetup=
|
|
120
|
-
if(window.stx)window.stx._latestSetup=
|
|
121
|
-
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="
|
|
119
|
+
window.__stx_latestSetup=__stx_setup_1787503695064_10;
|
|
120
|
+
if(window.stx)window.stx._latestSetup=__stx_setup_1787503695064_10;
|
|
121
|
+
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1787503695064_10"><a data-stx-scope="stx_scope_nav_13" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="active" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment & secrets</a><a class="" href="/data/backups?env=production">Backups & recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
|
|
122
122
|
(function() {
|
|
123
123
|
var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
124
124
|
var __destroyHooks = [];
|
|
@@ -469,6 +469,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1787415905687_9;
|
|
|
469
469
|
|
|
470
470
|
|
|
471
471
|
try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
|
|
472
|
-
window.stx._scopes['
|
|
472
|
+
window.stx._scopes['stx_scope_nav_13'] = __scopeRegistration;
|
|
473
473
|
})();
|
|
474
474
|
</script> <main class="releases-wrap wrap" id="main-content"><div class="crumbs">Operations <span class="sep">/</span> Releases & promotion</div><header class="page"><div><h1>Releases & promotion</h1><p>One immutable artifact history across static, compute, serverless, containers, and Compose.</p></div><button class="btn ghost" @click="refresh()">Refresh</button></header><p class="notice" @show="!!message()" x-cloak>{{message()}}</p><section class="section stats"><div class="panel"><small>Total releases</small><strong x-cloak>{{data().releases.length}}</strong></div><div class="panel"><small>Active</small><strong x-cloak>{{data().releases.filter(v=>v.status==='active').length}}</strong></div><div class="panel"><small>Needs attention</small><strong x-cloak>{{data().releases.filter(v=>['failed','awaiting_approval'].includes(v.status)).length}}</strong></div><div class="panel"><small>Pinned</small><strong x-cloak>{{data().releases.filter(v=>v.pinned).length}}</strong></div></section><section class="panel section toolbar"><label>Environment<select :value="filters().environment" @change="filters.set({...filters(),environment:$event.target.value})"><option value="">All</option><option @each="env in data().environments" :value="env.id">{{env.name}}</option></select></label><label>Status<select :value="filters().status" @change="filters.set({...filters(),status:$event.target.value})"><option value="">All</option><option @each="status in ['built','awaiting_approval','activating','active','failed','rolled_back','superseded']" :value="status">{{status}}</option></select></label><label>Kind<select :value="filters().kind" @change="filters.set({...filters(),kind:$event.target.value})"><option value="">All</option><option @each="kind in ['static','compute','serverless_zip','serverless_image','container','compose']" :value="kind">{{kind}}</option></select></label></section><div class="release-layout section"><section class="panel release-list"><div class="empty" @show="!visible().length" x-cloak><b>No releases match this view</b><span>Create a release from a verified artifact with the CLI or API.</span></div><button class="release-row" :class="selected()===item.id?'selected':''" @each="item in visible()" :key="item.id" @click="selected.set(item.id)" x-cloak><span class="pill" :class="tone(item.status)" x-cloak>{{item.status}}</span><strong x-cloak>{{item.resource?.name||item.resourceId}}</strong><small x-cloak>{{item.environment?.name}} · {{item.kind}} · {{item.strategy}}</small><code x-cloak>{{short(item.sourceSha)}} · {{short(item.artifact?.digest)}}</code><time x-cloak>{{new Date(item.createdAt).toLocaleString()}}</time></button></section><section class="detail" @show="!!current()" x-cloak><article class="hero panel" x-cloak><div x-cloak><span class="pill" :class="tone(current()?.status)" x-cloak>{{current()?.status}}</span><h2 x-cloak>{{current()?.resource?.name}}</h2><p x-cloak>{{current()?.environment?.name}} · {{current()?.kind}} · {{current()?.strategy}}</p></div><div class="actions"></div></article><article class="facts panel"><h3>Immutable identity</h3><dl><div><dt>Source commit</dt><dd class="mono" x-cloak>{{current()?.sourceSha||'Not recorded'}}</dd></div><div><dt>Artifact digest</dt><dd class="mono" x-cloak>{{current()?.artifact?.digest}}</dd></div><div><dt>Artifact URI</dt><dd class="mono" x-cloak>{{current()?.artifact?.uri}}</dd></div><div><dt>Config hash</dt><dd class="mono" x-cloak>{{current()?.configHash}}</dd></div><div><dt>Trigger / actor</dt><dd x-cloak>{{current()?.trigger}} · {{short(current()?.actorId)}}</dd></div><div><dt>Duration</dt><dd x-cloak>{{duration(current())}}</dd></div><div><dt>Provider versions</dt><dd class="mono" x-cloak>{{JSON.stringify(current()?.transitions.at(-1)?.health||{})}}</dd></div><div><dt>Provenance / attestation</dt><dd class="mono" x-cloak>{{JSON.stringify({provenance:current()?.artifact?.provenance,attestation:current()?.artifact?.attestation})}}</dd></div></dl></article><article class="caveat panel" @show="!!current()?.comparison" x-cloak><h3>Change and rollback preview</h3><div class="change-grid" x-cloak><span x-cloak>Artifact <b x-cloak>{{current()?.comparison.artifactChanged?'changed':'identical'}}</b></span><span x-cloak>Source <b x-cloak>{{current()?.comparison.sourceChanged?'changed':'identical'}}</b></span><span x-cloak>Config <b x-cloak>{{current()?.comparison.configChanged?'changed':'identical'}}</b></span><span x-cloak>Manifest <b x-cloak>{{current()?.comparison.manifestChanges.length}} change(s)</b></span></div><p x-cloak>{{current()?.comparison.dataCaveat}}</p><p class="bad-text" @show="current()?.hooks.migrations==='irreversible'" x-cloak>Irreversible migration hooks are recorded. Traffic rollback will not restore data.</p></article><article class="panel"><h3>Activation steps & health</h3><div class="timeline" x-cloak><div @each="step in current()?.transitions||[]" x-cloak><span x-cloak>{{step.trafficPercent==null?'—':step.trafficPercent+'%'}}</span><b x-cloak>{{step.toStatus}}</b><p x-cloak>{{step.message}}</p><time x-cloak>{{new Date(step.createdAt).toLocaleString()}}</time></div></div></article><article class="panel"><h3>Strategy capability</h3><div class="strategy-grid" x-cloak><div @each="cap in current()?.capabilities||[]" :class="cap.supported?'supported':'unsupported'" x-cloak><b x-cloak>{{cap.strategy}}</b><span x-cloak>{{cap.supported?'Available':'Unavailable'}}</span><p x-cloak>{{cap.explanation}}</p><small x-cloak>{{cap.capacityMultiplier}}× capacity · {{cap.costImpact}} cost</small><small x-cloak>{{cap.rollback}}</small></div></div></article></section></div></main><style>.releases-wrap{max-width:1500px}.page,.hero,.actions{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.stats strong{display:block;font-size:1.7rem;margin-top:8px}.toolbar{display:flex;gap:12px}.toolbar label,.promotion label{display:grid;gap:5px}.release-layout{display:grid;grid-template-columns:340px minmax(0,1fr);gap:14px;align-items:start}.release-list{padding:7px;max-height:1100px;overflow:auto}.release-row{width:100%;display:grid;grid-template-columns:auto 1fr;text-align:left;gap:4px 8px;padding:12px;background:transparent;color:inherit;border:0;border-bottom:1px solid var(--line);cursor:pointer}.release-row:hover,.release-row.selected{background:var(--bg3)}.release-row small,.release-row code,.release-row time{grid-column:2;color:var(--txt3);font-size:11px}.detail{display:grid;gap:12px}.hero h2{margin:8px 0 3px}.hero p{margin:0;color:var(--txt3)}.facts dl{display:grid;grid-template-columns:1fr 1fr;gap:10px}.facts dt{color:var(--txt3);font-size:10px}.facts dd{margin:3px 0;overflow-wrap:anywhere}.change-grid,.strategy-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.change-grid span,.strategy-grid>div{border:1px solid var(--line);padding:10px;border-radius:8px}.strategy-grid>div{display:grid;gap:6px}.strategy-grid .unsupported{opacity:.6}.strategy-grid p{margin:0;font-size:12px}.strategy-grid small{color:var(--txt3)}.timeline>div{display:grid;grid-template-columns:55px 110px 1fr auto;gap:10px;padding:10px 0;border-bottom:1px solid var(--line);align-items:center}.timeline p{margin:0}.timeline time{color:var(--txt3);font-size:11px}.promotion{display:grid;gap:10px}.check{display:flex!important;align-items:center}.empty span{display:block;color:var(--txt3);margin-top:5px}@media(max-width:1050px){.release-layout{grid-template-columns:1fr}.release-list{max-height:360px}.strategy-grid{grid-template-columns:1fr 1fr}}@media(max-width:650px){.stats,.facts dl,.change-grid,.strategy-grid{grid-template-columns:1fr 1fr}.toolbar,.page,.hero{display:grid}.timeline>div{grid-template-columns:45px 1fr}.timeline p,.timeline time{grid-column:2}}@media(max-width:420px){.stats,.facts dl,.change-grid,.strategy-grid{grid-template-columns:1fr}}</style></body></html>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="
|
|
2
|
-
function
|
|
1
|
+
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mt61jpq58ij9e5"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud · Spend & budgets</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-runtime src="/_stx/runtime.c696d17a.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <script data-stx-scoped>
|
|
2
|
+
function __stx_setup_1787503695067_12() {
|
|
3
3
|
const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
4
4
|
|
|
5
5
|
var acknowledge = undefined;
|
|
@@ -205,9 +205,9 @@ trusted = __stxBundle_55dcf44f8138["trusted"];
|
|
|
205
205
|
when = __stxBundle_55dcf44f8138["when"];
|
|
206
206
|
return { acknowledge, api, createBudget, form, guard, lastUpdatedAt, load, money, optional, patchBudget, pct, pollingError, pollingState, refresh, release, removeBudget, report, runCheck, scopeOf, setPeriod, severityTone, tone, trusted, when, __stxBundle_55dcf44f8138 };
|
|
207
207
|
}
|
|
208
|
-
window.__stx_latestSetup=
|
|
209
|
-
if(window.stx)window.stx._latestSetup=
|
|
210
|
-
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="
|
|
208
|
+
window.__stx_latestSetup=__stx_setup_1787503695067_12;
|
|
209
|
+
if(window.stx)window.stx._latestSetup=__stx_setup_1787503695067_12;
|
|
210
|
+
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1787503695067_12"><a data-stx-scope="stx_scope_nav_16" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="active" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment & secrets</a><a class="" href="/data/backups?env=production">Backups & recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
|
|
211
211
|
(function() {
|
|
212
212
|
var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
213
213
|
var __destroyHooks = [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="
|
|
2
|
-
function
|
|
1
|
+
<!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mt61jpq58ij9e5"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.c696d17a.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Workloads</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
|
|
2
|
+
function __stx_setup_1787503695065_11() {
|
|
3
3
|
const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
4
4
|
|
|
5
5
|
var age = undefined;
|
|
@@ -409,9 +409,9 @@ uploadName = __stxBundle_cc737a64e01f["uploadName"];
|
|
|
409
409
|
visible = __stxBundle_cc737a64e01f["visible"];
|
|
410
410
|
return { age, bytes, capability, chooseUpload, close, columns, connectStream, disconnectStream, eventStream, execCommand, fileBusy, filePath, fileRequest, inventory, lastUpdatedAt, load, logs, logsBusy, message, open, operationBusy, params, pollingError, pollingLabel, pollingState, provider, query, readLogs, refresh, replicaLabel, replicas, run, selected, selectedId, serviceFilter, setFilter, sources, startExec, startLogFollow, status, stopStream, streamSession, streamState, syncUrl, tone, typed, uploadBase64, uploadName, visible, __stxBundle_cc737a64e01f };
|
|
411
411
|
}
|
|
412
|
-
window.__stx_latestSetup=
|
|
413
|
-
if(window.stx)window.stx._latestSetup=
|
|
414
|
-
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="
|
|
412
|
+
window.__stx_latestSetup=__stx_setup_1787503695065_11;
|
|
413
|
+
if(window.stx)window.stx._latestSetup=__stx_setup_1787503695065_11;
|
|
414
|
+
</script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1787503695065_11"><a data-stx-scope="stx_scope_nav_15" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="active" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment & secrets</a><a class="" href="/data/backups?env=production">Backups & recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
|
|
415
415
|
(function() {
|
|
416
416
|
var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
|
|
417
417
|
var __destroyHooks = [];
|
|
@@ -762,6 +762,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1787415905688_10;
|
|
|
762
762
|
|
|
763
763
|
|
|
764
764
|
try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
|
|
765
|
-
window.stx._scopes['
|
|
765
|
+
window.stx._scopes['stx_scope_nav_15'] = __scopeRegistration;
|
|
766
766
|
})();
|
|
767
767
|
</script> <main class="workload-wrap wrap" id="main-content"><div class="crumbs">Operations <span class="sep">/</span> Workloads</div><header class="page"><div><h1>Workloads</h1><p>One live inventory for services, containers, tasks, and functions—with explicit provider capabilities and release context.</p></div><div class="freshness" x-cloak><span class="pill" :class="pollingState() === 'live' ? 'ok' : 'warn'" x-cloak>{{ pollingLabel() }}</span><small x-cloak>{{ lastUpdatedAt() ? lastUpdatedAt().toLocaleTimeString() : 'connecting' }}</small><button class="btn ghost sm" type="button" @click="refresh()">Refresh</button></div></header><div class="bad notice" role="status" @show="!!pollingError()" x-cloak>{{ pollingError() }}</div><section class="source-strip" aria-label="Runtime discovery sources" x-cloak><template :for="item in sources()"><span :class="item.status === 'fresh' ? 'fresh' : 'degraded'" x-cloak><b x-cloak>{{ item.id }}</b> {{ item.status }} · {{ item.itemCount }}<small @show="!!item.message" x-cloak>{{ item.message }}</small></span></template></section><section class="panel workload-toolbar"><label class="search-label">Search<input type="search" placeholder="Name, ID, image, tag…" :value="query()" @input="setFilter(query, $event.target.value)"></label><label>Provider<select :value="provider()" @change="setFilter(provider, $event.target.value)"><option value="">All</option><option value="systemd">systemd</option><option value="docker">docker</option><option value="ecs">ecs</option><option value="lambda">lambda</option></select></label><label>Status<select :value="status()" @change="setFilter(status, $event.target.value)"><option value="">All</option><option value="running">running</option><option value="starting">starting</option><option value="degraded">degraded</option><option value="stopping">stopping</option><option value="stopped">stopped</option><option value="failed">failed</option><option value="unknown">unknown</option></select></label><details><summary>Columns</summary><div class="column-menu"><label><input type="checkbox" :checked="columns().replicas" @change="columns.set({...columns(), replicas: $event.target.checked})">Replicas</label><label><input type="checkbox" :checked="columns().image" @change="columns.set({...columns(), image: $event.target.checked})">Image/runtime</label><label><input type="checkbox" :checked="columns().resources" @change="columns.set({...columns(), resources: $event.target.checked})">Resources</label><label><input type="checkbox" :checked="columns().age" @change="columns.set({...columns(), age: $event.target.checked})">Age</label></div></details><button class="btn ghost sm" type="button" @show="!!serviceFilter()" @click="setFilter(serviceFilter, '')" x-cloak>Clear service: {{ serviceFilter() }}</button></section><div class="workload-layout" :class="{ inspecting: !!selected() }"><section class="panel workload-list"><div class="workload-table-wrap"><table class="workload-table"><thead><tr><th scope="col">Workload</th><th scope="col">Status</th><th scope="col">Provider</th><th scope="col" @show="columns().replicas" x-cloak>Replicas</th><th scope="col" @show="columns().image" x-cloak>Image / runtime</th><th scope="col" @show="columns().resources" x-cloak>Memory</th><th scope="col" @show="columns().age" x-cloak>Age</th></tr></thead><tbody><template :for="item in visible()"><tr class="workload-row" :class="{ selected: item.id === selectedId() }" tabindex="0" @click="open(item)" @keydown.enter="open(item)"><td x-cloak><b x-cloak>{{ item.displayName || item.name }}</b><small x-cloak>{{ item.links?.service || item.kind }} · {{ item.id }}</small></td><td x-cloak><span class="pill" :class="tone(item.status)" x-cloak>{{ item.status }}</span><small x-cloak>{{ item.rawStatus || 'normalized' }}</small></td><td x-cloak><span class="tag" x-cloak>{{ item.provider }}</span><small x-cloak>{{ item.runtime || item.kind }}</small></td><td @show="columns().replicas" x-cloak>{{ replicaLabel(item) }}</td><td class="mono" @show="columns().image" x-cloak>{{ item.image || item.runtime || '—' }}</td><td @show="columns().resources" x-cloak>{{ bytes(item.resources?.memoryBytes || item.resources?.memoryLimitBytes) }}</td><td @show="columns().age" x-cloak>{{ age(item.ageSeconds) }}</td></tr></template></tbody></table></div><div class="empty" @show="pollingState() !== 'loading' && visible().length === 0" x-cloak><strong>No matching workloads</strong><span>Change the filters, or inspect degraded sources above for discovery guidance.</span></div></section><aside class="panel workload-detail" @show="!!selected()" x-cloak><button class="detail-close" type="button" aria-label="Close workload detail" @click="close()">×</button><template :if="selected()" x-cloak><div class="detail-content" x-cloak><span class="tag" x-cloak>{{ selected().provider }} · {{ selected().kind }}</span><h2 x-cloak>{{ selected().displayName || selected().name }}</h2><div class="detail-meta" x-cloak><span class="pill" :class="tone(selected().status)" x-cloak>{{ selected().status }}</span><span class="mono" x-cloak>{{ selected().id }}</span></div><nav class="context-links" aria-label="Related resources" x-cloak><a @show="!!selected().links?.service" :href="'/server/sites?service=' + encodeURIComponent(selected().links.service)" x-cloak>Service {{ selected().links?.service }}</a><a @show="!!selected().links?.release" :href="'/operations/releases?release=' + encodeURIComponent(selected().links.release)" x-cloak>Release {{ selected().links?.release }}</a><span @show="!!selected().links?.server" x-cloak>Server {{ selected().links?.server }}</span></nav><h3>Lifecycle</h3><div class="capability-grid"><button class="btn ghost sm" type="button" :disabled="operationBusy() || typed() !== selected().name || !capability(selected(), 'start').supported" :title="capability(selected(), 'start').supported ? `start ${selected().name}` : capability(selected(), 'start').reason" @click="run('start')">start</button><button class="btn danger sm" type="button" :disabled="operationBusy() || typed() !== selected().name || !capability(selected(), 'stop').supported" :title="capability(selected(), 'stop').supported ? `stop ${selected().name}` : capability(selected(), 'stop').reason" @click="run('stop')">stop</button><button class="btn ghost sm" type="button" :disabled="operationBusy() || typed() !== selected().name || !capability(selected(), 'restart').supported" :title="capability(selected(), 'restart').supported ? `restart ${selected().name}` : capability(selected(), 'restart').reason" @click="run('restart')">restart</button><button class="btn ghost sm" type="button" :disabled="operationBusy() || typed() !== selected().name || !capability(selected(), 'redeploy').supported" :title="capability(selected(), 'redeploy').supported ? `redeploy ${selected().name}` : capability(selected(), 'redeploy').reason" @click="run('redeploy')">redeploy</button><button class="btn ghost sm" type="button" :disabled="operationBusy() || typed() !== selected().name || !capability(selected(), 'scale').supported" :title="capability(selected(), 'scale').supported ? `scale ${selected().name}` : capability(selected(), 'scale').reason" @click="run('scale')">scale</button></div><div class="scale-row" @show="capability(selected(), 'scale').supported" x-cloak><label>Desired replicas<input type="number" min="0" max="10000" :value="replicas()" @input="replicas.set($event.target.value)"></label></div><label class="confirm-label" x-cloak>Type <b x-cloak>{{ selected().name }}</b> to run a mutation<input :value="typed()" @input="typed.set($event.target.value)" autocomplete="off"></label><p class="notice" role="status" @show="!!message()" x-cloak>{{ message() }}</p><details open><summary x-cloak>Replicas / processes ({{ selected().replicas?.length || 0 }})</summary><div class="detail-list" x-cloak><template :for="replica in selected().replicas || []"><div x-cloak><b x-cloak>{{ replica.name || replica.id }}</b><span x-cloak>{{ replica.status }} · PID {{ replica.pid || '—' }} · restarts {{ replica.restartCount || 0 }}</span></div></template><span @show="!(selected().replicas || []).length" x-cloak>Provider-managed or no active replica.</span></div></details><details><summary x-cloak>Networks ({{ selected().networks?.length || 0 }})</summary><pre x-cloak>{{ JSON.stringify(selected().networks || [], null, 2) }}</pre></details><details><summary x-cloak>Mounts ({{ selected().mounts?.length || 0 }})</summary><pre x-cloak>{{ JSON.stringify(selected().mounts || [], null, 2) }}</pre></details><details><summary>Redacted configuration</summary><pre x-cloak>{{ JSON.stringify(selected().config || {}, null, 2) }}</pre></details><details><summary>Provider capabilities</summary><div class="detail-list" x-cloak><template :for="entry in Object.entries(selected().capabilities || {})"><div x-cloak><b x-cloak>{{ entry[0] }}</b><span x-cloak>{{ entry[1].supported ? 'supported' : entry[1].reason }}</span></div></template></div></details><details @show="capability(selected(), 'exec').supported" x-cloak><summary>Elevated diagnostics and exec</summary><p class="note" x-cloak>Target: <b x-cloak>{{ selected().name }}</b> on {{ selected().links?.server || selected().provider }}. Presets are read-only; free-form access is container-only.</p><div class="capability-grid"><button class="btn ghost sm" type="button" :disabled="typed() !== selected().name || streamState() === 'live'" @click="startExec('process')">Process status</button><button class="btn ghost sm" type="button" :disabled="typed() !== selected().name || streamState() === 'live'" @click="startExec('sockets')">Listening sockets</button><button class="btn ghost sm" type="button" :disabled="typed() !== selected().name || streamState() === 'live'" @click="startExec('filesystem')">Filesystem usage</button></div><label class="confirm-label" @show="selected().provider === 'docker'" x-cloak>Container command<input :value="execCommand()" @input="execCommand.set($event.target.value)" placeholder="id"></label><button class="btn danger sm" type="button" @show="selected().provider === 'docker'" :disabled="typed() !== selected().name || !execCommand().trim() || streamState() === 'live'" @click="startExec('')" x-cloak>Run container command</button></details><details @show="capability(selected(), 'files').supported" x-cloak><summary>Scoped file transfer</summary><p class="note">Only service-owned roots and discovered mount targets are allowed. Transfers are capped at 48 KB and uploads replace files atomically with mode 0600.</p><label class="confirm-label">Absolute path<input :value="filePath()" @input="filePath.set($event.target.value)" placeholder="/var/www/project/service/file.txt"></label><label class="confirm-label">Upload file<input type="file" @change="chooseUpload($event)"></label><small @show="!!uploadName()" x-cloak>Ready: {{ uploadName() }}</small><div class="capability-grid"><button class="btn ghost sm" type="button" :disabled="typed() !== selected().name || !filePath() || fileBusy()" @click="fileRequest('read')">Download</button><button class="btn danger sm" type="button" :disabled="typed() !== selected().name || !filePath() || !uploadBase64() || fileBusy()" @click="fileRequest('write')">Upload and replace</button></div></details><div class="logs-head" x-cloak><h3 x-cloak>Logs <small x-cloak>{{ streamState() }}</small></h3><div class="capability-grid" x-cloak><button class="btn ghost sm" type="button" :disabled="logsBusy() || !capability(selected(), 'logs').supported" :title="capability(selected(), 'logs').reason || ''" @click="readLogs()" x-cloak>{{ logsBusy() ? 'Loading…' : 'Load logs' }}</button><button class="btn ghost sm" type="button" :disabled="streamState() === 'live' || !capability(selected(), 'logs').supported" @click="startLogFollow()">Follow</button><button class="btn danger sm" type="button" :disabled="!streamSession()" @click="stopStream()">Close stream</button></div></div><div class="logs" aria-live="polite" x-cloak><template :for="line in logs()"><div :class="line.stream === 'stderr' ? 'bad' : ''" x-cloak><span class="ts" x-cloak>{{ line.timestamp || '—' }}</span> {{ line.message }}</div></template><span @show="!logs().length" x-cloak>No log lines loaded.</span></div></div></template></aside></div></main><style> .workload-wrap{max-width:1540px}.freshness{display:flex;gap:8px;align-items:center;color:var(--txt3)}.source-strip{display:flex;gap:8px;overflow:auto;margin-bottom:12px}.source-strip>span{display:grid;min-width:max-content;padding:8px 10px;border:1px solid var(--line);border-radius:9px;color:var(--txt3);font-size:11px}.source-strip .fresh{border-color:color-mix(in srgb,var(--ok) 30%,var(--line))}.source-strip .degraded{border-color:color-mix(in srgb,var(--bad) 35%,var(--line))}.source-strip small{max-width:360px;white-space:normal;margin-top:3px}.workload-toolbar{display:flex;align-items:end;gap:10px;margin-bottom:14px;padding:14px}.workload-toolbar>label{display:grid;gap:5px;color:var(--txt3);font-size:11px}.workload-toolbar input,.workload-toolbar select,.confirm-label input,.scale-row input{background:var(--bg2);border:1px solid var(--line);border-radius:8px;color:var(--txt);padding:8px 10px}.search-label{flex:1;min-width:230px}.column-menu{position:absolute;z-index:5;display:grid;gap:8px;margin-top:6px;padding:12px;background:var(--panel);border:1px solid var(--line);border-radius:9px}.workload-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:14px}.workload-layout.inspecting{grid-template-columns:minmax(650px,1.5fr) minmax(360px,.7fr)}.workload-list{padding:0;overflow:hidden}.workload-table-wrap{overflow:auto}.workload-table{min-width:900px}.workload-row{cursor:pointer}.workload-row.selected{background:color-mix(in srgb,var(--accent) 9%,transparent)}.workload-row td small{display:block;max-width:330px;margin-top:4px;color:var(--txt3);font-size:10px;overflow:hidden;text-overflow:ellipsis}.workload-detail{position:sticky;top:14px;align-self:start;max-height:calc(100vh - 28px);overflow:auto;padding:20px}.detail-close{float:right;border:0;background:transparent;color:var(--txt3);font-size:24px;cursor:pointer}.detail-meta,.context-links,.capability-grid,.logs-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.detail-meta .mono{font-size:10px;color:var(--txt3);overflow-wrap:anywhere}.context-links{margin:12px 0}.context-links>*{font-size:11px}.capability-grid{margin:8px 0}.confirm-label,.scale-row label{display:grid;gap:6px;margin:12px 0;color:var(--txt3);font-size:11px}.workload-detail details{border-top:1px solid var(--line);padding:12px 0}.workload-detail summary{cursor:pointer;font-weight:700}.workload-detail pre{max-height:260px;overflow:auto;margin-top:10px;background:#090c12;padding:10px;border-radius:8px;font-size:10px;white-space:pre-wrap}.detail-list{display:grid;gap:8px;margin-top:10px}.detail-list>div{display:grid;gap:2px}.detail-list span{color:var(--txt3);font-size:11px}.logs-head{justify-content:space-between}.logs{min-height:80px}.notice{padding:9px 10px} @media(max-width:1100px){.workload-layout.inspecting{grid-template-columns:1fr}.workload-detail{position:static;max-height:none}} @media(max-width:700px){.source-strip{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow:visible}.source-strip>span{min-width:0;overflow-wrap:anywhere}.workload-toolbar{align-items:stretch;flex-direction:column}.workload-toolbar>*{width:100%}.workload-table{min-width:0}.workload-table thead{display:none}.workload-table tbody,.workload-row{display:block}.workload-row{padding:12px}.workload-row td{display:grid;grid-template-columns:100px 1fr;padding:5px 0;border:0}.workload-row td:before{color:var(--txt3);font-size:10px}.workload-row td:nth-child(1):before{content:'Workload'}.workload-row td:nth-child(2):before{content:'Status'}.workload-row td:nth-child(3):before{content:'Provider'}.workload-row td:nth-child(4):before{content:'Replicas'}.workload-row td:nth-child(5):before{content:'Image'}.workload-row td:nth-child(6):before{content:'Memory'}.workload-row td:nth-child(7):before{content:'Age'}} </style></body></html>
|