cdd-cli 3.2.2 → 4.1.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/README.es.md +222 -0
- package/README.md +108 -26
- package/dist/App.js +7 -1
- package/dist/components/ContainerCreationPrompt.js +26 -10
- package/dist/components/ControlsHUD.js +106 -0
- package/dist/components/SuggestionPanel.js +16 -7
- package/dist/components/UsageMenu.js +1 -1
- package/dist/helpers/appState.js +26 -0
- package/dist/helpers/constants.js +60 -21
- package/dist/helpers/dockerHubService.js +111 -0
- package/dist/helpers/dockerService/serviceComponents/containerExec.js +211 -0
- package/dist/helpers/logger.js +1 -1
- package/dist/hooks/creation/useContainerActions.js +22 -5
- package/dist/hooks/creation/useContainerCreation.js +414 -107
- package/dist/hooks/useContainerCommandRouter.js +13 -3
- package/dist/hooks/useControls.js +28 -7
- package/dist/hooks/useShellMode.js +101 -0
- package/dist/index.js +10 -1
- package/package.json +4 -1
- package/.atl/skill-registry.md +0 -30
- package/.editorconfig +0 -12
- package/.eslintrc.json +0 -30
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -30
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/.github/PULL_REQUEST_TEMPLATE/pull_request.md +0 -14
- package/.github/workflows/ci.yml +0 -32
- package/.github/workflows/docs.yml +0 -42
- package/.prettierignore +0 -4
- package/.prettierrc +0 -8
- package/CHANGELOG.md +0 -165
- package/CODE_OF_CONDUCT.md +0 -12
- package/CONTRIBUTING.md +0 -35
- package/SECURITY.md +0 -5
- package/__mocks__/ink.cjs +0 -17
- package/_config.yml +0 -13
- package/babel.config.cjs +0 -23
- package/coverage/clover.xml +0 -694
- package/coverage/coverage-final.json +0 -21
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +0 -376
- package/coverage/lcov-report/components/PromptField.jsx.html +0 -229
- package/coverage/lcov-report/components/SuggestionPanel.jsx.html +0 -244
- package/coverage/lcov-report/components/index.html +0 -146
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/helpers/constants.js.html +0 -298
- package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +0 -244
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +0 -931
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +0 -307
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +0 -131
- package/coverage/lcov-report/helpers/imageNameUtils.js.html +0 -181
- package/coverage/lcov-report/helpers/index.html +0 -191
- package/coverage/lcov-report/helpers/logger.js.html +0 -424
- package/coverage/lcov-report/helpers/safeCall.js.html +0 -139
- package/coverage/lcov-report/helpers/validationHelpers.js.html +0 -346
- package/coverage/lcov-report/hooks/creation/index.html +0 -146
- package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +0 -313
- package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +0 -805
- package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +0 -238
- package/coverage/lcov-report/hooks/debug/index.html +0 -116
- package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +0 -187
- package/coverage/lcov-report/hooks/index.html +0 -161
- package/coverage/lcov-report/hooks/navigation/index.html +0 -116
- package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +0 -169
- package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +0 -454
- package/coverage/lcov-report/hooks/useControls.js.html +0 -826
- package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +0 -202
- package/coverage/lcov-report/hooks/useExitHandler.js.html +0 -292
- package/coverage/lcov-report/index.html +0 -206
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -1402
- package/fix-imports.cjs +0 -54
- package/jest.config.cjs +0 -14
- package/src/App.jsx +0 -96
- package/src/components/ContainerCreationPrompt.jsx +0 -97
- package/src/components/ContainerList.jsx +0 -32
- package/src/components/ContainerRow.jsx +0 -84
- package/src/components/ContainerSection.jsx +0 -24
- package/src/components/Footer.jsx +0 -15
- package/src/components/Header.jsx +0 -41
- package/src/components/LogViewer.jsx +0 -36
- package/src/components/MessageFeedback.jsx +0 -25
- package/src/components/PromptField.jsx +0 -48
- package/src/components/StatsBar.jsx +0 -70
- package/src/components/SuggestionPanel.jsx +0 -53
- package/src/components/UsageMenu.jsx +0 -52
- package/src/helpers/appInfo.js +0 -23
- package/src/helpers/constants.js +0 -71
- package/src/helpers/containerOptionsBuilder.js +0 -53
- package/src/helpers/dockerService/dockerService.js +0 -28
- package/src/helpers/dockerService/serviceComponents/containerActions.js +0 -282
- package/src/helpers/dockerService/serviceComponents/containerList.js +0 -74
- package/src/helpers/dockerService/serviceComponents/containerLogs.js +0 -60
- package/src/helpers/dockerService/serviceComponents/containerStats.js +0 -69
- package/src/helpers/dockerService/serviceComponents/imageUtils.js +0 -32
- package/src/helpers/exitWithMessage.js +0 -32
- package/src/helpers/imageNameUtils.js +0 -32
- package/src/helpers/logger.js +0 -113
- package/src/helpers/safeCall.js +0 -18
- package/src/helpers/validationHelpers.js +0 -87
- package/src/hooks/creation/useContainerActions.js +0 -76
- package/src/hooks/creation/useContainerCreation.js +0 -240
- package/src/hooks/creation/useLogsViewer.js +0 -51
- package/src/hooks/debug/useDebugLogs.js +0 -34
- package/src/hooks/navigation/useContainerSelection.js +0 -28
- package/src/hooks/useContainerCommandRouter.js +0 -123
- package/src/hooks/useContainerStats.js +0 -44
- package/src/hooks/useContainers.js +0 -26
- package/src/hooks/useControls.js +0 -247
- package/src/hooks/useEraseConfirmation.js +0 -39
- package/src/hooks/useExitHandler.js +0 -69
- package/src/index.js +0 -16
- package/test/ContainerCreationPrompt.dom.test.js +0 -68
- package/test/SuggestionPanel.dom.test.js +0 -53
- package/test/constants.test.js +0 -34
- package/test/containerActions.test.js +0 -229
- package/test/containerList.test.js +0 -79
- package/test/containerOptionsBuilder.test.js +0 -36
- package/test/jest.setup.js +0 -7
- package/test/safeCall.test.js +0 -25
- package/test/useContainerCreation.dom.test.js +0 -264
- package/test/useControls.dom.test.js +0 -313
- package/test/validationHelpers.test.js +0 -111
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared reference to the Ink render instance.
|
|
3
|
+
* Set once in index.js after render(<App />) and read by useShellMode
|
|
4
|
+
* to unmount/remount the UI around interactive shell sessions.
|
|
5
|
+
*
|
|
6
|
+
* @module appState
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** @type {import('ink').RenderReturnType | null} */
|
|
10
|
+
var inkApp = null;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Store the Ink render return value.
|
|
14
|
+
* @param {import('ink').RenderReturnType} app
|
|
15
|
+
*/
|
|
16
|
+
export function setInkApp(app) {
|
|
17
|
+
inkApp = app;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the Ink render return value.
|
|
22
|
+
* @returns {import('ink').RenderReturnType | null}
|
|
23
|
+
*/
|
|
24
|
+
export function getInkApp() {
|
|
25
|
+
return inkApp;
|
|
26
|
+
}
|
|
@@ -44,101 +44,140 @@ export var IMAGE_PROFILES = {
|
|
|
44
44
|
nginx: {
|
|
45
45
|
requiredEnv: [],
|
|
46
46
|
defaultPort: '80',
|
|
47
|
-
suggestedEnv: []
|
|
47
|
+
suggestedEnv: [],
|
|
48
|
+
defaultTag: '1.27-alpine'
|
|
48
49
|
},
|
|
49
50
|
httpd: {
|
|
50
51
|
requiredEnv: [],
|
|
51
52
|
defaultPort: '80',
|
|
52
|
-
suggestedEnv: []
|
|
53
|
+
suggestedEnv: [],
|
|
54
|
+
defaultTag: '2.4-alpine'
|
|
53
55
|
},
|
|
54
56
|
caddy: {
|
|
55
57
|
requiredEnv: [],
|
|
56
58
|
defaultPort: '80',
|
|
57
|
-
suggestedEnv: []
|
|
59
|
+
suggestedEnv: [],
|
|
60
|
+
defaultTag: '2-alpine'
|
|
58
61
|
},
|
|
59
62
|
node: {
|
|
60
63
|
requiredEnv: [],
|
|
61
64
|
defaultPort: '3000',
|
|
62
|
-
suggestedEnv: ['NODE_ENV=production']
|
|
65
|
+
suggestedEnv: ['NODE_ENV=production'],
|
|
66
|
+
defaultTag: '22-alpine'
|
|
63
67
|
},
|
|
64
68
|
python: {
|
|
65
69
|
requiredEnv: [],
|
|
66
70
|
defaultPort: '8000',
|
|
67
|
-
suggestedEnv: ['PYTHONUNBUFFERED=1']
|
|
71
|
+
suggestedEnv: ['PYTHONUNBUFFERED=1'],
|
|
72
|
+
defaultTag: '3.12-slim'
|
|
68
73
|
},
|
|
69
74
|
openjdk: {
|
|
70
75
|
requiredEnv: [],
|
|
71
76
|
defaultPort: '8080',
|
|
72
|
-
suggestedEnv: ['JAVA_OPTS=-Xms256m -Xmx512m']
|
|
77
|
+
suggestedEnv: ['JAVA_OPTS=-Xms256m -Xmx512m'],
|
|
78
|
+
defaultTag: '21-slim'
|
|
73
79
|
},
|
|
74
80
|
golang: {
|
|
75
81
|
requiredEnv: [],
|
|
76
82
|
defaultPort: '8080',
|
|
77
|
-
suggestedEnv: ['GOMAXPROCS=2']
|
|
83
|
+
suggestedEnv: ['GOMAXPROCS=2'],
|
|
84
|
+
defaultTag: '1.22-alpine'
|
|
78
85
|
},
|
|
79
86
|
redis: {
|
|
80
87
|
requiredEnv: [],
|
|
81
88
|
defaultPort: '6379',
|
|
82
|
-
suggestedEnv: ['REDIS_PASSWORD=change-me']
|
|
89
|
+
suggestedEnv: ['REDIS_PASSWORD=change-me'],
|
|
90
|
+
defaultTag: '7-alpine'
|
|
83
91
|
},
|
|
84
92
|
memcached: {
|
|
85
93
|
requiredEnv: [],
|
|
86
94
|
defaultPort: '11211',
|
|
87
|
-
suggestedEnv: []
|
|
95
|
+
suggestedEnv: [],
|
|
96
|
+
defaultTag: '1.6-alpine'
|
|
88
97
|
},
|
|
89
98
|
postgres: {
|
|
90
99
|
requiredEnv: ['POSTGRES_PASSWORD'],
|
|
91
100
|
defaultPort: '5432',
|
|
92
|
-
suggestedEnv: ['POSTGRES_USER=postgres', 'POSTGRES_DB=app']
|
|
101
|
+
suggestedEnv: ['POSTGRES_PASSWORD=secret', 'POSTGRES_USER=postgres', 'POSTGRES_DB=app'],
|
|
102
|
+
defaultTag: '17-alpine'
|
|
93
103
|
},
|
|
94
104
|
mysql: {
|
|
95
105
|
requiredEnv: ['MYSQL_ROOT_PASSWORD'],
|
|
96
106
|
defaultPort: '3306',
|
|
97
|
-
suggestedEnv: ['MYSQL_DATABASE=app', 'MYSQL_USER=app', 'MYSQL_PASSWORD=app123']
|
|
107
|
+
suggestedEnv: ['MYSQL_ROOT_PASSWORD=secret', 'MYSQL_DATABASE=app', 'MYSQL_USER=app', 'MYSQL_PASSWORD=app123'],
|
|
108
|
+
defaultTag: '8.0'
|
|
98
109
|
},
|
|
99
110
|
mariadb: {
|
|
100
111
|
requiredEnv: ['MARIADB_ROOT_PASSWORD'],
|
|
101
112
|
defaultPort: '3306',
|
|
102
|
-
suggestedEnv: ['MARIADB_DATABASE=app', 'MARIADB_USER=app', 'MARIADB_PASSWORD=app123']
|
|
113
|
+
suggestedEnv: ['MARIADB_ROOT_PASSWORD=secret', 'MARIADB_DATABASE=app', 'MARIADB_USER=app', 'MARIADB_PASSWORD=app123'],
|
|
114
|
+
defaultTag: '11-alpine'
|
|
103
115
|
},
|
|
104
116
|
mongo: {
|
|
105
117
|
requiredEnv: [],
|
|
106
118
|
defaultPort: '27017',
|
|
107
|
-
suggestedEnv: ['MONGO_INITDB_ROOT_USERNAME=admin', 'MONGO_INITDB_ROOT_PASSWORD=secret']
|
|
119
|
+
suggestedEnv: ['MONGO_INITDB_ROOT_USERNAME=admin', 'MONGO_INITDB_ROOT_PASSWORD=secret'],
|
|
120
|
+
defaultTag: '7.0'
|
|
108
121
|
},
|
|
109
122
|
mssql: {
|
|
110
123
|
requiredEnv: ['ACCEPT_EULA', 'SA_PASSWORD'],
|
|
111
124
|
defaultPort: '1433',
|
|
112
|
-
suggestedEnv: ['ACCEPT_EULA=Y', 'MSSQL_PID=Developer']
|
|
125
|
+
suggestedEnv: ['ACCEPT_EULA=Y', 'SA_PASSWORD=Strong!Passw0rd', 'MSSQL_PID=Developer'],
|
|
126
|
+
defaultTag: '2022-latest'
|
|
113
127
|
},
|
|
114
128
|
rabbitmq: {
|
|
115
129
|
requiredEnv: [],
|
|
116
130
|
defaultPort: '5672',
|
|
117
|
-
suggestedEnv: ['RABBITMQ_DEFAULT_USER=guest', 'RABBITMQ_DEFAULT_PASS=guest']
|
|
131
|
+
suggestedEnv: ['RABBITMQ_DEFAULT_USER=guest', 'RABBITMQ_DEFAULT_PASS=guest'],
|
|
132
|
+
defaultTag: '3-management-alpine'
|
|
118
133
|
},
|
|
119
134
|
kafka: {
|
|
120
135
|
requiredEnv: [],
|
|
121
136
|
defaultPort: '9092',
|
|
122
|
-
suggestedEnv: ['KAFKA_CFG_LISTENERS=PLAINTEXT://:9092']
|
|
137
|
+
suggestedEnv: ['KAFKA_CFG_LISTENERS=PLAINTEXT://:9092', 'KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092'],
|
|
138
|
+
defaultTag: '3.7'
|
|
123
139
|
},
|
|
124
140
|
zookeeper: {
|
|
125
141
|
requiredEnv: [],
|
|
126
142
|
defaultPort: '2181',
|
|
127
|
-
suggestedEnv: ['ALLOW_ANONYMOUS_LOGIN=yes']
|
|
143
|
+
suggestedEnv: ['ALLOW_ANONYMOUS_LOGIN=yes'],
|
|
144
|
+
defaultTag: '3.9'
|
|
128
145
|
},
|
|
129
146
|
elasticsearch: {
|
|
130
147
|
requiredEnv: [],
|
|
131
148
|
defaultPort: '9200',
|
|
132
|
-
suggestedEnv: ['discovery.type=single-node', 'xpack.security.enabled=false']
|
|
149
|
+
suggestedEnv: ['discovery.type=single-node', 'xpack.security.enabled=false'],
|
|
150
|
+
defaultTag: '8.13.0'
|
|
133
151
|
},
|
|
134
152
|
minio: {
|
|
135
153
|
requiredEnv: ['MINIO_ROOT_USER', 'MINIO_ROOT_PASSWORD'],
|
|
136
154
|
defaultPort: '9000',
|
|
137
|
-
suggestedEnv: ['MINIO_CONSOLE_ADDRESS=:9001']
|
|
155
|
+
suggestedEnv: ['MINIO_ROOT_USER=admin', 'MINIO_ROOT_PASSWORD=secret', 'MINIO_CONSOLE_ADDRESS=:9001'],
|
|
156
|
+
defaultTag: 'latest'
|
|
138
157
|
},
|
|
139
158
|
wordpress: {
|
|
140
159
|
requiredEnv: ['WORDPRESS_DB_HOST', 'WORDPRESS_DB_USER', 'WORDPRESS_DB_PASSWORD', 'WORDPRESS_DB_NAME'],
|
|
141
160
|
defaultPort: '8080',
|
|
142
|
-
suggestedEnv: ['WORDPRESS_TABLE_PREFIX=wp_']
|
|
161
|
+
suggestedEnv: ['WORDPRESS_DB_HOST=db', 'WORDPRESS_DB_USER=wp', 'WORDPRESS_DB_PASSWORD=secret', 'WORDPRESS_DB_NAME=wordpress', 'WORDPRESS_TABLE_PREFIX=wp_'],
|
|
162
|
+
defaultTag: '6.5-apache'
|
|
143
163
|
}
|
|
144
|
-
};
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Given an image name (with or without tag), returns the image name with a
|
|
168
|
+
* default tag appended when the image matches a known profile and has no
|
|
169
|
+
* explicit tag. Returns the input unchanged otherwise.
|
|
170
|
+
*
|
|
171
|
+
* @param {string} imageName - e.g. 'postgres', 'postgres:15', 'unknownimage'
|
|
172
|
+
* @param {Record<string, { defaultTag: string }>} profiles
|
|
173
|
+
* @returns {string}
|
|
174
|
+
*/
|
|
175
|
+
export function resolveImageTag(imageName) {
|
|
176
|
+
var profiles = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : IMAGE_PROFILES;
|
|
177
|
+
if (!imageName) return imageName;
|
|
178
|
+
if (imageName.includes(':')) return imageName;
|
|
179
|
+
var baseName = imageName.trim().toLowerCase().split('/').pop();
|
|
180
|
+
var profile = profiles[baseName];
|
|
181
|
+
if (!(profile !== null && profile !== void 0 && profile.defaultTag)) return imageName;
|
|
182
|
+
return "".concat(imageName, ":").concat(profile.defaultTag);
|
|
183
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
/**
|
|
6
|
+
* Docker Hub search helper.
|
|
7
|
+
* Pure function — no side effects beyond HTTP. All state management
|
|
8
|
+
* lives in the calling hook (useContainerCreation).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
var DOCKER_HUB_SEARCH_URL = 'https://hub.docker.com/v2/search/repositories/';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Format a Docker Hub search result object into a display string.
|
|
15
|
+
*
|
|
16
|
+
* Format rules:
|
|
17
|
+
* - Official: "name [★ official] [Npulls+]" (if pullCount > 0)
|
|
18
|
+
* - Non-official with pulls: "name [Npulls+]"
|
|
19
|
+
* - Otherwise: "name"
|
|
20
|
+
*
|
|
21
|
+
* Pull count suffixes: ≥1B → "1B+", ≥1M → "1M+", ≥1K → "1K+", else raw number
|
|
22
|
+
*
|
|
23
|
+
* @param {{ name: string, isOfficial: boolean, pullCount: number }} result
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
export function formatHubResult(result) {
|
|
27
|
+
var name = result.name,
|
|
28
|
+
isOfficial = result.isOfficial,
|
|
29
|
+
pullCount = result.pullCount;
|
|
30
|
+
var pullSuffix = '';
|
|
31
|
+
if (pullCount >= 1e9) {
|
|
32
|
+
pullSuffix = " [1B+ pulls]";
|
|
33
|
+
} else if (pullCount >= 1e6) {
|
|
34
|
+
pullSuffix = " [".concat(Math.floor(pullCount / 1e6), "M+ pulls]");
|
|
35
|
+
} else if (pullCount >= 1e3) {
|
|
36
|
+
pullSuffix = " [".concat(Math.floor(pullCount / 1e3), "K+ pulls]");
|
|
37
|
+
} else if (pullCount > 0) {
|
|
38
|
+
pullSuffix = " [".concat(pullCount, " pulls]");
|
|
39
|
+
}
|
|
40
|
+
if (isOfficial) {
|
|
41
|
+
return "".concat(name, " [\u2605 official]").concat(pullSuffix);
|
|
42
|
+
}
|
|
43
|
+
return "".concat(name).concat(pullSuffix);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Search Docker Hub for images matching the given query.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} query - Search term (will be trimmed and encoded)
|
|
50
|
+
* @param {Object} [options]
|
|
51
|
+
* @param {AbortSignal} [options.signal] - Abort signal; defaults to AbortSignal.timeout(5000)
|
|
52
|
+
* @returns {Promise<Array<{ name: string, isOfficial: boolean, pullCount: number, description: string }>>}
|
|
53
|
+
* @throws {Error} If response.ok is false or the network call rejects
|
|
54
|
+
*/
|
|
55
|
+
export function searchDockerHub(_x) {
|
|
56
|
+
return _searchDockerHub.apply(this, arguments);
|
|
57
|
+
}
|
|
58
|
+
function _searchDockerHub() {
|
|
59
|
+
_searchDockerHub = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(query) {
|
|
60
|
+
var _options$signal, _data$results;
|
|
61
|
+
var options,
|
|
62
|
+
q,
|
|
63
|
+
url,
|
|
64
|
+
signal,
|
|
65
|
+
response,
|
|
66
|
+
data,
|
|
67
|
+
results,
|
|
68
|
+
_args = arguments;
|
|
69
|
+
return _regenerator().w(function (_context) {
|
|
70
|
+
while (1) switch (_context.n) {
|
|
71
|
+
case 0:
|
|
72
|
+
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
|
|
73
|
+
q = query.trim();
|
|
74
|
+
if (q) {
|
|
75
|
+
_context.n = 1;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
return _context.a(2, []);
|
|
79
|
+
case 1:
|
|
80
|
+
url = "".concat(DOCKER_HUB_SEARCH_URL, "?query=").concat(encodeURIComponent(q), "&page_size=10");
|
|
81
|
+
signal = (_options$signal = options.signal) !== null && _options$signal !== void 0 ? _options$signal : AbortSignal.timeout(5000);
|
|
82
|
+
_context.n = 2;
|
|
83
|
+
return fetch(url, {
|
|
84
|
+
signal: signal
|
|
85
|
+
});
|
|
86
|
+
case 2:
|
|
87
|
+
response = _context.v;
|
|
88
|
+
if (response.ok) {
|
|
89
|
+
_context.n = 3;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
throw new Error("Docker Hub search failed: ".concat(response.status));
|
|
93
|
+
case 3:
|
|
94
|
+
_context.n = 4;
|
|
95
|
+
return response.json();
|
|
96
|
+
case 4:
|
|
97
|
+
data = _context.v;
|
|
98
|
+
results = (_data$results = data.results) !== null && _data$results !== void 0 ? _data$results : [];
|
|
99
|
+
return _context.a(2, results.map(function (item) {
|
|
100
|
+
return {
|
|
101
|
+
name: item.repo_name,
|
|
102
|
+
isOfficial: item.is_official,
|
|
103
|
+
pullCount: item.pull_count,
|
|
104
|
+
description: item.short_description
|
|
105
|
+
};
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
}, _callee);
|
|
109
|
+
}));
|
|
110
|
+
return _searchDockerHub.apply(this, arguments);
|
|
111
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
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 { spawn } from 'child_process';
|
|
6
|
+
import { docker } from '../dockerService.js';
|
|
7
|
+
import { logger } from '../../logger.js';
|
|
8
|
+
import { TIMEOUTS } from '../../constants.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detect the default shell available inside a running container.
|
|
12
|
+
* Tries `bash` first, falls back to `sh`.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} containerId - Docker container id
|
|
15
|
+
* @returns {Promise<string>} The shell command (e.g. 'bash' or 'sh')
|
|
16
|
+
*/
|
|
17
|
+
export function detectShell(_x) {
|
|
18
|
+
return _detectShell.apply(this, arguments);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Spawn an interactive shell inside a running container using `docker exec -it`.
|
|
23
|
+
* Returns a promise that resolves when the user exits the shell.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} containerId - Docker container id
|
|
26
|
+
* @param {Object} [options]
|
|
27
|
+
* @param {string} [options.shell] - Shell to use (auto-detected if omitted)
|
|
28
|
+
* @param {string} [options.workingDir] - Working directory inside the container
|
|
29
|
+
* @returns {Promise<{code: number|null, signal: string|null}>} Exit info
|
|
30
|
+
*/
|
|
31
|
+
function _detectShell() {
|
|
32
|
+
_detectShell = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(containerId) {
|
|
33
|
+
var container, tryShell, hasBash, _t;
|
|
34
|
+
return _regenerator().w(function (_context) {
|
|
35
|
+
while (1) switch (_context.p = _context.n) {
|
|
36
|
+
case 0:
|
|
37
|
+
container = docker.getContainer(containerId);
|
|
38
|
+
tryShell = function tryShell(shell) {
|
|
39
|
+
return new Promise(function (resolve) {
|
|
40
|
+
container.exec({
|
|
41
|
+
Cmd: ['which', shell],
|
|
42
|
+
AttachStdout: true,
|
|
43
|
+
AttachStderr: false,
|
|
44
|
+
Tty: false
|
|
45
|
+
}, function (err, exec) {
|
|
46
|
+
if (err) {
|
|
47
|
+
resolve(false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
exec.start({
|
|
51
|
+
Tty: false
|
|
52
|
+
}, function (startErr, stream) {
|
|
53
|
+
if (startErr) {
|
|
54
|
+
resolve(false);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
var output = '';
|
|
58
|
+
stream.on('data', function (chunk) {
|
|
59
|
+
output += chunk.toString();
|
|
60
|
+
});
|
|
61
|
+
stream.on('end', function () {
|
|
62
|
+
resolve(output.trim().length > 0);
|
|
63
|
+
});
|
|
64
|
+
stream.on('error', function () {
|
|
65
|
+
return resolve(false);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
_context.p = 1;
|
|
72
|
+
_context.n = 2;
|
|
73
|
+
return Promise.race([tryShell('bash'), new Promise(function (r) {
|
|
74
|
+
return setTimeout(function () {
|
|
75
|
+
return r(false);
|
|
76
|
+
}, TIMEOUTS.CONTAINER_OP);
|
|
77
|
+
})]);
|
|
78
|
+
case 2:
|
|
79
|
+
hasBash = _context.v;
|
|
80
|
+
if (!hasBash) {
|
|
81
|
+
_context.n = 3;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
logger.debug('Detected bash in container %s', containerId);
|
|
85
|
+
return _context.a(2, 'bash');
|
|
86
|
+
case 3:
|
|
87
|
+
_context.n = 5;
|
|
88
|
+
break;
|
|
89
|
+
case 4:
|
|
90
|
+
_context.p = 4;
|
|
91
|
+
_t = _context.v;
|
|
92
|
+
case 5:
|
|
93
|
+
logger.debug('Falling back to sh in container %s', containerId);
|
|
94
|
+
return _context.a(2, 'sh');
|
|
95
|
+
}
|
|
96
|
+
}, _callee, null, [[1, 4]]);
|
|
97
|
+
}));
|
|
98
|
+
return _detectShell.apply(this, arguments);
|
|
99
|
+
}
|
|
100
|
+
export function execInteractive(_x2) {
|
|
101
|
+
return _execInteractive.apply(this, arguments);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Execute a non-interactive command inside a running container.
|
|
106
|
+
* Returns stdout and stderr as strings.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} containerId - Docker container id
|
|
109
|
+
* @param {string[]} cmd - Command to execute (e.g. ['ls', '-la'])
|
|
110
|
+
* @param {Object} [options]
|
|
111
|
+
* @param {number} [options.timeout] - Timeout in ms
|
|
112
|
+
* @returns {Promise<{stdout: string, stderr: string, exitCode: number}>}
|
|
113
|
+
*/
|
|
114
|
+
function _execInteractive() {
|
|
115
|
+
_execInteractive = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(containerId) {
|
|
116
|
+
var options,
|
|
117
|
+
shell,
|
|
118
|
+
args,
|
|
119
|
+
_args2 = arguments,
|
|
120
|
+
_t2;
|
|
121
|
+
return _regenerator().w(function (_context2) {
|
|
122
|
+
while (1) switch (_context2.n) {
|
|
123
|
+
case 0:
|
|
124
|
+
options = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : {};
|
|
125
|
+
_t2 = options.shell;
|
|
126
|
+
if (_t2) {
|
|
127
|
+
_context2.n = 2;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
_context2.n = 1;
|
|
131
|
+
return detectShell(containerId);
|
|
132
|
+
case 1:
|
|
133
|
+
_t2 = _context2.v;
|
|
134
|
+
case 2:
|
|
135
|
+
shell = _t2;
|
|
136
|
+
args = ['exec', '-it', containerId, shell];
|
|
137
|
+
if (options.workingDir) {
|
|
138
|
+
args.splice(3, 0, '-w', options.workingDir);
|
|
139
|
+
}
|
|
140
|
+
logger.info('Opening interactive shell in container %s (shell=%s)', containerId, shell);
|
|
141
|
+
return _context2.a(2, new Promise(function (resolve, reject) {
|
|
142
|
+
var child = spawn('docker', args, {
|
|
143
|
+
stdio: 'inherit',
|
|
144
|
+
shell: false
|
|
145
|
+
});
|
|
146
|
+
child.on('error', function (err) {
|
|
147
|
+
logger.error('Failed to spawn docker exec', err);
|
|
148
|
+
reject(new Error("Failed to open shell: ".concat(err.message)));
|
|
149
|
+
});
|
|
150
|
+
child.on('close', function (code, signal) {
|
|
151
|
+
logger.info('Interactive shell exited (code=%s, signal=%s)', code, signal);
|
|
152
|
+
resolve({
|
|
153
|
+
code: code,
|
|
154
|
+
signal: signal
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
}, _callee2);
|
|
160
|
+
}));
|
|
161
|
+
return _execInteractive.apply(this, arguments);
|
|
162
|
+
}
|
|
163
|
+
export function execCommand(containerId, cmd) {
|
|
164
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
165
|
+
return new Promise(function (resolve, reject) {
|
|
166
|
+
var container = docker.getContainer(containerId);
|
|
167
|
+
container.exec({
|
|
168
|
+
Cmd: cmd,
|
|
169
|
+
AttachStdout: true,
|
|
170
|
+
AttachStderr: true,
|
|
171
|
+
Tty: false
|
|
172
|
+
}, function (err, exec) {
|
|
173
|
+
if (err) {
|
|
174
|
+
return reject(new Error("Exec create failed: ".concat(err.message)));
|
|
175
|
+
}
|
|
176
|
+
exec.start({
|
|
177
|
+
Tty: false
|
|
178
|
+
}, function (startErr, stream) {
|
|
179
|
+
if (startErr) {
|
|
180
|
+
return reject(new Error("Exec start failed: ".concat(startErr.message)));
|
|
181
|
+
}
|
|
182
|
+
var stdout = '';
|
|
183
|
+
var stderr = '';
|
|
184
|
+
stream.on('data', function (chunk) {
|
|
185
|
+
var str = chunk.toString();
|
|
186
|
+
// Docker multiplexed streams use 8-byte headers.
|
|
187
|
+
// For Tty=false, output is multiplexed; for simplicity we accumulate.
|
|
188
|
+
stdout += str;
|
|
189
|
+
});
|
|
190
|
+
stream.on('end', function () {
|
|
191
|
+
exec.inspect(function (inspectErr, info) {
|
|
192
|
+
var _info$ExitCode;
|
|
193
|
+
resolve({
|
|
194
|
+
stdout: stdout.trim(),
|
|
195
|
+
stderr: stderr.trim(),
|
|
196
|
+
exitCode: (_info$ExitCode = info === null || info === void 0 ? void 0 : info.ExitCode) !== null && _info$ExitCode !== void 0 ? _info$ExitCode : -1
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
stream.on('error', function (streamErr) {
|
|
201
|
+
reject(new Error("Stream error: ".concat(streamErr.message)));
|
|
202
|
+
});
|
|
203
|
+
if (options.timeout) {
|
|
204
|
+
setTimeout(function () {
|
|
205
|
+
reject(new Error('Command timed out'));
|
|
206
|
+
}, options.timeout);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
package/dist/helpers/logger.js
CHANGED
|
@@ -58,7 +58,7 @@ 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
63
|
var method = level === 'debug' ? 'log' : level;
|
|
64
64
|
if (typeof console[method] === 'function') {
|
|
@@ -8,7 +8,7 @@ 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 'react';
|
|
11
|
+
import { useState, useRef, useEffect } from 'react';
|
|
12
12
|
import { safeCall } from '../../helpers/safeCall.js';
|
|
13
13
|
import { startContainer as svcStartContainer, stopContainer as svcStopContainer, restartContainer as svcRestartContainer, removeContainer as svcRemoveContainer } from '../../helpers/dockerService/serviceComponents/containerActions.js';
|
|
14
14
|
|
|
@@ -32,6 +32,24 @@ export function useContainerActions(_ref) {
|
|
|
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.
|
|
@@ -76,16 +94,14 @@ export function useContainerActions(_ref) {
|
|
|
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,
|