dockly 3.22.2 → 3.23.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/package.json +4 -4
- package/src/enum.js +11 -0
- package/src/screen.js +7 -5
- package/src/widgetsTemplates/help.widget.template.js +1 -0
- package/src/widgetsTemplates/info.widget.template.js +2 -1
- package/src/widgetsTemplates/list.widget.template.js +1 -0
- package/widgets/actionStatus.widget.js +1 -0
- package/widgets/actionsMenu.widget.js +7 -2
- package/widgets/containers/containerList.widget.js +32 -21
- package/widgets/containers/containerSortList.widget.js +103 -0
- package/widgets/images/imageList.widget.js +2 -2
- package/widgets/searchInput.widget.js +1 -0
- package/widgets/toolbar.widget.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dockly",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.23.1",
|
|
4
4
|
"description": "Immersive terminal interface for managing docker containers and services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -68,15 +68,15 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"blessed": "^0.1.81",
|
|
70
70
|
"blessed-contrib": "^4.10.1",
|
|
71
|
-
"chalk": "
|
|
71
|
+
"chalk": "^4",
|
|
72
72
|
"clipboardy": "^2.3.0",
|
|
73
73
|
"command-line-args": "^5.1.2",
|
|
74
74
|
"command-line-usage": "^5.0.5",
|
|
75
|
-
"dockerode": "
|
|
75
|
+
"dockerode": "3.3.4",
|
|
76
76
|
"figures": "^2.0.0",
|
|
77
77
|
"glob": "^7.2.0",
|
|
78
78
|
"lockfile-lint": "^3.0.9",
|
|
79
|
-
"semver": "
|
|
79
|
+
"semver": "7.3.8"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"standard": "^12.0.1"
|
package/src/enum.js
ADDED
package/src/screen.js
CHANGED
|
@@ -11,16 +11,17 @@ const MODES = require('../lib/modes')
|
|
|
11
11
|
// from the user (index.js)
|
|
12
12
|
const CONTAINERS_GRID_LAYOUT = {
|
|
13
13
|
'actionsMenu': [4, 4, 4, 4],
|
|
14
|
-
'
|
|
15
|
-
'actionStatus': [6, 0, 1, 10],
|
|
14
|
+
'help': [4, 4, 4, 4],
|
|
16
15
|
'containerInfo': [2, 2, 8, 8],
|
|
16
|
+
'containerSortList': [4, 5, 3, 2],
|
|
17
17
|
'containerList': [0, 0, 6, 10],
|
|
18
|
-
'
|
|
18
|
+
'actionStatus': [6, 0, 1, 10],
|
|
19
19
|
'containerStatus': [0, 10, 2, 2],
|
|
20
20
|
'containerUtilization': [2, 10, 3, 2],
|
|
21
21
|
'containerVsImages': [5, 10, 2, 2],
|
|
22
|
-
'
|
|
23
|
-
'toolbar': [11, 0, 1, 12]
|
|
22
|
+
'containerLogs': [7, 0, 4, 12],
|
|
23
|
+
'toolbar': [11, 0, 1, 12],
|
|
24
|
+
'searchInput': [11, 0, 1, 12]
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const SERVICES_GRID_LAYOUT = {
|
|
@@ -208,6 +209,7 @@ class screen {
|
|
|
208
209
|
this.clearWidgets()
|
|
209
210
|
this.toggleMode()
|
|
210
211
|
this.screen.destroy()
|
|
212
|
+
// TODO refactor this so that all of the assets aren't reloaded on screen switch
|
|
211
213
|
this.init()
|
|
212
214
|
})
|
|
213
215
|
}
|
|
@@ -50,7 +50,7 @@ class myWidget extends baseWidget() {
|
|
|
50
50
|
// then show the information on the item
|
|
51
51
|
this.getItemById(itemId, (err, data) => {
|
|
52
52
|
if (!err) {
|
|
53
|
-
this.update(util.inspect(data))
|
|
53
|
+
this.update(util.inspect(data, { depth: null, colors: true }))
|
|
54
54
|
this.screen.render()
|
|
55
55
|
}
|
|
56
56
|
})
|
|
@@ -97,6 +97,7 @@ class myWidget extends baseWidget() {
|
|
|
97
97
|
align: 'left',
|
|
98
98
|
width: '70%',
|
|
99
99
|
height: '70%',
|
|
100
|
+
vi: true,
|
|
100
101
|
top: 'center',
|
|
101
102
|
left: 'center',
|
|
102
103
|
content: 'Loading...'
|
|
@@ -119,7 +119,7 @@ class myWidget extends baseWidget() {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
getWidget () {
|
|
122
|
-
return this.
|
|
122
|
+
return this.blessed.list({
|
|
123
123
|
label: this.label,
|
|
124
124
|
scrollable: true,
|
|
125
125
|
alwaysScroll: true,
|
|
@@ -136,7 +136,12 @@ class myWidget extends baseWidget() {
|
|
|
136
136
|
fg: 'blue',
|
|
137
137
|
ch: '|'
|
|
138
138
|
},
|
|
139
|
-
|
|
139
|
+
vi: true,
|
|
140
|
+
align: 'center',
|
|
141
|
+
left: 'center',
|
|
142
|
+
top: 'center',
|
|
143
|
+
width: '33%',
|
|
144
|
+
height: '33%'
|
|
140
145
|
})
|
|
141
146
|
}
|
|
142
147
|
|
|
@@ -5,11 +5,14 @@ const figures = require('figures')
|
|
|
5
5
|
|
|
6
6
|
const ListWidget = require('../../src/widgetsTemplates/list.widget.template')
|
|
7
7
|
|
|
8
|
+
const ContainerState = require('../../src/enum.js').ContainerState
|
|
9
|
+
|
|
8
10
|
class myWidget extends ListWidget {
|
|
9
11
|
constructor ({ blessed = {}, contrib = {}, screen = {}, grid = {} }) {
|
|
10
12
|
super({ blessed, contrib, screen, grid })
|
|
11
13
|
this.containersList = {}
|
|
12
14
|
this.containersListData = []
|
|
15
|
+
this.sortBy = ContainerState.running
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
getLabel () {
|
|
@@ -56,10 +59,20 @@ class myWidget extends ListWidget {
|
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
|
|
62
|
+
sortContainersByState (state) {
|
|
63
|
+
this.sortBy = state
|
|
64
|
+
this.refreshList()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// TODO refactor this
|
|
59
68
|
formatList (containers) {
|
|
60
69
|
const containerList = {}
|
|
61
70
|
if (containers) {
|
|
62
71
|
containers.forEach((container) => {
|
|
72
|
+
let containerPortPublic = (container.Ports[0] && container.Ports[0].PublicPort) ? String(container.Ports[0].PublicPort) : ''
|
|
73
|
+
let containerPortPrivate = (container.Ports[0] && container.Ports[0].PrivatePort) ? String(container.Ports[0].PrivatePort) : ''
|
|
74
|
+
let containerPort = containerPortPrivate + ':' + containerPortPublic
|
|
75
|
+
|
|
63
76
|
containerList[container.Id] = [
|
|
64
77
|
container.Id.substring(0, 5),
|
|
65
78
|
container.Names[0].substring(0, 40),
|
|
@@ -67,7 +80,8 @@ class myWidget extends ListWidget {
|
|
|
67
80
|
// remove any new lines or carriage return line feed from the string in container.Command
|
|
68
81
|
container.Command.substring(0, 30).replace(/(\r\n|\n|\r)/gm, ''),
|
|
69
82
|
container.State,
|
|
70
|
-
container.Status
|
|
83
|
+
container.Status,
|
|
84
|
+
containerPort
|
|
71
85
|
]
|
|
72
86
|
})
|
|
73
87
|
}
|
|
@@ -77,13 +91,20 @@ class myWidget extends ListWidget {
|
|
|
77
91
|
let container = []
|
|
78
92
|
|
|
79
93
|
container = containerList[key]
|
|
94
|
+
const status = container[4]
|
|
80
95
|
container[4] = this.formatContainerState(container[4])
|
|
81
96
|
container[5] = this.formatContainerStatus(container[5])
|
|
97
|
+
container[7] = status
|
|
82
98
|
|
|
83
99
|
return container
|
|
84
100
|
})
|
|
85
101
|
|
|
86
|
-
list.
|
|
102
|
+
list.sort(this.sortContainers(this.sortBy))
|
|
103
|
+
list = list.map(a => {
|
|
104
|
+
a.pop()
|
|
105
|
+
return a
|
|
106
|
+
})
|
|
107
|
+
list.unshift(['Id', 'Name', 'Image', 'Command', 'State', 'Status', 'Ports'])
|
|
87
108
|
this.containersListData = list
|
|
88
109
|
this.containersList = containerList
|
|
89
110
|
|
|
@@ -136,27 +157,17 @@ class myWidget extends ListWidget {
|
|
|
136
157
|
return this.widget.getItem(this.widget.selected).getContent().toString().trim().split(' ').shift()
|
|
137
158
|
}
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
* @returns {number} for position
|
|
145
|
-
*/
|
|
146
|
-
sortContainers (a, b) {
|
|
147
|
-
if (a[4] === 'running' && b[4] !== 'running') {
|
|
148
|
-
return -1
|
|
149
|
-
}
|
|
160
|
+
sortContainers (state) {
|
|
161
|
+
return (a, b) => {
|
|
162
|
+
if (a[7] === state && b[7] !== state) {
|
|
163
|
+
return -1
|
|
164
|
+
}
|
|
150
165
|
|
|
151
|
-
|
|
152
|
-
|
|
166
|
+
if (b[7] === state && a[7] !== state) {
|
|
167
|
+
return 1
|
|
168
|
+
}
|
|
169
|
+
return 0
|
|
153
170
|
}
|
|
154
|
-
|
|
155
|
-
if (a[4] === 'exited' && b[4] !== 'exited') {
|
|
156
|
-
return 1
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return 0
|
|
160
171
|
}
|
|
161
172
|
}
|
|
162
173
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const baseWidget = require('../../src/baseWidget')
|
|
2
|
+
const { ContainerState } = require('../../src/enum')
|
|
3
|
+
|
|
4
|
+
class ContainerSortListWidget extends baseWidget() {
|
|
5
|
+
constructor ({ blessed = {}, contrib = {}, screen = {}, grid = {} }) {
|
|
6
|
+
super()
|
|
7
|
+
this.blessed = blessed
|
|
8
|
+
this.contrib = contrib
|
|
9
|
+
this.screen = screen
|
|
10
|
+
this.grid = grid
|
|
11
|
+
this.label = 'Sort By:'
|
|
12
|
+
this.isVisible = false
|
|
13
|
+
const sortedStates = Object.keys(ContainerState)
|
|
14
|
+
sortedStates.sort((a, b) => a.length - b.length)
|
|
15
|
+
this.items = sortedStates
|
|
16
|
+
.map(state =>
|
|
17
|
+
({
|
|
18
|
+
[`By ${state.charAt(0).toUpperCase()}${state.slice(1)}`]:
|
|
19
|
+
{
|
|
20
|
+
handler: () => this.sortContainerList(state)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
).reduce((accum, obj) => ({ ...accum, ...obj }), {})
|
|
24
|
+
|
|
25
|
+
this.widget = this.getWidget()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
init () {
|
|
29
|
+
if (!this.widgetsRepo.has('toolbar')) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.registerEscapeKey()
|
|
34
|
+
this.registerSortHandler()
|
|
35
|
+
this.registerToolbarKey()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
sortContainerList (state) {
|
|
39
|
+
const containerList = this.widgetsRepo.get('containerList')
|
|
40
|
+
if (!containerList) {
|
|
41
|
+
// TODO throw error!
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
containerList.sortContainersByState(state)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
registerSortHandler () {
|
|
48
|
+
this.widget.on('select', (el) => {
|
|
49
|
+
this.items[el.getText()].handler()
|
|
50
|
+
this.toggleVisibility()
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
registerToolbarKey () {
|
|
55
|
+
const toolbar = this.widgetsRepo.get('toolbar')
|
|
56
|
+
toolbar.on('key', (keyString) => {
|
|
57
|
+
if (keyString === 'o') {
|
|
58
|
+
this.toggleVisibility()
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
registerEscapeKey () {
|
|
64
|
+
this.widget.on('keypress', (ch, key) => {
|
|
65
|
+
if (key.name === 'escape' || key.name === 'return') {
|
|
66
|
+
this.toggleVisibility()
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
toggleVisibility () {
|
|
72
|
+
if (this.isVisible) {
|
|
73
|
+
this.screen.remove(this.widget)
|
|
74
|
+
} else {
|
|
75
|
+
this.screen.append(this.widget)
|
|
76
|
+
this.screen.render()
|
|
77
|
+
this.widget.focus()
|
|
78
|
+
}
|
|
79
|
+
this.isVisible = !this.isVisible
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getWidget () {
|
|
83
|
+
return this.blessed.list({
|
|
84
|
+
label: this.label,
|
|
85
|
+
keys: true,
|
|
86
|
+
align: 'center',
|
|
87
|
+
border: {
|
|
88
|
+
type: 'line'
|
|
89
|
+
},
|
|
90
|
+
left: 'center',
|
|
91
|
+
top: 'center',
|
|
92
|
+
width: '16%',
|
|
93
|
+
height: '25%',
|
|
94
|
+
style: this.getWidgetStyle(),
|
|
95
|
+
items: Object.keys(this.items)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
renderWidget () {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = ContainerSortListWidget
|
|
@@ -45,11 +45,11 @@ class myWidget extends ListWidget {
|
|
|
45
45
|
|
|
46
46
|
if (images) {
|
|
47
47
|
images.forEach((image) => {
|
|
48
|
-
const getTag = (tag, part) => tag ? tag[0].split(':')[part] : 'none'
|
|
48
|
+
const getTag = (tag, part) => (tag && tag.length) ? tag[0].split(':')[part] : 'none'
|
|
49
49
|
|
|
50
50
|
imageList.push([
|
|
51
51
|
image.Id.substring(7, 12),
|
|
52
|
-
image.RepoDigests ? image.RepoDigests[0].split('@')[0] : getTag(image[2], 0),
|
|
52
|
+
(image.RepoDigests && image.RepoDigests.length) ? image.RepoDigests[0].split('@')[0] : getTag(image[2], 0),
|
|
53
53
|
getTag(image.RepoTags, 1),
|
|
54
54
|
this.timeDifference(image.Created),
|
|
55
55
|
this.formatBytes(image.Size)
|