cdd-cli 4.0.0 → 4.2.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 +60 -26
- package/README.md +60 -26
- package/dist/App.js +1 -0
- package/dist/components/ContainerCreationPrompt.js +14 -0
- package/dist/components/PromptField.js +13 -6
- package/dist/components/TextField.js +54 -0
- package/dist/components/UsageMenu.js +1 -1
- package/dist/helpers/appState.js +26 -0
- package/dist/helpers/dockerService/serviceComponents/containerExec.js +211 -0
- package/dist/helpers/textEditing.js +293 -0
- package/dist/hooks/creation/useContainerCreation.js +132 -15
- package/dist/hooks/useContainerCommandRouter.js +12 -2
- package/dist/hooks/useControls.js +21 -26
- package/dist/hooks/useShellMode.js +101 -0
- package/dist/index.js +3 -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/.~lock.ROADMAP.md# +0 -1
- package/CHANGELOG.md +0 -216
- package/CODE_OF_CONDUCT.md +0 -12
- package/CONTRIBUTING.md +0 -35
- package/ROADMAP.md +0 -647
- 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 -575
- package/coverage/coverage-final.json +0 -17
- package/coverage/lcov-report/ContainerCreationPrompt.jsx.html +0 -400
- package/coverage/lcov-report/ControlsHUD.jsx.html +0 -256
- 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 -394
- package/coverage/lcov-report/components/PromptField.jsx.html +0 -229
- package/coverage/lcov-report/components/SuggestionPanel.jsx.html +0 -268
- 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 -352
- package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +0 -244
- package/coverage/lcov-report/helpers/dockerHubService.js.html +0 -310
- 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 -206
- 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 -982
- 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 -868
- 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 -176
- 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 -1163
- package/fix-imports.cjs +0 -54
- package/jest.config.cjs +0 -14
- package/src/App.jsx +0 -102
- package/src/components/ContainerCreationPrompt.jsx +0 -107
- package/src/components/ContainerList.jsx +0 -32
- package/src/components/ContainerRow.jsx +0 -84
- package/src/components/ContainerSection.jsx +0 -24
- package/src/components/ControlsHUD.jsx +0 -66
- 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 -61
- package/src/components/UsageMenu.jsx +0 -52
- package/src/helpers/appInfo.js +0 -23
- package/src/helpers/constants.js +0 -89
- package/src/helpers/containerOptionsBuilder.js +0 -53
- package/src/helpers/dockerHubService.js +0 -75
- 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 -112
- package/src/helpers/safeCall.js +0 -18
- package/src/helpers/validationHelpers.js +0 -87
- package/src/hooks/creation/useContainerActions.js +0 -89
- package/src/hooks/creation/useContainerCreation.js +0 -377
- 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 -263
- package/src/hooks/useEraseConfirmation.js +0 -39
- package/src/hooks/useExitHandler.js +0 -69
- package/src/index.js +0 -20
- package/test/ContainerCreationPrompt.dom.test.js +0 -313
- package/test/ControlsHUD.dom.test.js +0 -125
- package/test/SuggestionPanel.dom.test.js +0 -83
- package/test/constants.test.js +0 -41
- package/test/containerActions.test.js +0 -229
- package/test/containerList.test.js +0 -79
- package/test/containerOptionsBuilder.test.js +0 -36
- package/test/dockerHubService.test.js +0 -213
- package/test/jest.setup.js +0 -7
- package/test/logger.test.js +0 -58
- package/test/resolveImageTag.test.js +0 -26
- package/test/safeCall.test.js +0 -25
- package/test/useContainerCreation.dom.test.js +0 -567
- package/test/useContainerCreationHub.dom.test.js +0 -184
- package/test/useControls.dom.test.js +0 -519
- package/test/validationHelpers.test.js +0 -111
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
6
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
8
|
+
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."); }
|
|
9
|
+
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; } }
|
|
10
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
11
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
12
|
+
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; }
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Object} TextState
|
|
15
|
+
* @property {string} value - Current field content
|
|
16
|
+
* @property {number} cursor - Cursor position (0..value.length)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {Object} EditResult
|
|
21
|
+
* @property {TextState} state - Resulting state (same object if no change)
|
|
22
|
+
* @property {boolean} handled - true if the key was consumed by the editor
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
var BREAK_CHARS = ' \t./\\,;:|(){}[]<>!@#$%^&*+=~`"\'-';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Splits a string into code points (handles emojis via Array.from).
|
|
29
|
+
* @param {string} s
|
|
30
|
+
* @returns {string[]}
|
|
31
|
+
*/
|
|
32
|
+
function chars(s) {
|
|
33
|
+
return Array.from(s);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns the index of the start of the word before cursor.
|
|
38
|
+
* A word boundary is any non-alphanumeric, non-underscore character.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} value
|
|
41
|
+
* @param {number} cursor
|
|
42
|
+
* @returns {number}
|
|
43
|
+
*/
|
|
44
|
+
export function wordStartBefore(value, cursor) {
|
|
45
|
+
var arr = chars(value);
|
|
46
|
+
if (cursor <= 0) return 0;
|
|
47
|
+
var i = cursor - 1;
|
|
48
|
+
// Skip trailing non-word chars
|
|
49
|
+
while (i > 0 && BREAK_CHARS.includes(arr[i])) i--;
|
|
50
|
+
// Skip word chars
|
|
51
|
+
while (i > 0 && !BREAK_CHARS.includes(arr[i - 1])) i--;
|
|
52
|
+
return i;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns the index of the start of the word after cursor.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} value
|
|
59
|
+
* @param {number} cursor
|
|
60
|
+
* @returns {number}
|
|
61
|
+
*/
|
|
62
|
+
export function wordStartAfter(value, cursor) {
|
|
63
|
+
var arr = chars(value);
|
|
64
|
+
if (cursor >= arr.length) return arr.length;
|
|
65
|
+
var i = cursor;
|
|
66
|
+
// Skip current word chars
|
|
67
|
+
while (i < arr.length && !BREAK_CHARS.includes(arr[i])) i++;
|
|
68
|
+
// Skip non-word chars (whitespace, punctuation)
|
|
69
|
+
while (i < arr.length && BREAK_CHARS.includes(arr[i])) i++;
|
|
70
|
+
return i;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Inserts text at the cursor position and leaves the cursor after the insertion.
|
|
75
|
+
*
|
|
76
|
+
* @param {TextState} state
|
|
77
|
+
* @param {string} text
|
|
78
|
+
* @returns {TextState}
|
|
79
|
+
*/
|
|
80
|
+
export function insertAt(state, text) {
|
|
81
|
+
if (!text) return state;
|
|
82
|
+
var arr = chars(state.value);
|
|
83
|
+
var before = arr.slice(0, state.cursor);
|
|
84
|
+
var after = arr.slice(state.cursor);
|
|
85
|
+
var result = [].concat(_toConsumableArray(before), _toConsumableArray(chars(text)), _toConsumableArray(after)).join('');
|
|
86
|
+
return {
|
|
87
|
+
value: result,
|
|
88
|
+
cursor: state.cursor + chars(text).length
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Deletes the character before the cursor.
|
|
94
|
+
*
|
|
95
|
+
* @param {TextState} state
|
|
96
|
+
* @returns {TextState}
|
|
97
|
+
*/
|
|
98
|
+
export function deleteBackward(state) {
|
|
99
|
+
var arr = chars(state.value);
|
|
100
|
+
if (state.cursor <= 0) return state;
|
|
101
|
+
var before = arr.slice(0, state.cursor - 1);
|
|
102
|
+
var after = arr.slice(state.cursor);
|
|
103
|
+
return {
|
|
104
|
+
value: before.concat(after).join(''),
|
|
105
|
+
cursor: state.cursor - 1
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Deletes the character under the cursor.
|
|
111
|
+
*
|
|
112
|
+
* @param {TextState} state
|
|
113
|
+
* @returns {TextState}
|
|
114
|
+
*/
|
|
115
|
+
export function deleteForward(state) {
|
|
116
|
+
var arr = chars(state.value);
|
|
117
|
+
if (state.cursor >= arr.length) return state;
|
|
118
|
+
var before = arr.slice(0, state.cursor);
|
|
119
|
+
var after = arr.slice(state.cursor + 1);
|
|
120
|
+
return {
|
|
121
|
+
value: before.concat(after).join(''),
|
|
122
|
+
cursor: state.cursor
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Applies a keypress to a text state.
|
|
128
|
+
* Pure function: reads and writes nothing outside its arguments.
|
|
129
|
+
*
|
|
130
|
+
* @param {TextState} state
|
|
131
|
+
* @param {string} input - Raw Ink input (1 char, a paste, or '')
|
|
132
|
+
* @param {import('ink').Key} key - Ink special key object
|
|
133
|
+
* @returns {EditResult}
|
|
134
|
+
*/
|
|
135
|
+
export function applyKeyToText(state, input, key) {
|
|
136
|
+
// No key combinations from this function
|
|
137
|
+
if (key.ctrl) {
|
|
138
|
+
if (input === 'a') {
|
|
139
|
+
// Ctrl+A → move to start
|
|
140
|
+
return {
|
|
141
|
+
state: _objectSpread(_objectSpread({}, state), {}, {
|
|
142
|
+
cursor: 0
|
|
143
|
+
}),
|
|
144
|
+
handled: true
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (input === 'e') {
|
|
148
|
+
// Ctrl+E → move to end
|
|
149
|
+
return {
|
|
150
|
+
state: _objectSpread(_objectSpread({}, state), {}, {
|
|
151
|
+
cursor: chars(state.value).length
|
|
152
|
+
}),
|
|
153
|
+
handled: true
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (input === 'w') {
|
|
157
|
+
// Ctrl+W → delete word before cursor
|
|
158
|
+
var newCursor = wordStartBefore(state.value, state.cursor);
|
|
159
|
+
var arr = chars(state.value);
|
|
160
|
+
var before = arr.slice(0, newCursor);
|
|
161
|
+
var after = arr.slice(state.cursor);
|
|
162
|
+
return {
|
|
163
|
+
state: {
|
|
164
|
+
value: before.concat(after).join(''),
|
|
165
|
+
cursor: newCursor
|
|
166
|
+
},
|
|
167
|
+
handled: true
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (input === 'u') {
|
|
171
|
+
// Ctrl+U → delete from start to cursor
|
|
172
|
+
var _arr = chars(state.value);
|
|
173
|
+
var _after = _arr.slice(state.cursor);
|
|
174
|
+
return {
|
|
175
|
+
state: {
|
|
176
|
+
value: _after.join(''),
|
|
177
|
+
cursor: 0
|
|
178
|
+
},
|
|
179
|
+
handled: true
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (input === 'k') {
|
|
183
|
+
// Ctrl+K → delete from cursor to end
|
|
184
|
+
var _arr2 = chars(state.value);
|
|
185
|
+
var _before = _arr2.slice(0, state.cursor);
|
|
186
|
+
return {
|
|
187
|
+
state: {
|
|
188
|
+
value: _before.join(''),
|
|
189
|
+
cursor: state.cursor
|
|
190
|
+
},
|
|
191
|
+
handled: true
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Other ctrl combos: not handled
|
|
195
|
+
return {
|
|
196
|
+
state: state,
|
|
197
|
+
handled: false
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (key.meta) {
|
|
201
|
+
return {
|
|
202
|
+
state: state,
|
|
203
|
+
handled: false
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (key.leftArrow) {
|
|
207
|
+
var _newCursor = Math.max(0, state.cursor - 1);
|
|
208
|
+
return {
|
|
209
|
+
state: _objectSpread(_objectSpread({}, state), {}, {
|
|
210
|
+
cursor: _newCursor
|
|
211
|
+
}),
|
|
212
|
+
handled: true
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
if (key.rightArrow) {
|
|
216
|
+
var len = chars(state.value).length;
|
|
217
|
+
var _newCursor2 = Math.min(len, state.cursor + 1);
|
|
218
|
+
return {
|
|
219
|
+
state: _objectSpread(_objectSpread({}, state), {}, {
|
|
220
|
+
cursor: _newCursor2
|
|
221
|
+
}),
|
|
222
|
+
handled: true
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (key.home) {
|
|
226
|
+
return {
|
|
227
|
+
state: _objectSpread(_objectSpread({}, state), {}, {
|
|
228
|
+
cursor: 0
|
|
229
|
+
}),
|
|
230
|
+
handled: true
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
if (key.end) {
|
|
234
|
+
return {
|
|
235
|
+
state: _objectSpread(_objectSpread({}, state), {}, {
|
|
236
|
+
cursor: chars(state.value).length
|
|
237
|
+
}),
|
|
238
|
+
handled: true
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (key.backspace) {
|
|
242
|
+
var newState = deleteBackward(state);
|
|
243
|
+
return {
|
|
244
|
+
state: newState,
|
|
245
|
+
handled: true
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
if (key["delete"]) {
|
|
249
|
+
var _newState = deleteForward(state);
|
|
250
|
+
return {
|
|
251
|
+
state: _newState,
|
|
252
|
+
handled: true
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Safety net: \x7f (DEL) is what most terminals send for Backspace.
|
|
257
|
+
// Ink v6 maps it to key.delete, but if we receive the raw char directly
|
|
258
|
+
// (e.g. from tests or non-Ink callers), handle it as backspace.
|
|
259
|
+
if (input === '\x7f' || input === '\b') {
|
|
260
|
+
var _newState2 = deleteBackward(state);
|
|
261
|
+
return {
|
|
262
|
+
state: _newState2,
|
|
263
|
+
handled: true
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Regular text input (single char or paste)
|
|
268
|
+
if (input && input.length >= 1) {
|
|
269
|
+
var _newState3 = insertAt(state, input);
|
|
270
|
+
return {
|
|
271
|
+
state: _newState3,
|
|
272
|
+
handled: true
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
state: state,
|
|
277
|
+
handled: false
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Creates a TextState from a string, with cursor at the end.
|
|
283
|
+
*
|
|
284
|
+
* @param {string} value
|
|
285
|
+
* @returns {TextState}
|
|
286
|
+
*/
|
|
287
|
+
export function textStateOf() {
|
|
288
|
+
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
289
|
+
return {
|
|
290
|
+
value: value,
|
|
291
|
+
cursor: chars(value).length
|
|
292
|
+
};
|
|
293
|
+
}
|
|
@@ -19,6 +19,7 @@ import { validatePorts, validateEnvVars } from '../../helpers/validationHelpers.
|
|
|
19
19
|
import { IMAGE_PROFILES, resolveImageTag } from '../../helpers/constants.js';
|
|
20
20
|
import { safeCall } from '../../helpers/safeCall.js';
|
|
21
21
|
import { searchDockerHub, formatHubResult } from '../../helpers/dockerHubService.js';
|
|
22
|
+
import { applyKeyToText } from '../../helpers/textEditing.js';
|
|
22
23
|
var MAX_VISIBLE = 6;
|
|
23
24
|
var INITIAL_FORM = {
|
|
24
25
|
step: 0,
|
|
@@ -26,6 +27,12 @@ var INITIAL_FORM = {
|
|
|
26
27
|
containerName: '',
|
|
27
28
|
portInput: '',
|
|
28
29
|
envInput: '',
|
|
30
|
+
cursors: {
|
|
31
|
+
imageName: 0,
|
|
32
|
+
containerName: 0,
|
|
33
|
+
portInput: 0,
|
|
34
|
+
envInput: 0
|
|
35
|
+
},
|
|
29
36
|
message: '',
|
|
30
37
|
messageColor: 'yellow',
|
|
31
38
|
suggestions: [],
|
|
@@ -76,6 +83,7 @@ export function useContainerCreation(_ref) {
|
|
|
76
83
|
containerName = form.containerName,
|
|
77
84
|
portInput = form.portInput,
|
|
78
85
|
envInput = form.envInput,
|
|
86
|
+
cursors = form.cursors,
|
|
79
87
|
message = form.message,
|
|
80
88
|
messageColor = form.messageColor,
|
|
81
89
|
suggestions = form.suggestions,
|
|
@@ -183,6 +191,76 @@ export function useContainerCreation(_ref) {
|
|
|
183
191
|
}
|
|
184
192
|
};
|
|
185
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Sets a field's text value and cursor position together.
|
|
196
|
+
* @param {'imageName'|'containerName'|'portInput'|'envInput'} fieldName
|
|
197
|
+
* @param {string} value
|
|
198
|
+
* @param {number} cursor
|
|
199
|
+
*/
|
|
200
|
+
function setFieldText(fieldName, value, cursor) {
|
|
201
|
+
dispatch({
|
|
202
|
+
type: 'SET',
|
|
203
|
+
payload: _defineProperty(_defineProperty({}, fieldName, value), "cursors", _objectSpread(_objectSpread({}, form.cursors), {}, _defineProperty({}, fieldName, cursor)))
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Returns the field name associated with a wizard step.
|
|
209
|
+
* @param {number} step
|
|
210
|
+
* @returns {'imageName'|'containerName'|'portInput'|'envInput'|null}
|
|
211
|
+
*/
|
|
212
|
+
function fieldForStep(step) {
|
|
213
|
+
var _step;
|
|
214
|
+
return (_step = ['imageName', 'containerName', 'portInput', 'envInput'][step]) !== null && _step !== void 0 ? _step : null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Applies a keypress to the field associated with the current step.
|
|
219
|
+
* When the edited field is imageName, recalculates suggestions.
|
|
220
|
+
* @param {string} input - Raw Ink input
|
|
221
|
+
* @param {import('ink').Key} key - Ink key object
|
|
222
|
+
* @returns {boolean} true if the key was consumed
|
|
223
|
+
*/
|
|
224
|
+
function handleFieldKey(input, key) {
|
|
225
|
+
var fieldName = fieldForStep(step);
|
|
226
|
+
if (!fieldName) return false;
|
|
227
|
+
var currentState = {
|
|
228
|
+
value: form[fieldName],
|
|
229
|
+
cursor: cursors[fieldName]
|
|
230
|
+
};
|
|
231
|
+
var _applyKeyToText = applyKeyToText(currentState, input, key),
|
|
232
|
+
newState = _applyKeyToText.state,
|
|
233
|
+
handled = _applyKeyToText.handled;
|
|
234
|
+
if (!handled) return false;
|
|
235
|
+
if (fieldName === 'imageName') {
|
|
236
|
+
var _activeHubRequestRef$;
|
|
237
|
+
// Recalculate suggestions when image name changes
|
|
238
|
+
(_activeHubRequestRef$ = activeHubRequestRef.current.controller) === null || _activeHubRequestRef$ === void 0 || _activeHubRequestRef$.abort();
|
|
239
|
+
activeHubRequestRef.current.requestId += 1;
|
|
240
|
+
setIsSearchingHub(false);
|
|
241
|
+
setHubResults(null);
|
|
242
|
+
var lower = newState.value.toLowerCase();
|
|
243
|
+
var matches = newState.value.trim() ? Object.keys(imageProfiles).filter(function (key) {
|
|
244
|
+
return key.includes(lower);
|
|
245
|
+
}) : [];
|
|
246
|
+
dispatch({
|
|
247
|
+
type: 'SET',
|
|
248
|
+
payload: {
|
|
249
|
+
imageName: newState.value,
|
|
250
|
+
cursors: _objectSpread(_objectSpread({}, form.cursors), {}, {
|
|
251
|
+
imageName: newState.cursor
|
|
252
|
+
}),
|
|
253
|
+
selectedSuggestionIndex: -1,
|
|
254
|
+
visibleOffset: 0,
|
|
255
|
+
suggestions: matches
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
} else {
|
|
259
|
+
setFieldText(fieldName, newState.value, newState.cursor);
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
|
|
186
264
|
// Docker Hub search state (kept as useState because they are independent of form)
|
|
187
265
|
var _useState = useState(false),
|
|
188
266
|
_useState2 = _slicedToArray(_useState, 2),
|
|
@@ -200,6 +278,25 @@ export function useContainerCreation(_ref) {
|
|
|
200
278
|
|
|
201
279
|
// Timer for auto-clearing messages
|
|
202
280
|
var messageTimerRef = useRef(null);
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Sets a permanent message (e.g. step instructions). No auto-clear.
|
|
284
|
+
*/
|
|
285
|
+
function setStepMessage(msg) {
|
|
286
|
+
var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'yellow';
|
|
287
|
+
clearTimeout(messageTimerRef.current);
|
|
288
|
+
dispatch({
|
|
289
|
+
type: 'SET',
|
|
290
|
+
payload: {
|
|
291
|
+
message: msg,
|
|
292
|
+
messageColor: color
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Sets a transient feedback message (e.g. validation errors). Auto-clears after `ms`.
|
|
299
|
+
*/
|
|
203
300
|
function setTimedMessage(msg) {
|
|
204
301
|
var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'yellow';
|
|
205
302
|
var ms = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 4000;
|
|
@@ -230,15 +327,19 @@ export function useContainerCreation(_ref) {
|
|
|
230
327
|
|
|
231
328
|
/**
|
|
232
329
|
* Updates the image name input and recalculates autocomplete suggestions.
|
|
330
|
+
* Accepts either a plain string (backward compatible) or a TextState object.
|
|
233
331
|
* Resets selectedSuggestionIndex to -1 on every keystroke.
|
|
234
332
|
* Also aborts any in-flight Hub search and clears Hub results.
|
|
235
333
|
*
|
|
236
|
-
* @param {string}
|
|
334
|
+
* @param {string|TextState} input - New image name (string or {value, cursor})
|
|
237
335
|
*/
|
|
238
|
-
function updateImageInput(
|
|
239
|
-
var _activeHubRequestRef
|
|
336
|
+
function updateImageInput(input) {
|
|
337
|
+
var _input$cursor, _activeHubRequestRef$2;
|
|
338
|
+
var value = typeof input === 'string' ? input : input.value;
|
|
339
|
+
var cursor = typeof input === 'string' ? value.length : (_input$cursor = input.cursor) !== null && _input$cursor !== void 0 ? _input$cursor : value.length;
|
|
340
|
+
|
|
240
341
|
// Abort any in-flight Hub search and clear its state
|
|
241
|
-
(_activeHubRequestRef$ = activeHubRequestRef.current.controller) === null || _activeHubRequestRef$ === void 0 || _activeHubRequestRef
|
|
342
|
+
(_activeHubRequestRef$2 = activeHubRequestRef.current.controller) === null || _activeHubRequestRef$2 === void 0 || _activeHubRequestRef$2.abort();
|
|
242
343
|
activeHubRequestRef.current.requestId += 1;
|
|
243
344
|
setIsSearchingHub(false);
|
|
244
345
|
setHubResults(null);
|
|
@@ -250,6 +351,9 @@ export function useContainerCreation(_ref) {
|
|
|
250
351
|
type: 'SET',
|
|
251
352
|
payload: {
|
|
252
353
|
imageName: value,
|
|
354
|
+
cursors: _objectSpread(_objectSpread({}, form.cursors), {}, {
|
|
355
|
+
imageName: cursor
|
|
356
|
+
}),
|
|
253
357
|
selectedSuggestionIndex: -1,
|
|
254
358
|
visibleOffset: 0,
|
|
255
359
|
suggestions: matches
|
|
@@ -274,7 +378,7 @@ export function useContainerCreation(_ref) {
|
|
|
274
378
|
*/
|
|
275
379
|
function _triggerHubSearch() {
|
|
276
380
|
_triggerHubSearch = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
277
|
-
var _activeHubRequestRef$
|
|
381
|
+
var _activeHubRequestRef$3;
|
|
278
382
|
var query, requestId, controller, results, _t;
|
|
279
383
|
return _regenerator().w(function (_context) {
|
|
280
384
|
while (1) switch (_context.p = _context.n) {
|
|
@@ -294,7 +398,7 @@ export function useContainerCreation(_ref) {
|
|
|
294
398
|
case 2:
|
|
295
399
|
// Abort previous request (should already be aborted from updateImageInput,
|
|
296
400
|
// but guard here too)
|
|
297
|
-
(_activeHubRequestRef$
|
|
401
|
+
(_activeHubRequestRef$3 = activeHubRequestRef.current.controller) === null || _activeHubRequestRef$3 === void 0 || _activeHubRequestRef$3.abort();
|
|
298
402
|
requestId = activeHubRequestRef.current.requestId + 1;
|
|
299
403
|
activeHubRequestRef.current.requestId = requestId;
|
|
300
404
|
controller = new AbortController();
|
|
@@ -367,10 +471,14 @@ export function useContainerCreation(_ref) {
|
|
|
367
471
|
function applyFocusedSuggestion() {
|
|
368
472
|
if (selectedSuggestionIndex < 0 || selectedSuggestionIndex >= suggestions.length) return;
|
|
369
473
|
var chosen = suggestions[selectedSuggestionIndex];
|
|
474
|
+
var resolved = resolveImageTag(chosen, imageProfiles);
|
|
370
475
|
dispatch({
|
|
371
476
|
type: 'SET',
|
|
372
477
|
payload: {
|
|
373
|
-
imageName:
|
|
478
|
+
imageName: resolved,
|
|
479
|
+
cursors: _objectSpread(_objectSpread({}, form.cursors), {}, {
|
|
480
|
+
imageName: resolved.length
|
|
481
|
+
}),
|
|
374
482
|
suggestions: [],
|
|
375
483
|
selectedSuggestionIndex: -1,
|
|
376
484
|
visibleOffset: 0
|
|
@@ -392,10 +500,13 @@ export function useContainerCreation(_ref) {
|
|
|
392
500
|
type: 'SET',
|
|
393
501
|
payload: {
|
|
394
502
|
imageName: resolved,
|
|
503
|
+
cursors: _objectSpread(_objectSpread({}, form.cursors), {}, {
|
|
504
|
+
imageName: resolved.length
|
|
505
|
+
}),
|
|
395
506
|
step: 1
|
|
396
507
|
}
|
|
397
508
|
});
|
|
398
|
-
|
|
509
|
+
setStepMessage('Optional: Enter container name or leave empty and press Enter', 'yellow');
|
|
399
510
|
return;
|
|
400
511
|
}
|
|
401
512
|
if (step === 1) {
|
|
@@ -405,7 +516,7 @@ export function useContainerCreation(_ref) {
|
|
|
405
516
|
step: 2
|
|
406
517
|
}
|
|
407
518
|
});
|
|
408
|
-
|
|
519
|
+
setStepMessage('Optional: Enter ports (format 8080:80,443:443) or leave empty and press Enter', 'yellow');
|
|
409
520
|
return;
|
|
410
521
|
}
|
|
411
522
|
if (step === 2) {
|
|
@@ -428,13 +539,13 @@ export function useContainerCreation(_ref) {
|
|
|
428
539
|
var profile = imageProfiles[_baseName];
|
|
429
540
|
if (profile && profile.requiredEnv && profile.requiredEnv.length) {
|
|
430
541
|
var suggestedPart = profile.suggestedEnv && profile.suggestedEnv.length ? " | Suggested: ".concat(profile.suggestedEnv.join(', ')) : '';
|
|
431
|
-
|
|
542
|
+
setStepMessage("Required env vars for ".concat(_baseName, ": ").concat(profile.requiredEnv.join(', '), ". Enter as VAR=val,VAR2=val2").concat(suggestedPart), 'yellow');
|
|
432
543
|
} else if (profile && profile.suggestedEnv && profile.suggestedEnv.length) {
|
|
433
|
-
|
|
544
|
+
setStepMessage("Suggested env vars for ".concat(_baseName, ": ").concat(profile.suggestedEnv.join(', '), ". Enter as VAR=val,VAR2=val2 or leave empty."), 'yellow');
|
|
434
545
|
} else if (isDb) {
|
|
435
|
-
|
|
546
|
+
setStepMessage('Warning: This image usually requires environment variables (e.g. MYSQL_ROOT_PASSWORD=my-secret-pw for MySQL, POSTGRES_PASSWORD=yourpassword for Postgres). Enter them as VAR=val,VAR2=val2 or leave empty and press Enter.', 'yellow');
|
|
436
547
|
} else {
|
|
437
|
-
|
|
548
|
+
setStepMessage('Optional: Enter environment variables (format VAR1=val1,VAR2=val2) or leave empty and press Enter', 'yellow');
|
|
438
549
|
}
|
|
439
550
|
return;
|
|
440
551
|
}
|
|
@@ -500,7 +611,10 @@ export function useContainerCreation(_ref) {
|
|
|
500
611
|
dispatch({
|
|
501
612
|
type: 'SET',
|
|
502
613
|
payload: {
|
|
503
|
-
envInput: newEnvInput
|
|
614
|
+
envInput: newEnvInput,
|
|
615
|
+
cursors: _objectSpread(_objectSpread({}, form.cursors), {}, {
|
|
616
|
+
envInput: newEnvInput.length
|
|
617
|
+
})
|
|
504
618
|
}
|
|
505
619
|
});
|
|
506
620
|
}
|
|
@@ -521,6 +635,7 @@ export function useContainerCreation(_ref) {
|
|
|
521
635
|
setPortInput: setPortInput,
|
|
522
636
|
envInput: envInput,
|
|
523
637
|
setEnvInput: setEnvInput,
|
|
638
|
+
cursors: cursors,
|
|
524
639
|
message: message,
|
|
525
640
|
setMessage: setMessage,
|
|
526
641
|
messageColor: messageColor,
|
|
@@ -538,6 +653,8 @@ export function useContainerCreation(_ref) {
|
|
|
538
653
|
cancelCreation: cancelCreation,
|
|
539
654
|
resetCreation: resetCreation,
|
|
540
655
|
insertNextSuggestedEnv: insertNextSuggestedEnv,
|
|
541
|
-
hasSuggestedEnv: hasSuggestedEnv
|
|
656
|
+
hasSuggestedEnv: hasSuggestedEnv,
|
|
657
|
+
fieldForStep: fieldForStep,
|
|
658
|
+
handleFieldKey: handleFieldKey
|
|
542
659
|
};
|
|
543
660
|
}
|
|
@@ -16,6 +16,7 @@ import { useCallback } from 'react';
|
|
|
16
16
|
* l — open logs viewer and start log stream
|
|
17
17
|
* c — open container creation wizard (reset + activate)
|
|
18
18
|
* d — toggle debug log panel
|
|
19
|
+
* s — open interactive shell in container
|
|
19
20
|
*
|
|
20
21
|
* @param {Object} params
|
|
21
22
|
* @param {Object} params.actions - API from useContainerActions
|
|
@@ -27,6 +28,7 @@ import { useCallback } from 'react';
|
|
|
27
28
|
* @param {Function} params.onStartErase - Callback: activates confirmErase state
|
|
28
29
|
* @param {Function} params.onToggleDebug - Callback: toggles showDebugLogs state
|
|
29
30
|
* @param {Function} params.onStartCreate - Callback: sets creatingContainer = true
|
|
31
|
+
* @param {Function} params.onOpenShell - Callback: opens interactive shell
|
|
30
32
|
* @returns {{ handleDockerCommands: Function }}
|
|
31
33
|
*/
|
|
32
34
|
export function useContainerCommandRouter(_ref) {
|
|
@@ -38,7 +40,8 @@ export function useContainerCommandRouter(_ref) {
|
|
|
38
40
|
startLogsStream = _ref.startLogsStream,
|
|
39
41
|
onStartErase = _ref.onStartErase,
|
|
40
42
|
onToggleDebug = _ref.onToggleDebug,
|
|
41
|
-
onStartCreate = _ref.onStartCreate
|
|
43
|
+
onStartCreate = _ref.onStartCreate,
|
|
44
|
+
onOpenShell = _ref.onOpenShell;
|
|
42
45
|
var handleDockerCommands = useCallback(function (input) {
|
|
43
46
|
var container = containers[selected];
|
|
44
47
|
if (input === 'i') {
|
|
@@ -143,8 +146,15 @@ export function useContainerCommandRouter(_ref) {
|
|
|
143
146
|
onToggleDebug();
|
|
144
147
|
return true;
|
|
145
148
|
}
|
|
149
|
+
if (input === 's') {
|
|
150
|
+
if (!container) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
onOpenShell(container);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
146
156
|
return false;
|
|
147
|
-
}, [actions, containers, creation, logsViewer, onStartCreate, onStartErase, onToggleDebug, selected, startLogsStream]);
|
|
157
|
+
}, [actions, containers, creation, logsViewer, onStartCreate, onStartErase, onToggleDebug, onOpenShell, selected, startLogsStream]);
|
|
148
158
|
return {
|
|
149
159
|
handleDockerCommands: handleDockerCommands
|
|
150
160
|
};
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
6
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
1
7
|
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
2
8
|
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
9
|
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
@@ -22,6 +28,7 @@ import { useDebugLogs } from './debug/useDebugLogs.js';
|
|
|
22
28
|
import { useEraseConfirmation } from './useEraseConfirmation.js';
|
|
23
29
|
import { useExitHandler } from './useExitHandler.js';
|
|
24
30
|
import { useContainerCommandRouter } from './useContainerCommandRouter.js';
|
|
31
|
+
import { useShellMode } from './useShellMode.js';
|
|
25
32
|
import { getLogsStream } from '../helpers/dockerService/serviceComponents/containerLogs.js';
|
|
26
33
|
import { createContainer as svcCreateContainer } from '../helpers/dockerService/serviceComponents/containerActions.js';
|
|
27
34
|
import { buildContainerOptions } from '../helpers/containerOptionsBuilder.js';
|
|
@@ -48,6 +55,7 @@ export function useControls() {
|
|
|
48
55
|
var actions = useContainerActions({
|
|
49
56
|
containers: containers
|
|
50
57
|
});
|
|
58
|
+
var shellMode = useShellMode();
|
|
51
59
|
var creation = useContainerCreation({
|
|
52
60
|
onCreate: function () {
|
|
53
61
|
var _onCreate = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(_ref) {
|
|
@@ -176,6 +184,9 @@ export function useControls() {
|
|
|
176
184
|
},
|
|
177
185
|
onStartCreate: function onStartCreate() {
|
|
178
186
|
return setCreatingContainer(true);
|
|
187
|
+
},
|
|
188
|
+
onOpenShell: function onOpenShell(container) {
|
|
189
|
+
return shellMode.openShell(container);
|
|
179
190
|
}
|
|
180
191
|
});
|
|
181
192
|
var exitHandler = useExitHandler({
|
|
@@ -192,14 +203,6 @@ export function useControls() {
|
|
|
192
203
|
*/
|
|
193
204
|
var processCreationInput = React.useCallback(function (input, key) {
|
|
194
205
|
var step = creation.step;
|
|
195
|
-
var removeLastChar = function removeLastChar(setter) {
|
|
196
|
-
return setter(function (value) {
|
|
197
|
-
return (value || '').slice(0, -1);
|
|
198
|
-
});
|
|
199
|
-
};
|
|
200
|
-
var appendChar = function appendChar(setter, current, ch) {
|
|
201
|
-
return setter((current || '') + ch);
|
|
202
|
-
};
|
|
203
206
|
if (key.escape) {
|
|
204
207
|
creation.cancelCreation();
|
|
205
208
|
setCreatingContainer(false);
|
|
@@ -238,24 +241,16 @@ export function useControls() {
|
|
|
238
241
|
return;
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
252
|
-
if (step === 0) {
|
|
253
|
-
creation.updateImageInput((creation.imageName || '') + input);
|
|
254
|
-
}
|
|
255
|
-
if (step === 1) appendChar(creation.setContainerName, creation.containerName, input);
|
|
256
|
-
if (step === 2) appendChar(creation.setPortInput, creation.portInput, input);
|
|
257
|
-
if (step === 3) appendChar(creation.setEnvInput, creation.envInput, input);
|
|
258
|
-
}
|
|
244
|
+
|
|
245
|
+
// Ink v6 maps \x7f (Backspace on most terminals) to key.delete instead
|
|
246
|
+
// of key.backspace. Normalize so text editing always receives backspace.
|
|
247
|
+
var normalizedKey = key["delete"] && !key.backspace ? _objectSpread(_objectSpread({}, key), {}, {
|
|
248
|
+
"delete": false,
|
|
249
|
+
backspace: true
|
|
250
|
+
}) : key;
|
|
251
|
+
|
|
252
|
+
// Delegate to the text editor for all field input
|
|
253
|
+
if (creation.handleFieldKey(input, normalizedKey)) return;
|
|
259
254
|
}, [creation, setCreatingContainer, triggerHubSearch, isSearchingHub, insertNextSuggestedEnv]);
|
|
260
255
|
|
|
261
256
|
// Single keyboard entry point
|