querysub 0.326.0 → 0.328.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 +3 -4
- package/src/-a-archives/archivesBackBlaze.ts +20 -0
- package/src/-a-archives/archivesDisk.ts +5 -5
- package/src/-a-archives/archivesLimitedCache.ts +118 -7
- package/src/-a-archives/archivesPrivateFileSystem.ts +3 -0
- package/src/-g-core-values/NodeCapabilities.ts +26 -11
- package/src/0-path-value-core/auditLogs.ts +4 -2
- package/src/2-proxy/PathValueProxyWatcher.ts +3 -0
- package/src/3-path-functions/PathFunctionRunner.ts +2 -2
- package/src/4-querysub/Querysub.ts +1 -1
- package/src/5-diagnostics/GenericFormat.tsx +2 -2
- package/src/deployManager/machineApplyMainCode.ts +10 -8
- package/src/deployManager/machineSchema.ts +4 -3
- package/src/deployManager/setupMachineMain.ts +3 -2
- package/src/diagnostics/logs/FastArchiveAppendable.ts +85 -59
- package/src/diagnostics/logs/FastArchiveController.ts +5 -2
- package/src/diagnostics/logs/FastArchiveViewer.tsx +222 -51
- package/src/diagnostics/logs/LogViewer2.tsx +83 -35
- package/src/diagnostics/logs/TimeRangeSelector.tsx +8 -0
- package/src/diagnostics/logs/diskLogGlobalContext.ts +3 -3
- package/src/diagnostics/logs/diskLogger.ts +70 -23
- package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +111 -82
- package/src/diagnostics/logs/errorNotifications/ErrorSuppressionUI.tsx +37 -3
- package/src/diagnostics/logs/errorNotifications/ErrorWarning.tsx +52 -22
- package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +8 -0
- package/src/diagnostics/logs/errorNotifications/errorWatchEntry.tsx +198 -52
- package/src/diagnostics/logs/lifeCycleAnalysis/spec.md +3 -2
- package/src/diagnostics/managementPages.tsx +5 -0
- package/src/email_ims_notifications/discord.tsx +203 -0
- package/src/fs.ts +9 -0
- package/src/functional/SocketChannel.ts +9 -0
- package/src/functional/throttleRender.ts +134 -0
- package/src/library-components/ATag.tsx +2 -2
- package/src/library-components/SyncedController.ts +5 -3
- package/src/misc.ts +13 -0
- package/src/misc2.ts +54 -0
- package/src/user-implementation/SecurityPage.tsx +11 -5
- package/src/user-implementation/userData.ts +31 -16
- package/testEntry2.ts +14 -5
- package/src/user-implementation/setEmailKey.ts +0 -25
- /package/src/{email → email_ims_notifications}/postmark.tsx +0 -0
- /package/src/{email → email_ims_notifications}/sendgrid.tsx +0 -0
|
@@ -5,7 +5,7 @@ import { DatumStats, FastArchiveAppendable } from "./FastArchiveAppendable";
|
|
|
5
5
|
import { Querysub } from "../../4-querysub/Querysub";
|
|
6
6
|
import { URLParam } from "../../library-components/URLParam";
|
|
7
7
|
import { TimeRangeSelector, getTimeRange } from "./TimeRangeSelector";
|
|
8
|
-
import { formatNumber, formatTime, formatVeryNiceDateTime } from "socket-function/src/formatting/format";
|
|
8
|
+
import { formatNumber, formatTime, formatVeryNiceDateTime, formatDateTime } from "socket-function/src/formatting/format";
|
|
9
9
|
import { list, sort, throttleFunction, timeInHour } from "socket-function/src/misc";
|
|
10
10
|
import { css } from "typesafecss";
|
|
11
11
|
import { logErrors } from "../../errors";
|
|
@@ -15,22 +15,24 @@ import { ButtonSelector } from "../../library-components/ButtonSelector";
|
|
|
15
15
|
import { Button } from "../../library-components/Button";
|
|
16
16
|
import { lazy } from "socket-function/src/caching";
|
|
17
17
|
import { LOG_LIMIT_FLAG } from "./diskLogger";
|
|
18
|
-
import { canHaveChildren } from "socket-function/src/types";
|
|
18
|
+
import { MaybePromise, canHaveChildren } from "socket-function/src/types";
|
|
19
19
|
import { niceParse } from "../../niceStringify";
|
|
20
20
|
import { FileMetadata } from "./FastArchiveController";
|
|
21
|
+
import { throttleRender } from "../../functional/throttleRender";
|
|
21
22
|
|
|
22
23
|
const RENDER_INTERVAL = 1000;
|
|
23
24
|
|
|
24
25
|
const HISTOGRAM_RERENDER_INTERVAL = 10000;
|
|
25
26
|
|
|
26
27
|
export const filterParam = new URLParam("filter", "");
|
|
27
|
-
const cacheBustParam = new URLParam("cacheBust", 0);
|
|
28
|
+
export const cacheBustParam = new URLParam("cacheBust", 0);
|
|
28
29
|
const caseInsensitiveParam = new URLParam("caseInsensitive", false);
|
|
29
|
-
|
|
30
|
+
const hideAllDataParam = new URLParam("hideAllData", false);
|
|
30
31
|
|
|
31
32
|
export class FastArchiveViewer<T> extends qreact.Component<{
|
|
32
33
|
fastArchives: FastArchiveAppendable<T>[];
|
|
33
|
-
|
|
34
|
+
runOnLoad?: boolean;
|
|
35
|
+
onStart: () => MaybePromise<void>;
|
|
34
36
|
getWantData?: (file: FileMetadata) => Promise<((posStart: number, posEnd: number, data: Buffer) => boolean) | undefined>;
|
|
35
37
|
onDatums: (source: FastArchiveAppendable<T>, datums: T[], metadata: FileMetadata) => void;
|
|
36
38
|
// Called after onData
|
|
@@ -38,15 +40,24 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
38
40
|
onFinish?: () => void;
|
|
39
41
|
}> {
|
|
40
42
|
state = t.state({
|
|
43
|
+
runCount: t.atomic<number>(0),
|
|
41
44
|
// rootPath =>
|
|
42
45
|
fileMetadata: t.atomic<({
|
|
43
46
|
files: FileMetadata[];
|
|
44
47
|
createTime?: number;
|
|
45
48
|
} | undefined)[]>([]),
|
|
46
|
-
finished: t.atomic(
|
|
49
|
+
finished: t.atomic(true),
|
|
47
50
|
error: t.atomic<string | undefined>(undefined),
|
|
48
51
|
pendingSyncInitializations: t.atomic<number>(0),
|
|
49
52
|
|
|
53
|
+
// Current sync parameters - set before synchronizeData is called
|
|
54
|
+
currentSyncParams: t.atomic<{
|
|
55
|
+
filterString: string;
|
|
56
|
+
startTime: number;
|
|
57
|
+
endTime: number;
|
|
58
|
+
fastArchivePaths: string[];
|
|
59
|
+
} | undefined>(undefined),
|
|
60
|
+
|
|
50
61
|
renderSeqNum: t.atomic<number>(0),
|
|
51
62
|
});
|
|
52
63
|
|
|
@@ -108,6 +119,11 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
108
119
|
this.latestSequenceNumber = this.currentSequenceNumber;
|
|
109
120
|
const mySequenceNumber = this.currentSequenceNumber;
|
|
110
121
|
|
|
122
|
+
// Increment run count for each new run
|
|
123
|
+
Querysub.commit(() => {
|
|
124
|
+
this.state.runCount++;
|
|
125
|
+
});
|
|
126
|
+
|
|
111
127
|
// Helper function to check if this sequence number is still the latest
|
|
112
128
|
const isLatestSync = () => mySequenceNumber === this.latestSequenceNumber;
|
|
113
129
|
|
|
@@ -131,6 +147,15 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
131
147
|
|
|
132
148
|
let scannedValueCount = 0;
|
|
133
149
|
|
|
150
|
+
// Store current sync parameters BEFORE calling synchronizeData
|
|
151
|
+
ifLatest(() => {
|
|
152
|
+
this.state.currentSyncParams = {
|
|
153
|
+
filterString,
|
|
154
|
+
startTime: timeRange.startTime,
|
|
155
|
+
endTime: timeRange.endTime,
|
|
156
|
+
fastArchivePaths: fastArchives.map(archive => archive.rootPath),
|
|
157
|
+
};
|
|
158
|
+
});
|
|
134
159
|
|
|
135
160
|
ifLatest(() => {
|
|
136
161
|
this.state.error = undefined;
|
|
@@ -150,7 +175,7 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
150
175
|
|
|
151
176
|
this.histogramStartTime = timeRange.startTime - this.histogramBucketTime * 2;
|
|
152
177
|
this.histogramEndTime = timeRange.endTime + this.histogramBucketTime * 2;
|
|
153
|
-
const bucketCount = Math.ceil((this.histogramEndTime - this.histogramStartTime) / this.histogramBucketTime);
|
|
178
|
+
const bucketCount = clamp(Math.ceil((this.histogramEndTime - this.histogramStartTime) / this.histogramBucketTime), 1, 10000);
|
|
154
179
|
|
|
155
180
|
this.histogramAllDataCounts = new Float64Array(bucketCount);
|
|
156
181
|
this.histogramSelectedDataCounts = new Float64Array(bucketCount);
|
|
@@ -181,9 +206,7 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
181
206
|
}
|
|
182
207
|
};
|
|
183
208
|
try {
|
|
184
|
-
|
|
185
|
-
onStart();
|
|
186
|
-
});
|
|
209
|
+
await onStart();
|
|
187
210
|
|
|
188
211
|
const caseInsensitive = Querysub.fastRead(() => caseInsensitiveParam.value);
|
|
189
212
|
let caseInsensitiveMapping = new Uint8Array(256);
|
|
@@ -408,6 +431,39 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
408
431
|
}
|
|
409
432
|
sort(progressEntries, x => x[1].initialTime);
|
|
410
433
|
|
|
434
|
+
// Group progress bars by the text after the pipe sign
|
|
435
|
+
const groupedProgress = new Map<string, {
|
|
436
|
+
displayName: string;
|
|
437
|
+
entries: Array<[string, { section: string, value: number, max: number, initialTime: number, lastSetTime: number }]>;
|
|
438
|
+
totalValue: number;
|
|
439
|
+
totalMax: number;
|
|
440
|
+
earliestTime: number;
|
|
441
|
+
latestTime: number;
|
|
442
|
+
}>();
|
|
443
|
+
|
|
444
|
+
for (const [key, progress] of progressEntries) {
|
|
445
|
+
const pipeIndex = progress.section.indexOf("|");
|
|
446
|
+
const displayName = pipeIndex >= 0 ? progress.section.substring(pipeIndex + 1) : progress.section;
|
|
447
|
+
|
|
448
|
+
if (!groupedProgress.has(displayName)) {
|
|
449
|
+
groupedProgress.set(displayName, {
|
|
450
|
+
displayName,
|
|
451
|
+
entries: [],
|
|
452
|
+
totalValue: 0,
|
|
453
|
+
totalMax: 0,
|
|
454
|
+
earliestTime: progress.initialTime,
|
|
455
|
+
latestTime: progress.lastSetTime,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const group = groupedProgress.get(displayName)!;
|
|
460
|
+
group.entries.push([key, progress]);
|
|
461
|
+
group.totalValue += progress.value;
|
|
462
|
+
group.totalMax += progress.max;
|
|
463
|
+
group.earliestTime = Math.min(group.earliestTime, progress.initialTime);
|
|
464
|
+
group.latestTime = Math.max(group.latestTime, progress.lastSetTime);
|
|
465
|
+
}
|
|
466
|
+
|
|
411
467
|
return (
|
|
412
468
|
<div className={css.hbox(10).wrap.alignItems("start").fillWidth}>
|
|
413
469
|
{!this.state.finished && (
|
|
@@ -420,33 +476,41 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
420
476
|
Cancel
|
|
421
477
|
</div>
|
|
422
478
|
)}
|
|
423
|
-
{
|
|
424
|
-
const fraction = clamp(
|
|
479
|
+
{Array.from(groupedProgress.values()).map((group) => {
|
|
480
|
+
const fraction = clamp(group.totalMax > 0 ? (group.totalValue / group.totalMax) * 1 : 1, 0, 1);
|
|
425
481
|
let progressTime = 0;
|
|
426
|
-
if (
|
|
427
|
-
progressTime =
|
|
482
|
+
if (group.totalValue >= group.totalMax) {
|
|
483
|
+
progressTime = group.latestTime;
|
|
428
484
|
} else {
|
|
429
485
|
progressTime = getNowTime();
|
|
430
486
|
}
|
|
431
|
-
const elapsedTime = progressTime -
|
|
487
|
+
const elapsedTime = progressTime - group.earliestTime;
|
|
488
|
+
|
|
489
|
+
// Create tooltip showing breakdown by original prefix
|
|
490
|
+
const tooltipContent = group.entries.map(([key, progress]) => {
|
|
491
|
+
const pipeIndex = progress.section.indexOf("|");
|
|
492
|
+
const prefix = pipeIndex >= 0 ? progress.section.substring(0, pipeIndex) : key;
|
|
493
|
+
return `${prefix}: ${formatNumber(progress.value)}/${formatNumber(progress.max)}`;
|
|
494
|
+
}).join("\n");
|
|
432
495
|
|
|
433
496
|
return (
|
|
434
|
-
<div key={
|
|
497
|
+
<div key={group.displayName} className={
|
|
435
498
|
// NOTE: There is no point making this proportionally to the time, because we stream the data, so the time overlaps, making everything take most of the time.
|
|
436
499
|
css.vbox(4)
|
|
437
|
-
}
|
|
500
|
+
}
|
|
501
|
+
title={tooltipContent}
|
|
502
|
+
>
|
|
438
503
|
<div className={css.vbox(2)}>
|
|
439
504
|
<div className={css.fontSize(14).colorhsl(0, 0, 20)}>
|
|
440
|
-
{
|
|
505
|
+
{group.displayName}
|
|
441
506
|
</div>
|
|
442
507
|
<div className={css.fontSize(12).colorhsl(0, 0, 40).width(150)}>
|
|
443
|
-
{formatNumber(
|
|
508
|
+
{formatNumber(group.totalValue)} {group.totalValue < group.totalMax && `/ ${formatNumber(group.totalMax)}`} ({formatTime(elapsedTime)})
|
|
444
509
|
</div>
|
|
445
510
|
</div>
|
|
446
511
|
<div className={css.fillWidth.height(8).bord2(200, 20, 80).hsl(200, 10, 95)}>
|
|
447
512
|
<div
|
|
448
|
-
className={css.height(8).hsl(200, 50, 70).transition("width 200ms")}
|
|
449
|
-
style={{ width: `${fraction * 100}%` }}
|
|
513
|
+
className={css.height(8).hsl(200, 50, 70).width(`${fraction * 100}%`).transition("width 200ms")}
|
|
450
514
|
/>
|
|
451
515
|
</div>
|
|
452
516
|
</div>
|
|
@@ -466,6 +530,8 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
466
530
|
let countsArray = Array.from(this.histogramAllDataCounts);
|
|
467
531
|
let selectedArray = Array.from(this.histogramSelectedDataCounts);
|
|
468
532
|
const maxAllCount = countsArray.reduce((a, b) => Math.max(a, b), 0);
|
|
533
|
+
const maxSelectedCount = selectedArray.reduce((a, b) => Math.max(a, b), 0);
|
|
534
|
+
const maxCountForScale = hideAllDataParam.value ? maxSelectedCount : maxAllCount;
|
|
469
535
|
const selected = css.hsla(120, 40, 50, 1);
|
|
470
536
|
const all = css.hsla(200, 40, 70, 1);
|
|
471
537
|
|
|
@@ -484,17 +550,19 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
484
550
|
className={css.relative.fillHeight.fillWidth.filter("brightness(1.1)", "hover")}
|
|
485
551
|
title={`${formatNumber(selectedCount)} filtered (${formatNumber(selectedSize)}B)\n${formatNumber(count)} all (${formatNumber(allSize)}B)\n${formatVeryNiceDateTime(this.histogramStartTime + index * this.histogramBucketTime)}`}
|
|
486
552
|
>
|
|
487
|
-
{count > 0 && <div
|
|
553
|
+
{count > 0 && !hideAllDataParam.value && <div
|
|
488
554
|
className={
|
|
489
555
|
all.absolute.bottom(0).left(0).right(1)
|
|
490
|
-
.height
|
|
556
|
+
.transition("height 200ms")
|
|
557
|
+
.height(`calc(max(3px, ${(count / maxCountForScale) * 100}%))`)
|
|
491
558
|
}
|
|
492
559
|
/>}
|
|
493
560
|
|
|
494
561
|
{selectedCount > 0 && <div
|
|
495
562
|
className={
|
|
496
563
|
selected.absolute.bottom(0).left(0).right(1)
|
|
497
|
-
.height
|
|
564
|
+
.transition("height 200ms")
|
|
565
|
+
.height(`calc(max(3px, ${(selectedCount / maxCountForScale) * 100}%))`)
|
|
498
566
|
}
|
|
499
567
|
/>}
|
|
500
568
|
</div>
|
|
@@ -502,19 +570,71 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
502
570
|
})}
|
|
503
571
|
</div>
|
|
504
572
|
<div className={css.hbox(20).fontSize(12)}>
|
|
505
|
-
|
|
506
|
-
<div className={
|
|
507
|
-
|
|
508
|
-
|
|
573
|
+
{!hideAllDataParam.value && (
|
|
574
|
+
<div className={css.hbox(5)}>
|
|
575
|
+
<div className={all.size(16, 16)} />
|
|
576
|
+
<span>All data (max {formatNumber(maxAllCount)} | {formatNumber(countsArray.reduce((a, b) => a + b, 0))} | {formatNumber(this.allSize)}B)</span>
|
|
577
|
+
</div>
|
|
578
|
+
)}
|
|
509
579
|
<div className={css.hbox(5)}>
|
|
510
580
|
<div className={selected.size(16, 16)} />
|
|
511
|
-
<span>Filtered data ({formatNumber(selectedArray.reduce((a, b) => a + b, 0))} | {formatNumber(this.matchedSize)}B)</span>
|
|
581
|
+
<span>Filtered data (max {formatNumber(maxSelectedCount)} | {formatNumber(selectedArray.reduce((a, b) => a + b, 0))} | {formatNumber(this.matchedSize)}B)</span>
|
|
512
582
|
</div>
|
|
583
|
+
<InputLabelURL
|
|
584
|
+
label="Only show filtered data"
|
|
585
|
+
checkbox
|
|
586
|
+
url={hideAllDataParam}
|
|
587
|
+
flavor="small"
|
|
588
|
+
/>
|
|
513
589
|
</div>
|
|
514
590
|
</div>
|
|
515
591
|
);
|
|
516
592
|
}
|
|
517
593
|
|
|
594
|
+
private getOutdatedInfo(): string[] {
|
|
595
|
+
const currentTimeRange = getTimeRange();
|
|
596
|
+
const currentFilterString = filterParam.value;
|
|
597
|
+
const currentArchivePaths = this.props.fastArchives.map(archive => archive.rootPath);
|
|
598
|
+
|
|
599
|
+
// Get stored sync parameters
|
|
600
|
+
const storedParams = this.state.currentSyncParams;
|
|
601
|
+
|
|
602
|
+
// If we have no stored params yet, not outdated (first run or loading)
|
|
603
|
+
if (!storedParams) {
|
|
604
|
+
return [];
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
let warnings: string[] = [];
|
|
608
|
+
|
|
609
|
+
// Check for parameter differences
|
|
610
|
+
if (storedParams.filterString !== currentFilterString) {
|
|
611
|
+
warnings.push("filter");
|
|
612
|
+
}
|
|
613
|
+
if (storedParams.startTime !== currentTimeRange.startTime) {
|
|
614
|
+
warnings.push("start time");
|
|
615
|
+
}
|
|
616
|
+
if (storedParams.endTime !== currentTimeRange.endTime) {
|
|
617
|
+
warnings.push("end time");
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Check for missing and extra archives
|
|
621
|
+
const currentArchivePathsSet = new Set(currentArchivePaths);
|
|
622
|
+
const storedArchivePathsSet = new Set(storedParams.fastArchivePaths);
|
|
623
|
+
|
|
624
|
+
for (let storedPath of storedParams.fastArchivePaths) {
|
|
625
|
+
if (!currentArchivePathsSet.has(storedPath)) {
|
|
626
|
+
warnings.push(`Missing ${storedPath}`);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
for (let currentPath of currentArchivePaths) {
|
|
630
|
+
if (!storedArchivePathsSet.has(currentPath)) {
|
|
631
|
+
warnings.push(`Extra ${currentPath}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return warnings;
|
|
636
|
+
}
|
|
637
|
+
|
|
518
638
|
public handleDownload = throttleFunction(500, () => {
|
|
519
639
|
console.log("handleDownload");
|
|
520
640
|
Querysub.onCommitFinished(() => {
|
|
@@ -522,6 +642,8 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
522
642
|
});
|
|
523
643
|
});
|
|
524
644
|
render() {
|
|
645
|
+
if (throttleRender({ key: "FastArchiveViewer", frameDelay: 30 })) return undefined;
|
|
646
|
+
|
|
525
647
|
let totalFileCount = 0;
|
|
526
648
|
let totalBackblazeByteCount = 0;
|
|
527
649
|
let totalLocalByteCount = 0;
|
|
@@ -545,6 +667,8 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
545
667
|
|
|
546
668
|
const infoDisplay = (hue: number) => css.pad2(12).bord2(hue, 50, 50).hsl(hue, 50, 95).colorhsl(hue, 50, 40);
|
|
547
669
|
|
|
670
|
+
|
|
671
|
+
|
|
548
672
|
return (
|
|
549
673
|
<div className={css.vbox(20).pad2(20).fillBoth}>
|
|
550
674
|
<div className={css.hbox(20).fillWidth}>
|
|
@@ -571,6 +695,11 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
571
695
|
flavor="large"
|
|
572
696
|
fillWidth
|
|
573
697
|
onKeyUp={this.handleDownload}
|
|
698
|
+
ref2={() => {
|
|
699
|
+
if (this.props.runOnLoad) {
|
|
700
|
+
void this.handleDownload();
|
|
701
|
+
}
|
|
702
|
+
}}
|
|
574
703
|
noEnterKeyBlur
|
|
575
704
|
placeholder="Filter terms, ex x | y & z"
|
|
576
705
|
/>
|
|
@@ -584,28 +713,71 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
584
713
|
flavor="small"
|
|
585
714
|
/>
|
|
586
715
|
<div className={css.vbox(10)}>
|
|
587
|
-
{this.state.
|
|
588
|
-
|
|
716
|
+
{this.state.runCount > 0 && (() => {
|
|
717
|
+
const outdatedWarnings = this.getOutdatedInfo();
|
|
718
|
+
return (
|
|
719
|
+
<div className={css.hbox(10).wrap}>
|
|
720
|
+
<div
|
|
721
|
+
className={infoDisplay(120)}
|
|
722
|
+
title={this.state.fileMetadata.map(x => x?.files || []).flat().map(x =>
|
|
723
|
+
`${x.path} (${formatNumber(x.size)})`
|
|
724
|
+
).join("\n")}
|
|
725
|
+
>
|
|
726
|
+
File count: {formatNumber(totalFileCount)}, Backblaze size: {formatNumber(totalBackblazeByteCount)}B (compressed), Disk size: {formatNumber(totalLocalByteCount)}B (uncompressed)
|
|
727
|
+
</div>
|
|
728
|
+
{outdatedWarnings.length > 0 && (
|
|
729
|
+
<div
|
|
730
|
+
className={infoDisplay(30).button}
|
|
731
|
+
onClick={() => {
|
|
732
|
+
void this.handleDownload();
|
|
733
|
+
}}
|
|
734
|
+
title={outdatedWarnings.join(", ")}
|
|
735
|
+
>
|
|
736
|
+
<div className={css.vbox(4)}>
|
|
737
|
+
<div className={css.boldStyle}>Search parameters outdated - Click to run updated search. Outdated:</div>
|
|
738
|
+
<div className={css.fontSize(12)}>
|
|
739
|
+
{outdatedWarnings.join(" | ")}
|
|
740
|
+
</div>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
)}
|
|
744
|
+
</div>
|
|
745
|
+
);
|
|
746
|
+
})()}
|
|
747
|
+
{this.state.runCount === 0 && (
|
|
748
|
+
<div className={infoDisplay(200).button} onClick={() => {
|
|
749
|
+
void this.handleDownload();
|
|
750
|
+
}}>
|
|
751
|
+
No data downloaded yet. Click here to download data.
|
|
752
|
+
</div>
|
|
753
|
+
)}
|
|
754
|
+
{this.state.finished && (() => {
|
|
755
|
+
if (readLocalTimes.length === 0) return null;
|
|
756
|
+
|
|
757
|
+
const timeRange = getTimeRange();
|
|
758
|
+
const earliestTime = Math.min(...readLocalTimes);
|
|
759
|
+
|
|
760
|
+
if (earliestTime >= timeRange.endTime) return null;
|
|
761
|
+
|
|
762
|
+
return (
|
|
589
763
|
<div
|
|
590
|
-
className={infoDisplay(
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
764
|
+
className={infoDisplay(0).button}
|
|
765
|
+
onClick={() => {
|
|
766
|
+
Querysub.commit(() => {
|
|
767
|
+
cacheBustParam.value = Date.now();
|
|
768
|
+
});
|
|
769
|
+
void this.handleDownload();
|
|
770
|
+
}}
|
|
594
771
|
>
|
|
595
|
-
|
|
772
|
+
<div className={css.hbox(8).alignItems("center").wrap}>
|
|
773
|
+
<span>Future data has been read</span>
|
|
774
|
+
<span className={css.fontSize(18).boldStyle}>{formatTime(timeRange.endTime - earliestTime)} into the future</span>
|
|
775
|
+
<span>({formatDateTime(earliestTime)})</span>
|
|
776
|
+
<span>Clear here to load possibly missing data data.</span>
|
|
777
|
+
</div>
|
|
596
778
|
</div>
|
|
597
|
-
)
|
|
598
|
-
|
|
599
|
-
className={infoDisplay(60).button}
|
|
600
|
-
onClick={() => {
|
|
601
|
-
Querysub.commit(() => {
|
|
602
|
-
cacheBustParam.value = Date.now();
|
|
603
|
-
});
|
|
604
|
-
void this.handleDownload();
|
|
605
|
-
}}
|
|
606
|
-
>
|
|
607
|
-
Snapshot from dates: {readLocalTimes.map(x => formatVeryNiceDateTime(x)).join(" | ")}. Clear here to reload data.
|
|
608
|
-
</div>}
|
|
779
|
+
);
|
|
780
|
+
})()}
|
|
609
781
|
{!this.state.finished && <LoaderAurora />}
|
|
610
782
|
{this.limitedScanCount > 0 && (
|
|
611
783
|
<div className={infoDisplay(60).boldStyle.button}
|
|
@@ -614,7 +786,7 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
614
786
|
void this.handleDownload();
|
|
615
787
|
}}
|
|
616
788
|
>
|
|
617
|
-
Click here to see {formatNumber(this.limitedScanCount)} scanned logs were rate limited at a file level.
|
|
789
|
+
Click here to see {formatNumber(this.limitedScanCount)} scanned logs were rate limited at a file level. This means lines might be missing. If this happens a lot, use pass {`{ [LOG_LINE_LIMIT_ID]: "INSERT RANDOM GUID HERE" }`} in the error/warn message to limit only the spamming line.
|
|
618
790
|
</div>
|
|
619
791
|
)}
|
|
620
792
|
{this.limitedMatchCount > 0 && filterParam.value && (
|
|
@@ -624,7 +796,7 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
624
796
|
void this.handleDownload();
|
|
625
797
|
}}
|
|
626
798
|
>
|
|
627
|
-
Click here to see {formatNumber(this.limitedMatchCount)} matched logs were rate limited at a file level.
|
|
799
|
+
Click here to see {formatNumber(this.limitedMatchCount)} matched logs were rate limited at a file level. This means lines might be missing. If this happens a lot, use pass {`{ [LOG_LINE_LIMIT_ID]: "INSERT RANDOM GUID HERE" }`} in the error/warn message to limit only the spamming line.
|
|
628
800
|
</div>
|
|
629
801
|
)}
|
|
630
802
|
{this.state.pendingSyncInitializations > 0 && (
|
|
@@ -651,7 +823,6 @@ export class FastArchiveViewer<T> extends qreact.Component<{
|
|
|
651
823
|
}
|
|
652
824
|
}
|
|
653
825
|
|
|
654
|
-
|
|
655
826
|
class LoaderAurora extends qreact.Component {
|
|
656
827
|
render() {
|
|
657
828
|
return (
|