querysub 0.634.0 → 0.635.0
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
|
@@ -532,7 +532,8 @@ async function runServerSyncLoops() {
|
|
|
532
532
|
|
|
533
533
|
console.log(magenta(`Node discovery is loaded`));
|
|
534
534
|
|
|
535
|
-
|
|
535
|
+
await runInfinitePollCallAtStart(HEARTBEAT_INTERVAL, writeHeartbeat);
|
|
536
|
+
// Delayed by a bit as it might take a little bit for our heartbeat to show up on startup, especially if we are the storage node that is supposed to store our own heartbeat.
|
|
536
537
|
delay(HEARTBEAT_INTERVAL * 5).then(() => runInfinitePoll(HEARTBEAT_INTERVAL, async function nodeDiscoverHeartbeat() {
|
|
537
538
|
// If we waited too long, other nodes might think we are dead. In which case, we SHOULD terminate.
|
|
538
539
|
if (!isNoNetwork()) {
|
|
@@ -556,8 +557,6 @@ async function runServerSyncLoops() {
|
|
|
556
557
|
ignoreErrors(NodeDiscoveryController.nodes[nodeId].addNode(getOwnNodeId()));
|
|
557
558
|
}
|
|
558
559
|
}
|
|
559
|
-
|
|
560
|
-
await writeHeartbeat();
|
|
561
560
|
}));
|
|
562
561
|
}
|
|
563
562
|
|
|
@@ -63,7 +63,8 @@ export class Table<RowT extends RowType> extends qreact.Component<TableType<RowT
|
|
|
63
63
|
return (
|
|
64
64
|
<table class={css.borderCollapse("collapse") + this.props.class}>
|
|
65
65
|
<tr class={
|
|
66
|
-
|
|
66
|
+
// Above the rows, as they hold positioned content (bars, palettes) which otherwise paints over the sticky header as it scrolls under it
|
|
67
|
+
css.position("sticky").top(0).zIndex(1)
|
|
67
68
|
+ (this.props.dark && css.hsla(0, 0, 10, 0.9))
|
|
68
69
|
+ (!this.props.dark && css.hsla(0, 0, 95, 0.9))
|
|
69
70
|
}>
|
|
@@ -17,6 +17,8 @@ const DEAD_COLOR = { h: 0, s: 0, l: 92 };
|
|
|
17
17
|
const OUTPUT_BUFFER_LIMIT = 1_000_000;
|
|
18
18
|
const OUTPUT_BUFFER_KEPT = 100_000;
|
|
19
19
|
const OUTPUT_MAX_HEIGHT = "40vh";
|
|
20
|
+
// Within this of the bottom still counts as "at the bottom", as scroll positions land a few pixels off the exact end
|
|
21
|
+
const OUTPUT_PIN_THRESHOLD_PX = 40;
|
|
20
22
|
const DETAIL_FONT_SIZE = 12;
|
|
21
23
|
const ANSI_SATURATION = 70;
|
|
22
24
|
const ANSI_LIGHTNESS = 70;
|
|
@@ -68,12 +70,27 @@ class ProcessOutput extends qreact.Component<{ record: ProcessRecord; machineNod
|
|
|
68
70
|
await stopWatchingProcessOutput({ callbackId });
|
|
69
71
|
});
|
|
70
72
|
}
|
|
73
|
+
private outputDiv: HTMLDivElement | undefined;
|
|
74
|
+
// The pane opens showing the newest output and follows it as it streams; scrolling up to read releases the pin, scrolling back down re-engages it
|
|
75
|
+
private pinnedToBottom = true;
|
|
76
|
+
componentDidUpdate() {
|
|
77
|
+
if (this.pinnedToBottom && this.outputDiv) {
|
|
78
|
+
this.outputDiv.scrollTop = this.outputDiv.scrollHeight;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
71
81
|
render() {
|
|
72
|
-
return <div
|
|
73
|
-
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
return <div
|
|
83
|
+
className={
|
|
84
|
+
css.fontFamily("monospace").whiteSpace("pre-wrap").fillWidth
|
|
85
|
+
.maxHeight(OUTPUT_MAX_HEIGHT).overflow("auto").pad2(10, 8)
|
|
86
|
+
.hsl(0, 0, 12).colorhsl(0, 0, 90)
|
|
87
|
+
}
|
|
88
|
+
ref={element => this.outputDiv = element as HTMLDivElement || undefined}
|
|
89
|
+
onScroll={element => {
|
|
90
|
+
let div = element.currentTarget;
|
|
91
|
+
this.pinnedToBottom = div.scrollHeight - div.scrollTop - div.clientHeight < OUTPUT_PIN_THRESHOLD_PX;
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
77
94
|
{parseAnsiColors(this.state.data).map(({ text, color }) => {
|
|
78
95
|
if (!color) return <span>{text}</span>;
|
|
79
96
|
// The pane is dark, so the ansi colour only sets the hue - the lightness has to stay readable against it
|
|
@@ -91,7 +91,7 @@ export class StorageLogsPage extends qreact.Component {
|
|
|
91
91
|
let listings = this.getListings();
|
|
92
92
|
let files = this.getSelectedFiles(listings).map(file => ({ url: file.url, name: file.name }));
|
|
93
93
|
let query = storageLogSearchParam.value;
|
|
94
|
-
let { startTime, endTime } = getTimeRange();
|
|
94
|
+
let { startTime, endTime, searchFromStart } = getTimeRange();
|
|
95
95
|
this.state.searching = true;
|
|
96
96
|
this.state.error = "";
|
|
97
97
|
this.state.doneFiles = 0;
|
|
@@ -126,7 +126,9 @@ export class StorageLogsPage extends qreact.Component {
|
|
|
126
126
|
rows.push({ server: file.url, file: file.name, ...fields });
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
// Ordered the way the time range UI says: from the end (newest first) by default, oldest first when searching from the start
|
|
130
|
+
let direction = searchFromStart ? 1 : -1;
|
|
131
|
+
rows.sort((a, b) => direction * ((typeof a.time === "number" && a.time || 0) - (typeof b.time === "number" && b.time || 0)));
|
|
130
132
|
Querysub.commit(() => {
|
|
131
133
|
this.state.rows = rows;
|
|
132
134
|
this.state.columns = columns;
|
|
@@ -188,7 +190,7 @@ export class StorageLogsPage extends qreact.Component {
|
|
|
188
190
|
<InputLabelURL
|
|
189
191
|
flavor="large"
|
|
190
192
|
fillWidth
|
|
191
|
-
label="Search
|
|
193
|
+
label="Search"
|
|
192
194
|
url={storageLogSearchParam}
|
|
193
195
|
onKeyDown={e => {
|
|
194
196
|
if (e.key === "Enter") {
|