mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
feat(docker): add the attach-an-existing-container panel
The Docker tab gains an "Attach to an existing container" toggle. Ticking it swaps the create-time fields (image, network, advanced) — which describe a `docker create` attaching never runs — for the container name, and routes the submit to the adopt endpoint. Reuses the existing linkDockerCase flow end to end: only the final call differs. The docker-host upsert still applies, since it is what resolves the engine/context/daemon for `docker exec`; its create-time fields are simply never read for an attached case.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
* Mirror of the `owned:false` remote-SSH contract (COD-105).
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import {
|
||||
toSessionDocker,
|
||||
isAdoptedContainer,
|
||||
@@ -158,6 +159,41 @@ describe('adopted container: mutating verbs fail closed at the builder', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('adopted container: the Add Case panel id contract', () => {
|
||||
// The modal's load/save contract is getElementById by fixed id, so a renamed or
|
||||
// dropped id stops the control working with no error anywhere. Static guard in
|
||||
// the style of app-settings-structure / session-options-structure.
|
||||
const html = readFileSync(new URL('../src/web/public/index.html', import.meta.url), 'utf8');
|
||||
const ui = readFileSync(new URL('../src/web/public/session-ui.js', import.meta.url), 'utf8');
|
||||
const css = readFileSync(new URL('../src/web/public/styles.css', import.meta.url), 'utf8');
|
||||
|
||||
it('ships every id session-ui.js reads back', () => {
|
||||
for (const id of ['dockerAdoptExisting', 'dockerContainerName', 'dockerAdoptCheckBtn']) {
|
||||
expect(html).toContain(`id="${id}"`);
|
||||
expect(ui).toContain(`'${id}'`);
|
||||
}
|
||||
});
|
||||
|
||||
it('routes adoption to the endpoint that never creates a container', () => {
|
||||
expect(ui).toContain('/api/cases/docker-adopt');
|
||||
expect(ui).toContain('/api/docker-cases/adopt-preflight');
|
||||
// The create path must survive untouched beside it.
|
||||
expect(ui).toContain('/api/cases/docker-link');
|
||||
});
|
||||
|
||||
it('hides the adopt-only row until the toggle is on, so the panel is unchanged by default', () => {
|
||||
expect(css).toContain('#createCaseModal .docker-adopt-only');
|
||||
expect(css).toMatch(/#createCaseModal \.docker-adopt-only \{\s*display: none/);
|
||||
expect(css).toContain("#createCaseModal[data-docker-adopt='1'] .docker-adopt-only");
|
||||
});
|
||||
|
||||
it('marks the create-time rows so adoption hides the fields it never uses', () => {
|
||||
// image / network / advanced describe a `docker create` adoption never runs.
|
||||
expect(html.match(/docker-create-only/g)?.length).toBeGreaterThanOrEqual(3);
|
||||
expect(css).toContain("#createCaseModal[data-docker-adopt='1'] .docker-create-only");
|
||||
});
|
||||
});
|
||||
|
||||
describe('adopted container: drift is not evaluated', () => {
|
||||
it('reports no drift rather than demanding a recreate we may not perform', async () => {
|
||||
// An adopted container carries no codeman.confighash label, so a real
|
||||
|
||||
Reference in New Issue
Block a user