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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dockly",
3
- "version": "3.22.2",
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": "2.4.2",
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": "2.5.8",
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": "6.3.0"
79
+ "semver": "7.3.8"
80
80
  },
81
81
  "devDependencies": {
82
82
  "standard": "^12.0.1"
package/src/enum.js ADDED
@@ -0,0 +1,11 @@
1
+ module.exports = {
2
+ ContainerState: {
3
+ created: 'created',
4
+ restarting: 'restarting',
5
+ running: 'running',
6
+ removing: 'removing',
7
+ paused: 'paused',
8
+ exited: 'exited',
9
+ dead: 'dead'
10
+ }
11
+ }
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
- 'searchInput': [11, 0, 1, 12],
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
- 'containerLogs': [7, 0, 4, 12],
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
- 'help': [4, 4, 4, 4],
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
  }
@@ -83,6 +83,7 @@ class myWidget extends baseWidget() {
83
83
  align: 'left',
84
84
  width: '70%',
85
85
  height: '70%',
86
+ vi: true,
86
87
  top: 'center',
87
88
  left: 'center',
88
89
  content: 'Loading...'
@@ -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...'
@@ -90,6 +90,7 @@ class myWidget extends baseWidget(EventEmitter) {
90
90
  tags: true,
91
91
  interactive: true,
92
92
  border: 'line',
93
+ vi: true,
93
94
  hover: {
94
95
  bg: 'blue'
95
96
  },
@@ -42,6 +42,7 @@ class myWidget extends baseWidget(EventEmitter) {
42
42
  fg: 'blue',
43
43
  ch: '|'
44
44
  },
45
+ vi: true,
45
46
  align: 'left',
46
47
  content: ''
47
48
  })
@@ -119,7 +119,7 @@ class myWidget extends baseWidget() {
119
119
  }
120
120
 
121
121
  getWidget () {
122
- return this.grid.gridObj.set(...this.grid.gridLayout, this.blessed.list, {
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
- align: 'center'
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.unshift(['Id', 'Name', 'Image', 'Command', 'State', 'Status'])
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
- * Sort containers by their state: running, created, then exited.
141
- *
142
- * @param item left
143
- * @param item right
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
- if (a[4] === 'paused' && b[4] !== 'paused') {
152
- return -1
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)
@@ -94,6 +94,7 @@ class myWidget extends baseWidget(EventEmitter) {
94
94
  style: this.getWidgetStyle({ bg: 'yellow', fg: 'black' }),
95
95
  align: 'left',
96
96
  inputOnFocus: true,
97
+ vi: true,
97
98
  value: ''
98
99
  })
99
100
  }
@@ -74,6 +74,10 @@ class myWidget extends baseWidget(EventEmitter) {
74
74
  'menu': {
75
75
  keys: ['m'],
76
76
  callback: () => { this.emit('key', 'm') }
77
+ },
78
+ 'sort': {
79
+ keys: ['o'],
80
+ callback: () => { this.emit('key', 'o') }
77
81
  }
78
82
  }
79
83