cdd-cli 2.0.3 → 3.0.1
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/LICENSE +23 -0
- package/PLAN_KEYBINDINGS_Y_REALTIME.md +260 -0
- package/README.md +14 -3
- package/dist/App.js +26 -12
- package/dist/components/ContainerList.js +19 -0
- package/dist/components/ContainerRow.js +3 -3
- package/dist/components/LogViewer.js +22 -0
- package/dist/components/MessageFeedback.js +12 -0
- package/dist/components/StatsViewer.js +0 -0
- package/dist/helpers/actionHelpers.js +61 -0
- package/dist/helpers/dockerActions.js +51 -0
- package/dist/{dockerService.js → helpers/dockerService.js} +109 -21
- package/dist/helpers/exitWithMessage.js +26 -0
- package/dist/hooks/useContainers.js +1 -1
- package/dist/hooks/useControls.js +142 -0
- package/dist/hooks/useLogsStream.js +34 -0
- package/dist/hooks/useStatsPolling.js +54 -0
- package/docs/en/README.md +167 -0
- package/package.json +1 -1
- package/src/App.jsx +35 -7
- package/src/components/ContainerList.jsx +31 -0
- package/src/components/ContainerRow.jsx +10 -7
- package/src/components/LogViewer.jsx +23 -0
- package/src/components/MessageFeedback.jsx +11 -0
- package/src/components/StatsViewer.jsx +0 -0
- package/src/helpers/actionHelpers.js +31 -0
- package/src/helpers/dockerActions.js +52 -0
- package/src/helpers/dockerService.js +100 -0
- package/src/helpers/exitWithMessage.js +15 -0
- package/src/hooks/useContainers.js +11 -1
- package/src/hooks/useControls.js +98 -0
- package/src/hooks/useLogsStream.js +25 -0
- package/src/index.js +13 -0
- package/src/dockerService.js +0 -49
|
@@ -1,59 +1,147 @@
|
|
|
1
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
2
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
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; } }
|
|
4
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
5
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
6
|
+
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; }
|
|
1
7
|
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
2
8
|
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
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); }
|
|
4
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); }); }; }
|
|
5
|
-
import Docker from
|
|
11
|
+
import Docker from "dockerode";
|
|
6
12
|
var docker = new Docker({
|
|
7
|
-
socketPath:
|
|
13
|
+
socketPath: "/var/run/docker.sock"
|
|
8
14
|
});
|
|
15
|
+
export function getLogsStream(containerId, onData, onEnd, onError) {
|
|
16
|
+
var container = docker.getContainer(containerId);
|
|
17
|
+
container.logs({
|
|
18
|
+
follow: true,
|
|
19
|
+
stdout: true,
|
|
20
|
+
stderr: true,
|
|
21
|
+
tail: 100
|
|
22
|
+
}, function (err, stream) {
|
|
23
|
+
if (err) {
|
|
24
|
+
onError === null || onError === void 0 || onError(err);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
stream.on('data', function (chunk) {
|
|
28
|
+
return onData === null || onData === void 0 ? void 0 : onData(chunk.toString());
|
|
29
|
+
});
|
|
30
|
+
stream.on('end', function () {
|
|
31
|
+
return onEnd === null || onEnd === void 0 ? void 0 : onEnd();
|
|
32
|
+
});
|
|
33
|
+
stream.on('error', function (err) {
|
|
34
|
+
return onError === null || onError === void 0 ? void 0 : onError(err);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export function startContainer(_x) {
|
|
39
|
+
return _startContainer.apply(this, arguments);
|
|
40
|
+
}
|
|
41
|
+
function _startContainer() {
|
|
42
|
+
_startContainer = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(containerId) {
|
|
43
|
+
var container;
|
|
44
|
+
return _regenerator().w(function (_context) {
|
|
45
|
+
while (1) switch (_context.n) {
|
|
46
|
+
case 0:
|
|
47
|
+
container = docker.getContainer(containerId);
|
|
48
|
+
_context.n = 1;
|
|
49
|
+
return container.start();
|
|
50
|
+
case 1:
|
|
51
|
+
return _context.a(2);
|
|
52
|
+
}
|
|
53
|
+
}, _callee);
|
|
54
|
+
}));
|
|
55
|
+
return _startContainer.apply(this, arguments);
|
|
56
|
+
}
|
|
57
|
+
export function stopContainer(_x2) {
|
|
58
|
+
return _stopContainer.apply(this, arguments);
|
|
59
|
+
}
|
|
60
|
+
function _stopContainer() {
|
|
61
|
+
_stopContainer = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(containerId) {
|
|
62
|
+
var container;
|
|
63
|
+
return _regenerator().w(function (_context2) {
|
|
64
|
+
while (1) switch (_context2.n) {
|
|
65
|
+
case 0:
|
|
66
|
+
container = docker.getContainer(containerId);
|
|
67
|
+
_context2.n = 1;
|
|
68
|
+
return container.stop();
|
|
69
|
+
case 1:
|
|
70
|
+
return _context2.a(2);
|
|
71
|
+
}
|
|
72
|
+
}, _callee2);
|
|
73
|
+
}));
|
|
74
|
+
return _stopContainer.apply(this, arguments);
|
|
75
|
+
}
|
|
76
|
+
export function restartContainer(_x3) {
|
|
77
|
+
return _restartContainer.apply(this, arguments);
|
|
78
|
+
}
|
|
79
|
+
function _restartContainer() {
|
|
80
|
+
_restartContainer = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(containerId) {
|
|
81
|
+
var container;
|
|
82
|
+
return _regenerator().w(function (_context3) {
|
|
83
|
+
while (1) switch (_context3.n) {
|
|
84
|
+
case 0:
|
|
85
|
+
container = docker.getContainer(containerId);
|
|
86
|
+
_context3.n = 1;
|
|
87
|
+
return container.restart();
|
|
88
|
+
case 1:
|
|
89
|
+
return _context3.a(2);
|
|
90
|
+
}
|
|
91
|
+
}, _callee3);
|
|
92
|
+
}));
|
|
93
|
+
return _restartContainer.apply(this, arguments);
|
|
94
|
+
}
|
|
9
95
|
export function getContainers() {
|
|
10
96
|
return _getContainers.apply(this, arguments);
|
|
11
97
|
}
|
|
12
98
|
function _getContainers() {
|
|
13
|
-
_getContainers = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
99
|
+
_getContainers = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
|
|
14
100
|
var containers;
|
|
15
|
-
return _regenerator().w(function (
|
|
16
|
-
while (1) switch (
|
|
101
|
+
return _regenerator().w(function (_context4) {
|
|
102
|
+
while (1) switch (_context4.n) {
|
|
17
103
|
case 0:
|
|
18
|
-
|
|
104
|
+
_context4.n = 1;
|
|
19
105
|
return docker.listContainers({
|
|
20
106
|
all: true
|
|
21
107
|
});
|
|
22
108
|
case 1:
|
|
23
|
-
containers =
|
|
24
|
-
return
|
|
109
|
+
containers = _context4.v;
|
|
110
|
+
return _context4.a(2, containers.map(function (container) {
|
|
25
111
|
return {
|
|
26
112
|
id: container.Id,
|
|
27
|
-
name: container.Names[0].replace(
|
|
113
|
+
name: container.Names[0].replace("/", ""),
|
|
28
114
|
image: container.Image,
|
|
29
115
|
state: container.State,
|
|
30
116
|
status: container.Status,
|
|
31
|
-
ports: container.Ports.
|
|
32
|
-
return
|
|
33
|
-
}).
|
|
117
|
+
ports: _toConsumableArray(new Set(container.Ports.filter(function (port) {
|
|
118
|
+
return port.PublicPort;
|
|
119
|
+
}).map(function (port) {
|
|
120
|
+
return "".concat(port.PublicPort, ":").concat(port.PrivatePort);
|
|
121
|
+
})))
|
|
34
122
|
};
|
|
35
123
|
}));
|
|
36
124
|
}
|
|
37
|
-
},
|
|
125
|
+
}, _callee4);
|
|
38
126
|
}));
|
|
39
127
|
return _getContainers.apply(this, arguments);
|
|
40
128
|
}
|
|
41
|
-
export function getStats(
|
|
129
|
+
export function getStats(_x4) {
|
|
42
130
|
return _getStats.apply(this, arguments);
|
|
43
131
|
}
|
|
44
132
|
function _getStats() {
|
|
45
|
-
_getStats = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
133
|
+
_getStats = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(containerId) {
|
|
46
134
|
var container, stream, cpuDelta, systemDelta, cpuPercent, memUsage, memLimit, memPercent, rx, tx;
|
|
47
|
-
return _regenerator().w(function (
|
|
48
|
-
while (1) switch (
|
|
135
|
+
return _regenerator().w(function (_context5) {
|
|
136
|
+
while (1) switch (_context5.n) {
|
|
49
137
|
case 0:
|
|
50
138
|
container = docker.getContainer(containerId);
|
|
51
|
-
|
|
139
|
+
_context5.n = 1;
|
|
52
140
|
return container.stats({
|
|
53
141
|
stream: false
|
|
54
142
|
});
|
|
55
143
|
case 1:
|
|
56
|
-
stream =
|
|
144
|
+
stream = _context5.v;
|
|
57
145
|
cpuDelta = stream.cpu_stats.cpu_usage.total_usage - stream.precpu_stats.cpu_usage.total_usage;
|
|
58
146
|
systemDelta = stream.cpu_stats.system_cpu_usage - stream.precpu_stats.system_cpu_usage;
|
|
59
147
|
cpuPercent = systemDelta > 0 ? cpuDelta / systemDelta * 100 : 0;
|
|
@@ -70,7 +158,7 @@ function _getStats() {
|
|
|
70
158
|
}).reduce(function (a, b) {
|
|
71
159
|
return a + b;
|
|
72
160
|
}, 0) : 0;
|
|
73
|
-
return
|
|
161
|
+
return _context5.a(2, {
|
|
74
162
|
cpuPercent: cpuPercent.toFixed(1),
|
|
75
163
|
memPercent: memPercent.toFixed(1),
|
|
76
164
|
netIO: {
|
|
@@ -79,7 +167,7 @@ function _getStats() {
|
|
|
79
167
|
}
|
|
80
168
|
});
|
|
81
169
|
}
|
|
82
|
-
},
|
|
170
|
+
}, _callee5);
|
|
83
171
|
}));
|
|
84
172
|
return _getStats.apply(this, arguments);
|
|
85
173
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
export function exitWithMessage(_ref) {
|
|
3
|
+
var setMessage = _ref.setMessage,
|
|
4
|
+
setMessageColor = _ref.setMessageColor,
|
|
5
|
+
_ref$message = _ref.message,
|
|
6
|
+
message = _ref$message === void 0 ? "Exiting..." : _ref$message,
|
|
7
|
+
_ref$color = _ref.color,
|
|
8
|
+
color = _ref$color === void 0 ? "yellow" : _ref$color,
|
|
9
|
+
_ref$delay = _ref.delay,
|
|
10
|
+
delay = _ref$delay === void 0 ? 1500 : _ref$delay;
|
|
11
|
+
setMessage(message);
|
|
12
|
+
setMessageColor(color);
|
|
13
|
+
setTimeout(function () {
|
|
14
|
+
setMessage("");
|
|
15
|
+
if (process.platform === "win32") {
|
|
16
|
+
spawn("cmd", ["/c", "cls"], {
|
|
17
|
+
stdio: "inherit"
|
|
18
|
+
});
|
|
19
|
+
} else {
|
|
20
|
+
spawn("clear", [], {
|
|
21
|
+
stdio: "inherit"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
process.exit();
|
|
25
|
+
}, delay);
|
|
26
|
+
}
|
|
@@ -9,7 +9,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
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
11
|
import React, { useState, useEffect } from "react";
|
|
12
|
-
import { getContainers } from "../dockerService.js";
|
|
12
|
+
import { getContainers } from "../helpers/dockerService.js";
|
|
13
13
|
export function useContainers() {
|
|
14
14
|
var _useState = useState([]),
|
|
15
15
|
_useState2 = _slicedToArray(_useState, 2),
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
2
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
4
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
5
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
6
|
+
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."); }
|
|
7
|
+
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; } }
|
|
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
|
+
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
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
11
|
+
import React, { useState, useRef } from "react";
|
|
12
|
+
import { useInput } from "ink";
|
|
13
|
+
import { startContainer, stopContainer, restartContainer, getLogsStream } from "../helpers/dockerService.js";
|
|
14
|
+
import { handleAction } from "../helpers/actionHelpers.js";
|
|
15
|
+
import { exitWithMessage } from "../helpers/exitWithMessage.js";
|
|
16
|
+
export function useControls() {
|
|
17
|
+
var containers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
18
|
+
var _useState = useState(0),
|
|
19
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
20
|
+
selected = _useState2[0],
|
|
21
|
+
setSelected = _useState2[1];
|
|
22
|
+
var _useState3 = useState(""),
|
|
23
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
24
|
+
message = _useState4[0],
|
|
25
|
+
setMessage = _useState4[1];
|
|
26
|
+
var _useState5 = useState("yellow"),
|
|
27
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
28
|
+
messageColor = _useState6[0],
|
|
29
|
+
setMessageColor = _useState6[1];
|
|
30
|
+
var _useState7 = useState(false),
|
|
31
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
32
|
+
showLogs = _useState8[0],
|
|
33
|
+
setShowLogs = _useState8[1];
|
|
34
|
+
var _useState9 = useState([]),
|
|
35
|
+
_useState0 = _slicedToArray(_useState9, 2),
|
|
36
|
+
logs = _useState0[0],
|
|
37
|
+
setLogs = _useState0[1];
|
|
38
|
+
var logsStreamRef = useRef(null);
|
|
39
|
+
var total = containers.length;
|
|
40
|
+
|
|
41
|
+
// Handler para salir de la vista de logs
|
|
42
|
+
var exitLogs = function exitLogs() {
|
|
43
|
+
setShowLogs(false);
|
|
44
|
+
setLogs([]);
|
|
45
|
+
if (logsStreamRef.current) {
|
|
46
|
+
var _logsStreamRef$curren, _logsStreamRef$curren2;
|
|
47
|
+
(_logsStreamRef$curren = (_logsStreamRef$curren2 = logsStreamRef.current).destroy) === null || _logsStreamRef$curren === void 0 || _logsStreamRef$curren.call(_logsStreamRef$curren2);
|
|
48
|
+
logsStreamRef.current = null;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
useInput(function (input, key) {
|
|
52
|
+
if (showLogs) {
|
|
53
|
+
if (input === "q" || key.escape) {
|
|
54
|
+
exitLogs();
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//==========================================================
|
|
60
|
+
// Menu Navigation
|
|
61
|
+
//==========================================================
|
|
62
|
+
if (key.upArrow && total > 0) {
|
|
63
|
+
setSelected(function (i) {
|
|
64
|
+
return i === 0 ? total - 1 : i - 1;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (key.downArrow && total > 0) {
|
|
68
|
+
setSelected(function (i) {
|
|
69
|
+
return i === total - 1 ? 0 : i + 1;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (input === "q") {
|
|
73
|
+
exitWithMessage({
|
|
74
|
+
setMessage: setMessage,
|
|
75
|
+
setMessageColor: setMessageColor
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//==========================================================
|
|
81
|
+
// Docker commands
|
|
82
|
+
//==========================================================
|
|
83
|
+
if (input === "i") {
|
|
84
|
+
handleAction({
|
|
85
|
+
containers: containers,
|
|
86
|
+
selected: selected,
|
|
87
|
+
actionFn: startContainer,
|
|
88
|
+
actionLabel: "Starting",
|
|
89
|
+
setMessage: setMessage,
|
|
90
|
+
setMessageColor: setMessageColor,
|
|
91
|
+
stateCheck: function stateCheck(c) {
|
|
92
|
+
return (c.state === "running" || c.status === "running") && "Container is already running.";
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (input === "p") {
|
|
97
|
+
handleAction({
|
|
98
|
+
containers: containers,
|
|
99
|
+
selected: selected,
|
|
100
|
+
actionFn: stopContainer,
|
|
101
|
+
actionLabel: "Stopping",
|
|
102
|
+
setMessage: setMessage,
|
|
103
|
+
setMessageColor: setMessageColor,
|
|
104
|
+
stateCheck: function stateCheck(c) {
|
|
105
|
+
return (c.state === "exited" || c.status === "exited" || c.state === "stopped" || c.status === "stopped") && "Container is already stopped.";
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (input === "r") {
|
|
110
|
+
handleAction({
|
|
111
|
+
containers: containers,
|
|
112
|
+
selected: selected,
|
|
113
|
+
actionFn: restartContainer,
|
|
114
|
+
actionLabel: "Restarting",
|
|
115
|
+
setMessage: setMessage,
|
|
116
|
+
setMessageColor: setMessageColor
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (input === "l" && containers[selected]) {
|
|
120
|
+
setShowLogs(true);
|
|
121
|
+
setLogs([]);
|
|
122
|
+
getLogsStream(containers[selected].id, function (data) {
|
|
123
|
+
return setLogs(function (prev) {
|
|
124
|
+
return [].concat(_toConsumableArray(prev), _toConsumableArray(data.split("\n").filter(Boolean)));
|
|
125
|
+
});
|
|
126
|
+
}, function () {}, function (err) {
|
|
127
|
+
return setLogs(function (prev) {
|
|
128
|
+
return [].concat(_toConsumableArray(prev), ["Error: ".concat(err.message)]);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
selected: selected,
|
|
135
|
+
setSelected: setSelected,
|
|
136
|
+
message: message,
|
|
137
|
+
messageColor: messageColor,
|
|
138
|
+
showLogs: showLogs,
|
|
139
|
+
logs: logs,
|
|
140
|
+
exitLogs: exitLogs
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
2
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
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; } }
|
|
4
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
5
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
6
|
+
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; }
|
|
7
|
+
import React, { useRef, useCallback } from "react";
|
|
8
|
+
import { getLogsStream } from "../helpers/dockerService.js";
|
|
9
|
+
export function useLogsStream() {
|
|
10
|
+
var logsStreamRef = useRef(null);
|
|
11
|
+
var openLogs = useCallback(function (containerId, setLogs) {
|
|
12
|
+
setLogs([]);
|
|
13
|
+
logsStreamRef.current = getLogsStream(containerId, function (data) {
|
|
14
|
+
return setLogs(function (prev) {
|
|
15
|
+
return [].concat(_toConsumableArray(prev), _toConsumableArray(data.split("\n").filter(Boolean)));
|
|
16
|
+
});
|
|
17
|
+
}, function () {}, function (err) {
|
|
18
|
+
return setLogs(function (prev) {
|
|
19
|
+
return [].concat(_toConsumableArray(prev), ["Error: ".concat(err.message)]);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}, []);
|
|
23
|
+
var closeLogs = useCallback(function () {
|
|
24
|
+
if (logsStreamRef.current) {
|
|
25
|
+
var _logsStreamRef$curren, _logsStreamRef$curren2;
|
|
26
|
+
(_logsStreamRef$curren = (_logsStreamRef$curren2 = logsStreamRef.current).destroy) === null || _logsStreamRef$curren === void 0 || _logsStreamRef$curren.call(_logsStreamRef$curren2);
|
|
27
|
+
logsStreamRef.current = null;
|
|
28
|
+
}
|
|
29
|
+
}, []);
|
|
30
|
+
return {
|
|
31
|
+
openLogs: openLogs,
|
|
32
|
+
closeLogs: closeLogs
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
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
|
+
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
|
+
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 React, { useEffect } from "react";
|
|
6
|
+
export function useStatsPolling(_ref) {
|
|
7
|
+
var showStats = _ref.showStats,
|
|
8
|
+
selected = _ref.selected,
|
|
9
|
+
containers = _ref.containers,
|
|
10
|
+
setStats = _ref.setStats;
|
|
11
|
+
useEffect(function () {
|
|
12
|
+
var intervalId;
|
|
13
|
+
var mounted = true;
|
|
14
|
+
function fetchStats() {
|
|
15
|
+
return _fetchStats.apply(this, arguments);
|
|
16
|
+
}
|
|
17
|
+
function _fetchStats() {
|
|
18
|
+
_fetchStats = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
19
|
+
var _yield$import, getStats, statsData;
|
|
20
|
+
return _regenerator().w(function (_context) {
|
|
21
|
+
while (1) switch (_context.n) {
|
|
22
|
+
case 0:
|
|
23
|
+
if (!(showStats && containers[selected])) {
|
|
24
|
+
_context.n = 3;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
_context.n = 1;
|
|
28
|
+
return import("../helpers/dockerService.js");
|
|
29
|
+
case 1:
|
|
30
|
+
_yield$import = _context.v;
|
|
31
|
+
getStats = _yield$import.getStats;
|
|
32
|
+
_context.n = 2;
|
|
33
|
+
return getStats(containers[selected].id);
|
|
34
|
+
case 2:
|
|
35
|
+
statsData = _context.v;
|
|
36
|
+
if (mounted) setStats(statsData);
|
|
37
|
+
case 3:
|
|
38
|
+
return _context.a(2);
|
|
39
|
+
}
|
|
40
|
+
}, _callee);
|
|
41
|
+
}));
|
|
42
|
+
return _fetchStats.apply(this, arguments);
|
|
43
|
+
}
|
|
44
|
+
if (showStats && containers[selected]) {
|
|
45
|
+
setStats(null);
|
|
46
|
+
fetchStats();
|
|
47
|
+
intervalId = setInterval(fetchStats, 2000);
|
|
48
|
+
}
|
|
49
|
+
return function () {
|
|
50
|
+
mounted = false;
|
|
51
|
+
if (intervalId) clearInterval(intervalId);
|
|
52
|
+
};
|
|
53
|
+
}, [showStats, selected, containers, setStats]);
|
|
54
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# README (ENGLISH)
|
|
2
|
+
*Generated: 2025-10-13*
|
|
3
|
+
|
|
4
|
+
## Table of Contents
|
|
5
|
+
- [Project Scope](#project-scope)
|
|
6
|
+
- [Objectives & Roadmap](#objectives--roadmap)
|
|
7
|
+
- [Requirements](#requirements)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Quick Start](#quick-start)
|
|
10
|
+
- [Use Cases](#use-cases)
|
|
11
|
+
- [Technical Documentation](#technical-documentation)
|
|
12
|
+
- [API Reference](#api-reference)
|
|
13
|
+
- [License](#license)
|
|
14
|
+
- [Contributing](#contributing)
|
|
15
|
+
- [Code of Conduct](#code-of-conduct)
|
|
16
|
+
- [Changelog](#changelog)
|
|
17
|
+
- [FAQ](#faq)
|
|
18
|
+
- [Publishing & Maintenance](#publishing--maintenance)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Project Scope
|
|
23
|
+
This project is a cross-platform CLI tool for managing Docker containers with real-time log streaming and keyboard shortcuts. It is designed for developers and DevOps engineers who need fast, scriptable, and interactive container management from the terminal.
|
|
24
|
+
|
|
25
|
+
**What it does:**
|
|
26
|
+
- Lists, starts, stops, and removes Docker containers.
|
|
27
|
+
- Streams logs in real time.
|
|
28
|
+
- Provides keyboard shortcuts for common actions.
|
|
29
|
+
- Offers feedback and stats in the terminal.
|
|
30
|
+
|
|
31
|
+
**What it does NOT do:**
|
|
32
|
+
- Does not replace Docker Compose or advanced orchestration tools.
|
|
33
|
+
- Does not manage images or networks directly.
|
|
34
|
+
- No GUI; terminal only.
|
|
35
|
+
|
|
36
|
+
## Objectives & Roadmap
|
|
37
|
+
**Short-term (3 months):**
|
|
38
|
+
- Polish CLI UX and error handling.
|
|
39
|
+
- Add more keyboard shortcuts.
|
|
40
|
+
- Improve documentation and add more use cases.
|
|
41
|
+
|
|
42
|
+
**Medium-term (6 months):**
|
|
43
|
+
- Add plugin system for custom actions.
|
|
44
|
+
- Support for container stats export (JSON/CSV).
|
|
45
|
+
- Integration with CI/CD pipelines.
|
|
46
|
+
|
|
47
|
+
**Known limitations:**
|
|
48
|
+
- Requires Docker daemon running locally.
|
|
49
|
+
- Only supports local containers (no remote).
|
|
50
|
+
- Limited to Node.js LTS versions.
|
|
51
|
+
|
|
52
|
+
## Requirements
|
|
53
|
+
| Requirement | Minimum | Recommended |
|
|
54
|
+
|--------------------|----------------|-----------------|
|
|
55
|
+
| Node.js | 16.x | 18.x+ |
|
|
56
|
+
| npm | 7.x | 8.x+ |
|
|
57
|
+
| OS | Linux, macOS, Windows | Linux, macOS |
|
|
58
|
+
| Docker | 20.x | Latest stable |
|
|
59
|
+
| Permissions | Docker group or sudo | Docker group |
|
|
60
|
+
|
|
61
|
+
**Development:**
|
|
62
|
+
- ESLint, Prettier
|
|
63
|
+
- Jest or Mocha for tests
|
|
64
|
+
- GitHub Actions for CI
|
|
65
|
+
|
|
66
|
+
**Production:**
|
|
67
|
+
- Only Node.js and Docker required
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
### Global install
|
|
71
|
+
```bash
|
|
72
|
+
npm install -g cdd-cli
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Update
|
|
76
|
+
```bash
|
|
77
|
+
npm update -g cdd-cli
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Uninstall
|
|
81
|
+
```bash
|
|
82
|
+
npm uninstall -g cdd-cli
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Check version
|
|
86
|
+
```bash
|
|
87
|
+
cdd -v
|
|
88
|
+
cdd --version
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Notes
|
|
92
|
+
- On Linux/macOS, you may need `sudo` for global install.
|
|
93
|
+
- Ensure your global npm bin is in your PATH.
|
|
94
|
+
- On Windows, use an Administrator terminal if needed.
|
|
95
|
+
|
|
96
|
+
## Quick Start
|
|
97
|
+
```bash
|
|
98
|
+
cdd list
|
|
99
|
+
cdd logs <container>
|
|
100
|
+
cdd start <container>
|
|
101
|
+
cdd stop <container>
|
|
102
|
+
cdd remove <container>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Use Cases
|
|
106
|
+
1. **List all containers**
|
|
107
|
+
- `cdd list`
|
|
108
|
+
- *Shows all containers with status.*
|
|
109
|
+
2. **Start a container**
|
|
110
|
+
- `cdd start my_container`
|
|
111
|
+
- *Starts the specified container.*
|
|
112
|
+
3. **Stop a container**
|
|
113
|
+
- `cdd stop my_container`
|
|
114
|
+
- *Stops the specified container.*
|
|
115
|
+
4. **Stream logs in real time**
|
|
116
|
+
- `cdd logs my_container`
|
|
117
|
+
- *Shows live logs with color highlighting.*
|
|
118
|
+
5. **Remove a container**
|
|
119
|
+
- `cdd remove my_container`
|
|
120
|
+
- *Deletes the container after confirmation.*
|
|
121
|
+
6. **Use keyboard shortcuts**
|
|
122
|
+
- While viewing logs, press `q` to quit, `r` to restart, etc.
|
|
123
|
+
|
|
124
|
+
## Technical Documentation
|
|
125
|
+
See inline JSDoc comments in source files. Example:
|
|
126
|
+
```js
|
|
127
|
+
/**
|
|
128
|
+
* Start a Docker container by name.
|
|
129
|
+
* @param {string} name - Container name
|
|
130
|
+
* @returns {Promise<boolean>} True if started
|
|
131
|
+
* @throws {Error} If Docker is not running
|
|
132
|
+
* @example
|
|
133
|
+
* await startContainer('my_container');
|
|
134
|
+
*/
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## API Reference
|
|
138
|
+
See [API Reference](./api.md) for all exported functions and CLI commands.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
MIT License. See [LICENSE](../../LICENSE).
|
|
142
|
+
|
|
143
|
+
## Contributing
|
|
144
|
+
See [CONTRIBUTING.md](../../CONTRIBUTING.md).
|
|
145
|
+
|
|
146
|
+
## Code of Conduct
|
|
147
|
+
See [CODE_OF_CONDUCT.md](../../CODE_OF_CONDUCT.md).
|
|
148
|
+
|
|
149
|
+
## Changelog
|
|
150
|
+
See [CHANGELOG.md](../../CHANGELOG.md).
|
|
151
|
+
|
|
152
|
+
## FAQ
|
|
153
|
+
- **Does it work with Docker Desktop?**
|
|
154
|
+
- Yes, as long as Docker CLI is available.
|
|
155
|
+
- **Can I use it in CI?**
|
|
156
|
+
- Yes, see examples below.
|
|
157
|
+
- **How do I add my own commands?**
|
|
158
|
+
- Plugin system coming soon.
|
|
159
|
+
|
|
160
|
+
## Publishing & Maintenance
|
|
161
|
+
To publish to npm:
|
|
162
|
+
```bash
|
|
163
|
+
npm login
|
|
164
|
+
npm publish --access public
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Keep documentation updated with every release. See CONTRIBUTING.md for details.
|