websocket-text-relay 1.1.2 → 1.1.4
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/.prettierignore +3 -0
- package/.prettierrc +4 -0
- package/changelog.md +11 -0
- package/docs/code-structure.md +1 -1
- package/eslint.config.js +28 -0
- package/package.json +15 -10
- package/{index.js → src/index.js} +25 -23
- package/src/language-server/JsonRpcInterface.js +59 -29
- package/src/language-server/JsonRpcInterface.test.js +102 -72
- package/src/language-server/LspReader.js +30 -20
- package/src/language-server/LspReader.test.js +147 -65
- package/src/language-server/LspWriter.js +5 -5
- package/src/language-server/LspWriter.test.js +31 -24
- package/src/ui/css/fonts.css +0 -1
- package/src/ui/css/main.css +7 -7
- package/src/ui/index.html +4 -4
- package/src/ui/js/components/ActivityTimeseriesGraph.js +83 -32
- package/src/ui/js/components/HeaderSummary.js +11 -5
- package/src/ui/js/components/ServerStatus.js +19 -7
- package/src/ui/js/components/SessionLabels.js +197 -49
- package/src/ui/js/components/SessionWedges.js +44 -24
- package/src/ui/js/components/StatusRing.js +20 -8
- package/src/ui/js/components/grids.js +14 -7
- package/src/ui/js/index.js +23 -19
- package/src/ui/js/main.js +53 -21
- package/src/ui/js/util/DependencyManager.js +5 -5
- package/src/ui/js/util/EventEmitter.js +11 -7
- package/src/ui/js/util/WebsocketClient.js +28 -22
- package/src/ui/js/util/constants.js +2 -2
- package/src/ui/js/util/drawing.js +58 -28
- package/src/websocket-interface/WebsocketClient.js +15 -15
- package/src/websocket-interface/WebsocketInterface.js +30 -22
- package/src/websocket-interface/WtrSession.js +49 -33
- package/src/websocket-interface/httpServer.js +24 -14
- package/src/websocket-interface/sessionManager.js +16 -13
- package/src/websocket-interface/util.js +1 -1
- package/src/websocket-interface/websocketApi.js +51 -34
- package/src/websocket-interface/websocketServer.js +9 -9
- package/start.js +1 -1
- package/.eslintrc +0 -29
|
@@ -1,47 +1,93 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
exportDeps,
|
|
3
|
+
polarToCartesian,
|
|
4
|
+
coordsToPathData,
|
|
5
|
+
drawLinearPath,
|
|
6
|
+
drawCircle,
|
|
7
|
+
drawText,
|
|
8
|
+
drawSvgElement,
|
|
9
|
+
drawToolTip,
|
|
10
|
+
} = window.__WTR__
|
|
2
11
|
|
|
3
12
|
// a value with a colored circle and tooltip
|
|
4
|
-
const drawSummaryValue
|
|
5
|
-
const tooltipWrapperGroup = drawSvgElement({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
const drawSummaryValue = ({ x, y, label, circleClass, parentNode }) => {
|
|
14
|
+
const tooltipWrapperGroup = drawSvgElement({
|
|
15
|
+
tag: "g",
|
|
16
|
+
className: "tooltip_wrapper_group",
|
|
17
|
+
parent: parentNode,
|
|
18
|
+
})
|
|
19
|
+
drawCircle({
|
|
20
|
+
cx: x,
|
|
21
|
+
cy: y - 0.0032,
|
|
22
|
+
r: summaryCircleRadius,
|
|
23
|
+
className: circleClass,
|
|
24
|
+
parentNode: tooltipWrapperGroup,
|
|
25
|
+
})
|
|
26
|
+
drawToolTip({ x: x, y: y - 0.0032, text: label, parentNode: tooltipWrapperGroup })
|
|
27
|
+
return drawText({
|
|
28
|
+
x: x + summaryCircleRadius * 2,
|
|
29
|
+
y: y,
|
|
30
|
+
dominantBaseline: "middle",
|
|
31
|
+
text: "0",
|
|
32
|
+
className: "summary_text_value",
|
|
33
|
+
parentNode: tooltipWrapperGroup,
|
|
34
|
+
})
|
|
9
35
|
}
|
|
10
36
|
|
|
11
37
|
// similar to summary value, but with an update function that automatically handles moving the circle on the left as the text size changes
|
|
12
|
-
const drawRightAlignedSummaryValue
|
|
13
|
-
const tooltipWrapperGroup = drawSvgElement({
|
|
14
|
-
|
|
15
|
-
|
|
38
|
+
const drawRightAlignedSummaryValue = ({ x, y, label, circleClass, parentNode }) => {
|
|
39
|
+
const tooltipWrapperGroup = drawSvgElement({
|
|
40
|
+
tag: "g",
|
|
41
|
+
className: "tooltip_wrapper_group",
|
|
42
|
+
parent: parentNode,
|
|
43
|
+
})
|
|
44
|
+
drawToolTip({ x: x, y: y - 0.0032, text: label, parentNode: tooltipWrapperGroup })
|
|
45
|
+
const textElement = drawText({
|
|
46
|
+
x: x + summaryCircleRadius * 2,
|
|
47
|
+
y: y,
|
|
48
|
+
dominantBaseline: "middle",
|
|
49
|
+
text: "0",
|
|
50
|
+
textAnchor: "end",
|
|
51
|
+
className: "summary_text_value",
|
|
52
|
+
parentNode: tooltipWrapperGroup,
|
|
53
|
+
})
|
|
16
54
|
const xDiff = textElement.getBBox().width
|
|
17
|
-
const labelCircle = drawCircle({
|
|
55
|
+
const labelCircle = drawCircle({
|
|
56
|
+
cx: x - xDiff,
|
|
57
|
+
cy: y - 0.0032,
|
|
58
|
+
r: summaryCircleRadius,
|
|
59
|
+
className: circleClass,
|
|
60
|
+
parentNode: tooltipWrapperGroup,
|
|
61
|
+
})
|
|
18
62
|
const update = (value) => {
|
|
19
63
|
textElement.textContent = value
|
|
20
64
|
const xDiff = textElement.getBBox().width
|
|
21
65
|
labelCircle.setAttribute("cx", x - xDiff)
|
|
22
66
|
}
|
|
23
|
-
return {textElement, update}
|
|
67
|
+
return { textElement, update }
|
|
24
68
|
}
|
|
25
69
|
|
|
26
70
|
const underlinePadding = 0.01
|
|
27
|
-
const summaryCircleRadius = 0.
|
|
71
|
+
const summaryCircleRadius = 0.014
|
|
28
72
|
const summaryLeftPadding = 0.03
|
|
29
73
|
const summaryValueSpacing = 0.065
|
|
30
74
|
const editorSummaryPadding = 0.025
|
|
31
75
|
|
|
32
|
-
const addPadding = ({x, y, height, width}, horizontalPadding, verticalPadding) => {
|
|
33
|
-
if (verticalPadding == null) {
|
|
76
|
+
const addPadding = ({ x, y, height, width }, horizontalPadding, verticalPadding) => {
|
|
77
|
+
if (verticalPadding == null) {
|
|
78
|
+
verticalPadding = horizontalPadding
|
|
79
|
+
}
|
|
34
80
|
x -= horizontalPadding
|
|
35
81
|
width += horizontalPadding * 2
|
|
36
82
|
y -= verticalPadding
|
|
37
83
|
height += verticalPadding * 2
|
|
38
|
-
return {x, y, height, width}
|
|
84
|
+
return { x, y, height, width }
|
|
39
85
|
}
|
|
40
86
|
|
|
41
87
|
const labelLineDistance = 0.07
|
|
42
88
|
|
|
43
89
|
class ClientLabel {
|
|
44
|
-
constructor
|
|
90
|
+
constructor({ wedgeCenterAngle, wedgeCenterRadius, parentNode }) {
|
|
45
91
|
this.parentNode = parentNode
|
|
46
92
|
this.wedgeCenterAngle = wedgeCenterAngle
|
|
47
93
|
this.wedgeCenterRadius = wedgeCenterRadius
|
|
@@ -49,30 +95,72 @@ class ClientLabel {
|
|
|
49
95
|
this.draw()
|
|
50
96
|
}
|
|
51
97
|
|
|
52
|
-
draw
|
|
98
|
+
draw() {
|
|
53
99
|
const textStart = polarToCartesian(this.wedgeCenterAngle, this.wedgeCenterRadius + labelLineDistance)
|
|
54
100
|
|
|
55
|
-
this.topNameElement = drawText({
|
|
56
|
-
|
|
101
|
+
this.topNameElement = drawText({
|
|
102
|
+
x: textStart[0],
|
|
103
|
+
y: textStart[1] - 0.06 - underlinePadding / 2,
|
|
104
|
+
text: "",
|
|
105
|
+
className: ["wedge_identifier", "small_text"],
|
|
106
|
+
parentNode: this.parentNode,
|
|
107
|
+
})
|
|
108
|
+
this.nameTextElement = drawText({
|
|
109
|
+
x: textStart[0],
|
|
110
|
+
y: textStart[1] - 0.017 - underlinePadding / 2,
|
|
111
|
+
text: ".",
|
|
112
|
+
className: "wedge_identifier",
|
|
113
|
+
parentNode: this.parentNode,
|
|
114
|
+
})
|
|
57
115
|
|
|
58
|
-
drawCircle({
|
|
116
|
+
drawCircle({
|
|
117
|
+
cx: this.wedgeCenter[0],
|
|
118
|
+
cy: this.wedgeCenter[1],
|
|
119
|
+
r: 0.01,
|
|
120
|
+
className: "test_circle",
|
|
121
|
+
parentNode: this.parentNode,
|
|
122
|
+
})
|
|
59
123
|
|
|
60
|
-
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.
|
|
61
|
-
const underlineCoords = [
|
|
62
|
-
|
|
124
|
+
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.0, underlinePadding)
|
|
125
|
+
const underlineCoords = [
|
|
126
|
+
[this.wedgeCenter[0], this.wedgeCenter[1]],
|
|
127
|
+
[textBbox.x, textBbox.y + textBbox.height],
|
|
128
|
+
[textBbox.x + textBbox.width, textBbox.y + textBbox.height],
|
|
129
|
+
]
|
|
130
|
+
this.underlinePath = drawLinearPath({
|
|
131
|
+
coords: underlineCoords,
|
|
132
|
+
className: "test_line",
|
|
133
|
+
parentNode: this.parentNode,
|
|
134
|
+
})
|
|
63
135
|
|
|
64
136
|
const summaryMidY = textBbox.y + textBbox.height + underlinePadding + summaryCircleRadius / 2 + 0.02
|
|
65
137
|
const summaryStartX = textBbox.x + summaryLeftPadding
|
|
66
|
-
this.watchedCountElement = drawSummaryValue({
|
|
138
|
+
this.watchedCountElement = drawSummaryValue({
|
|
139
|
+
x: summaryStartX,
|
|
140
|
+
y: summaryMidY,
|
|
141
|
+
label: "Watched Files",
|
|
142
|
+
circleClass: "summary_watched_circle",
|
|
143
|
+
parentNode: this.parentNode,
|
|
144
|
+
})
|
|
67
145
|
const watchedCountBbox = this.watchedCountElement.getBBox()
|
|
68
146
|
|
|
69
147
|
const xDiff = summaryValueSpacing + watchedCountBbox.width
|
|
70
|
-
this.activeCountTranslateWrapper = drawSvgElement({
|
|
71
|
-
|
|
148
|
+
this.activeCountTranslateWrapper = drawSvgElement({
|
|
149
|
+
tag: "g",
|
|
150
|
+
attributes: { transform: `translate(${xDiff}, 0)` },
|
|
151
|
+
parent: this.parentNode,
|
|
152
|
+
})
|
|
153
|
+
this.activeCountElement = drawSummaryValue({
|
|
154
|
+
x: summaryStartX,
|
|
155
|
+
y: summaryMidY,
|
|
156
|
+
label: "Active Files",
|
|
157
|
+
circleClass: "summary_active_circle",
|
|
158
|
+
parentNode: this.activeCountTranslateWrapper,
|
|
159
|
+
})
|
|
72
160
|
}
|
|
73
161
|
|
|
74
|
-
update
|
|
75
|
-
let {name} = client
|
|
162
|
+
update(client) {
|
|
163
|
+
let { name } = client
|
|
76
164
|
if (!name || name.length === 0) {
|
|
77
165
|
name = "."
|
|
78
166
|
}
|
|
@@ -90,8 +178,12 @@ class ClientLabel {
|
|
|
90
178
|
this.nameTextElement.textContent = name
|
|
91
179
|
}
|
|
92
180
|
|
|
93
|
-
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.
|
|
94
|
-
const underlineCoords = [
|
|
181
|
+
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.0, underlinePadding)
|
|
182
|
+
const underlineCoords = [
|
|
183
|
+
[this.wedgeCenter[0], this.wedgeCenter[1]],
|
|
184
|
+
[textBbox.x, textBbox.y + textBbox.height],
|
|
185
|
+
[textBbox.x + textBbox.width, textBbox.y + textBbox.height],
|
|
186
|
+
]
|
|
95
187
|
const newUnderlinePathData = coordsToPathData(underlineCoords)
|
|
96
188
|
this.underlinePath.setAttribute("d", newUnderlinePathData)
|
|
97
189
|
|
|
@@ -104,7 +196,7 @@ class ClientLabel {
|
|
|
104
196
|
}
|
|
105
197
|
|
|
106
198
|
class EditorLabel {
|
|
107
|
-
constructor
|
|
199
|
+
constructor({ wedgeCenterAngle, wedgeCenterRadius, parentNode }) {
|
|
108
200
|
this.parentNode = parentNode
|
|
109
201
|
this.wedgeCenterAngle = wedgeCenterAngle
|
|
110
202
|
this.wedgeCenterRadius = wedgeCenterRadius
|
|
@@ -112,31 +204,80 @@ class EditorLabel {
|
|
|
112
204
|
this.draw()
|
|
113
205
|
}
|
|
114
206
|
|
|
115
|
-
draw
|
|
207
|
+
draw() {
|
|
116
208
|
const textStart = polarToCartesian(this.wedgeCenterAngle, this.wedgeCenterRadius + labelLineDistance)
|
|
117
209
|
|
|
118
|
-
this.topNameElement = drawText({
|
|
119
|
-
|
|
210
|
+
this.topNameElement = drawText({
|
|
211
|
+
x: textStart[0],
|
|
212
|
+
y: textStart[1] - 0.06 - underlinePadding / 2,
|
|
213
|
+
text: "",
|
|
214
|
+
textAnchor: "end",
|
|
215
|
+
className: ["wedge_identifier", "small_text"],
|
|
216
|
+
parentNode: this.parentNode,
|
|
217
|
+
})
|
|
218
|
+
this.nameTextElement = drawText({
|
|
219
|
+
x: textStart[0],
|
|
220
|
+
y: textStart[1] - 0.017 - underlinePadding / 2,
|
|
221
|
+
text: ".",
|
|
222
|
+
textAnchor: "end",
|
|
223
|
+
className: "wedge_identifier",
|
|
224
|
+
parentNode: this.parentNode,
|
|
225
|
+
})
|
|
120
226
|
|
|
121
|
-
drawCircle({
|
|
227
|
+
drawCircle({
|
|
228
|
+
cx: this.wedgeCenter[0],
|
|
229
|
+
cy: this.wedgeCenter[1],
|
|
230
|
+
r: 0.01,
|
|
231
|
+
className: "test_circle",
|
|
232
|
+
parentNode: this.parentNode,
|
|
233
|
+
})
|
|
122
234
|
|
|
123
|
-
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.
|
|
124
|
-
const underlineCoords = [
|
|
125
|
-
|
|
235
|
+
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.0, underlinePadding)
|
|
236
|
+
const underlineCoords = [
|
|
237
|
+
[this.wedgeCenter[0], this.wedgeCenter[1]],
|
|
238
|
+
[textBbox.x, textBbox.y + textBbox.height],
|
|
239
|
+
[textBbox.x + textBbox.width, textBbox.y + textBbox.height],
|
|
240
|
+
]
|
|
241
|
+
this.underlinePath = drawLinearPath({
|
|
242
|
+
coords: underlineCoords,
|
|
243
|
+
className: "test_line",
|
|
244
|
+
parentNode: this.parentNode,
|
|
245
|
+
})
|
|
126
246
|
|
|
127
247
|
const summaryStartX = textBbox.x + textBbox.width - summaryLeftPadding
|
|
128
248
|
const summaryMidY = textBbox.y + textBbox.height + underlinePadding * 3 + summaryCircleRadius / 2
|
|
129
249
|
|
|
130
|
-
this.activeCountSummaryValue = drawRightAlignedSummaryValue({
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
250
|
+
this.activeCountSummaryValue = drawRightAlignedSummaryValue({
|
|
251
|
+
x: summaryStartX,
|
|
252
|
+
y: summaryMidY,
|
|
253
|
+
label: "Active Files",
|
|
254
|
+
circleClass: "summary_active_circle",
|
|
255
|
+
parentNode: this.parentNode,
|
|
256
|
+
})
|
|
257
|
+
const xDiff =
|
|
258
|
+
this.activeCountSummaryValue.textElement.getBBox().width +
|
|
259
|
+
summaryCircleRadius +
|
|
260
|
+
editorSummaryPadding * 2
|
|
261
|
+
this.openFilesTransformGroup = drawSvgElement({
|
|
262
|
+
tag: "g",
|
|
263
|
+
attributes: { transform: `translate(${-xDiff})` },
|
|
264
|
+
parent: this.parentNode,
|
|
265
|
+
})
|
|
266
|
+
this.openCountSummaryValue = drawRightAlignedSummaryValue({
|
|
267
|
+
x: summaryStartX,
|
|
268
|
+
y: summaryMidY,
|
|
269
|
+
label: "Open Files",
|
|
270
|
+
circleClass: "summary_watched_circle",
|
|
271
|
+
parentNode: this.openFilesTransformGroup,
|
|
272
|
+
})
|
|
134
273
|
}
|
|
135
274
|
|
|
136
|
-
update
|
|
137
|
-
let {name} = editor
|
|
275
|
+
update(editor) {
|
|
276
|
+
let { name } = editor
|
|
138
277
|
if (!name || name.length === 0) {
|
|
139
278
|
name = "."
|
|
279
|
+
} else if (name === "Visual Studio Code") {
|
|
280
|
+
name = "VSCode"
|
|
140
281
|
}
|
|
141
282
|
|
|
142
283
|
if (editor.isServer) {
|
|
@@ -156,16 +297,23 @@ class EditorLabel {
|
|
|
156
297
|
this.nameTextElement.textContent = name
|
|
157
298
|
}
|
|
158
299
|
|
|
159
|
-
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.
|
|
160
|
-
const underlineCoords = [
|
|
300
|
+
const textBbox = addPadding(this.nameTextElement.getBBox(), 0.0, underlinePadding)
|
|
301
|
+
const underlineCoords = [
|
|
302
|
+
[this.wedgeCenter[0], this.wedgeCenter[1]],
|
|
303
|
+
[textBbox.x + textBbox.width, textBbox.y + textBbox.height],
|
|
304
|
+
[textBbox.x, textBbox.y + textBbox.height],
|
|
305
|
+
]
|
|
161
306
|
const newUnderlinePathData = coordsToPathData(underlineCoords)
|
|
162
307
|
this.underlinePath.setAttribute("d", newUnderlinePathData)
|
|
163
308
|
|
|
164
309
|
this.activeCountSummaryValue.update(editor.activeOpenCount)
|
|
165
310
|
this.openCountSummaryValue.update(editor.openCount)
|
|
166
|
-
const xDiff =
|
|
311
|
+
const xDiff =
|
|
312
|
+
this.activeCountSummaryValue.textElement.getBBox().width +
|
|
313
|
+
summaryCircleRadius +
|
|
314
|
+
editorSummaryPadding * 2
|
|
167
315
|
this.openFilesTransformGroup.setAttribute("transform", `translate(${-xDiff})`)
|
|
168
316
|
}
|
|
169
317
|
}
|
|
170
318
|
|
|
171
|
-
exportDeps({ClientLabel, EditorLabel})
|
|
319
|
+
exportDeps({ ClientLabel, EditorLabel })
|
|
@@ -4,8 +4,8 @@ const numWedges = 5
|
|
|
4
4
|
const wedgeSpacing = 0.01
|
|
5
5
|
const wedgeWidth = 0.08
|
|
6
6
|
|
|
7
|
-
const flashAnimationKeyframes = [{fill: "#fff"}, {fill: "var(--wedge-active-color)"}]
|
|
8
|
-
const flashAnimationProps = {duration: 250, easing: "ease-out", iterations: 1}
|
|
7
|
+
const flashAnimationKeyframes = [{ fill: "#fff" }, { fill: "var(--wedge-active-color)" }]
|
|
8
|
+
const flashAnimationProps = { duration: 250, easing: "ease-out", iterations: 1 }
|
|
9
9
|
|
|
10
10
|
const createSessionSummary = (sessions) => {
|
|
11
11
|
const summary = {
|
|
@@ -13,8 +13,7 @@ const createSessionSummary = (sessions) => {
|
|
|
13
13
|
watchCount: 0,
|
|
14
14
|
activeWatchCount: 0,
|
|
15
15
|
openCount: 0,
|
|
16
|
-
activeOpenCount: 0
|
|
17
|
-
|
|
16
|
+
activeOpenCount: 0,
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
for (let i = numWedges - 1; i < sessions.length; i++) {
|
|
@@ -29,7 +28,7 @@ const createSessionSummary = (sessions) => {
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
class SessionWedges {
|
|
32
|
-
constructor
|
|
31
|
+
constructor({ outerRingRadius, outerArcSize, direction = 1, Label, parentNode }) {
|
|
33
32
|
this.outerRingRadius = outerRingRadius
|
|
34
33
|
this.outerArcSize = outerArcSize
|
|
35
34
|
this.parentNode = parentNode
|
|
@@ -38,36 +37,52 @@ class SessionWedges {
|
|
|
38
37
|
this.draw()
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
draw
|
|
40
|
+
draw() {
|
|
42
41
|
this.parentNode.innerHTML = ""
|
|
43
42
|
this.wedgeNodes = []
|
|
44
|
-
const totalStartAngle = 0.25 + this.direction * this.outerArcSize / 2
|
|
43
|
+
const totalStartAngle = 0.25 + (this.direction * this.outerArcSize) / 2
|
|
45
44
|
const totalAngleDelta = 0.5 - this.outerArcSize - wedgeSpacing
|
|
46
|
-
const wedgeAngleDelta =
|
|
45
|
+
const wedgeAngleDelta = totalAngleDelta / numWedges - wedgeSpacing
|
|
47
46
|
const innerRadius = this.outerRingRadius - wedgeWidth / 2
|
|
48
47
|
for (let i = 0; i < numWedges; i++) {
|
|
49
|
-
const group = drawSvgElement({
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
const group = drawSvgElement({
|
|
49
|
+
tag: "g",
|
|
50
|
+
className: "single_wedge_group",
|
|
51
|
+
parent: this.parentNode,
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
let startAngle =
|
|
55
|
+
totalStartAngle + this.direction * (i + 1) * wedgeSpacing + this.direction * i * wedgeAngleDelta
|
|
52
56
|
if (this.direction === -1) {
|
|
53
57
|
startAngle -= wedgeAngleDelta
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
const wedge = drawWedge({
|
|
60
|
+
const wedge = drawWedge({
|
|
61
|
+
startAngle,
|
|
62
|
+
angleDelta: wedgeAngleDelta,
|
|
63
|
+
innerRadius,
|
|
64
|
+
radiusDelta: wedgeWidth,
|
|
65
|
+
className: "wedge_node",
|
|
66
|
+
parentNode: group,
|
|
67
|
+
})
|
|
57
68
|
|
|
58
69
|
const wedgeCenterAngle = startAngle + wedgeAngleDelta / 2
|
|
59
|
-
const label = new this.Label({
|
|
70
|
+
const label = new this.Label({
|
|
71
|
+
wedgeCenterAngle,
|
|
72
|
+
wedgeCenterRadius: this.outerRingRadius,
|
|
73
|
+
parentNode: group,
|
|
74
|
+
})
|
|
60
75
|
|
|
61
|
-
this.wedgeNodes.push({group, label, wedge})
|
|
76
|
+
this.wedgeNodes.push({ group, label, wedge })
|
|
62
77
|
}
|
|
63
78
|
this.drawCalled = true
|
|
64
79
|
}
|
|
65
80
|
|
|
66
|
-
update
|
|
81
|
+
update(sessions) {
|
|
67
82
|
this.sessionsData = sessions
|
|
68
83
|
for (let i = 0; i < numWedges; i++) {
|
|
69
|
-
const {group, label} = this.wedgeNodes[i]
|
|
70
|
-
group.classList.remove(
|
|
84
|
+
const { group, label } = this.wedgeNodes[i]
|
|
85
|
+
group.classList.remove("active", "online")
|
|
71
86
|
let session = sessions[i]
|
|
72
87
|
if (!session) {
|
|
73
88
|
continue
|
|
@@ -78,30 +93,35 @@ class SessionWedges {
|
|
|
78
93
|
}
|
|
79
94
|
|
|
80
95
|
if (session.activeWatchCount > 0 || session.activeOpenCount > 0) {
|
|
81
|
-
group.classList.add(
|
|
96
|
+
group.classList.add("active")
|
|
82
97
|
} else {
|
|
83
|
-
group.classList.add(
|
|
98
|
+
group.classList.add("online")
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
label.update(session)
|
|
87
102
|
}
|
|
88
103
|
}
|
|
89
104
|
|
|
90
|
-
triggerActivity
|
|
105
|
+
triggerActivity(sessionIds) {
|
|
91
106
|
const sessions = this.sessionsData
|
|
92
|
-
if (!sessions) {
|
|
107
|
+
if (!sessions) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
93
110
|
for (let i = 0; i < numWedges; i++) {
|
|
94
|
-
const {wedge} = this.wedgeNodes[i]
|
|
111
|
+
const { wedge } = this.wedgeNodes[i]
|
|
95
112
|
const session = sessions[i]
|
|
96
113
|
if (!session) {
|
|
97
114
|
continue
|
|
98
115
|
}
|
|
99
116
|
|
|
100
|
-
if (
|
|
117
|
+
if (
|
|
118
|
+
(typeof sessionIds === "number" && session.id === sessionIds) ||
|
|
119
|
+
(sessionIds.has && sessionIds.has(session.id))
|
|
120
|
+
) {
|
|
101
121
|
wedge.animate(flashAnimationKeyframes, flashAnimationProps)
|
|
102
122
|
}
|
|
103
123
|
}
|
|
104
124
|
}
|
|
105
125
|
}
|
|
106
126
|
|
|
107
|
-
exportDeps({SessionWedges})
|
|
127
|
+
exportDeps({ SessionWedges })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { exportDeps, drawCircle, drawWedge } = window.__WTR__
|
|
2
2
|
|
|
3
3
|
class StatusRing {
|
|
4
|
-
constructor
|
|
4
|
+
constructor({ innerRingRadius, outerRingRadius, outerArcSize, parentNode }) {
|
|
5
5
|
this.innerRingRadius = innerRingRadius
|
|
6
6
|
this.outerRingRadius = outerRingRadius
|
|
7
7
|
this.outerArcSize = outerArcSize
|
|
@@ -9,19 +9,31 @@ class StatusRing {
|
|
|
9
9
|
this.draw()
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
draw
|
|
12
|
+
draw() {
|
|
13
13
|
this.parentNode.innerHTML = ""
|
|
14
14
|
this.parentNode.classList.remove(...this.parentNode.classList)
|
|
15
|
-
this.currentClassName =
|
|
15
|
+
this.currentClassName = "offline"
|
|
16
16
|
this.parentNode.classList.add(this.currentClassName)
|
|
17
17
|
|
|
18
18
|
drawCircle({ cx: 0, cy: 0, r: this.innerRingRadius, parentNode: this.parentNode })
|
|
19
|
-
drawWedge({
|
|
20
|
-
|
|
19
|
+
drawWedge({
|
|
20
|
+
startAngle: 0.25 - this.outerArcSize / 2,
|
|
21
|
+
angleDelta: this.outerArcSize,
|
|
22
|
+
innerRadius: this.outerRingRadius,
|
|
23
|
+
radiusDelta: 0,
|
|
24
|
+
parentNode: this.parentNode,
|
|
25
|
+
})
|
|
26
|
+
drawWedge({
|
|
27
|
+
startAngle: 0.75 - this.outerArcSize / 2,
|
|
28
|
+
angleDelta: this.outerArcSize,
|
|
29
|
+
innerRadius: this.outerRingRadius,
|
|
30
|
+
radiusDelta: 0,
|
|
31
|
+
parentNode: this.parentNode,
|
|
32
|
+
})
|
|
21
33
|
}
|
|
22
34
|
|
|
23
|
-
update
|
|
24
|
-
const hasActiveClient = data.clients.some(client => client.activeWatchCount > 0)
|
|
35
|
+
update(data) {
|
|
36
|
+
const hasActiveClient = data.clients.some((client) => client.activeWatchCount > 0)
|
|
25
37
|
let newClassName
|
|
26
38
|
if (hasActiveClient) {
|
|
27
39
|
newClassName = "active"
|
|
@@ -39,4 +51,4 @@ class StatusRing {
|
|
|
39
51
|
}
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
exportDeps({StatusRing})
|
|
54
|
+
exportDeps({ StatusRing })
|
|
@@ -6,10 +6,10 @@ const maxGrid = 1
|
|
|
6
6
|
const drawGrid = (parentNode) => {
|
|
7
7
|
for (let i = 0; i < maxGrid; i += gridCellWidth) {
|
|
8
8
|
const className = i === 0 ? "grid_axis" : "grid_line"
|
|
9
|
-
drawLine({x1: -1, y1: i, x2: 1, y2: i, className, parentNode})
|
|
10
|
-
drawLine({x1: -1, y1: -i, x2: 1, y2: -i, className, parentNode})
|
|
11
|
-
drawLine({x1: i, y1: -1, x2: i, y2: 1, className, parentNode})
|
|
12
|
-
drawLine({x1: -i, y1: -1, x2: -i, y2: 1, className, parentNode})
|
|
9
|
+
drawLine({ x1: -1, y1: i, x2: 1, y2: i, className, parentNode })
|
|
10
|
+
drawLine({ x1: -1, y1: -i, x2: 1, y2: -i, className, parentNode })
|
|
11
|
+
drawLine({ x1: i, y1: -1, x2: i, y2: 1, className, parentNode })
|
|
12
|
+
drawLine({ x1: -i, y1: -1, x2: -i, y2: 1, className, parentNode })
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -18,12 +18,19 @@ const angleDiff = 0.025
|
|
|
18
18
|
|
|
19
19
|
const drawPolarGrid = (parentNode) => {
|
|
20
20
|
for (let r = 0; r <= 1.0001; r += radiusDiff) {
|
|
21
|
-
drawCircle({cx: 0, cy: 0, r, className: "grid_line", parentNode})
|
|
21
|
+
drawCircle({ cx: 0, cy: 0, r, className: "grid_line", parentNode })
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
for (let angle = 0; angle < 1; angle += angleDiff) {
|
|
25
|
-
drawPolarLine({
|
|
25
|
+
drawPolarLine({
|
|
26
|
+
startAngle: 0,
|
|
27
|
+
startRadius: 0,
|
|
28
|
+
endAngle: angle,
|
|
29
|
+
endRadius: 1,
|
|
30
|
+
className: "grid_line",
|
|
31
|
+
parentNode,
|
|
32
|
+
})
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
exportDeps({drawGrid, drawPolarGrid})
|
|
36
|
+
exportDeps({ drawGrid, drawPolarGrid })
|
package/src/ui/js/index.js
CHANGED
|
@@ -20,15 +20,15 @@ const jsFiles = [
|
|
|
20
20
|
"js/components/SessionLabels.js",
|
|
21
21
|
"js/components/ActivityTimeseriesGraph.js",
|
|
22
22
|
"js/components/ServerStatus.js",
|
|
23
|
-
MAIN_JS_FILE
|
|
23
|
+
MAIN_JS_FILE,
|
|
24
24
|
]
|
|
25
25
|
|
|
26
|
-
const svgRoot = document.getElementById(
|
|
27
|
-
const cssElement = document.getElementById(
|
|
26
|
+
const svgRoot = document.getElementById("svg_root")
|
|
27
|
+
const cssElement = document.getElementById("main_style")
|
|
28
28
|
|
|
29
|
-
const {hostname, port, protocol} = window.location
|
|
29
|
+
const { hostname, port, protocol } = window.location
|
|
30
30
|
const wsProtocol = protocol === "http:" ? "ws" : "wss"
|
|
31
|
-
const ws = new WebsocketClient({port: port, host: hostname, protocol: wsProtocol})
|
|
31
|
+
const ws = new WebsocketClient({ port: port, host: hostname, protocol: wsProtocol })
|
|
32
32
|
|
|
33
33
|
const handleCss = (contents) => {
|
|
34
34
|
cssElement.innerText = contents
|
|
@@ -45,14 +45,16 @@ const handleJs = (contents) => {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
ws.emitter.on(
|
|
48
|
+
ws.emitter.on("message", (message) => {
|
|
49
49
|
console.log("got emitter message", message)
|
|
50
50
|
if (message.endsWith === cssEndsWith) {
|
|
51
51
|
handleCss(message.contents)
|
|
52
52
|
return
|
|
53
53
|
}
|
|
54
|
-
if (message.method === "watch-file" && message.endsWith.endsWith(
|
|
55
|
-
if (!initFinished) {
|
|
54
|
+
if (message.method === "watch-file" && message.endsWith.endsWith(".js")) {
|
|
55
|
+
if (!initFinished) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
56
58
|
cleanupEventHandlers()
|
|
57
59
|
handleJs(message.contents)
|
|
58
60
|
if (message.endsWith === mainJsEndsWith) {
|
|
@@ -63,26 +65,29 @@ ws.emitter.on('message', (message) => {
|
|
|
63
65
|
return
|
|
64
66
|
}
|
|
65
67
|
if (message.method === "watch-wtr-status") {
|
|
66
|
-
statusDataEmitter.emit(
|
|
68
|
+
statusDataEmitter.emit("data", message.data)
|
|
67
69
|
return
|
|
68
70
|
}
|
|
69
71
|
if (message.method === "watch-wtr-activity") {
|
|
70
|
-
statusDataEmitter.emit(
|
|
72
|
+
statusDataEmitter.emit("activity", message.data)
|
|
71
73
|
return
|
|
72
74
|
}
|
|
73
75
|
})
|
|
74
76
|
|
|
75
|
-
ws.emitter.on(
|
|
76
|
-
ws.emitter.on(
|
|
77
|
+
ws.emitter.on("socket-open", () => statusDataEmitter.emit("socket-open"))
|
|
78
|
+
ws.emitter.on("socket-close", () => statusDataEmitter.emit("socket-close"))
|
|
77
79
|
|
|
78
80
|
const initFiles = async () => {
|
|
79
|
-
await fetch(CSS_FILE)
|
|
81
|
+
await fetch(CSS_FILE)
|
|
82
|
+
.then((r) => r.text())
|
|
83
|
+
.then(handleCss)
|
|
80
84
|
const jsFetches = jsFiles.map(async (fileName) => {
|
|
81
|
-
return fetch(fileName).then(r => r.text())
|
|
85
|
+
return fetch(fileName).then((r) => r.text())
|
|
82
86
|
})
|
|
83
87
|
const jsResults = await Promise.all(jsFetches)
|
|
84
88
|
lastMainContents = jsResults.at(-1)
|
|
85
|
-
requestAnimationFrame(() => {
|
|
89
|
+
requestAnimationFrame(() => {
|
|
90
|
+
// make sure css is applied first
|
|
86
91
|
jsResults.forEach((contents) => {
|
|
87
92
|
handleJs(contents)
|
|
88
93
|
})
|
|
@@ -91,16 +96,15 @@ const initFiles = async () => {
|
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
const subscribeWatchers = () => {
|
|
94
|
-
ws.sendMessage({method: "watch-log-messages"})
|
|
95
|
-
ws.sendMessage({method: "watch-wtr-status"})
|
|
96
|
-
ws.sendMessage({method: "watch-wtr-activity"})
|
|
99
|
+
ws.sendMessage({ method: "watch-log-messages" })
|
|
100
|
+
ws.sendMessage({ method: "watch-wtr-status" })
|
|
101
|
+
ws.sendMessage({ method: "watch-wtr-activity" })
|
|
97
102
|
ws.sendMessage({ method: "init", name: "status-ui" })
|
|
98
103
|
ws.sendMessage({ method: "watch-file", endsWith: cssEndsWith })
|
|
99
104
|
jsFiles.forEach((jsFile) => {
|
|
100
105
|
const jsEndsWith = FILE_PREFIX + jsFile
|
|
101
106
|
ws.sendMessage({ method: "watch-file", endsWith: jsEndsWith })
|
|
102
107
|
})
|
|
103
|
-
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
await initFiles()
|