cdd-cli 3.2.0 → 4.0.0
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/.atl/skill-registry.md +30 -0
- package/.editorconfig +12 -0
- package/.eslintrc.json +1 -1
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/.~lock.ROADMAP.md# +1 -0
- package/CHANGELOG.md +80 -0
- package/README.es.md +198 -0
- package/README.md +81 -23
- package/ROADMAP.md +647 -0
- package/SECURITY.md +5 -0
- package/__mocks__/ink.cjs +17 -0
- package/coverage/clover.xml +471 -500
- package/coverage/coverage-final.json +16 -16
- package/coverage/lcov-report/ContainerCreationPrompt.jsx.html +400 -0
- package/coverage/lcov-report/ControlsHUD.jsx.html +256 -0
- package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +394 -0
- package/coverage/lcov-report/components/PromptField.jsx.html +229 -0
- package/coverage/lcov-report/components/SuggestionPanel.jsx.html +268 -0
- package/coverage/lcov-report/components/index.html +146 -0
- package/coverage/lcov-report/helpers/constants.js.html +139 -22
- package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +75 -42
- package/coverage/lcov-report/helpers/dockerHubService.js.html +310 -0
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +162 -84
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +50 -32
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +21 -21
- package/coverage/lcov-report/helpers/imageNameUtils.js.html +181 -0
- package/coverage/lcov-report/helpers/index.html +84 -54
- package/coverage/lcov-report/helpers/logger.js.html +68 -68
- package/coverage/lcov-report/helpers/safeCall.js.html +15 -15
- package/coverage/lcov-report/helpers/validationHelpers.js.html +66 -114
- package/coverage/lcov-report/hooks/creation/index.html +20 -20
- package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +38 -17
- package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +593 -89
- package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +7 -7
- package/coverage/lcov-report/hooks/debug/index.html +5 -5
- package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +35 -20
- package/coverage/lcov-report/hooks/index.html +40 -40
- package/coverage/lcov-report/hooks/navigation/index.html +19 -19
- package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +38 -29
- package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +119 -80
- package/coverage/lcov-report/hooks/useControls.js.html +306 -123
- package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +8 -8
- package/coverage/lcov-report/hooks/useExitHandler.js.html +50 -41
- package/coverage/lcov-report/index.html +52 -67
- package/coverage/lcov.info +899 -952
- package/dist/App.js +18 -12
- package/dist/components/ContainerCreationPrompt.js +50 -13
- package/dist/components/ContainerList.js +3 -3
- package/dist/components/ContainerRow.js +20 -20
- package/dist/components/ContainerSection.js +3 -3
- package/dist/components/ControlsHUD.js +106 -0
- package/dist/components/Footer.js +2 -2
- package/dist/components/Header.js +7 -7
- package/dist/components/LogViewer.js +3 -3
- package/dist/components/MessageFeedback.js +2 -2
- package/dist/components/PromptField.js +4 -4
- package/dist/components/StatsBar.js +5 -5
- package/dist/components/SuggestionPanel.js +53 -0
- package/dist/components/UsageMenu.js +3 -3
- package/dist/helpers/appInfo.js +7 -7
- package/dist/helpers/constants.js +154 -1
- package/dist/helpers/containerOptionsBuilder.js +3 -3
- package/dist/helpers/dockerHubService.js +111 -0
- package/dist/helpers/dockerService/dockerService.js +1 -1
- package/dist/helpers/dockerService/serviceComponents/containerActions.js +99 -40
- package/dist/helpers/dockerService/serviceComponents/containerList.js +11 -11
- package/dist/helpers/dockerService/serviceComponents/containerLogs.js +9 -9
- package/dist/helpers/dockerService/serviceComponents/containerStats.js +5 -5
- package/dist/helpers/dockerService/serviceComponents/imageUtils.js +1 -1
- package/dist/helpers/exitWithMessage.js +10 -10
- package/dist/helpers/imageNameUtils.js +32 -0
- package/dist/helpers/logger.js +13 -13
- package/dist/helpers/safeCall.js +2 -2
- package/dist/helpers/validationHelpers.js +76 -21
- package/dist/hooks/creation/useContainerActions.js +28 -11
- package/dist/hooks/creation/useContainerCreation.js +452 -62
- package/dist/hooks/creation/useLogsViewer.js +2 -2
- package/dist/hooks/debug/useDebugLogs.js +4 -4
- package/dist/hooks/useContainerCommandRouter.js +14 -14
- package/dist/hooks/useContainers.js +3 -3
- package/dist/hooks/useControls.js +85 -38
- package/dist/hooks/useEraseConfirmation.js +3 -3
- package/dist/index.js +9 -2
- package/jest.config.cjs +7 -0
- package/package.json +7 -3
- package/src/App.jsx +39 -16
- package/src/components/ContainerCreationPrompt.jsx +54 -10
- package/src/components/ContainerList.jsx +3 -3
- package/src/components/ContainerRow.jsx +19 -16
- package/src/components/ContainerSection.jsx +3 -3
- package/src/components/ControlsHUD.jsx +66 -0
- package/src/components/Footer.jsx +2 -2
- package/src/components/Header.jsx +7 -7
- package/src/components/LogViewer.jsx +5 -3
- package/src/components/MessageFeedback.jsx +2 -2
- package/src/components/PromptField.jsx +4 -4
- package/src/components/StatsBar.jsx +11 -7
- package/src/components/SuggestionPanel.jsx +61 -0
- package/src/components/UsageMenu.jsx +18 -13
- package/src/helpers/appInfo.js +7 -7
- package/src/helpers/constants.js +48 -9
- package/src/helpers/containerOptionsBuilder.js +16 -5
- package/src/helpers/dockerHubService.js +75 -0
- package/src/helpers/dockerService/dockerService.js +1 -1
- package/src/helpers/dockerService/serviceComponents/containerActions.js +87 -61
- package/src/helpers/dockerService/serviceComponents/containerList.js +31 -25
- package/src/helpers/dockerService/serviceComponents/containerLogs.js +41 -26
- package/src/helpers/dockerService/serviceComponents/containerStats.js +13 -11
- package/src/helpers/dockerService/serviceComponents/imageUtils.js +5 -4
- package/src/helpers/exitWithMessage.js +13 -7
- package/src/helpers/imageNameUtils.js +32 -0
- package/src/helpers/logger.js +15 -16
- package/src/helpers/safeCall.js +2 -2
- package/src/helpers/validationHelpers.js +13 -29
- package/src/hooks/creation/useContainerActions.js +32 -12
- package/src/hooks/creation/useContainerCreation.js +293 -47
- package/src/hooks/creation/useLogsViewer.js +2 -2
- package/src/hooks/debug/useDebugLogs.js +15 -10
- package/src/hooks/navigation/useContainerSelection.js +17 -14
- package/src/hooks/useContainerCommandRouter.js +71 -58
- package/src/hooks/useContainers.js +4 -4
- package/src/hooks/useControls.js +135 -72
- package/src/hooks/useEraseConfirmation.js +3 -3
- package/src/hooks/useExitHandler.js +29 -26
- package/src/index.js +8 -4
- package/test/ContainerCreationPrompt.dom.test.js +313 -0
- package/test/ControlsHUD.dom.test.js +125 -0
- package/test/SuggestionPanel.dom.test.js +83 -0
- package/test/constants.test.js +41 -0
- package/test/dockerHubService.test.js +213 -0
- package/test/logger.test.js +58 -0
- package/test/resolveImageTag.test.js +26 -0
- package/test/useContainerCreation.dom.test.js +428 -2
- package/test/useContainerCreationHub.dom.test.js +184 -0
- package/test/useControls.dom.test.js +406 -4
|
@@ -8,9 +8,9 @@ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(
|
|
|
8
8
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
9
9
|
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
10
10
|
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
11
|
-
import { docker } from
|
|
12
|
-
import { logger } from
|
|
13
|
-
var DEFAULT_CONTAINER_NAME =
|
|
11
|
+
import { docker } from '../dockerService.js';
|
|
12
|
+
import { logger } from '../../logger.js';
|
|
13
|
+
var DEFAULT_CONTAINER_NAME = 'Unknown';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Produce a safe, display-friendly container name from the raw Docker payload.
|
|
@@ -21,19 +21,19 @@ var DEFAULT_CONTAINER_NAME = "Unknown";
|
|
|
21
21
|
function normalizeContainerName(container) {
|
|
22
22
|
var names = container === null || container === void 0 ? void 0 : container.Names;
|
|
23
23
|
var rawName;
|
|
24
|
-
if (Array.isArray(names) && names.length > 0 && typeof names[0] ===
|
|
24
|
+
if (Array.isArray(names) && names.length > 0 && typeof names[0] === 'string') {
|
|
25
25
|
rawName = names[0];
|
|
26
|
-
} else if (typeof names ===
|
|
26
|
+
} else if (typeof names === 'string' && names.trim().length > 0) {
|
|
27
27
|
rawName = names;
|
|
28
|
-
} else if (typeof (container === null || container === void 0 ? void 0 : container.Name) ===
|
|
28
|
+
} else if (typeof (container === null || container === void 0 ? void 0 : container.Name) === 'string' && container.Name.trim().length > 0) {
|
|
29
29
|
rawName = container.Name;
|
|
30
30
|
} else {
|
|
31
31
|
rawName = DEFAULT_CONTAINER_NAME;
|
|
32
32
|
}
|
|
33
|
-
if (typeof rawName !==
|
|
33
|
+
if (typeof rawName !== 'string') {
|
|
34
34
|
return DEFAULT_CONTAINER_NAME;
|
|
35
35
|
}
|
|
36
|
-
var cleanedName = rawName.replace(/^\/+/,
|
|
36
|
+
var cleanedName = rawName.replace(/^\/+/, '').trim();
|
|
37
37
|
return cleanedName.length > 0 ? cleanedName : DEFAULT_CONTAINER_NAME;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -50,7 +50,7 @@ function _getContainers() {
|
|
|
50
50
|
return _regenerator().w(function (_context) {
|
|
51
51
|
while (1) switch (_context.p = _context.n) {
|
|
52
52
|
case 0:
|
|
53
|
-
logger.debug(
|
|
53
|
+
logger.debug('Listing containers');
|
|
54
54
|
_context.p = 1;
|
|
55
55
|
_context.n = 2;
|
|
56
56
|
return docker.listContainers({
|
|
@@ -58,7 +58,7 @@ function _getContainers() {
|
|
|
58
58
|
});
|
|
59
59
|
case 2:
|
|
60
60
|
containers = _context.v;
|
|
61
|
-
logger.debug(
|
|
61
|
+
logger.debug('Retrieved %d containers', containers.length);
|
|
62
62
|
return _context.a(2, containers.map(function (container) {
|
|
63
63
|
return {
|
|
64
64
|
id: container.Id,
|
|
@@ -88,7 +88,7 @@ function _getContainers() {
|
|
|
88
88
|
case 3:
|
|
89
89
|
_context.p = 3;
|
|
90
90
|
_t = _context.v;
|
|
91
|
-
logger.error(
|
|
91
|
+
logger.error('Failed to list containers', _t);
|
|
92
92
|
throw _t;
|
|
93
93
|
case 4:
|
|
94
94
|
return _context.a(2);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { docker } from
|
|
2
|
-
import { safeCall } from
|
|
3
|
-
import { logger } from
|
|
1
|
+
import { docker } from '../dockerService.js';
|
|
2
|
+
import { safeCall } from '../../safeCall.js';
|
|
3
|
+
import { logger } from '../../logger.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Return a stream of logs from a container and call callbacks for events.
|
|
@@ -15,7 +15,7 @@ export function getLogsStream(containerId, onData, onEnd, onError) {
|
|
|
15
15
|
|
|
16
16
|
try {
|
|
17
17
|
var container = docker.getContainer(containerId);
|
|
18
|
-
logger.debug(
|
|
18
|
+
logger.debug('Opening logs stream for container %s', containerId);
|
|
19
19
|
container.logs({
|
|
20
20
|
follow: true,
|
|
21
21
|
stdout: true,
|
|
@@ -23,25 +23,25 @@ export function getLogsStream(containerId, onData, onEnd, onError) {
|
|
|
23
23
|
tail: 100
|
|
24
24
|
}, function (err, stream) {
|
|
25
25
|
if (err) {
|
|
26
|
-
logger.error(
|
|
26
|
+
logger.error('Failed to open logs stream for container %s', containerId, err);
|
|
27
27
|
safeCall(onError, err);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
logger.info(
|
|
30
|
+
logger.info('Logs stream established for container %s', containerId);
|
|
31
31
|
stream.on('data', function (chunk) {
|
|
32
32
|
return safeCall(onData, chunk.toString());
|
|
33
33
|
});
|
|
34
34
|
stream.on('end', function () {
|
|
35
|
-
logger.debug(
|
|
35
|
+
logger.debug('Logs stream ended for container %s', containerId);
|
|
36
36
|
safeCall(onEnd);
|
|
37
37
|
});
|
|
38
38
|
stream.on('error', function (streamErr) {
|
|
39
|
-
logger.error(
|
|
39
|
+
logger.error('Logs stream error for container %s', containerId, streamErr);
|
|
40
40
|
safeCall(onError, streamErr);
|
|
41
41
|
});
|
|
42
42
|
});
|
|
43
43
|
} catch (err) {
|
|
44
|
-
logger.error(
|
|
44
|
+
logger.error('Unexpected error while opening logs stream for container %s', containerId, err);
|
|
45
45
|
safeCall(onError, err);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -2,8 +2,8 @@ function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present,
|
|
|
2
2
|
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
|
|
3
3
|
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
4
4
|
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
5
|
-
import { docker } from
|
|
6
|
-
import { logger } from
|
|
5
|
+
import { docker } from '../dockerService.js';
|
|
6
|
+
import { logger } from '../../logger.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Retrieve a snapshot of container resource usage (CPU, memory, network).
|
|
@@ -21,7 +21,7 @@ function _getStats() {
|
|
|
21
21
|
while (1) switch (_context.p = _context.n) {
|
|
22
22
|
case 0:
|
|
23
23
|
container = docker.getContainer(containerId);
|
|
24
|
-
logger.debug(
|
|
24
|
+
logger.debug('Fetching stats for container %s', containerId);
|
|
25
25
|
_context.p = 1;
|
|
26
26
|
_context.n = 2;
|
|
27
27
|
return container.stats({
|
|
@@ -34,7 +34,7 @@ function _getStats() {
|
|
|
34
34
|
case 3:
|
|
35
35
|
_context.p = 3;
|
|
36
36
|
_t = _context.v;
|
|
37
|
-
logger.error(
|
|
37
|
+
logger.error('Failed to fetch stats for container %s', containerId, _t);
|
|
38
38
|
throw _t;
|
|
39
39
|
case 4:
|
|
40
40
|
cpuDelta = stream.cpu_stats.cpu_usage.total_usage - stream.precpu_stats.cpu_usage.total_usage;
|
|
@@ -69,7 +69,7 @@ function _getStats() {
|
|
|
69
69
|
tx: tx
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
|
-
logger.debug(
|
|
72
|
+
logger.debug('Stats fetched for container %s', containerId, snapshot);
|
|
73
73
|
return _context.a(2, snapshot);
|
|
74
74
|
}
|
|
75
75
|
}, _callee, null, [[1, 3]]);
|
|
@@ -2,7 +2,7 @@ function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present,
|
|
|
2
2
|
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
|
|
3
3
|
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
4
4
|
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
5
|
-
import { docker } from
|
|
5
|
+
import { docker } from '../dockerService.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Check whether an image exists locally.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { spawn } from
|
|
2
|
-
import { EXIT_DELAY } from
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { EXIT_DELAY } from './constants.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Show an exit message using provided setters, clear the terminal and exit after a delay.
|
|
@@ -15,22 +15,22 @@ export function exitWithMessage(_ref) {
|
|
|
15
15
|
var setMessage = _ref.setMessage,
|
|
16
16
|
setMessageColor = _ref.setMessageColor,
|
|
17
17
|
_ref$message = _ref.message,
|
|
18
|
-
message = _ref$message === void 0 ?
|
|
18
|
+
message = _ref$message === void 0 ? 'Exiting...' : _ref$message,
|
|
19
19
|
_ref$color = _ref.color,
|
|
20
|
-
color = _ref$color === void 0 ?
|
|
20
|
+
color = _ref$color === void 0 ? 'yellow' : _ref$color,
|
|
21
21
|
_ref$delay = _ref.delay,
|
|
22
22
|
delay = _ref$delay === void 0 ? EXIT_DELAY : _ref$delay;
|
|
23
23
|
setMessage(message);
|
|
24
24
|
setMessageColor(color);
|
|
25
25
|
setTimeout(function () {
|
|
26
|
-
setMessage(
|
|
27
|
-
if (process.platform ===
|
|
28
|
-
spawn(
|
|
29
|
-
stdio:
|
|
26
|
+
setMessage('');
|
|
27
|
+
if (process.platform === 'win32') {
|
|
28
|
+
spawn('cmd', ['/c', 'cls'], {
|
|
29
|
+
stdio: 'inherit'
|
|
30
30
|
});
|
|
31
31
|
} else {
|
|
32
|
-
spawn(
|
|
33
|
-
stdio:
|
|
32
|
+
spawn('clear', [], {
|
|
33
|
+
stdio: 'inherit'
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
process.exit();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility for normalizing Docker image names.
|
|
3
|
+
* Extracted from validationHelpers.js and containerActions.js — both had
|
|
4
|
+
* identical implementations; consolidated here to avoid duplication.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Normalize an image name to its base name (strips registry prefix and tag).
|
|
9
|
+
*
|
|
10
|
+
* Examples:
|
|
11
|
+
* "docker.io/library/postgres:16-alpine" → "postgres"
|
|
12
|
+
* "nginx:alpine" → "nginx"
|
|
13
|
+
* "myregistry.io/myorg/myapp:latest" → "myapp"
|
|
14
|
+
*
|
|
15
|
+
* @param {string} imageName - Raw image name (from user input or Docker API)
|
|
16
|
+
* @returns {string} Base image name in lowercase, empty string if input is falsy
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeImageName(imageName) {
|
|
19
|
+
if (!imageName) return '';
|
|
20
|
+
// Remove registry prefix (everything up to and including the last '/')
|
|
21
|
+
var name = imageName;
|
|
22
|
+
var slashIdx = name.lastIndexOf('/');
|
|
23
|
+
if (slashIdx !== -1) {
|
|
24
|
+
name = name.slice(slashIdx + 1);
|
|
25
|
+
}
|
|
26
|
+
// Remove tag (everything from the first ':' onward)
|
|
27
|
+
var colonIdx = name.indexOf(':');
|
|
28
|
+
if (colonIdx !== -1) {
|
|
29
|
+
name = name.slice(0, colonIdx);
|
|
30
|
+
}
|
|
31
|
+
return name.toLowerCase();
|
|
32
|
+
}
|
package/dist/helpers/logger.js
CHANGED
|
@@ -25,7 +25,7 @@ var LOG_LEVELS = {
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
function parseLevel(value) {
|
|
28
|
-
if (typeof value !==
|
|
28
|
+
if (typeof value !== 'string') {
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
31
|
var normalized = value.trim().toLowerCase();
|
|
@@ -35,11 +35,11 @@ function parseLevel(value) {
|
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
var envLevel = (_ref = (_parseLevel = parseLevel(process.env.CDD_LOG_LEVEL)) !== null && _parseLevel !== void 0 ? _parseLevel : parseLevel(process.env.LOG_LEVEL)) !== null && _ref !== void 0 ? _ref : LOG_LEVELS.info;
|
|
38
|
-
var currentLevel = typeof envLevel ===
|
|
38
|
+
var currentLevel = typeof envLevel === 'number' ? envLevel : LOG_LEVELS.info;
|
|
39
39
|
var listeners = new Set();
|
|
40
40
|
function shouldLog(level) {
|
|
41
41
|
var target = LOG_LEVELS[level];
|
|
42
|
-
return typeof target ===
|
|
42
|
+
return typeof target === 'number' && target <= currentLevel;
|
|
43
43
|
}
|
|
44
44
|
function log(level, message) {
|
|
45
45
|
if (!shouldLog(level)) {
|
|
@@ -58,10 +58,10 @@ function log(level, message) {
|
|
|
58
58
|
timestamp: timestamp,
|
|
59
59
|
formatted: formatted
|
|
60
60
|
};
|
|
61
|
-
var shouldWriteToConsole = listeners.size === 0
|
|
61
|
+
var shouldWriteToConsole = listeners.size === 0;
|
|
62
62
|
if (shouldWriteToConsole) {
|
|
63
|
-
var method = level ===
|
|
64
|
-
if (typeof console[method] ===
|
|
63
|
+
var method = level === 'debug' ? 'log' : level;
|
|
64
|
+
if (typeof console[method] === 'function') {
|
|
65
65
|
var _console;
|
|
66
66
|
(_console = console)[method].apply(_console, [formatted].concat(args));
|
|
67
67
|
} else {
|
|
@@ -88,34 +88,34 @@ export var logger = {
|
|
|
88
88
|
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
|
89
89
|
args[_key2 - 1] = arguments[_key2];
|
|
90
90
|
}
|
|
91
|
-
log.apply(void 0, [
|
|
91
|
+
log.apply(void 0, ['debug', message].concat(args));
|
|
92
92
|
},
|
|
93
93
|
info: function info(message) {
|
|
94
94
|
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
|
95
95
|
args[_key3 - 1] = arguments[_key3];
|
|
96
96
|
}
|
|
97
|
-
log.apply(void 0, [
|
|
97
|
+
log.apply(void 0, ['info', message].concat(args));
|
|
98
98
|
},
|
|
99
99
|
warn: function warn(message) {
|
|
100
100
|
for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
|
|
101
101
|
args[_key4 - 1] = arguments[_key4];
|
|
102
102
|
}
|
|
103
|
-
log.apply(void 0, [
|
|
103
|
+
log.apply(void 0, ['warn', message].concat(args));
|
|
104
104
|
},
|
|
105
105
|
error: function error(message) {
|
|
106
106
|
for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
|
|
107
107
|
args[_key5 - 1] = arguments[_key5];
|
|
108
108
|
}
|
|
109
|
-
log.apply(void 0, [
|
|
109
|
+
log.apply(void 0, ['error', message].concat(args));
|
|
110
110
|
},
|
|
111
111
|
/**
|
|
112
112
|
* Subscribe to log events.
|
|
113
113
|
*
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
* @param {LogListener} listener Listener invoked for every log entry that passes the current level filter.
|
|
115
|
+
* @returns {function(): void} Cleanup function that removes the listener when called.
|
|
116
116
|
*/
|
|
117
117
|
subscribe: function subscribe(listener) {
|
|
118
|
-
if (typeof listener !==
|
|
118
|
+
if (typeof listener !== 'function') {
|
|
119
119
|
return function () {};
|
|
120
120
|
}
|
|
121
121
|
listeners.add(listener);
|
package/dist/helpers/safeCall.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logger } from
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Call a function safely: if it's a function call it with provided args and
|
|
@@ -15,7 +15,7 @@ export function safeCall(fn) {
|
|
|
15
15
|
}
|
|
16
16
|
return fn.apply(void 0, args);
|
|
17
17
|
} catch (e) {
|
|
18
|
-
logger.error(
|
|
18
|
+
logger.error('safeCall caught error', e);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
|
|
1
2
|
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
2
3
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
4
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
@@ -5,6 +6,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
5
6
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
7
|
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
7
8
|
// Reusable validations for ports and environment variables
|
|
9
|
+
import { normalizeImageName } from './imageNameUtils.js';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Validate a comma-separated list of port mappings in the form "host:container".
|
|
@@ -16,12 +18,12 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
|
16
18
|
export function validatePorts(portInput) {
|
|
17
19
|
// Empty or whitespace-only input is considered valid (ports are optional)
|
|
18
20
|
if (!portInput || !portInput.trim()) return true;
|
|
19
|
-
var ports = portInput.split(
|
|
21
|
+
var ports = portInput.split(',').map(function (p) {
|
|
20
22
|
return p.trim();
|
|
21
23
|
}).filter(Boolean);
|
|
22
24
|
if (ports.length === 0) return true;
|
|
23
25
|
var invalid = ports.find(function (pair) {
|
|
24
|
-
var _pair$split = pair.split(
|
|
26
|
+
var _pair$split = pair.split(':'),
|
|
25
27
|
_pair$split2 = _slicedToArray(_pair$split, 2),
|
|
26
28
|
host = _pair$split2[0],
|
|
27
29
|
cont = _pair$split2[1];
|
|
@@ -32,27 +34,80 @@ export function validatePorts(portInput) {
|
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Validate environment variable input as comma-separated VAR=value pairs.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
37
|
+
*
|
|
38
|
+
* When called with 3 arguments (envInput, imageName, imageProfiles), performs
|
|
39
|
+
* contextual validation: checks that all required env vars for the given image
|
|
40
|
+
* are present and non-empty. Returns an object { valid, errors, parsedEnv }.
|
|
41
|
+
*
|
|
42
|
+
* When called with 1 argument (legacy), returns a boolean for backward compatibility.
|
|
38
43
|
*
|
|
39
44
|
* @param {string} envInput - Comma-separated environment variable assignments
|
|
40
|
-
* @
|
|
45
|
+
* @param {string} [imageName] - Optional Docker image name for contextual validation
|
|
46
|
+
* @param {Object} [imageProfiles] - Optional map of image profiles (from constants.js)
|
|
47
|
+
* @returns {boolean|{valid: boolean, errors: string[], parsedEnv: Record<string,string>}}
|
|
41
48
|
*/
|
|
42
|
-
export function validateEnvVars(envInput) {
|
|
43
|
-
|
|
49
|
+
export function validateEnvVars(envInput, imageName, imageProfiles) {
|
|
50
|
+
var contextual = imageName !== undefined && imageProfiles !== undefined;
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
var
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
// Parse: split on FIRST '=' only
|
|
53
|
+
var parsedEnv = {};
|
|
54
|
+
var syntaxErrors = [];
|
|
55
|
+
if (envInput && envInput.trim()) {
|
|
56
|
+
var vars = envInput.split(',').map(function (v) {
|
|
57
|
+
return v.trim();
|
|
58
|
+
}).filter(Boolean);
|
|
59
|
+
var _iterator = _createForOfIteratorHelper(vars),
|
|
60
|
+
_step;
|
|
61
|
+
try {
|
|
62
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
63
|
+
var v = _step.value;
|
|
64
|
+
var eqIdx = v.indexOf('=');
|
|
65
|
+
if (eqIdx === -1) {
|
|
66
|
+
syntaxErrors.push("\"".concat(v, "\" is missing an '=' sign"));
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
var varName = v.slice(0, eqIdx).trim();
|
|
70
|
+
var varValue = v.slice(eqIdx + 1);
|
|
71
|
+
if (!/^[A-Z_][A-Z0-9_]*$/i.test(varName)) {
|
|
72
|
+
syntaxErrors.push("\"".concat(varName, "\" is not a valid variable name"));
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
parsedEnv[varName] = varValue;
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
_iterator.e(err);
|
|
79
|
+
} finally {
|
|
80
|
+
_iterator.f();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!contextual) {
|
|
84
|
+
// Legacy: return boolean
|
|
85
|
+
return syntaxErrors.length === 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Contextual: also check required env vars from the profile
|
|
89
|
+
var errors = [].concat(syntaxErrors);
|
|
90
|
+
var baseName = normalizeImageName(imageName);
|
|
91
|
+
var profile = imageProfiles[baseName];
|
|
92
|
+
if (profile && profile.requiredEnv && profile.requiredEnv.length) {
|
|
93
|
+
var _iterator2 = _createForOfIteratorHelper(profile.requiredEnv),
|
|
94
|
+
_step2;
|
|
95
|
+
try {
|
|
96
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
97
|
+
var required = _step2.value;
|
|
98
|
+
if (!parsedEnv[required] || parsedEnv[required].trim() === '') {
|
|
99
|
+
errors.push("Missing required env var: ".concat(required));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
_iterator2.e(err);
|
|
104
|
+
} finally {
|
|
105
|
+
_iterator2.f();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
valid: errors.length === 0,
|
|
110
|
+
errors: errors,
|
|
111
|
+
parsedEnv: parsedEnv
|
|
112
|
+
};
|
|
58
113
|
}
|
|
@@ -8,9 +8,9 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
|
|
|
8
8
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
9
9
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
10
10
|
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
11
|
-
import { useState } from
|
|
12
|
-
import { safeCall } from
|
|
13
|
-
import { startContainer as svcStartContainer, stopContainer as svcStopContainer, restartContainer as svcRestartContainer, removeContainer as svcRemoveContainer } from
|
|
11
|
+
import { useState, useRef, useEffect } from 'react';
|
|
12
|
+
import { safeCall } from '../../helpers/safeCall.js';
|
|
13
|
+
import { startContainer as svcStartContainer, stopContainer as svcStopContainer, restartContainer as svcRestartContainer, removeContainer as svcRemoveContainer } from '../../helpers/dockerService/serviceComponents/containerActions.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Custom hook to manage container actions (start, stop, restart, remove).
|
|
@@ -24,14 +24,32 @@ import { startContainer as svcStartContainer, stopContainer as svcStopContainer,
|
|
|
24
24
|
export function useContainerActions(_ref) {
|
|
25
25
|
var containers = _ref.containers,
|
|
26
26
|
onAction = _ref.onAction;
|
|
27
|
-
var _useState = useState(
|
|
27
|
+
var _useState = useState(''),
|
|
28
28
|
_useState2 = _slicedToArray(_useState, 2),
|
|
29
29
|
message = _useState2[0],
|
|
30
30
|
setMessage = _useState2[1];
|
|
31
|
-
var _useState3 = useState(
|
|
31
|
+
var _useState3 = useState('yellow'),
|
|
32
32
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
33
33
|
messageColor = _useState4[0],
|
|
34
34
|
setMessageColor = _useState4[1];
|
|
35
|
+
var messageTimerRef = useRef(null);
|
|
36
|
+
function setTimedMessage(msg) {
|
|
37
|
+
var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'yellow';
|
|
38
|
+
var ms = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 4000;
|
|
39
|
+
clearTimeout(messageTimerRef.current);
|
|
40
|
+
setMessage(msg);
|
|
41
|
+
if (color !== undefined) setMessageColor(color);
|
|
42
|
+
if (msg) {
|
|
43
|
+
messageTimerRef.current = setTimeout(function () {
|
|
44
|
+
return setMessage('');
|
|
45
|
+
}, ms);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
useEffect(function () {
|
|
49
|
+
return function () {
|
|
50
|
+
return clearTimeout(messageTimerRef.current);
|
|
51
|
+
};
|
|
52
|
+
}, []);
|
|
35
53
|
|
|
36
54
|
/**
|
|
37
55
|
* Handles a generic container action and sets feedback.
|
|
@@ -67,25 +85,23 @@ export function useContainerActions(_ref) {
|
|
|
67
85
|
break;
|
|
68
86
|
}
|
|
69
87
|
setMessage(checkMsg);
|
|
70
|
-
setMessageColor(
|
|
88
|
+
setMessageColor('yellow');
|
|
71
89
|
return _context5.a(2);
|
|
72
90
|
case 2:
|
|
73
91
|
setMessage("".concat(actionLabel, " container..."));
|
|
74
|
-
setMessageColor(
|
|
92
|
+
setMessageColor('yellow');
|
|
75
93
|
_context5.p = 3;
|
|
76
94
|
_context5.n = 4;
|
|
77
95
|
return actionFn(container.id);
|
|
78
96
|
case 4:
|
|
79
|
-
|
|
80
|
-
setMessageColor("green");
|
|
97
|
+
setTimedMessage("".concat(actionLabel, " container successful."), 'green');
|
|
81
98
|
safeCall(onAction);
|
|
82
99
|
_context5.n = 6;
|
|
83
100
|
break;
|
|
84
101
|
case 5:
|
|
85
102
|
_context5.p = 5;
|
|
86
103
|
_t = _context5.v;
|
|
87
|
-
|
|
88
|
-
setMessageColor("red");
|
|
104
|
+
setTimedMessage("Failed to ".concat(actionLabel.toLowerCase(), " container: ").concat(_t.message), 'red');
|
|
89
105
|
case 6:
|
|
90
106
|
return _context5.a(2);
|
|
91
107
|
}
|
|
@@ -96,6 +112,7 @@ export function useContainerActions(_ref) {
|
|
|
96
112
|
return {
|
|
97
113
|
message: message,
|
|
98
114
|
setMessage: setMessage,
|
|
115
|
+
setTimedMessage: setTimedMessage,
|
|
99
116
|
messageColor: messageColor,
|
|
100
117
|
setMessageColor: setMessageColor,
|
|
101
118
|
handleAction: handleAction,
|