dockly 3.24.4 → 3.24.6
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.md +5 -4
- package/package.json +12 -9
- package/src/grid.config.js +43 -0
- package/src/screen.js +1 -38
- package/src/widgetsTemplates/list.widget.template.js +6 -1
- package/widgets/containers/containerList.widget.js +12 -5
- package/widgets/images/imageList.widget.js +10 -2
- package/widgets/searchInput.widget.js +8 -4
- package/widgets/services/servicesList.widget.js +10 -3
package/README.md
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
[](https://www.npmjs.org/package/dockly)
|
|
13
13
|
[](./SECURITY.md
|
|
14
14
|
)
|
|
15
|
-
[](https://snyk.io/advisor/npm-package/dockly)
|
|
16
15
|
|
|
17
16
|
Dockly has been highlighted, featured and chosen as favorite docker container management tool on:
|
|
18
17
|
|
|
@@ -21,9 +20,7 @@ Dockly has been highlighted, featured and chosen as favorite docker container ma
|
|
|
21
20
|
[](https://github.com/k4m4/terminals-are-sexy) [](https://mailchi.mp/programmerweekly/programmer-weekly-issue-94?e=e8c11d0390) [](https://console.dev/
|
|
25
|
-
|
|
26
|
-
<a href="https://console.dev" title="Visit Console - the best tools for developers"><img src="https://console.dev/img/badges/1.0/png/console-badge-pick-green1-dark.png" alt="Console - Developer Tool of the Week" /></a>
|
|
23
|
+
)](https://console.dev/)
|
|
27
24
|
|
|
28
25
|

|
|
29
26
|
|
|
@@ -137,6 +134,10 @@ See [Awesome Docker list](https://github.com/veggiemonk/awesome-docker/blob/mast
|
|
|
137
134
|
- [Dockly – Manage Docker Containers From Terminal](https://ostechnix.com/dockly-manage-docker-containers-from-terminal/)
|
|
138
135
|
- [Clever cloud CEO, Quentin Adam, tweeting about dockly](https://twitter.com/waxzce/status/1123886351924043777)
|
|
139
136
|
|
|
137
|
+
## Contributing
|
|
138
|
+
|
|
139
|
+
Please consult [CONTRIBUTING](./CONTRIBUTING.md) for guidelines on contributing to this project.
|
|
140
|
+
|
|
140
141
|
# Author
|
|
141
142
|
Liran Tal <liran.tal@gmail.com>
|
|
142
143
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dockly",
|
|
3
|
-
"version": "3.24.
|
|
3
|
+
"version": "3.24.6",
|
|
4
4
|
"description": "Immersive terminal interface for managing docker containers and services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
8
|
-
"lint": "standard &&
|
|
7
|
+
"test": "npm run lint",
|
|
8
|
+
"lint": "standard && npm run lint:lockfile",
|
|
9
9
|
"lint:fix": "standard --fix",
|
|
10
|
-
"lint:lockfile": "lockfile-lint --path
|
|
10
|
+
"lint:lockfile": "lockfile-lint --path package-lock.json --type npm --validate-https --allowed-hosts npm",
|
|
11
11
|
"debug": "node --inspect=0.0.0.0:9222 ./index.js "
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"dockerRunScript.sh"
|
|
20
20
|
],
|
|
21
21
|
"engines": {
|
|
22
|
-
"
|
|
22
|
+
"npm": ">=11.10.0",
|
|
23
|
+
"node": ">=24.0.0"
|
|
23
24
|
},
|
|
24
25
|
"bin": {
|
|
25
26
|
"dockly": "./index.js"
|
|
@@ -75,18 +76,20 @@
|
|
|
75
76
|
"dockerode": "3.3.5",
|
|
76
77
|
"figures": "^2.0.0",
|
|
77
78
|
"glob": "^7.2.3",
|
|
78
|
-
"lockfile-lint": "^
|
|
79
|
+
"lockfile-lint": "^4.12.0",
|
|
79
80
|
"semver": "7.6.3"
|
|
80
81
|
},
|
|
81
82
|
"devDependencies": {
|
|
83
|
+
"semantic-release": "25.0.3",
|
|
82
84
|
"standard": "^12.0.1"
|
|
83
85
|
},
|
|
84
|
-
"release": {
|
|
85
|
-
"branches": "main"
|
|
86
|
-
},
|
|
87
86
|
"standard": {
|
|
88
87
|
"ignore": [
|
|
89
88
|
"docs/**"
|
|
90
89
|
]
|
|
90
|
+
},
|
|
91
|
+
"publishConfig": {
|
|
92
|
+
"provenance": true,
|
|
93
|
+
"access": "public"
|
|
91
94
|
}
|
|
92
95
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const CONTAINERS_GRID_LAYOUT = {
|
|
2
|
+
'actionsMenu': [4, 4, 4, 4],
|
|
3
|
+
'help': [4, 4, 4, 4],
|
|
4
|
+
'containerInfo': [2, 2, 8, 8],
|
|
5
|
+
'containerSortList': [4, 5, 3, 2],
|
|
6
|
+
'containerList': [0, 0, 6, 10],
|
|
7
|
+
'actionStatus': [6, 0, 1.5, 10],
|
|
8
|
+
'containerStatus': [0, 10, 2, 2],
|
|
9
|
+
'containerUtilization': [2, 10, 3, 2],
|
|
10
|
+
'containerVsImages': [5, 10, 2, 2],
|
|
11
|
+
'containerLogs': [7.5, 0, 4, 12],
|
|
12
|
+
'toolbar': [11.5, 0, 1, 12],
|
|
13
|
+
'searchInput': [11, 0, 1, 12]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const SERVICES_GRID_LAYOUT = {
|
|
17
|
+
'actionsMenu': [4, 4, 4, 4],
|
|
18
|
+
'actionStatus': [6, 0, 1.5, 10],
|
|
19
|
+
'searchInput': [11, 0, 1, 12],
|
|
20
|
+
'help': [4, 4, 4, 4],
|
|
21
|
+
'servicesInfo': [2, 2, 8, 8],
|
|
22
|
+
'servicesList': [0, 0, 6, 10],
|
|
23
|
+
'servicesLogs': [7.5, 0, 4, 12],
|
|
24
|
+
'servicesStatus': [0, 10, 2, 2],
|
|
25
|
+
'servicesVsImages': [2, 10, 2, 2],
|
|
26
|
+
'toolbar': [11, 0, 1, 12]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const IMAGES_GRID_LAYOUT = {
|
|
30
|
+
'imageInfo': [2, 2, 8, 8],
|
|
31
|
+
'imageList': [0, 0, 6, 10],
|
|
32
|
+
'searchInput': [11, 0, 1, 12],
|
|
33
|
+
'actionStatus': [6, 0, 1.5, 10],
|
|
34
|
+
'help': [4, 4, 4, 4],
|
|
35
|
+
'toolbar': [11, 0, 1, 12],
|
|
36
|
+
'imageUtilization': [0, 10, 2, 2]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
CONTAINERS_GRID_LAYOUT,
|
|
41
|
+
SERVICES_GRID_LAYOUT,
|
|
42
|
+
IMAGES_GRID_LAYOUT
|
|
43
|
+
}
|
package/src/screen.js
CHANGED
|
@@ -4,48 +4,11 @@ const path = require('path')
|
|
|
4
4
|
const blessed = require('blessed')
|
|
5
5
|
const contrib = require('blessed-contrib')
|
|
6
6
|
const assetsLoader = require(path.join(__dirname, '/assetsLoader'))
|
|
7
|
-
|
|
7
|
+
const { CONTAINERS_GRID_LAYOUT, SERVICES_GRID_LAYOUT, IMAGES_GRID_LAYOUT } = require('./grid.config')
|
|
8
8
|
const MODES = require('../lib/modes')
|
|
9
9
|
|
|
10
10
|
// @TODO should be moved outside and used as a config
|
|
11
11
|
// from the user (index.js)
|
|
12
|
-
const CONTAINERS_GRID_LAYOUT = {
|
|
13
|
-
'actionsMenu': [4, 4, 4, 4],
|
|
14
|
-
'help': [4, 4, 4, 4],
|
|
15
|
-
'containerInfo': [2, 2, 8, 8],
|
|
16
|
-
'containerSortList': [4, 5, 3, 2],
|
|
17
|
-
'containerList': [0, 0, 6, 10],
|
|
18
|
-
'actionStatus': [6, 0, 1, 10],
|
|
19
|
-
'containerStatus': [0, 10, 2, 2],
|
|
20
|
-
'containerUtilization': [2, 10, 3, 2],
|
|
21
|
-
'containerVsImages': [5, 10, 2, 2],
|
|
22
|
-
'containerLogs': [7, 0, 4, 12],
|
|
23
|
-
'toolbar': [11, 0, 1, 12],
|
|
24
|
-
'searchInput': [11, 0, 1, 12]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const SERVICES_GRID_LAYOUT = {
|
|
28
|
-
'actionsMenu': [4, 4, 4, 4],
|
|
29
|
-
'actionStatus': [6, 0, 1, 10],
|
|
30
|
-
'searchInput': [11, 0, 1, 12],
|
|
31
|
-
'help': [4, 4, 4, 4],
|
|
32
|
-
'servicesInfo': [2, 2, 8, 8],
|
|
33
|
-
'servicesList': [0, 0, 6, 10],
|
|
34
|
-
'servicesLogs': [7, 0, 4, 12],
|
|
35
|
-
'servicesStatus': [0, 10, 2, 2],
|
|
36
|
-
'servicesVsImages': [2, 10, 2, 2],
|
|
37
|
-
'toolbar': [11, 0, 1, 12]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const IMAGES_GRID_LAYOUT = {
|
|
41
|
-
'imageInfo': [2, 2, 8, 8],
|
|
42
|
-
'imageList': [0, 0, 6, 10],
|
|
43
|
-
'searchInput': [11, 0, 1, 12],
|
|
44
|
-
'actionStatus': [6, 0, 1, 10],
|
|
45
|
-
'help': [4, 4, 4, 4],
|
|
46
|
-
'toolbar': [11, 0, 1, 12],
|
|
47
|
-
'imageUtilization': [0, 10, 2, 2]
|
|
48
|
-
}
|
|
49
12
|
|
|
50
13
|
const GRID_LAYOUT = {}
|
|
51
14
|
GRID_LAYOUT[MODES.container] = CONTAINERS_GRID_LAYOUT
|
|
@@ -34,7 +34,6 @@ class myWidget extends baseWidget(EventEmitter) {
|
|
|
34
34
|
if (err) {
|
|
35
35
|
return null
|
|
36
36
|
}
|
|
37
|
-
|
|
38
37
|
// clear log box of previous logs
|
|
39
38
|
this.clearItemLogs()
|
|
40
39
|
|
|
@@ -75,6 +74,12 @@ class myWidget extends baseWidget(EventEmitter) {
|
|
|
75
74
|
})
|
|
76
75
|
|
|
77
76
|
searchInput.on('exitSearch', () => {
|
|
77
|
+
this.update(
|
|
78
|
+
this.containersListData ||
|
|
79
|
+
this.imagesListData ||
|
|
80
|
+
this.servicesListData ||
|
|
81
|
+
[])
|
|
82
|
+
this.screen.render()
|
|
78
83
|
this.focus()
|
|
79
84
|
})
|
|
80
85
|
}
|
|
@@ -45,7 +45,7 @@ class myWidget extends ListWidget {
|
|
|
45
45
|
let filteredContainersList = this.containersListData[0]
|
|
46
46
|
let containersList = this.containersListData.slice(1)
|
|
47
47
|
let filteredContainers = []
|
|
48
|
-
|
|
48
|
+
const headerRow = this.containersListData[0]
|
|
49
49
|
if (data) {
|
|
50
50
|
filteredContainers = containersList.filter((container, index, containerItems) => {
|
|
51
51
|
const containerName = container[1]
|
|
@@ -56,12 +56,19 @@ class myWidget extends ListWidget {
|
|
|
56
56
|
}
|
|
57
57
|
})
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
// Render filtered services if available; otherwise, it means either the user hasn't provided input or no matches were found.
|
|
60
60
|
if (filteredContainers.length > 0) {
|
|
61
61
|
filteredContainers.unshift(filteredContainersList)
|
|
62
62
|
this.update(filteredContainers)
|
|
63
63
|
} else {
|
|
64
|
-
|
|
64
|
+
if (data.length > 0) {
|
|
65
|
+
this.update([
|
|
66
|
+
headerRow,
|
|
67
|
+
['', 'No containers found matching: ' + data, '', '', '', '', '']
|
|
68
|
+
])
|
|
69
|
+
} else {
|
|
70
|
+
this.update(this.containersListData)
|
|
71
|
+
}
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
|
|
@@ -75,8 +82,8 @@ class myWidget extends ListWidget {
|
|
|
75
82
|
const containerList = {}
|
|
76
83
|
if (containers) {
|
|
77
84
|
containers.forEach((container) => {
|
|
78
|
-
let containerPortPublic = (container.Ports[0] && container.Ports[0].PublicPort) ? String(container.Ports[0].PublicPort) : ''
|
|
79
|
-
let containerPortPrivate = (container.Ports[0] && container.Ports[0].PrivatePort) ? String(container.Ports[0].PrivatePort) : ''
|
|
85
|
+
let containerPortPublic = (container.Ports && container.Ports[0] && container.Ports[0].PublicPort) ? String(container.Ports[0].PublicPort) : ''
|
|
86
|
+
let containerPortPrivate = (container.Ports && container.Ports[0] && container.Ports[0].PrivatePort) ? String(container.Ports[0].PrivatePort) : ''
|
|
80
87
|
let containerPort = containerPortPrivate + ':' + containerPortPublic
|
|
81
88
|
|
|
82
89
|
containerList[container.Id] = [
|
|
@@ -20,6 +20,7 @@ class myWidget extends ListWidget {
|
|
|
20
20
|
let imageTitleList = this.imagesListData[0]
|
|
21
21
|
let imageList = this.imagesListData.slice(1)
|
|
22
22
|
let filteredimages = []
|
|
23
|
+
const headerRow = this.imagesListData[0]
|
|
23
24
|
|
|
24
25
|
if (data) {
|
|
25
26
|
filteredimages = imageList.filter((container, index, containerItems) => {
|
|
@@ -31,12 +32,19 @@ class myWidget extends ListWidget {
|
|
|
31
32
|
}
|
|
32
33
|
})
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
+
// Render filtered services if available; otherwise, it means either the user hasn't provided input or no matches were found.
|
|
35
36
|
if (filteredimages.length > 0) {
|
|
36
37
|
filteredimages.unshift(imageTitleList)
|
|
37
38
|
this.update(filteredimages)
|
|
38
39
|
} else {
|
|
39
|
-
|
|
40
|
+
if (data.length > 0) {
|
|
41
|
+
this.update([
|
|
42
|
+
headerRow,
|
|
43
|
+
['', 'No Images found matching: ' + data, '', '', '', '', '']
|
|
44
|
+
])
|
|
45
|
+
} else {
|
|
46
|
+
this.update(this.imagesListData)
|
|
47
|
+
}
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
|
|
@@ -64,8 +64,13 @@ class myWidget extends baseWidget(EventEmitter) {
|
|
|
64
64
|
this.inputValue = []
|
|
65
65
|
this.widget.destroy()
|
|
66
66
|
this.emit('exitSearch')
|
|
67
|
+
this.screen.remove(this.widget)
|
|
68
|
+
this.screen.render()
|
|
67
69
|
} else {
|
|
68
|
-
|
|
70
|
+
const searchText = this.captureText(key)
|
|
71
|
+
this.widget.setValue(searchText)
|
|
72
|
+
this.emit('keypress', searchText)
|
|
73
|
+
this.screen.render()
|
|
69
74
|
}
|
|
70
75
|
})
|
|
71
76
|
|
|
@@ -86,12 +91,11 @@ class myWidget extends baseWidget(EventEmitter) {
|
|
|
86
91
|
// by default, remove this widget from the screen
|
|
87
92
|
this.screen.remove(this.widget)
|
|
88
93
|
}
|
|
89
|
-
|
|
90
94
|
getWidget () {
|
|
91
95
|
return this.grid.gridObj.set(...this.grid.gridLayout, this.blessed.textbox, {
|
|
92
|
-
focused:
|
|
96
|
+
focused: true,
|
|
93
97
|
border: 'line',
|
|
94
|
-
style: this.getWidgetStyle(
|
|
98
|
+
style: this.getWidgetStyle(),
|
|
95
99
|
align: 'left',
|
|
96
100
|
inputOnFocus: true,
|
|
97
101
|
vi: true,
|
|
@@ -32,23 +32,30 @@ class myWidget extends ListWidget {
|
|
|
32
32
|
let filteredContainersList = this.servicesListData[0]
|
|
33
33
|
let serviceList = this.servicesListData.slice(1)
|
|
34
34
|
let filteredServices = []
|
|
35
|
+
const headerRow = this.servicesListData[0]
|
|
35
36
|
|
|
36
37
|
if (data) {
|
|
37
38
|
filteredServices = serviceList.filter((service) => {
|
|
38
39
|
const serviceName = service[1]
|
|
39
40
|
const serviceImageName = service[2]
|
|
40
|
-
|
|
41
41
|
if ((serviceName.indexOf(data) !== -1) || (serviceImageName.indexOf(data) !== -1)) {
|
|
42
42
|
return true
|
|
43
43
|
}
|
|
44
44
|
})
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
// Render filtered services if available; otherwise, it means either the user hasn't provided input or no matches were found.
|
|
47
47
|
if (filteredServices.length > 0) {
|
|
48
48
|
filteredServices.unshift(filteredContainersList)
|
|
49
49
|
this.update(filteredServices)
|
|
50
50
|
} else {
|
|
51
|
-
|
|
51
|
+
if (data.length > 0) {
|
|
52
|
+
this.update([
|
|
53
|
+
headerRow,
|
|
54
|
+
['', 'No Services found matching: ' + data, '', '', '', '', '']
|
|
55
|
+
])
|
|
56
|
+
} else {
|
|
57
|
+
this.update(this.servicesListData)
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
|