websocket-text-relay 1.1.4 → 1.1.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/changelog.md +4 -0
- package/docs/code-structure.md +15 -11
- package/eslint.config.js +5 -1
- package/package.json +9 -9
- package/src/ui/css/main.css +22 -78
- package/src/ui/favicon.png +0 -0
- package/src/ui/index.html +19 -14
- package/src/ui/js/components/activityLabels.js +41 -0
- package/src/ui/js/components/activityTimeSeries.js +58 -0
- package/src/ui/js/components/drawSessionLabel.js +117 -0
- package/src/ui/js/components/footerStatus.js +37 -0
- package/src/ui/js/components/headers.js +100 -0
- package/src/ui/js/components/sessionWedges.js +96 -0
- package/src/ui/js/components/statusRing.js +51 -0
- package/src/ui/js/data/wtrActivity.js +85 -0
- package/src/ui/js/data/wtrActivity.types.js +3 -0
- package/src/ui/js/data/wtrStatus.js +134 -0
- package/src/ui/js/data/wtrStatus.types.js +61 -0
- package/src/ui/js/{util → setup}/EventEmitter.js +5 -1
- package/src/ui/js/{util → setup}/WebsocketClient.js +1 -4
- package/src/ui/js/setup/dependencyManager.js +9 -0
- package/src/ui/js/setup/evalOnChange.js +18 -0
- package/src/ui/js/setup/eventSubscriber.js +21 -0
- package/src/ui/js/setup.js +141 -0
- package/src/ui/js/util/constants.js +5 -1
- package/src/ui/js/util/drawing.js +26 -76
- package/src/websocket-interface/httpServer.js +1 -1
- package/src/ui/js/components/ActivityTimeseriesGraph.js +0 -194
- package/src/ui/js/components/HeaderSummary.js +0 -22
- package/src/ui/js/components/ServerStatus.js +0 -43
- package/src/ui/js/components/SessionLabels.js +0 -319
- package/src/ui/js/components/SessionWedges.js +0 -127
- package/src/ui/js/components/StatusRing.js +0 -54
- package/src/ui/js/components/grids.js +0 -36
- package/src/ui/js/index.js +0 -121
- package/src/ui/js/main.js +0 -128
- package/src/ui/js/util/DependencyManager.js +0 -31
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
exportDeps,
|
|
3
|
-
polarToCartesian,
|
|
4
|
-
coordsToPathData,
|
|
5
|
-
drawLinearPath,
|
|
6
|
-
drawCircle,
|
|
7
|
-
drawText,
|
|
8
|
-
drawSvgElement,
|
|
9
|
-
drawToolTip,
|
|
10
|
-
} = window.__WTR__
|
|
11
|
-
|
|
12
|
-
// a value with a colored circle and tooltip
|
|
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
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// similar to summary value, but with an update function that automatically handles moving the circle on the left as the text size changes
|
|
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
|
-
})
|
|
54
|
-
const xDiff = textElement.getBBox().width
|
|
55
|
-
const labelCircle = drawCircle({
|
|
56
|
-
cx: x - xDiff,
|
|
57
|
-
cy: y - 0.0032,
|
|
58
|
-
r: summaryCircleRadius,
|
|
59
|
-
className: circleClass,
|
|
60
|
-
parentNode: tooltipWrapperGroup,
|
|
61
|
-
})
|
|
62
|
-
const update = (value) => {
|
|
63
|
-
textElement.textContent = value
|
|
64
|
-
const xDiff = textElement.getBBox().width
|
|
65
|
-
labelCircle.setAttribute("cx", x - xDiff)
|
|
66
|
-
}
|
|
67
|
-
return { textElement, update }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const underlinePadding = 0.01
|
|
71
|
-
const summaryCircleRadius = 0.014
|
|
72
|
-
const summaryLeftPadding = 0.03
|
|
73
|
-
const summaryValueSpacing = 0.065
|
|
74
|
-
const editorSummaryPadding = 0.025
|
|
75
|
-
|
|
76
|
-
const addPadding = ({ x, y, height, width }, horizontalPadding, verticalPadding) => {
|
|
77
|
-
if (verticalPadding == null) {
|
|
78
|
-
verticalPadding = horizontalPadding
|
|
79
|
-
}
|
|
80
|
-
x -= horizontalPadding
|
|
81
|
-
width += horizontalPadding * 2
|
|
82
|
-
y -= verticalPadding
|
|
83
|
-
height += verticalPadding * 2
|
|
84
|
-
return { x, y, height, width }
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const labelLineDistance = 0.07
|
|
88
|
-
|
|
89
|
-
class ClientLabel {
|
|
90
|
-
constructor({ wedgeCenterAngle, wedgeCenterRadius, parentNode }) {
|
|
91
|
-
this.parentNode = parentNode
|
|
92
|
-
this.wedgeCenterAngle = wedgeCenterAngle
|
|
93
|
-
this.wedgeCenterRadius = wedgeCenterRadius
|
|
94
|
-
this.wedgeCenter = polarToCartesian(this.wedgeCenterAngle, this.wedgeCenterRadius)
|
|
95
|
-
this.draw()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
draw() {
|
|
99
|
-
const textStart = polarToCartesian(this.wedgeCenterAngle, this.wedgeCenterRadius + labelLineDistance)
|
|
100
|
-
|
|
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
|
-
})
|
|
115
|
-
|
|
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
|
-
})
|
|
123
|
-
|
|
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
|
-
})
|
|
135
|
-
|
|
136
|
-
const summaryMidY = textBbox.y + textBbox.height + underlinePadding + summaryCircleRadius / 2 + 0.02
|
|
137
|
-
const summaryStartX = textBbox.x + summaryLeftPadding
|
|
138
|
-
this.watchedCountElement = drawSummaryValue({
|
|
139
|
-
x: summaryStartX,
|
|
140
|
-
y: summaryMidY,
|
|
141
|
-
label: "Watched Files",
|
|
142
|
-
circleClass: "summary_watched_circle",
|
|
143
|
-
parentNode: this.parentNode,
|
|
144
|
-
})
|
|
145
|
-
const watchedCountBbox = this.watchedCountElement.getBBox()
|
|
146
|
-
|
|
147
|
-
const xDiff = summaryValueSpacing + watchedCountBbox.width
|
|
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
|
-
})
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
update(client) {
|
|
163
|
-
let { name } = client
|
|
164
|
-
if (!name || name.length === 0) {
|
|
165
|
-
name = "."
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (name.length > 14) {
|
|
169
|
-
const halfIndex = Math.floor(name.length / 2)
|
|
170
|
-
const nameFirstHalf = name.substring(0, halfIndex)
|
|
171
|
-
const nameSecondHalf = name.substring(halfIndex, name.length)
|
|
172
|
-
this.topNameElement.textContent = nameFirstHalf
|
|
173
|
-
this.nameTextElement.textContent = nameSecondHalf
|
|
174
|
-
this.nameTextElement.classList.add("small_text")
|
|
175
|
-
} else {
|
|
176
|
-
this.topNameElement.innerHTML = ""
|
|
177
|
-
this.nameTextElement.classList.remove("small_text")
|
|
178
|
-
this.nameTextElement.textContent = name
|
|
179
|
-
}
|
|
180
|
-
|
|
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
|
-
]
|
|
187
|
-
const newUnderlinePathData = coordsToPathData(underlineCoords)
|
|
188
|
-
this.underlinePath.setAttribute("d", newUnderlinePathData)
|
|
189
|
-
|
|
190
|
-
this.watchedCountElement.textContent = client.watchCount
|
|
191
|
-
this.activeCountElement.textContent = client.activeWatchCount
|
|
192
|
-
|
|
193
|
-
const xDiff = summaryValueSpacing + this.watchedCountElement.getBBox().width
|
|
194
|
-
this.activeCountTranslateWrapper.setAttribute("transform", `translate(${xDiff}, 0)`)
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
class EditorLabel {
|
|
199
|
-
constructor({ wedgeCenterAngle, wedgeCenterRadius, parentNode }) {
|
|
200
|
-
this.parentNode = parentNode
|
|
201
|
-
this.wedgeCenterAngle = wedgeCenterAngle
|
|
202
|
-
this.wedgeCenterRadius = wedgeCenterRadius
|
|
203
|
-
this.wedgeCenter = polarToCartesian(this.wedgeCenterAngle, this.wedgeCenterRadius)
|
|
204
|
-
this.draw()
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
draw() {
|
|
208
|
-
const textStart = polarToCartesian(this.wedgeCenterAngle, this.wedgeCenterRadius + labelLineDistance)
|
|
209
|
-
|
|
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
|
-
})
|
|
226
|
-
|
|
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
|
-
})
|
|
234
|
-
|
|
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
|
-
})
|
|
246
|
-
|
|
247
|
-
const summaryStartX = textBbox.x + textBbox.width - summaryLeftPadding
|
|
248
|
-
const summaryMidY = textBbox.y + textBbox.height + underlinePadding * 3 + summaryCircleRadius / 2
|
|
249
|
-
|
|
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
|
-
})
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
update(editor) {
|
|
276
|
-
let { name } = editor
|
|
277
|
-
if (!name || name.length === 0) {
|
|
278
|
-
name = "."
|
|
279
|
-
} else if (name === "Visual Studio Code") {
|
|
280
|
-
name = "VSCode"
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (editor.isServer) {
|
|
284
|
-
name = "* " + name
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (name.length > 14) {
|
|
288
|
-
const halfIndex = Math.floor(name.length / 2)
|
|
289
|
-
const nameFirstHalf = name.substring(0, halfIndex)
|
|
290
|
-
const nameSecondHalf = name.substring(halfIndex, name.length)
|
|
291
|
-
this.topNameElement.textContent = nameFirstHalf
|
|
292
|
-
this.nameTextElement.textContent = nameSecondHalf
|
|
293
|
-
this.nameTextElement.classList.add("small_text")
|
|
294
|
-
} else {
|
|
295
|
-
this.topNameElement.innerHTML = ""
|
|
296
|
-
this.nameTextElement.classList.remove("small_text")
|
|
297
|
-
this.nameTextElement.textContent = name
|
|
298
|
-
}
|
|
299
|
-
|
|
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
|
-
]
|
|
306
|
-
const newUnderlinePathData = coordsToPathData(underlineCoords)
|
|
307
|
-
this.underlinePath.setAttribute("d", newUnderlinePathData)
|
|
308
|
-
|
|
309
|
-
this.activeCountSummaryValue.update(editor.activeOpenCount)
|
|
310
|
-
this.openCountSummaryValue.update(editor.openCount)
|
|
311
|
-
const xDiff =
|
|
312
|
-
this.activeCountSummaryValue.textElement.getBBox().width +
|
|
313
|
-
summaryCircleRadius +
|
|
314
|
-
editorSummaryPadding * 2
|
|
315
|
-
this.openFilesTransformGroup.setAttribute("transform", `translate(${-xDiff})`)
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
exportDeps({ ClientLabel, EditorLabel })
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
const { exportDeps, drawSvgElement, drawWedge } = window.__WTR__
|
|
2
|
-
|
|
3
|
-
const numWedges = 5
|
|
4
|
-
const wedgeSpacing = 0.01
|
|
5
|
-
const wedgeWidth = 0.08
|
|
6
|
-
|
|
7
|
-
const flashAnimationKeyframes = [{ fill: "#fff" }, { fill: "var(--wedge-active-color)" }]
|
|
8
|
-
const flashAnimationProps = { duration: 250, easing: "ease-out", iterations: 1 }
|
|
9
|
-
|
|
10
|
-
const createSessionSummary = (sessions) => {
|
|
11
|
-
const summary = {
|
|
12
|
-
name: `${sessions.length - numWedges + 1} others...`,
|
|
13
|
-
watchCount: 0,
|
|
14
|
-
activeWatchCount: 0,
|
|
15
|
-
openCount: 0,
|
|
16
|
-
activeOpenCount: 0,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
for (let i = numWedges - 1; i < sessions.length; i++) {
|
|
20
|
-
const session = sessions[i]
|
|
21
|
-
summary.watchCount += session.watchCount
|
|
22
|
-
summary.activeWatchCount += session.activeWatchCount
|
|
23
|
-
summary.openCount += session.openCount
|
|
24
|
-
summary.activeOpenCount += session.activeOpenCount
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return summary
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
class SessionWedges {
|
|
31
|
-
constructor({ outerRingRadius, outerArcSize, direction = 1, Label, parentNode }) {
|
|
32
|
-
this.outerRingRadius = outerRingRadius
|
|
33
|
-
this.outerArcSize = outerArcSize
|
|
34
|
-
this.parentNode = parentNode
|
|
35
|
-
this.direction = direction
|
|
36
|
-
this.Label = Label
|
|
37
|
-
this.draw()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
draw() {
|
|
41
|
-
this.parentNode.innerHTML = ""
|
|
42
|
-
this.wedgeNodes = []
|
|
43
|
-
const totalStartAngle = 0.25 + (this.direction * this.outerArcSize) / 2
|
|
44
|
-
const totalAngleDelta = 0.5 - this.outerArcSize - wedgeSpacing
|
|
45
|
-
const wedgeAngleDelta = totalAngleDelta / numWedges - wedgeSpacing
|
|
46
|
-
const innerRadius = this.outerRingRadius - wedgeWidth / 2
|
|
47
|
-
for (let i = 0; i < numWedges; i++) {
|
|
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
|
|
56
|
-
if (this.direction === -1) {
|
|
57
|
-
startAngle -= wedgeAngleDelta
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const wedge = drawWedge({
|
|
61
|
-
startAngle,
|
|
62
|
-
angleDelta: wedgeAngleDelta,
|
|
63
|
-
innerRadius,
|
|
64
|
-
radiusDelta: wedgeWidth,
|
|
65
|
-
className: "wedge_node",
|
|
66
|
-
parentNode: group,
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const wedgeCenterAngle = startAngle + wedgeAngleDelta / 2
|
|
70
|
-
const label = new this.Label({
|
|
71
|
-
wedgeCenterAngle,
|
|
72
|
-
wedgeCenterRadius: this.outerRingRadius,
|
|
73
|
-
parentNode: group,
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
this.wedgeNodes.push({ group, label, wedge })
|
|
77
|
-
}
|
|
78
|
-
this.drawCalled = true
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
update(sessions) {
|
|
82
|
-
this.sessionsData = sessions
|
|
83
|
-
for (let i = 0; i < numWedges; i++) {
|
|
84
|
-
const { group, label } = this.wedgeNodes[i]
|
|
85
|
-
group.classList.remove("active", "online")
|
|
86
|
-
let session = sessions[i]
|
|
87
|
-
if (!session) {
|
|
88
|
-
continue
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (i === numWedges - 1 && sessions.length > numWedges) {
|
|
92
|
-
session = createSessionSummary(sessions)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (session.activeWatchCount > 0 || session.activeOpenCount > 0) {
|
|
96
|
-
group.classList.add("active")
|
|
97
|
-
} else {
|
|
98
|
-
group.classList.add("online")
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
label.update(session)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
triggerActivity(sessionIds) {
|
|
106
|
-
const sessions = this.sessionsData
|
|
107
|
-
if (!sessions) {
|
|
108
|
-
return
|
|
109
|
-
}
|
|
110
|
-
for (let i = 0; i < numWedges; i++) {
|
|
111
|
-
const { wedge } = this.wedgeNodes[i]
|
|
112
|
-
const session = sessions[i]
|
|
113
|
-
if (!session) {
|
|
114
|
-
continue
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
(typeof sessionIds === "number" && session.id === sessionIds) ||
|
|
119
|
-
(sessionIds.has && sessionIds.has(session.id))
|
|
120
|
-
) {
|
|
121
|
-
wedge.animate(flashAnimationKeyframes, flashAnimationProps)
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
exportDeps({ SessionWedges })
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
const { exportDeps, drawCircle, drawWedge } = window.__WTR__
|
|
2
|
-
|
|
3
|
-
class StatusRing {
|
|
4
|
-
constructor({ innerRingRadius, outerRingRadius, outerArcSize, parentNode }) {
|
|
5
|
-
this.innerRingRadius = innerRingRadius
|
|
6
|
-
this.outerRingRadius = outerRingRadius
|
|
7
|
-
this.outerArcSize = outerArcSize
|
|
8
|
-
this.parentNode = parentNode
|
|
9
|
-
this.draw()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
draw() {
|
|
13
|
-
this.parentNode.innerHTML = ""
|
|
14
|
-
this.parentNode.classList.remove(...this.parentNode.classList)
|
|
15
|
-
this.currentClassName = "offline"
|
|
16
|
-
this.parentNode.classList.add(this.currentClassName)
|
|
17
|
-
|
|
18
|
-
drawCircle({ cx: 0, cy: 0, r: this.innerRingRadius, parentNode: this.parentNode })
|
|
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
|
-
})
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
update(data) {
|
|
36
|
-
const hasActiveClient = data.clients.some((client) => client.activeWatchCount > 0)
|
|
37
|
-
let newClassName
|
|
38
|
-
if (hasActiveClient) {
|
|
39
|
-
newClassName = "active"
|
|
40
|
-
} else if (data.clients.length > 0) {
|
|
41
|
-
newClassName = "online"
|
|
42
|
-
} else {
|
|
43
|
-
newClassName = "offline"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (newClassName != this.currentClassName) {
|
|
47
|
-
this.parentNode.classList.remove(this.currentClassName)
|
|
48
|
-
this.parentNode.classList.add(newClassName)
|
|
49
|
-
this.currentClassName = newClassName
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
exportDeps({ StatusRing })
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const { exportDeps, drawLine, drawCircle, drawPolarLine } = window.__WTR__
|
|
2
|
-
|
|
3
|
-
const gridCellWidth = 0.08
|
|
4
|
-
const maxGrid = 1
|
|
5
|
-
|
|
6
|
-
const drawGrid = (parentNode) => {
|
|
7
|
-
for (let i = 0; i < maxGrid; i += gridCellWidth) {
|
|
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 })
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const radiusDiff = 0.04
|
|
17
|
-
const angleDiff = 0.025
|
|
18
|
-
|
|
19
|
-
const drawPolarGrid = (parentNode) => {
|
|
20
|
-
for (let r = 0; r <= 1.0001; r += radiusDiff) {
|
|
21
|
-
drawCircle({ cx: 0, cy: 0, r, className: "grid_line", parentNode })
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
for (let angle = 0; angle < 1; angle += angleDiff) {
|
|
25
|
-
drawPolarLine({
|
|
26
|
-
startAngle: 0,
|
|
27
|
-
startRadius: 0,
|
|
28
|
-
endAngle: angle,
|
|
29
|
-
endRadius: 1,
|
|
30
|
-
className: "grid_line",
|
|
31
|
-
parentNode,
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
exportDeps({ drawGrid, drawPolarGrid })
|
package/src/ui/js/index.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { WebsocketClient } from "./util/WebsocketClient.js"
|
|
2
|
-
import "./util/DependencyManager.js"
|
|
3
|
-
|
|
4
|
-
const { cleanupEventHandlers, statusDataEmitter } = window.__WTR__
|
|
5
|
-
|
|
6
|
-
const FILE_PREFIX = "websocket-text-relay/src/ui/"
|
|
7
|
-
const CSS_FILE = "css/main.css"
|
|
8
|
-
const cssEndsWith = FILE_PREFIX + CSS_FILE
|
|
9
|
-
|
|
10
|
-
const MAIN_JS_FILE = "js/main.js"
|
|
11
|
-
const mainJsEndsWith = FILE_PREFIX + MAIN_JS_FILE
|
|
12
|
-
|
|
13
|
-
const jsFiles = [
|
|
14
|
-
"js/util/constants.js",
|
|
15
|
-
"js/util/drawing.js",
|
|
16
|
-
"js/components/grids.js",
|
|
17
|
-
"js/components/HeaderSummary.js",
|
|
18
|
-
"js/components/StatusRing.js",
|
|
19
|
-
"js/components/SessionWedges.js",
|
|
20
|
-
"js/components/SessionLabels.js",
|
|
21
|
-
"js/components/ActivityTimeseriesGraph.js",
|
|
22
|
-
"js/components/ServerStatus.js",
|
|
23
|
-
MAIN_JS_FILE,
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
const svgRoot = document.getElementById("svg_root")
|
|
27
|
-
const cssElement = document.getElementById("main_style")
|
|
28
|
-
|
|
29
|
-
const { hostname, port, protocol } = window.location
|
|
30
|
-
const wsProtocol = protocol === "http:" ? "ws" : "wss"
|
|
31
|
-
const ws = new WebsocketClient({ port: port, host: hostname, protocol: wsProtocol })
|
|
32
|
-
|
|
33
|
-
const handleCss = (contents) => {
|
|
34
|
-
cssElement.innerText = contents
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let lastMainContents = null
|
|
38
|
-
let initFinished = false
|
|
39
|
-
const handleJs = (contents) => {
|
|
40
|
-
try {
|
|
41
|
-
eval(contents)
|
|
42
|
-
} catch (e) {
|
|
43
|
-
window._lastEvalError = e
|
|
44
|
-
console.log(e)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
ws.emitter.on("message", (message) => {
|
|
49
|
-
console.log("got emitter message", message)
|
|
50
|
-
if (message.endsWith === cssEndsWith) {
|
|
51
|
-
handleCss(message.contents)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
if (message.method === "watch-file" && message.endsWith.endsWith(".js")) {
|
|
55
|
-
if (!initFinished) {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
cleanupEventHandlers()
|
|
59
|
-
handleJs(message.contents)
|
|
60
|
-
if (message.endsWith === mainJsEndsWith) {
|
|
61
|
-
lastMainContents = message.contents
|
|
62
|
-
} else if (lastMainContents != null) {
|
|
63
|
-
handleJs(lastMainContents)
|
|
64
|
-
}
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
if (message.method === "watch-wtr-status") {
|
|
68
|
-
statusDataEmitter.emit("data", message.data)
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
if (message.method === "watch-wtr-activity") {
|
|
72
|
-
statusDataEmitter.emit("activity", message.data)
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
ws.emitter.on("socket-open", () => statusDataEmitter.emit("socket-open"))
|
|
78
|
-
ws.emitter.on("socket-close", () => statusDataEmitter.emit("socket-close"))
|
|
79
|
-
|
|
80
|
-
const initFiles = async () => {
|
|
81
|
-
await fetch(CSS_FILE)
|
|
82
|
-
.then((r) => r.text())
|
|
83
|
-
.then(handleCss)
|
|
84
|
-
const jsFetches = jsFiles.map(async (fileName) => {
|
|
85
|
-
return fetch(fileName).then((r) => r.text())
|
|
86
|
-
})
|
|
87
|
-
const jsResults = await Promise.all(jsFetches)
|
|
88
|
-
lastMainContents = jsResults.at(-1)
|
|
89
|
-
requestAnimationFrame(() => {
|
|
90
|
-
// make sure css is applied first
|
|
91
|
-
jsResults.forEach((contents) => {
|
|
92
|
-
handleJs(contents)
|
|
93
|
-
})
|
|
94
|
-
initFinished = true
|
|
95
|
-
})
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const subscribeWatchers = () => {
|
|
99
|
-
ws.sendMessage({ method: "watch-log-messages" })
|
|
100
|
-
ws.sendMessage({ method: "watch-wtr-status" })
|
|
101
|
-
ws.sendMessage({ method: "watch-wtr-activity" })
|
|
102
|
-
ws.sendMessage({ method: "init", name: "status-ui" })
|
|
103
|
-
ws.sendMessage({ method: "watch-file", endsWith: cssEndsWith })
|
|
104
|
-
jsFiles.forEach((jsFile) => {
|
|
105
|
-
const jsEndsWith = FILE_PREFIX + jsFile
|
|
106
|
-
ws.sendMessage({ method: "watch-file", endsWith: jsEndsWith })
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
await initFiles()
|
|
111
|
-
subscribeWatchers()
|
|
112
|
-
|
|
113
|
-
const updateSvgDimensions = () => {
|
|
114
|
-
svgRoot.setAttribute("height", window.innerHeight - 4)
|
|
115
|
-
svgRoot.setAttribute("width", window.innerWidth)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
updateSvgDimensions()
|
|
119
|
-
window.addEventListener("resize", () => {
|
|
120
|
-
updateSvgDimensions()
|
|
121
|
-
})
|