[grade=A] Shipdeck fleet module and manual deploy flow

Adds validated fleet install/lifecycle routes, bridge-backed Git and OCI workflows, persistent service cards, and the Local-tab Shipdeck deployment UI while preserving catalog and External flows.

Judge: urn:ump:if6udffdyelsf4qvskkr65ikhuprsjiajzij6h653fhf2zgyynzq
This commit is contained in:
DashCaddy Polish Loop
2026-09-15 11:13:29 -07:00
parent f9cbb13a3d
commit 0dd8493f98
14 changed files with 1624 additions and 230 deletions
+29
View File
@@ -0,0 +1,29 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const modal = fs.readFileSync(path.join(__dirname, '../js/core/service-modals.js'), 'utf8');
const flow = fs.readFileSync(path.join(__dirname, '../js/core/service-create.js'), 'utf8');
const bundle = fs.readFileSync(path.join(__dirname, '../dist/core.js'), 'utf8');
test('Add Service keeps Local and External tabs and adds Shipdeck fields', () => {
for (const id of ['service-type-local', 'service-type-external', 'service-name-input', 'service-subdomain-input', 'service-port-input', 'service-source-url', 'service-sha256-input', 'service-git-token', 'service-ip-input', 'service-logo-input', 'shipdeckfile-preview']) {
assert.match(modal, new RegExp(`id=["']${id}["']`), id);
}
assert.match(modal, /id="service-git-token"[^>]*type="password"|type="password"[^>]*id="service-git-token"/);
});
test('Local deployment calls fleet route and renders lifecycle status', () => {
assert.match(flow, /secureFetch\('\/api\/v1\/fleet\/from-git'/);
assert.match(flow, /\/api\/v1\/fleet\/shipdeckfile\?id=/);
assert.match(flow, /Building.*Deploying.*Live/s);
assert.match(flow, /service-git-token'\)\.value = ''/);
});
test('External service flow remains present and unchanged in the bundle', () => {
assert.match(flow, /async function createExternalService/);
assert.match(flow, /\/api\/v1\/site\/external/);
assert.match(bundle, /\/api\/v1\/fleet\/from-git/);
assert.match(bundle, /\/api\/v1\/site\/external/);
});