querysub 0.636.0 → 0.638.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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "querysub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.638.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
80
80
|
"pako": "^2.1.0",
|
|
81
81
|
"peggy": "^5.0.6",
|
|
82
|
-
"sliftutils": "^1.7.
|
|
82
|
+
"sliftutils": "^1.7.108",
|
|
83
83
|
"socket-function": "^1.2.31",
|
|
84
84
|
"terser": "^5.31.0",
|
|
85
85
|
"typenode": "^6.6.1",
|
|
@@ -6,7 +6,7 @@ import { Querysub } from "../../../4-querysub/Querysub";
|
|
|
6
6
|
import { t } from "../../../2-proxy/schema2";
|
|
7
7
|
import { isDefined } from "../../../misc";
|
|
8
8
|
import { formatNumber, formatTime, formatDateTime } from "socket-function/src/formatting/format";
|
|
9
|
-
import { timeInSecond } from "socket-function/src/misc";
|
|
9
|
+
import { timeInMinute, timeInSecond } from "socket-function/src/misc";
|
|
10
10
|
import type { LogFileInfo } from "sliftutils/storage/StreamingLogs";
|
|
11
11
|
import { MachineServiceController } from "../../machineSchema";
|
|
12
12
|
import { getStorageServers } from "./storageServers";
|
|
@@ -163,19 +163,51 @@ export class StorageLogsPage extends qreact.Component {
|
|
|
163
163
|
return selected;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
/** fresh drops the log file listings and the per-file search cache first, so everything searched is refetched. */
|
|
167
|
+
private search(fresh?: boolean) {
|
|
167
168
|
if (this.state.searching) return;
|
|
168
|
-
// State and synced reads are captured HERE, in the tracked part, before the async work
|
|
169
|
+
// State and synced reads are captured HERE, in the tracked part, before the async work (and before the invalidation below, which would turn the listings back into loading)
|
|
169
170
|
let listings = this.getListings();
|
|
170
|
-
let
|
|
171
|
+
let cachedFiles = this.getSelectedFiles(listings).map(file => ({ url: file.url, name: file.name }));
|
|
172
|
+
let urls = listings.map(listing => listing.url);
|
|
171
173
|
let query = storageLogSearchParam.value;
|
|
172
174
|
let { startTime, endTime, searchFromStart } = getTimeRange();
|
|
175
|
+
let synced = StorageLogsSynced(SocketFunction.browserNodeId());
|
|
176
|
+
if (fresh) {
|
|
177
|
+
invalidateStorageLogSearchCache();
|
|
178
|
+
synced.getServerLogFiles.resetAll();
|
|
179
|
+
}
|
|
173
180
|
this.state.searching = true;
|
|
174
181
|
this.state.error = "";
|
|
175
182
|
this.state.doneFiles = 0;
|
|
176
|
-
this.state.totalFiles =
|
|
183
|
+
this.state.totalFiles = fresh ? 0 : cachedFiles.length;
|
|
177
184
|
this.state.currentFile = "";
|
|
185
|
+
// Cleared up front, so anything on screen during the search is never stale results from the previous one
|
|
186
|
+
this.state.rows = [];
|
|
187
|
+
this.state.fields = [];
|
|
188
|
+
this.state.failedFiles = [];
|
|
189
|
+
this.state.durationTime = 0;
|
|
190
|
+
this.state.resultsFetchTime = 0;
|
|
178
191
|
Querysub.onCommitFinished(async () => {
|
|
192
|
+
let files = cachedFiles;
|
|
193
|
+
if (fresh) {
|
|
194
|
+
// The selection has to wait for the fresh listings; a server that fails costs only its own files (its error also shows on its listing row, which refetches the same way)
|
|
195
|
+
files = [];
|
|
196
|
+
await Promise.all(urls.map(async url => {
|
|
197
|
+
try {
|
|
198
|
+
let listing = await synced.getServerLogFiles.promise(url);
|
|
199
|
+
for (let file of listing.files) {
|
|
200
|
+
if (!fileOverlapsRange(file, startTime, endTime)) continue;
|
|
201
|
+
files.push({ url, name: file.name });
|
|
202
|
+
}
|
|
203
|
+
} catch (e) {
|
|
204
|
+
console.error(`Listing log files on ${url} failed, continuing with the other servers:`, (e as Error).stack ?? e);
|
|
205
|
+
}
|
|
206
|
+
}));
|
|
207
|
+
Querysub.commit(() => {
|
|
208
|
+
this.state.totalFiles = files.length;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
179
211
|
try {
|
|
180
212
|
let result = await searchStorageLogs({
|
|
181
213
|
files,
|
|
@@ -234,7 +266,7 @@ export class StorageLogsPage extends qreact.Component {
|
|
|
234
266
|
let selectedBytes = selectedFiles.reduce((sum, file) => sum + file.size, 0);
|
|
235
267
|
let loadedListings = listings.filter(listing => listing.fetchTime);
|
|
236
268
|
let oldestListingTime = loadedListings.length && Math.min(...loadedListings.map(listing => listing.fetchTime || 0)) || 0;
|
|
237
|
-
let now = Querysub.nowDelayed(
|
|
269
|
+
let now = Querysub.nowDelayed(timeInMinute);
|
|
238
270
|
|
|
239
271
|
// Defaults show unless explicitly toggled off, plus whatever was explicitly toggled on
|
|
240
272
|
let selectedSet = new Set<string>();
|
|
@@ -328,6 +360,15 @@ export class StorageLogsPage extends qreact.Component {
|
|
|
328
360
|
>
|
|
329
361
|
{this.state.searching && `Searching ${this.state.doneFiles}/${this.state.totalFiles}...` || "Search"}
|
|
330
362
|
</Button>
|
|
363
|
+
<Button
|
|
364
|
+
flavor="large"
|
|
365
|
+
hue={120}
|
|
366
|
+
title="Invalidates the log file listings and the cached search results, then searches"
|
|
367
|
+
onClick={() => this.search(true)}
|
|
368
|
+
className={this.state.searching && css.opacity(0.5) || undefined}
|
|
369
|
+
>
|
|
370
|
+
Fresh Search
|
|
371
|
+
</Button>
|
|
331
372
|
</div>
|
|
332
373
|
<div className={css.vbox(4)}>
|
|
333
374
|
{listings.map(listing => {
|