querysub 0.462.0 → 0.463.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 +1 -1
- package/src/-d-trust/NetworkTrust2.ts +1 -1
- package/src/0-path-value-core/LockWatcher2.ts +2 -5
- package/src/0-path-value-core/PathRouter.ts +2 -3
- package/src/0-path-value-core/PathRouterConstants.ts +4 -0
- package/src/0-path-value-core/PathValueCommitter.ts +0 -1
- package/src/0-path-value-core/PathValueController.ts +1 -1
- package/src/0-path-value-core/PathWatcher.ts +14 -5
- package/src/0-path-value-core/ValidStateComputer.ts +234 -86
- package/src/0-path-value-core/pathValueCore.ts +57 -78
- package/src/1-path-client/RemoteWatcher.ts +2 -1
- package/src/1-path-client/pathValueClientWatcher.ts +28 -2
- package/src/2-proxy/PathValueProxyWatcher.ts +29 -24
- package/src/2-proxy/TransactionDelayer.ts +44 -22
- package/src/2-proxy/archiveMoveHarness.ts +2 -2
- package/src/3-path-functions/PathFunctionRunner.ts +30 -22
- package/src/3-path-functions/PathFunctionRunnerMain.ts +1 -3
- package/src/4-deploy/deployFunctions.ts +1 -1
- package/src/4-deploy/deployMain.ts +1 -1
- package/src/4-deploy/edgeClientWatcher.tsx +1 -1
- package/src/4-deploy/edgeNodes.ts +1 -1
- package/src/4-dom/qreactTest.tsx +1 -1
- package/src/4-querysub/Querysub.ts +8 -9
- package/src/4-querysub/QuerysubController.ts +19 -1
- package/src/4-querysub/permissions.ts +1 -1
- package/src/4-querysub/predictionQueue.tsx +1 -1
- package/src/4-querysub/querysubPrediction.ts +25 -12
- package/src/5-diagnostics/GenericFormat.tsx +1 -1
- package/src/5-diagnostics/qreactDebug.tsx +2 -2
- package/src/archiveapps/archiveGCEntry.tsx +1 -1
- package/src/archiveapps/archiveJoinEntry.ts +3 -3
- package/src/config.ts +5 -1
- package/src/config2.ts +9 -7
- package/src/deployManager/components/CommitModal.tsx +1 -1
- package/src/deployManager/components/DeployProgressView.tsx +1 -1
- package/src/deployManager/components/MachineDetailPage.tsx +1 -1
- package/src/deployManager/components/MachinesListPage.tsx +1 -1
- package/src/deployManager/components/ServiceDetailPage.tsx +1 -1
- package/src/deployManager/components/ServicesListPage.tsx +1 -1
- package/src/deployManager/components/Tools.tsx +1 -1
- package/src/deployManager/machineApplyMainCode.ts +1 -1
- package/src/deployManager/machineController.ts +1 -1
- package/src/deployManager/machineSchema.ts +1 -1
- package/src/deployManager/setupMachineMain.ts +1 -1
- package/src/diagnostics/FunctionCallInfoState.ts +6 -3
- package/src/diagnostics/MachineThreadInfo.tsx +1 -1
- package/src/diagnostics/NodeViewer.tsx +2 -1
- package/src/diagnostics/StatWarning.tsx +56 -0
- package/src/diagnostics/StatsHeader.tsx +248 -0
- package/src/diagnostics/StatsOverrides.ts +50 -0
- package/src/diagnostics/SyncTestPage.tsx +3 -3
- package/src/diagnostics/TimeDebug.tsx +1 -1
- package/src/diagnostics/debugger/mcp-server.ts +1 -1
- package/src/diagnostics/grossStats/GrossStatsPage.tsx +1 -1
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +1 -1
- package/src/diagnostics/logs/IndexedLogs/MCPIndexedLogsEntry.ts +1 -1
- package/src/diagnostics/logs/TimeRangeSelector.tsx +1 -1
- package/src/diagnostics/logs/errorNotifications2/ErrorNotificationPage.tsx +1 -1
- package/src/diagnostics/logs/errorNotifications2/ErrorWarning.tsx +0 -1
- package/src/diagnostics/logs/errorNotifications2/errorNotifications.ts +1 -1
- package/src/diagnostics/logs/errorNotifications2/errorWatchEntry.ts +1 -1
- package/src/diagnostics/logs/errorNotifications2/errorWatcher.ts +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryEditor.tsx +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryReadMode.tsx +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePage.tsx +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleSearch.tsx +1 -1
- package/src/diagnostics/managementPages.tsx +4 -9
- package/src/diagnostics/misc-pages/ArchiveViewer.tsx +1 -1
- package/src/diagnostics/misc-pages/ArchiveViewerTree.tsx +1 -1
- package/src/diagnostics/misc-pages/DNSPage.tsx +1 -1
- package/src/diagnostics/pathAuditer.ts +6 -6
- package/src/diagnostics/statsDefinitions.tsx +253 -0
- package/src/functional/throttleRender.ts +1 -1
- package/src/library-components/AspectSizedComponent.tsx +1 -1
- package/src/library-components/Button.tsx +1 -1
- package/src/library-components/ButtonSelector.tsx +1 -1
- package/src/library-components/DropdownCustom.tsx +1 -1
- package/src/library-components/DropdownSelector.tsx +1 -1
- package/src/library-components/Histogram.tsx +1 -1
- package/src/library-components/InlinePopup.tsx +1 -1
- package/src/library-components/LazyComponent.tsx +5 -1
- package/src/library-components/StickyBottomScroll.tsx +1 -1
- package/src/library-components/TypedConfigEditor.tsx +1 -1
- package/src/library-components/URLParam.ts +5 -9
- package/src/library-components/drag.ts +1 -1
- package/src/misc/formatJSX.tsx +1 -1
- package/src/user-implementation/userData.ts +1 -1
- package/test2.ts +1 -1
- package/testEntry2.ts +1 -1
- package/valid.md +205 -0
- package/src/deployManager/LaunchTrackingHeader.tsx +0 -65
- package/src/diagnostics/FunctionCallInfo.tsx +0 -141
- package/src/diagnostics/PathDistributionInfo.tsx +0 -110
- package/src/diagnostics/ValuePathWarning.tsx +0 -68
|
@@ -3,7 +3,7 @@ import "../inject";
|
|
|
3
3
|
import { measureWrap } from "socket-function/src/profiling/measure";
|
|
4
4
|
import { getOwnMachineId } from "../-a-auth/certs";
|
|
5
5
|
import { forceRemoveNode, getOurNodeId, getOurNodeIdAssert } from "../-f-node-discovery/NodeDiscovery";
|
|
6
|
-
import { Querysub } from "../4-querysub/
|
|
6
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
7
7
|
import { MACHINE_RESYNC_INTERVAL, MachineServiceControllerBase, MachineInfo, ServiceConfig, serviceConfigs, SERVICE_FOLDER, machineInfos, SERVICE_NODE_FILE_NAME, getEffectiveServiceConfigs, recordLaunch } from "./machineSchema";
|
|
8
8
|
import { runPromise } from "../functional/runCommand";
|
|
9
9
|
import { getExternalIP } from "socket-function/src/networking";
|
|
@@ -6,7 +6,7 @@ import { timeInMinute } from "socket-function/src/misc";
|
|
|
6
6
|
import { assertIsManagementUser } from "../diagnostics/managementPages";
|
|
7
7
|
import { isNode } from "typesafecss";
|
|
8
8
|
import { streamScreenOutput, getRollingServiceInfo, killRollingServicesForService } from "./machineApplyMainCode";
|
|
9
|
-
import { Querysub } from "../4-querysub/
|
|
9
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
10
10
|
import { getPathStr2 } from "../path";
|
|
11
11
|
import { getGitURLLive, setGitRef } from "../4-deploy/git";
|
|
12
12
|
import os from "os";
|
|
@@ -21,7 +21,7 @@ import { runPromise } from "../functional/runCommand";
|
|
|
21
21
|
import { isNode } from "typesafecss";
|
|
22
22
|
import { DeployProgress, deployFunctions, deployGetFunctions } from "../4-deploy/deployFunctions";
|
|
23
23
|
import { FunctionSpec, functionSchema } from "../3-path-functions/PathFunctionRunner";
|
|
24
|
-
import { Querysub } from "../4-querysub/
|
|
24
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
25
25
|
import { green, red } from "socket-function/src/formatting/logColors";
|
|
26
26
|
import { fsExistsAsync } from "../fs";
|
|
27
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getBackblazePath } from "../-a-archives/archivesBackBlaze";
|
|
2
2
|
import { getGitURLLive, getGitRefLive } from "../4-deploy/git";
|
|
3
|
-
import { Querysub } from "../4-querysub/
|
|
3
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
4
4
|
import { runPromise } from "../functional/runCommand";
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import os from "os";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Querysub } from "../4-querysub/
|
|
1
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
2
2
|
import { onPredictionFinished } from "../4-querysub/querysubPrediction";
|
|
3
3
|
import { lazy } from "socket-function/src/caching";
|
|
4
4
|
import { t } from "../2-proxy/schema2";
|
|
@@ -23,6 +23,7 @@ interface CallStatsData {
|
|
|
23
23
|
remotePathCount: number;
|
|
24
24
|
totalValueCount: number;
|
|
25
25
|
proxyWatcherCount: number;
|
|
26
|
+
callsByServer: { [creatorId: string]: number };
|
|
26
27
|
perFunctionStats: {
|
|
27
28
|
[functionId: string]: {
|
|
28
29
|
totalCalls: number;
|
|
@@ -56,6 +57,7 @@ let statsData: CallStatsData = {
|
|
|
56
57
|
remotePathCount: 0,
|
|
57
58
|
totalValueCount: 0,
|
|
58
59
|
proxyWatcherCount: 0,
|
|
60
|
+
callsByServer: {},
|
|
59
61
|
perFunctionStats: {},
|
|
60
62
|
};
|
|
61
63
|
|
|
@@ -75,8 +77,9 @@ export function callState(): CallStatsData {
|
|
|
75
77
|
export let ensureSubscribed = lazy(() => {
|
|
76
78
|
onPredictionFinished((data) => {
|
|
77
79
|
statsData.totalCalls++;
|
|
78
|
-
statsData.
|
|
79
|
-
statsData.
|
|
80
|
+
statsData.callsByServer[data.creatorId] = (statsData.callsByServer[data.creatorId] || 0) + 1;
|
|
81
|
+
statsData.totalInternalReruns += data.result.totalInternalLoopCount - 1;
|
|
82
|
+
statsData.totalFullReruns += data.result.outerLoopCount - 1;
|
|
80
83
|
addToStatsValue(statsData.evalTimeStats, data.result.evalTime);
|
|
81
84
|
addToStatsValue(statsData.timeTakenStats, data.result.timeTaken);
|
|
82
85
|
addToStatsValue(statsData.totalTimeStats, data.result.totalTime);
|
|
@@ -15,7 +15,7 @@ import dns from "dns";
|
|
|
15
15
|
import { isDefined } from "../misc";
|
|
16
16
|
import { getDebuggerUrl } from "./listenOnDebugger";
|
|
17
17
|
import { Button } from "../library-components/Button";
|
|
18
|
-
import { Querysub } from "../4-querysub/
|
|
18
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
19
19
|
import { NodeViewerController } from "./NodeViewer";
|
|
20
20
|
import { showFullscreenModal } from "../5-diagnostics/FullscreenModal";
|
|
21
21
|
import { css } from "../4-dom/css";
|
|
@@ -3,7 +3,8 @@ import { SocketFunction } from "socket-function/SocketFunction";
|
|
|
3
3
|
import { css } from "typesafecss";
|
|
4
4
|
import { getAllNodeIds, getBrowserUrlNode, syncNodesNow } from "../../src/-f-node-discovery/NodeDiscovery";
|
|
5
5
|
import { errorToUndefined, errorToUndefinedSilent, logErrors, timeoutToError } from "../../src/errors";
|
|
6
|
-
import {
|
|
6
|
+
import { QuerysubController } from "../../src/4-querysub/QuerysubController";
|
|
7
|
+
import { Querysub } from "../../src/4-querysub/Querysub";
|
|
7
8
|
import { NodeCapabilitiesController, getControllerNodeIdList } from "../../src/-g-core-values/NodeCapabilities";
|
|
8
9
|
import { lazy } from "socket-function/src/caching";
|
|
9
10
|
import { atomicObjectWrite } from "../../src/2-proxy/PathValueProxyWatcher";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { qreact } from "../4-dom/qreact";
|
|
2
|
+
import { css } from "../4-dom/css";
|
|
3
|
+
|
|
4
|
+
module.hotreload = true;
|
|
5
|
+
|
|
6
|
+
const FLASH_CLASS_NAME = "StatWarning-flash";
|
|
7
|
+
|
|
8
|
+
export type StatWarningAction = { label: string; onClick: () => void };
|
|
9
|
+
|
|
10
|
+
export class StatWarning extends qreact.Component<{
|
|
11
|
+
emoji: string;
|
|
12
|
+
name: string;
|
|
13
|
+
threshold: number;
|
|
14
|
+
flashing?: boolean;
|
|
15
|
+
actions?: StatWarningAction[];
|
|
16
|
+
children?: qreact.ComponentChildren;
|
|
17
|
+
}> {
|
|
18
|
+
render() {
|
|
19
|
+
let isFlashing = this.props.flashing !== false;
|
|
20
|
+
let actions = this.props.actions || [];
|
|
21
|
+
let alertClass = css.hbox(6).pad2(6, 2) + " " + css.hsl(0, 80, 60)
|
|
22
|
+
+ (isFlashing && (" " + FLASH_CLASS_NAME) || "");
|
|
23
|
+
let restClass = css.hbox(8).pad2(6, 2).wrap + " " + css.hsl(0, 0, 25);
|
|
24
|
+
return <div className={css.hbox(0).wrap}>
|
|
25
|
+
<div className={alertClass}>
|
|
26
|
+
<span>{this.props.emoji}</span>
|
|
27
|
+
<span>Threshold exceeded: {this.props.threshold}</span>
|
|
28
|
+
</div>
|
|
29
|
+
<div className={restClass}>
|
|
30
|
+
<span>{this.props.children}</span>
|
|
31
|
+
<span> -</span>
|
|
32
|
+
<span>{this.props.name}</span>
|
|
33
|
+
{actions.map(action =>
|
|
34
|
+
<div
|
|
35
|
+
className={css.button.pad2(6, 2).background("hsla(0, 0%, 100%, 0.15)")}
|
|
36
|
+
onClick={event => {
|
|
37
|
+
event.stopPropagation();
|
|
38
|
+
action.onClick();
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
{action.label}
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
{isFlashing && <style>{`
|
|
46
|
+
@keyframes ${FLASH_CLASS_NAME}-anim {
|
|
47
|
+
0%, 100% { background-color: hsl(0, 80%, 60%); }
|
|
48
|
+
50% { background-color: hsl(0, 80%, 30%); }
|
|
49
|
+
}
|
|
50
|
+
.${FLASH_CLASS_NAME} {
|
|
51
|
+
animation: ${FLASH_CLASS_NAME}-anim 0.6s infinite;
|
|
52
|
+
}
|
|
53
|
+
`}</style>}
|
|
54
|
+
</div>;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { qreact } from "../4-dom/qreact";
|
|
2
|
+
import { css } from "../4-dom/css";
|
|
3
|
+
import { t } from "../2-proxy/schema2";
|
|
4
|
+
import { timeInHour } from "socket-function/src/misc";
|
|
5
|
+
import { isCurrentUserSuperUser } from "../user-implementation/userData";
|
|
6
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
7
|
+
import { StatWarning, StatWarningAction } from "./StatWarning";
|
|
8
|
+
import { getStatOverridesSync, setStatOverride, statOffenderKey } from "./StatsOverrides";
|
|
9
|
+
|
|
10
|
+
module.hotreload = true;
|
|
11
|
+
|
|
12
|
+
const IGNORE_SHORT_MS = 12 * timeInHour;
|
|
13
|
+
const IGNORE_LONG_MS = 3 * 24 * timeInHour;
|
|
14
|
+
const PEAK_MULTIPLIER = 2;
|
|
15
|
+
const REEVALUATE_INTERVAL_MS = 60_000;
|
|
16
|
+
|
|
17
|
+
export interface StatDefinition {
|
|
18
|
+
category: string;
|
|
19
|
+
title: string;
|
|
20
|
+
emoji: string;
|
|
21
|
+
// Warns when >= threshold
|
|
22
|
+
threshold: number;
|
|
23
|
+
// Highlights with a blue background when >= dietThreshold (and below threshold). No dismiss action.
|
|
24
|
+
dietThreshold?: number;
|
|
25
|
+
formatter?: (value: number) => qreact.ComponentChildren;
|
|
26
|
+
getValue: () => number;
|
|
27
|
+
// Per-instance offenders responsible for the warning; used to render extra "raise/ignore for this one" buttons.
|
|
28
|
+
getOffenders?: () => { id: string; value: number }[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let peakValues = new Map<string, number>();
|
|
32
|
+
let offenderPeaks = new Map<string, number>();
|
|
33
|
+
|
|
34
|
+
type StatInfo = {
|
|
35
|
+
stat: StatDefinition;
|
|
36
|
+
value: number;
|
|
37
|
+
threshold: number;
|
|
38
|
+
isOverThreshold: boolean;
|
|
39
|
+
isIgnored: boolean;
|
|
40
|
+
isOverDiet: boolean;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export class StatsHeader extends qreact.Component<{ getStats: () => StatDefinition[] }> {
|
|
44
|
+
state = t.state({
|
|
45
|
+
expanded: t.lookup({ open: t.booleanOptional }),
|
|
46
|
+
nowTick: t.number,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
componentDidMount() {
|
|
50
|
+
setInterval(() => {
|
|
51
|
+
Querysub.localCommit(() => {
|
|
52
|
+
this.state.nowTick = Date.now();
|
|
53
|
+
});
|
|
54
|
+
}, REEVALUATE_INTERVAL_MS);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
toggle(category: string) {
|
|
58
|
+
if (category in this.state.expanded) {
|
|
59
|
+
delete this.state.expanded[category];
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.state.expanded[category] = { open: true };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
buildInfos(): { categories: string[]; byCategory: Map<string, StatInfo[]>; infos: StatInfo[] } {
|
|
66
|
+
let now = Date.now();
|
|
67
|
+
let overrides = getStatOverridesSync();
|
|
68
|
+
let categories: string[] = [];
|
|
69
|
+
let byCategory = new Map<string, StatInfo[]>();
|
|
70
|
+
let infos: StatInfo[] = [];
|
|
71
|
+
|
|
72
|
+
for (let stat of this.props.getStats()) {
|
|
73
|
+
let value = stat.getValue();
|
|
74
|
+
let priorPeak = peakValues.get(stat.title) || 0;
|
|
75
|
+
if (value > priorPeak) {
|
|
76
|
+
peakValues.set(stat.title, value);
|
|
77
|
+
}
|
|
78
|
+
if (stat.getOffenders) {
|
|
79
|
+
for (let offender of stat.getOffenders()) {
|
|
80
|
+
let key = statOffenderKey(stat.title, offender.id);
|
|
81
|
+
let priorOffenderPeak = offenderPeaks.get(key) || 0;
|
|
82
|
+
if (offender.value > priorOffenderPeak) {
|
|
83
|
+
offenderPeaks.set(key, offender.value);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
let override = overrides[stat.title] || {};
|
|
88
|
+
let threshold = override.thresholdOverride || stat.threshold;
|
|
89
|
+
let ignoredUntil = override.ignoreUntilMs || 0;
|
|
90
|
+
let isOverThreshold = value >= threshold;
|
|
91
|
+
let isIgnored = isOverThreshold && ignoredUntil > now;
|
|
92
|
+
let isOverDiet = !isOverThreshold && !!stat.dietThreshold && value >= stat.dietThreshold;
|
|
93
|
+
let info: StatInfo = { stat, value, threshold, isOverThreshold, isIgnored, isOverDiet };
|
|
94
|
+
infos.push(info);
|
|
95
|
+
|
|
96
|
+
let list = byCategory.get(stat.category);
|
|
97
|
+
if (!list) {
|
|
98
|
+
list = [];
|
|
99
|
+
byCategory.set(stat.category, list);
|
|
100
|
+
categories.push(stat.category);
|
|
101
|
+
}
|
|
102
|
+
list.push(info);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { categories, byCategory, infos };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
renderWarning(info: StatInfo): qreact.ComponentChildren {
|
|
109
|
+
let title = info.stat.title;
|
|
110
|
+
let actions: StatWarningAction[] = [
|
|
111
|
+
{
|
|
112
|
+
label: `Raise to ${PEAK_MULTIPLIER}× peak`,
|
|
113
|
+
onClick: () => {
|
|
114
|
+
let peak = peakValues.get(title) || info.value;
|
|
115
|
+
setStatOverride(title, { thresholdOverride: peak * PEAK_MULTIPLIER });
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
label: "Ignore 12h",
|
|
120
|
+
onClick: () => {
|
|
121
|
+
setStatOverride(title, { ignoreUntilMs: Date.now() + IGNORE_SHORT_MS });
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
label: "Ignore 3d",
|
|
126
|
+
onClick: () => {
|
|
127
|
+
setStatOverride(title, { ignoreUntilMs: Date.now() + IGNORE_LONG_MS });
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
if (info.stat.getOffenders) {
|
|
132
|
+
for (let offender of info.stat.getOffenders()) {
|
|
133
|
+
let offenderKey = statOffenderKey(title, offender.id);
|
|
134
|
+
actions.push({
|
|
135
|
+
label: `${offender.id}: ${PEAK_MULTIPLIER}× peak`,
|
|
136
|
+
onClick: () => {
|
|
137
|
+
let peak = offenderPeaks.get(offenderKey) || offender.value;
|
|
138
|
+
setStatOverride(offenderKey, { thresholdOverride: peak * PEAK_MULTIPLIER });
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
actions.push({
|
|
142
|
+
label: `${offender.id}: ignore 12h`,
|
|
143
|
+
onClick: () => {
|
|
144
|
+
setStatOverride(offenderKey, { ignoreUntilMs: Date.now() + IGNORE_SHORT_MS });
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
actions.push({
|
|
148
|
+
label: `${offender.id}: ignore 3d`,
|
|
149
|
+
onClick: () => {
|
|
150
|
+
setStatOverride(offenderKey, { ignoreUntilMs: Date.now() + IGNORE_LONG_MS });
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
let formatted = info.stat.formatter && info.stat.formatter(info.value) || info.value;
|
|
156
|
+
return <StatWarning
|
|
157
|
+
emoji={info.stat.emoji}
|
|
158
|
+
name={title}
|
|
159
|
+
threshold={info.threshold}
|
|
160
|
+
actions={actions}
|
|
161
|
+
>
|
|
162
|
+
{formatted}
|
|
163
|
+
</StatWarning>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
renderStatInline(info: StatInfo): qreact.ComponentChildren {
|
|
167
|
+
let stat = info.stat;
|
|
168
|
+
let formatted = stat.formatter && stat.formatter(info.value) || info.value;
|
|
169
|
+
let baseClass = css.hbox(4).pad2(6, 2);
|
|
170
|
+
let className = info.isOverDiet
|
|
171
|
+
&& baseClass + " " + css.background("hsl(210, 70%, 35%)")
|
|
172
|
+
|| baseClass;
|
|
173
|
+
let dietSuffix = info.isOverDiet && ` (diet threshold ${stat.dietThreshold})` || "";
|
|
174
|
+
return <span
|
|
175
|
+
title={`${stat.title}${dietSuffix}`}
|
|
176
|
+
className={className}
|
|
177
|
+
>
|
|
178
|
+
{stat.emoji} {formatted}
|
|
179
|
+
</span>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
render() {
|
|
183
|
+
if (!isCurrentUserSuperUser()) return undefined;
|
|
184
|
+
|
|
185
|
+
let { categories, byCategory, infos } = this.buildInfos();
|
|
186
|
+
let activeWarnings = infos.filter(info =>
|
|
187
|
+
info.isOverThreshold && !info.isIgnored && !(info.stat.category in this.state.expanded)
|
|
188
|
+
);
|
|
189
|
+
let activeDietWarnings = infos.filter(info =>
|
|
190
|
+
info.isOverDiet && !(info.stat.category in this.state.expanded)
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return <div className={css.vbox(4)}>
|
|
194
|
+
<div className={css.hbox(2).wrap}>
|
|
195
|
+
{categories.map(category => {
|
|
196
|
+
let isOpen = category in this.state.expanded;
|
|
197
|
+
let baseClass = css.button.hbox(4).pad2(10, 4)
|
|
198
|
+
.bord(1, "hsla(0, 0%, 100%, 0.25)")
|
|
199
|
+
.background(isOpen && "hsla(0, 0%, 100%, 0.18)" || "hsla(0, 0%, 100%, 0.06)");
|
|
200
|
+
return <div
|
|
201
|
+
className={baseClass + ""}
|
|
202
|
+
onClick={() => this.toggle(category)}
|
|
203
|
+
>
|
|
204
|
+
<span>{category}</span>
|
|
205
|
+
</div>;
|
|
206
|
+
})}
|
|
207
|
+
</div>
|
|
208
|
+
{categories.filter(category => category in this.state.expanded).map(category => {
|
|
209
|
+
let list = byCategory.get(category) || [];
|
|
210
|
+
let inline = list.filter(info => !info.isOverThreshold);
|
|
211
|
+
let warnings = list.filter(info => info.isOverThreshold);
|
|
212
|
+
return <div className={css.vbox(2).pad2(6, 2).background("hsla(0, 0%, 100%, 0.04)")}>
|
|
213
|
+
<div className={css.colorhsl(0, 0, 50).fontSize(11)}>{category}</div>
|
|
214
|
+
<div className={css.hbox(12).wrap}>
|
|
215
|
+
{inline.map(info => this.renderStatInline(info))}
|
|
216
|
+
</div>
|
|
217
|
+
{warnings.length > 0 && <div className={css.vbox(4)}>
|
|
218
|
+
{warnings.map(info => this.renderWarning(info))}
|
|
219
|
+
</div>}
|
|
220
|
+
</div>;
|
|
221
|
+
})}
|
|
222
|
+
{activeDietWarnings.length > 0 && <div className={css.vbox(4)}>
|
|
223
|
+
{(() => {
|
|
224
|
+
let dietCategories: string[] = [];
|
|
225
|
+
let dietByCategory = new Map<string, StatInfo[]>();
|
|
226
|
+
for (let info of activeDietWarnings) {
|
|
227
|
+
let list = dietByCategory.get(info.stat.category);
|
|
228
|
+
if (!list) {
|
|
229
|
+
list = [];
|
|
230
|
+
dietByCategory.set(info.stat.category, list);
|
|
231
|
+
dietCategories.push(info.stat.category);
|
|
232
|
+
}
|
|
233
|
+
list.push(info);
|
|
234
|
+
}
|
|
235
|
+
return dietCategories.map(category =>
|
|
236
|
+
<div className={css.hbox(8).wrap}>
|
|
237
|
+
<span className={css.colorhsl(0, 0, 50).fontSize(11)}>{category}</span>
|
|
238
|
+
{(dietByCategory.get(category) || []).map(info => this.renderStatInline(info))}
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
})()}
|
|
242
|
+
</div>}
|
|
243
|
+
{activeWarnings.length > 0 && <div className={css.vbox(4)}>
|
|
244
|
+
{activeWarnings.map(info => this.renderWarning(info))}
|
|
245
|
+
</div>}
|
|
246
|
+
</div>;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
2
|
+
import { t } from "../2-proxy/schema2";
|
|
3
|
+
|
|
4
|
+
const LOCAL_STORAGE_KEY = "StatsHeader.overrides.v2";
|
|
5
|
+
|
|
6
|
+
export type StatOverride = { thresholdOverride?: number; ignoreUntilMs?: number };
|
|
7
|
+
type OverridesMap = { [key: string]: StatOverride };
|
|
8
|
+
|
|
9
|
+
let cachedOverrides: OverridesMap | undefined;
|
|
10
|
+
|
|
11
|
+
let overridesSchema = Querysub.createLocalSchema("statsOverrides", {
|
|
12
|
+
sequenceNumber: t.number,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function loadFromStorage(): OverridesMap {
|
|
16
|
+
if (cachedOverrides) {
|
|
17
|
+
return cachedOverrides;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
let raw = localStorage.getItem(LOCAL_STORAGE_KEY);
|
|
21
|
+
cachedOverrides = raw && JSON.parse(raw) as OverridesMap || {};
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.error(`StatsOverrides: failed to load:`, (e as Error)?.stack || e);
|
|
24
|
+
cachedOverrides = {};
|
|
25
|
+
}
|
|
26
|
+
return cachedOverrides;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getStatOverridesSync(): OverridesMap {
|
|
30
|
+
overridesSchema().sequenceNumber;
|
|
31
|
+
return loadFromStorage();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getStatOverrideSync(key: string): StatOverride {
|
|
35
|
+
return getStatOverridesSync()[key] || {};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function setStatOverride(key: string, patch: StatOverride) {
|
|
39
|
+
let current = loadFromStorage();
|
|
40
|
+
let next: OverridesMap = { ...current };
|
|
41
|
+
next[key] = { ...next[key], ...patch };
|
|
42
|
+
cachedOverrides = next;
|
|
43
|
+
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(next));
|
|
44
|
+
let schema = overridesSchema();
|
|
45
|
+
schema.sequenceNumber = schema.sequenceNumber + 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function statOffenderKey(statTitle: string, offenderId: string): string {
|
|
49
|
+
return `${statTitle}::${offenderId}`;
|
|
50
|
+
}
|
|
@@ -2,7 +2,7 @@ import { SocketFunction } from "socket-function/SocketFunction";
|
|
|
2
2
|
import { qreact } from "../4-dom/qreact";
|
|
3
3
|
import { assertIsManagementUser } from "./managementPages";
|
|
4
4
|
import { getSyncedController } from "../library-components/SyncedController";
|
|
5
|
-
import { Querysub } from "../4-querysub/
|
|
5
|
+
import { Querysub } from "../4-querysub/Querysub";
|
|
6
6
|
import { isRegisteredUserPERMISSIONS, isSuperUserPERMISSIONS } from "../user-implementation/userData";
|
|
7
7
|
import { css } from "typesafecss";
|
|
8
8
|
import { Button } from "../library-components/Button";
|
|
@@ -58,7 +58,7 @@ let { data, functions } = Querysub.createSchema({
|
|
|
58
58
|
}
|
|
59
59
|
for (let path of watcher.pendingWatches.paths) {
|
|
60
60
|
if (!path.includes("syncText")) continue;
|
|
61
|
-
let pathValue = authorityStorage.
|
|
61
|
+
let pathValue = authorityStorage.getValueAtOrBeforeTime(path, undefined, false, "noAudit");
|
|
62
62
|
let source = remoteWatcher.getExistingWatchRemoteNodeId(path);
|
|
63
63
|
console.log("Path value", pathValue?.time.time, pathValueSerializer.getPathValue(pathValue), path, source);
|
|
64
64
|
}
|
|
@@ -315,7 +315,7 @@ class SyncTestControllerBase {
|
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
public async getValueAndTime(path: string) {
|
|
318
|
-
let pathValue = authorityStorage.
|
|
318
|
+
let pathValue = authorityStorage.getValueAtOrBeforeTime(path, undefined, false, "noAudit");
|
|
319
319
|
let value = pathValueSerializer.getPathValue(pathValue);
|
|
320
320
|
let time = pathValue?.time.time;
|
|
321
321
|
return { value, time };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import preact from "preact"; import { qreact } from "../../src/4-dom/qreact";
|
|
2
|
-
import { Querysub } from "../../src/4-querysub/
|
|
2
|
+
import { Querysub } from "../../src/4-querysub/Querysub";
|
|
3
3
|
import { formatTime } from "socket-function/src/formatting/format";
|
|
4
4
|
import { getTrueTimeOffset } from "socket-function/time/trueTimeShim";
|
|
5
5
|
import { css } from "typesafecss";
|
|
@@ -41,7 +41,7 @@ import * as dns from "dns";
|
|
|
41
41
|
import "../../inject";
|
|
42
42
|
|
|
43
43
|
import { DebuggerRemote } from "./debugger-remote";
|
|
44
|
-
import { Querysub } from "../../4-querysub/
|
|
44
|
+
import { Querysub } from "../../4-querysub/Querysub";
|
|
45
45
|
import { getAllNodeIds } from "../../-f-node-discovery/NodeDiscovery";
|
|
46
46
|
import { NodeCapabilitiesController } from "../../-g-core-values/NodeCapabilities";
|
|
47
47
|
import { timeoutToUndefinedSilent } from "../../errors";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import preact from "preact";
|
|
2
2
|
import { qreact } from "../../4-dom/qreact";
|
|
3
3
|
import { css } from "../../4-dom/css";
|
|
4
|
-
import { Querysub } from "../../4-querysub/
|
|
4
|
+
import { Querysub } from "../../4-querysub/Querysub";
|
|
5
5
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
6
6
|
import { formatDateTime, formatNumber } from "socket-function/src/formatting/format";
|
|
7
7
|
import { timeInHour, timeInMinute } from "socket-function/src/misc";
|
|
@@ -8,7 +8,7 @@ import { getLoggers2Async, LogDatum } from "../diskLogger";
|
|
|
8
8
|
import { list, timeInDay, timeInHour, keyByArray, sort, throttleFunction } from "socket-function/src/misc";
|
|
9
9
|
import { formatDateTime, formatDateTimeDetailed, formatNumber, formatTime, formatPercent } from "socket-function/src/formatting/format";
|
|
10
10
|
import { IndexedLogs, TimeFilePathWithSize } from "./IndexedLogs";
|
|
11
|
-
import { Querysub } from "../../../4-querysub/
|
|
11
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
12
12
|
import { URLParam } from "../../../library-components/URLParam";
|
|
13
13
|
import { getOwnMachineId, getOwnThreadId } from "../../../-f-node-discovery/NodeDiscovery";
|
|
14
14
|
import { FilePathSelector, FilePathsByMachine } from "./FilePathSelector";
|
|
@@ -15,7 +15,7 @@ import "../../../inject";
|
|
|
15
15
|
|
|
16
16
|
import * as http from "http";
|
|
17
17
|
import { logErrors, timeoutToUndefinedSilent } from "../../../errors";
|
|
18
|
-
import { Querysub } from "../../../4-querysub/
|
|
18
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
19
19
|
import { MCPIndexedLogs } from "./MCPIndexedLogs";
|
|
20
20
|
import { getAllNodeIds } from "../../../-f-node-discovery/NodeDiscovery";
|
|
21
21
|
import { NodeCapabilitiesController } from "../../../-g-core-values/NodeCapabilities";
|
|
@@ -6,7 +6,7 @@ import { css } from "../../4-dom/css";
|
|
|
6
6
|
import { formatTime } from "socket-function/src/formatting/format";
|
|
7
7
|
import { InputLabel } from "../../library-components/InputLabel";
|
|
8
8
|
import { Button } from "../../library-components/Button";
|
|
9
|
-
import { Querysub } from "../../4-querysub/
|
|
9
|
+
import { Querysub } from "../../4-querysub/Querysub";
|
|
10
10
|
import { timeInDay, timeInHour, timeInMinute } from "socket-function/src/misc";
|
|
11
11
|
|
|
12
12
|
// URL parameters for time range
|
|
@@ -4,7 +4,7 @@ import { css } from "typesafecss";
|
|
|
4
4
|
import { LogDatum } from "../diskLogger";
|
|
5
5
|
import { sort, timeInDay } from "socket-function/src/misc";
|
|
6
6
|
import { formatDateTime, formatNumber, formatTime } from "socket-function/src/formatting/format";
|
|
7
|
-
import { Querysub } from "../../../4-querysub/
|
|
7
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
8
8
|
import { InputLabel } from "../../../library-components/InputLabel";
|
|
9
9
|
import { isPublic } from "../../../config";
|
|
10
10
|
import { MachineThreadInfo } from "../../MachineThreadInfo";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { qreact } from "../../../4-dom/qreact";
|
|
2
2
|
import { t } from "../../../2-proxy/schema2";
|
|
3
3
|
import { css } from "typesafecss";
|
|
4
|
-
import { Querysub } from "../../../4-querysub/QuerysubController";
|
|
5
4
|
import { ATag } from "../../../library-components/ATag";
|
|
6
5
|
import { managementPageURL, showingManagementURL } from "../../managementPages";
|
|
7
6
|
import { LogDatumRenderer } from "./ErrorNotificationPage";
|
|
@@ -2,7 +2,7 @@ import { cacheLimited, lazy } from "socket-function/src/caching";
|
|
|
2
2
|
import { nestArchives } from "../../../-a-archives/archives";
|
|
3
3
|
import { getArchivesBackblaze } from "../../../-a-archives/archivesBackBlaze";
|
|
4
4
|
import { archiveJSONT } from "../../../-a-archives/archivesJSONT";
|
|
5
|
-
import { Querysub } from "../../../4-querysub/
|
|
5
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
6
6
|
import { getDomain, isPublic } from "../../../config";
|
|
7
7
|
import { MachineInfo } from "../../../deployManager/machineSchema";
|
|
8
8
|
import { createMatchesPattern } from "../IndexedLogs/bufferSearchFindMatcher";
|
|
@@ -2,7 +2,7 @@ import "../../../forceProduction";
|
|
|
2
2
|
import "../../../inject";
|
|
3
3
|
|
|
4
4
|
import { logErrors } from "../../../errors";
|
|
5
|
-
import { Querysub } from "../../../4-querysub/
|
|
5
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
6
6
|
import { exposeErrorWatchService } from "./errorNotifications";
|
|
7
7
|
|
|
8
8
|
logErrors(main());
|
|
@@ -2,7 +2,7 @@ import { SocketFunction } from "socket-function/SocketFunction";
|
|
|
2
2
|
import { lazy } from "socket-function/src/caching";
|
|
3
3
|
import { nextId } from "socket-function/src/misc";
|
|
4
4
|
import { t } from "../../../2-proxy/schema2";
|
|
5
|
-
import { Querysub } from "../../../4-querysub/
|
|
5
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
6
6
|
import { LogDatum } from "../diskLogger";
|
|
7
7
|
import { SuppressionMatch, watchUnmatchedErrors, ErrorNotificationsController } from "./errorNotifications";
|
|
8
8
|
|
|
@@ -3,7 +3,7 @@ import { deepCloneJSON } from "socket-function/src/misc";
|
|
|
3
3
|
import { css } from "typesafecss";
|
|
4
4
|
import { t } from "../../../2-proxy/schema2";
|
|
5
5
|
import { qreact } from "../../../4-dom/qreact";
|
|
6
|
-
import { Querysub } from "../../../4-querysub/
|
|
6
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
7
7
|
import { Button } from "../../../library-components/Button";
|
|
8
8
|
import { InputLabel } from "../../../library-components/InputLabel";
|
|
9
9
|
import { LogDatum } from "../diskLogger";
|
|
@@ -3,7 +3,7 @@ import { deepCloneJSON } from "socket-function/src/misc";
|
|
|
3
3
|
import { css } from "typesafecss";
|
|
4
4
|
import { t } from "../../../2-proxy/schema2";
|
|
5
5
|
import { qreact } from "../../../4-dom/qreact";
|
|
6
|
-
import { Querysub } from "../../../4-querysub/
|
|
6
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
7
7
|
import { Button } from "../../../library-components/Button";
|
|
8
8
|
import { niceStringify } from "../../../niceStringify";
|
|
9
9
|
import { LogDatum } from "../diskLogger";
|
|
@@ -2,7 +2,7 @@ import { qreact } from "../../../4-dom/qreact";
|
|
|
2
2
|
import { t } from "../../../2-proxy/schema2";
|
|
3
3
|
import { css } from "typesafecss";
|
|
4
4
|
import { deepCloneJSON, nextId, sort } from "socket-function/src/misc";
|
|
5
|
-
import { Querysub } from "../../../4-querysub/
|
|
5
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
6
6
|
import { InputLabel } from "../../../library-components/InputLabel";
|
|
7
7
|
import { Button } from "../../../library-components/Button";
|
|
8
8
|
import { LifeCycle, LifeCycleEntry, LifeCyclesController, getVariables } from "./lifeCycles";
|
|
@@ -4,7 +4,7 @@ import { deepCloneJSON, nextId } from "socket-function/src/misc";
|
|
|
4
4
|
import { css } from "typesafecss";
|
|
5
5
|
import { t } from "../../../2-proxy/schema2";
|
|
6
6
|
import { qreact } from "../../../4-dom/qreact";
|
|
7
|
-
import { Querysub } from "../../../4-querysub/
|
|
7
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
8
8
|
import { formatValue } from "../../../5-diagnostics/GenericFormat";
|
|
9
9
|
import { Button } from "../../../library-components/Button";
|
|
10
10
|
import { InputLabel } from "../../../library-components/InputLabel";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Querysub } from "../../../4-querysub/
|
|
1
|
+
import { Querysub } from "../../../4-querysub/Querysub";
|
|
2
2
|
import { getTimeRange } from "../TimeRangeSelector";
|
|
3
3
|
import { throttleFunction, sort } from "socket-function/src/misc";
|
|
4
4
|
import { getLoggers2Async, LogDatum } from "../diskLogger";
|