querysub 0.403.0 → 0.405.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/.cursorrules +2 -0
- package/bin/audit-imports.js +4 -0
- package/bin/join.js +1 -1
- package/package.json +7 -4
- package/spec.txt +77 -0
- package/src/-a-archives/archiveCache.ts +9 -4
- package/src/-a-archives/archivesBackBlaze.ts +1039 -1039
- package/src/-a-auth/certs.ts +0 -12
- package/src/-c-identity/IdentityController.ts +12 -3
- package/src/-f-node-discovery/NodeDiscovery.ts +32 -26
- package/src/-g-core-values/NodeCapabilities.ts +12 -2
- package/src/0-path-value-core/AuthorityLookup.ts +239 -0
- package/src/0-path-value-core/LockWatcher2.ts +150 -0
- package/src/0-path-value-core/PathRouter.ts +543 -0
- package/src/0-path-value-core/PathRouterRouteOverride.ts +72 -0
- package/src/0-path-value-core/PathRouterServerAuthoritySpec.tsx +73 -0
- package/src/0-path-value-core/PathValueCommitter.ts +222 -488
- package/src/0-path-value-core/PathValueController.ts +277 -239
- package/src/0-path-value-core/PathWatcher.ts +534 -0
- package/src/0-path-value-core/ShardPrefixes.ts +31 -0
- package/src/0-path-value-core/ValidStateComputer.ts +303 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +1 -1
- package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +80 -44
- package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +13 -16
- package/src/0-path-value-core/auditLogs.ts +2 -0
- package/src/0-path-value-core/hackedPackedPathParentFiltering.ts +97 -0
- package/src/0-path-value-core/pathValueArchives.ts +491 -492
- package/src/0-path-value-core/pathValueCore.ts +195 -1496
- package/src/0-path-value-core/startupAuthority.ts +74 -0
- package/src/1-path-client/RemoteWatcher.ts +90 -82
- package/src/1-path-client/pathValueClientWatcher.ts +808 -815
- package/src/2-proxy/PathValueProxyWatcher.ts +10 -8
- package/src/2-proxy/archiveMoveHarness.ts +182 -214
- package/src/2-proxy/garbageCollection.ts +9 -8
- package/src/2-proxy/schema2.ts +21 -1
- package/src/3-path-functions/PathFunctionHelpers.ts +206 -180
- package/src/3-path-functions/PathFunctionRunner.ts +943 -766
- package/src/3-path-functions/PathFunctionRunnerMain.ts +5 -3
- package/src/3-path-functions/pathFunctionLoader.ts +2 -2
- package/src/3-path-functions/syncSchema.ts +596 -521
- package/src/4-deploy/deployFunctions.ts +19 -4
- package/src/4-deploy/deployGetFunctionsInner.ts +8 -2
- package/src/4-deploy/deployMain.ts +51 -68
- package/src/4-deploy/edgeClientWatcher.tsx +6 -1
- package/src/4-deploy/edgeNodes.ts +2 -2
- package/src/4-dom/qreact.tsx +2 -4
- package/src/4-dom/qreactTest.tsx +7 -13
- package/src/4-querysub/Querysub.ts +21 -8
- package/src/4-querysub/QuerysubController.ts +45 -29
- package/src/4-querysub/permissions.ts +2 -2
- package/src/4-querysub/querysubPrediction.ts +80 -70
- package/src/4-querysub/schemaHelpers.ts +5 -1
- package/src/5-diagnostics/GenericFormat.tsx +14 -9
- package/src/archiveapps/archiveGCEntry.tsx +9 -2
- package/src/archiveapps/archiveJoinEntry.ts +96 -84
- package/src/bits.ts +19 -0
- package/src/config.ts +21 -3
- package/src/config2.ts +23 -48
- package/src/deployManager/components/DeployPage.tsx +7 -3
- package/src/deployManager/machineSchema.ts +4 -1
- package/src/diagnostics/ActionsHistory.ts +3 -8
- package/src/diagnostics/AuditLogPage.tsx +2 -3
- package/src/diagnostics/FunctionCallInfo.tsx +141 -0
- package/src/diagnostics/FunctionCallInfoState.ts +162 -0
- package/src/diagnostics/MachineThreadInfo.tsx +1 -1
- package/src/diagnostics/NodeViewer.tsx +37 -48
- package/src/diagnostics/SyncTestPage.tsx +241 -0
- package/src/diagnostics/auditImportViolations.ts +185 -0
- package/src/diagnostics/listenOnDebugger.ts +3 -3
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +10 -4
- package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +2 -2
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +24 -22
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +1 -1
- package/src/diagnostics/logs/diskLogGlobalContext.ts +1 -0
- package/src/diagnostics/logs/errorNotifications2/logWatcher.ts +1 -3
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryEditor.tsx +34 -16
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryReadMode.tsx +4 -6
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleInstanceTableView.tsx +36 -5
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePage.tsx +19 -5
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +15 -7
- package/src/diagnostics/logs/lifeCycleAnalysis/NestedLifeCycleInfo.tsx +28 -106
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMatching.ts +2 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMisc.ts +0 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleSearch.tsx +18 -7
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +3 -0
- package/src/diagnostics/managementPages.tsx +10 -3
- package/src/diagnostics/misc-pages/ArchiveViewer.tsx +20 -26
- package/src/diagnostics/misc-pages/ArchiveViewerTree.tsx +6 -4
- package/src/diagnostics/misc-pages/ComponentSyncStats.tsx +2 -2
- package/src/diagnostics/misc-pages/LocalWatchViewer.tsx +7 -9
- package/src/diagnostics/misc-pages/SnapshotViewer.tsx +23 -12
- package/src/diagnostics/misc-pages/archiveViewerShared.tsx +1 -1
- package/src/diagnostics/pathAuditer.ts +486 -0
- package/src/diagnostics/pathAuditerCallback.ts +20 -0
- package/src/diagnostics/watchdog.ts +8 -1
- package/src/library-components/URLParam.ts +1 -1
- package/src/misc/hash.ts +1 -0
- package/src/path.ts +21 -7
- package/src/server.ts +54 -47
- package/src/user-implementation/loginEmail.tsx +1 -1
- package/tempnotes.txt +65 -0
- package/test.ts +298 -97
- package/src/0-path-value-core/NodePathAuthorities.ts +0 -1057
- package/src/0-path-value-core/PathController.ts +0 -1
- package/src/5-diagnostics/diskValueAudit.ts +0 -218
- package/src/5-diagnostics/memoryValueAudit.ts +0 -438
- package/src/archiveapps/archiveMergeEntry.tsx +0 -48
- package/src/archiveapps/lockTest.ts +0 -127
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { formatPercent, formatNumber } from "socket-function/src/formatting/format";
|
|
2
2
|
import { red } from "socket-function/src/formatting/logColors";
|
|
3
|
-
import { measureFnc } from "socket-function/src/profiling/measure";
|
|
3
|
+
import { measureFnc, measureWrap } from "socket-function/src/profiling/measure";
|
|
4
4
|
import { Unit, remapUnit } from "./BufferIndexHelpers";
|
|
5
|
+
import { devDebugbreak } from "../../../config";
|
|
5
6
|
|
|
6
7
|
export class UnitSet {
|
|
7
8
|
// Hash-based set for checking unit membership (no positions stored)
|
|
@@ -27,7 +28,7 @@ export class UnitSet {
|
|
|
27
28
|
return Buffer.from(new Uint32Array([0]).buffer);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
function tryEncodeWithRatio(estimatedUniqueRatio: number): { hashTable: Uint32Array; collisions: number; totalInserts: number; } | undefined {
|
|
31
|
+
const tryEncodeWithRatio = measureWrap(function tryEncodeWithRatio(estimatedUniqueRatio: number): { hashTable: Uint32Array; collisions: number; totalInserts: number; } | undefined {
|
|
31
32
|
const HASH_FACTOR = 2;
|
|
32
33
|
const estimatedUnique = Math.max(Math.ceil(totalUnits / estimatedUniqueRatio), 16);
|
|
33
34
|
const desiredCapacity = estimatedUnique * HASH_FACTOR;
|
|
@@ -87,7 +88,7 @@ export class UnitSet {
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
return { hashTable, collisions, totalInserts };
|
|
90
|
-
}
|
|
91
|
+
});
|
|
91
92
|
|
|
92
93
|
// Try with increasingly conservative ratios until we succeed
|
|
93
94
|
let ratio = 1000;
|
|
@@ -95,7 +96,12 @@ export class UnitSet {
|
|
|
95
96
|
while (true) {
|
|
96
97
|
result = tryEncodeWithRatio(ratio);
|
|
97
98
|
if (result) break;
|
|
98
|
-
ratio
|
|
99
|
+
if (ratio === 0.1) {
|
|
100
|
+
devDebugbreak();
|
|
101
|
+
console.error(`Failed to encode UnitSet even with max ratio of ${ratio}. Aborting. What kind of data is this?`);
|
|
102
|
+
return Buffer.alloc(0);
|
|
103
|
+
}
|
|
104
|
+
ratio = Math.max(ratio / 2, 0.1);
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
const collisionRate = result.totalInserts > 0 ? result.collisions / result.totalInserts : 0;
|
|
@@ -541,7 +541,7 @@ export class IndexedLogs<T> {
|
|
|
541
541
|
if (config.params.searchFromStart) {
|
|
542
542
|
sort(paths, x => x.startTime);
|
|
543
543
|
} else {
|
|
544
|
-
sort(paths, x => -
|
|
544
|
+
sort(paths, x => -x.startTime);
|
|
545
545
|
}
|
|
546
546
|
|
|
547
547
|
let localPaths = paths.filter(x => x.logCount === undefined);
|
|
@@ -605,7 +605,7 @@ export class IndexedLogs<T> {
|
|
|
605
605
|
},
|
|
606
606
|
keepIterating: () => !results.cancel && progressTracker.isSourceRelevant(path),
|
|
607
607
|
onResult: (match: Buffer) => {
|
|
608
|
-
|
|
608
|
+
// NOTE: We absolutely cannot do any limiting here, as that would just result in a lot of values that might be newer than the old values being discarded. Each loop itself has to do some kind of limiting as it knows how many it's found in its specific loop, and it knows the direction it's iterating and the direction of the values.
|
|
609
609
|
progressTracker.addResult(match, path);
|
|
610
610
|
},
|
|
611
611
|
results,
|
|
@@ -30,7 +30,7 @@ import { readProductionLogsURL, searchTextURL } from "./LogViewerParams";
|
|
|
30
30
|
import { RenderSearchStats } from "./RenderSearchStats";
|
|
31
31
|
import { LifeCyclesController, LifeCycle, LifeCycleEntry } from "../lifeCycleAnalysis/lifeCycles";
|
|
32
32
|
import { getLifecycleMatchesForDatum } from "../lifeCycleAnalysis/lifeCycleMatching";
|
|
33
|
-
import { lifecycleIdURL, additionalSearchURL } from "../lifeCycleAnalysis/LifeCyclePage";
|
|
33
|
+
import { lifecycleIdURL, additionalSearchURL, phase2AdditionalSearchURL } from "../lifeCycleAnalysis/LifeCyclePage";
|
|
34
34
|
import { ATag } from "../../../library-components/ATag";
|
|
35
35
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
36
36
|
import { managementPageURL } from "../../managementPages";
|
|
@@ -39,6 +39,10 @@ import { formatSearchString } from "./LogViewerParams";
|
|
|
39
39
|
|
|
40
40
|
let excludePendingResults = new URLParam("excludePendingResults", false);
|
|
41
41
|
let limitURL = new URLParam("limit", 16);
|
|
42
|
+
let enableLogsURL = new URLParam("enableLogs", true);
|
|
43
|
+
let enableInfosURL = new URLParam("enableInfos", true);
|
|
44
|
+
let enableWarningsURL = new URLParam("enableWarnings", true);
|
|
45
|
+
let enableErrorsURL = new URLParam("enableErrors", true);
|
|
42
46
|
|
|
43
47
|
let savedPathsURL = new URLParam("savedPaths", "");
|
|
44
48
|
let selectedFieldsURL = new URLParam("selectedFields", {} as Record<string, boolean>);
|
|
@@ -58,10 +62,6 @@ const defaultSelectedFields = {
|
|
|
58
62
|
export class LogViewer3 extends qreact.Component {
|
|
59
63
|
static renderInProgress = true;
|
|
60
64
|
state = t.state({
|
|
61
|
-
enableLogs: t.boolean(true),
|
|
62
|
-
enableInfos: t.boolean(true),
|
|
63
|
-
enableWarnings: t.boolean(true),
|
|
64
|
-
enableErrors: t.boolean(true),
|
|
65
65
|
results: t.atomic<LogDatum[]>([]),
|
|
66
66
|
searching: t.boolean,
|
|
67
67
|
searchingLogs: t.boolean,
|
|
@@ -137,10 +137,10 @@ export class LogViewer3 extends qreact.Component {
|
|
|
137
137
|
let loggers = await getLoggers2Async();
|
|
138
138
|
let selectedLoggers: typeof loggers.logLogs[] = [];
|
|
139
139
|
Querysub.localRead(() => {
|
|
140
|
-
if (
|
|
141
|
-
if (
|
|
142
|
-
if (
|
|
143
|
-
if (
|
|
140
|
+
if (enableLogsURL.value) selectedLoggers.push(loggers.logLogs);
|
|
141
|
+
if (enableInfosURL.value) selectedLoggers.push(loggers.infoLogs);
|
|
142
|
+
if (enableWarningsURL.value) selectedLoggers.push(loggers.warnLogs);
|
|
143
|
+
if (enableErrorsURL.value) selectedLoggers.push(loggers.errorLogs);
|
|
144
144
|
});
|
|
145
145
|
|
|
146
146
|
if (selectedLoggers.length === 0) {
|
|
@@ -215,19 +215,19 @@ export class LogViewer3 extends qreact.Component {
|
|
|
215
215
|
|
|
216
216
|
let selectedLoggers: typeof loggers.logLogs[] = [];
|
|
217
217
|
Querysub.localRead(() => {
|
|
218
|
-
if (
|
|
218
|
+
if (enableLogsURL.value) {
|
|
219
219
|
selectedLoggers.push(loggers.logLogs);
|
|
220
220
|
this.state.searchingLogs = true;
|
|
221
221
|
}
|
|
222
|
-
if (
|
|
222
|
+
if (enableInfosURL.value) {
|
|
223
223
|
selectedLoggers.push(loggers.infoLogs);
|
|
224
224
|
this.state.searchingInfos = true;
|
|
225
225
|
}
|
|
226
|
-
if (
|
|
226
|
+
if (enableWarningsURL.value) {
|
|
227
227
|
selectedLoggers.push(loggers.warnLogs);
|
|
228
228
|
this.state.searchingWarnings = true;
|
|
229
229
|
}
|
|
230
|
-
if (
|
|
230
|
+
if (enableErrorsURL.value) {
|
|
231
231
|
selectedLoggers.push(loggers.errorLogs);
|
|
232
232
|
this.state.searchingErrors = true;
|
|
233
233
|
}
|
|
@@ -560,9 +560,10 @@ export class LogViewer3 extends qreact.Component {
|
|
|
560
560
|
managementPageURL.getOverride("LifeCyclePage"),
|
|
561
561
|
lifecycleIdURL.getOverride(match.lifecycle.id),
|
|
562
562
|
additionalSearchURL.getOverride(formatSearchString(match.datum)),
|
|
563
|
+
phase2AdditionalSearchURL.getOverride(""),
|
|
563
564
|
startTimeParam.getOverride(datum.time - timeInHour),
|
|
564
565
|
endTimeParam.getOverride(datum.time + timeInHour),
|
|
565
|
-
]}>
|
|
566
|
+
]} title={match.entry.matchPattern}>
|
|
566
567
|
View {JSON.stringify(match.lifecycle.title)}
|
|
567
568
|
</ATag>
|
|
568
569
|
</div>
|
|
@@ -571,6 +572,7 @@ export class LogViewer3 extends qreact.Component {
|
|
|
571
572
|
managementPageURL.getOverride("LifeCyclePage"),
|
|
572
573
|
lifecycleIdURL.getOverride(firstMatch.lifecycle.id),
|
|
573
574
|
additionalSearchURL.getOverride(searchFilter),
|
|
575
|
+
phase2AdditionalSearchURL.getOverride(""),
|
|
574
576
|
startTimeParam.getOverride(minTime - timeInHour),
|
|
575
577
|
endTimeParam.getOverride(maxTime + timeInHour),
|
|
576
578
|
]}>
|
|
@@ -690,40 +692,40 @@ export class LogViewer3 extends qreact.Component {
|
|
|
690
692
|
<div className={css.hbox(10)}>
|
|
691
693
|
<Button
|
|
692
694
|
onClick={() => {
|
|
693
|
-
|
|
695
|
+
enableLogsURL.value = !enableLogsURL.value;
|
|
694
696
|
this.clearPaths();
|
|
695
697
|
}}
|
|
696
|
-
hue={
|
|
698
|
+
hue={enableLogsURL.value && 210 || undefined}
|
|
697
699
|
className={this.state.searchingLogs && css.opacity(0.5) || undefined}
|
|
698
700
|
>
|
|
699
701
|
Logs
|
|
700
702
|
</Button>
|
|
701
703
|
<Button
|
|
702
704
|
onClick={() => {
|
|
703
|
-
|
|
705
|
+
enableInfosURL.value = !enableInfosURL.value;
|
|
704
706
|
this.clearPaths();
|
|
705
707
|
}}
|
|
706
|
-
hue={
|
|
708
|
+
hue={enableInfosURL.value && 200 || undefined}
|
|
707
709
|
className={this.state.searchingInfos && css.opacity(0.5) || undefined}
|
|
708
710
|
>
|
|
709
711
|
Infos
|
|
710
712
|
</Button>
|
|
711
713
|
<Button
|
|
712
714
|
onClick={() => {
|
|
713
|
-
|
|
715
|
+
enableWarningsURL.value = !enableWarningsURL.value;
|
|
714
716
|
this.clearPaths();
|
|
715
717
|
}}
|
|
716
|
-
hue={
|
|
718
|
+
hue={enableWarningsURL.value && 40 || undefined}
|
|
717
719
|
className={this.state.searchingWarnings && css.opacity(0.5) || undefined}
|
|
718
720
|
>
|
|
719
721
|
Warnings
|
|
720
722
|
</Button>
|
|
721
723
|
<Button
|
|
722
724
|
onClick={() => {
|
|
723
|
-
|
|
725
|
+
enableErrorsURL.value = !enableErrorsURL.value;
|
|
724
726
|
this.clearPaths();
|
|
725
727
|
}}
|
|
726
|
-
hue={
|
|
728
|
+
hue={enableErrorsURL.value ? 0 : undefined}
|
|
727
729
|
className={this.state.searchingErrors && css.opacity(0.5) || undefined}
|
|
728
730
|
>
|
|
729
731
|
Errors
|
|
@@ -129,7 +129,7 @@ export async function moveLogsToPublic(config: {
|
|
|
129
129
|
|
|
130
130
|
if (!await tryToGetMoveLock()) return;
|
|
131
131
|
|
|
132
|
-
console.log(magenta(`Moving ${localPaths.length} log files to public (${blue(config.loggerName)})`), { loggerName: config.loggerName
|
|
132
|
+
console.log(magenta(`Moving ${localPaths.length} log files to public (${blue(config.loggerName)})`), { loggerName: config.loggerName });
|
|
133
133
|
|
|
134
134
|
let byStartTime = keyByArray(localPaths, x => x.startTime);
|
|
135
135
|
|
|
@@ -24,6 +24,7 @@ export function addBuiltInContext() {
|
|
|
24
24
|
__externalIP: cachedExternalIP(),
|
|
25
25
|
__os: process.platform,
|
|
26
26
|
__pid: process.pid,
|
|
27
|
+
__call: SocketFunction.TOTAL_CALLS,
|
|
27
28
|
};
|
|
28
29
|
});
|
|
29
30
|
const getHostname = lazy(() => child_process.execSync("hostname").toString().trim());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
2
|
-
import {
|
|
2
|
+
import { isOwnNodeId, watchDeltaNodeIds } from "../../../-f-node-discovery/NodeDiscovery";
|
|
3
3
|
import { IndexedLogs, loggerByName } from "../IndexedLogs/IndexedLogs";
|
|
4
4
|
import { nextId } from "socket-function/src/misc";
|
|
5
5
|
import { assertIsManagementUser, isManagementUser } from "../../managementPages";
|
|
@@ -30,8 +30,6 @@ export async function* watchAllValues<T>(logs: IndexedLogs<T>): AsyncGenerator<T
|
|
|
30
30
|
watchDeltaNodeIds((delta) => {
|
|
31
31
|
for (let nodeId of delta.newNodeIds) {
|
|
32
32
|
if (isOwnNodeId(nodeId)) continue;
|
|
33
|
-
let isPublicNode = !isNodeIdLocal(nodeId);
|
|
34
|
-
if (isPublicNode !== isPublic()) continue;
|
|
35
33
|
process.stdout.write(`Watching errors for ${logs.config.name} on node ${nodeId}\n`);
|
|
36
34
|
ignoreErrors(ErrorNotificationControllerRegistered.nodes[nodeId].watchErrors({
|
|
37
35
|
loggerName: logs.config.name,
|
|
@@ -229,7 +229,9 @@ export class LifeCycleEntryEditor extends qreact.Component<{
|
|
|
229
229
|
hue={0}
|
|
230
230
|
onClick={() => {
|
|
231
231
|
let updatedLifeCycle = deepCloneJSON(lifeCycle);
|
|
232
|
-
updatedLifeCycle.entries
|
|
232
|
+
updatedLifeCycle.entries.forEach((e, idx) => {
|
|
233
|
+
e.groupByKeys = e.groupByKeys.filter(k => k.ourKey !== keyConfig.ourKey);
|
|
234
|
+
});
|
|
233
235
|
Querysub.onCommitFinished(async () => {
|
|
234
236
|
await this.controller.setLifeCycle.promise(updatedLifeCycle);
|
|
235
237
|
});
|
|
@@ -256,7 +258,7 @@ export class LifeCycleEntryEditor extends qreact.Component<{
|
|
|
256
258
|
</div>
|
|
257
259
|
|
|
258
260
|
<div className={css.vbox(4)}>
|
|
259
|
-
{Object.entries(entry.variables).map(([key, varData]) => {
|
|
261
|
+
{Object.entries(entry.variables).map(([key, varData], varIdx) => {
|
|
260
262
|
let keyExistsInAllOtherEntries = lifeCycle.entries.every((e, idx) => {
|
|
261
263
|
if (idx === entryIndex) return true;
|
|
262
264
|
return key in e.variables;
|
|
@@ -281,21 +283,37 @@ export class LifeCycleEntryEditor extends qreact.Component<{
|
|
|
281
283
|
>
|
|
282
284
|
Copy to All
|
|
283
285
|
</Button>
|
|
284
|
-
<
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
286
|
+
<InputLabel
|
|
287
|
+
label="Pos"
|
|
288
|
+
number
|
|
289
|
+
value={varIdx.toString()}
|
|
290
|
+
onChangeValue={(value) => {
|
|
291
|
+
let newPos = parseInt(value);
|
|
292
|
+
if (isNaN(newPos)) return;
|
|
293
|
+
|
|
294
|
+
let updatedLifeCycle = deepCloneJSON(lifeCycle);
|
|
295
|
+
for (let e of updatedLifeCycle.entries) {
|
|
296
|
+
if (!(key in e.variables)) continue;
|
|
297
|
+
let keys = Object.keys(e.variables);
|
|
298
|
+
let currentPos = keys.indexOf(key);
|
|
299
|
+
if (currentPos < 0) continue;
|
|
300
|
+
|
|
301
|
+
let usedNewPos = newPos;
|
|
302
|
+
if (currentPos < usedNewPos) {
|
|
303
|
+
usedNewPos--;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
keys.splice(currentPos, 1);
|
|
307
|
+
keys.splice(usedNewPos, 0, key);
|
|
308
|
+
|
|
309
|
+
e.variables = Object.fromEntries(keys.map(k => [k, e.variables[k]]));
|
|
291
310
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
</Button>
|
|
311
|
+
Querysub.onCommitFinished(async () => {
|
|
312
|
+
await this.controller.setLifeCycle.promise(updatedLifeCycle);
|
|
313
|
+
});
|
|
314
|
+
}}
|
|
315
|
+
className={css.width(60)}
|
|
316
|
+
/>
|
|
299
317
|
<span className={css.minWidth(150).boldStyle}>{key}</span>
|
|
300
318
|
<InputLabel
|
|
301
319
|
placeholder="Variable title"
|
|
@@ -9,6 +9,7 @@ import { niceStringify } from "../../../niceStringify";
|
|
|
9
9
|
import { LogDatum } from "../diskLogger";
|
|
10
10
|
import { LifeCycle, LifeCycleEntry, LifeCyclesController, getVariables } from "./lifeCycles";
|
|
11
11
|
import { NestedLifeCycleInfo } from "./NestedLifeCycleInfo";
|
|
12
|
+
import { formatValue } from "../../../5-diagnostics/GenericFormat";
|
|
12
13
|
|
|
13
14
|
export class LifeCycleEntryReadMode extends qreact.Component<{
|
|
14
15
|
lifeCycle: LifeCycle;
|
|
@@ -89,13 +90,10 @@ export class LifeCycleEntryReadMode extends qreact.Component<{
|
|
|
89
90
|
let renderNestedInfo = (key: string, value: unknown) => {
|
|
90
91
|
if (value === undefined) return null;
|
|
91
92
|
|
|
92
|
-
let isGroupByKey = Array.isArray(entry.groupByKeys) && entry.groupByKeys.some(k => k.ourKey === key);
|
|
93
|
-
let aliases = isGroupByKey && entry.groupByKeys.find(k => k.ourKey === key)?.aliases || entry.variables[key]?.aliases || [];
|
|
94
|
-
|
|
95
93
|
return <NestedLifeCycleInfo
|
|
96
94
|
keyName={key}
|
|
97
95
|
value={value}
|
|
98
|
-
|
|
96
|
+
entry={entry}
|
|
99
97
|
currentLifeCycleId={lifeCycle.id}
|
|
100
98
|
/>;
|
|
101
99
|
};
|
|
@@ -116,7 +114,7 @@ export class LifeCycleEntryReadMode extends qreact.Component<{
|
|
|
116
114
|
<span className={css.minWidth(150).colorhsl(0, 0, 50)}>
|
|
117
115
|
{title || key}{title && ` (${key})` || ""}:
|
|
118
116
|
</span>
|
|
119
|
-
<span className={css.whiteSpace("pre-wrap")}>{
|
|
117
|
+
<span className={css.whiteSpace("pre-wrap")}>{formatValue(value)}</span>
|
|
120
118
|
{renderNestedInfo(key, value)}
|
|
121
119
|
</div>;
|
|
122
120
|
})}
|
|
@@ -130,7 +128,7 @@ export class LifeCycleEntryReadMode extends qreact.Component<{
|
|
|
130
128
|
<span className={css.minWidth(150).colorhsl(0, 0, 50)}>
|
|
131
129
|
{key}
|
|
132
130
|
</span>
|
|
133
|
-
<span className={css.whiteSpace("pre-wrap")}>{
|
|
131
|
+
<span className={css.whiteSpace("pre-wrap")}>{String(value)}</span>
|
|
134
132
|
{renderNestedInfo(key, value)}
|
|
135
133
|
</div>;
|
|
136
134
|
});
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { qreact } from "../../../4-dom/qreact";
|
|
2
|
-
import { Table } from "../../../5-diagnostics/Table";
|
|
2
|
+
import { ColumnsType, Table } from "../../../5-diagnostics/Table";
|
|
3
3
|
import { formatValue } from "../../../5-diagnostics/GenericFormat";
|
|
4
|
-
import { LifeCycle, getVariables } from "./lifeCycles";
|
|
4
|
+
import { LifeCycle, LifeCycleEntry, getVariables } from "./lifeCycles";
|
|
5
5
|
import { LifecycleInstance } from "./lifeCycleSearch";
|
|
6
|
+
import { Button } from "../../../library-components/Button";
|
|
7
|
+
import { NestedLifeCycleInfo } from "./NestedLifeCycleInfo";
|
|
8
|
+
import { formatDateTimeDetailed } from "socket-function/src/formatting/format";
|
|
6
9
|
|
|
7
10
|
export class LifeCycleInstanceTableView extends qreact.Component<{
|
|
8
11
|
lifeCycle: LifeCycle;
|
|
@@ -32,8 +35,10 @@ export class LifeCycleInstanceTableView extends qreact.Component<{
|
|
|
32
35
|
let entry = lifeCycle.entries.find(e => e.matchPattern === entryData.matchPattern);
|
|
33
36
|
let entryTitle = entry && (entry.description || entry.matchPattern) || entryData.matchPattern;
|
|
34
37
|
|
|
35
|
-
let row: { entryTitle: string;[key: string]: unknown } = {
|
|
38
|
+
let row: { entryTitle: string; logDatum: unknown; entry: unknown;[key: string]: unknown } = {
|
|
36
39
|
entryTitle: entryTitle,
|
|
40
|
+
logDatum: entryData.datum,
|
|
41
|
+
entry: entry,
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
if (entry) {
|
|
@@ -46,17 +51,43 @@ export class LifeCycleInstanceTableView extends qreact.Component<{
|
|
|
46
51
|
return row;
|
|
47
52
|
});
|
|
48
53
|
|
|
49
|
-
let columns:
|
|
54
|
+
let columns: ColumnsType = {
|
|
50
55
|
entryTitle: { title: "Entry" },
|
|
51
56
|
};
|
|
52
57
|
|
|
53
58
|
for (let columnKey of allColumnKeys) {
|
|
59
|
+
let hasDefinedValue = rows.some(row => row[columnKey] !== undefined);
|
|
60
|
+
if (!hasDefinedValue) continue;
|
|
61
|
+
|
|
54
62
|
columns[columnKey] = {
|
|
55
63
|
title: columnKeyToTitle.get(columnKey) || columnKey,
|
|
56
|
-
formatter: (value
|
|
64
|
+
formatter: (value, context) => {
|
|
65
|
+
const entry = context?.row?.entry;
|
|
66
|
+
let formattedValue = formatValue(value);
|
|
67
|
+
if (value && context?.columnName?.toString().toLowerCase().includes("timeid")) {
|
|
68
|
+
formattedValue = formatDateTimeDetailed(Number(value));
|
|
69
|
+
}
|
|
70
|
+
if (value && context?.columnName === "time") {
|
|
71
|
+
formattedValue = formatDateTimeDetailed(Number(value));
|
|
72
|
+
}
|
|
73
|
+
return <>
|
|
74
|
+
{formattedValue}
|
|
75
|
+
{entry && value && <NestedLifeCycleInfo
|
|
76
|
+
keyName={columnKey}
|
|
77
|
+
value={value}
|
|
78
|
+
entry={entry as LifeCycleEntry}
|
|
79
|
+
currentLifeCycleId={lifeCycle.id}
|
|
80
|
+
/> || undefined}
|
|
81
|
+
</>;
|
|
82
|
+
},
|
|
57
83
|
};
|
|
58
84
|
}
|
|
59
85
|
|
|
86
|
+
columns.logDatum = {
|
|
87
|
+
title: "Log",
|
|
88
|
+
formatter: datum => <Button onClick={() => console.log(datum)}>Log</Button>,
|
|
89
|
+
};
|
|
90
|
+
|
|
60
91
|
return <Table rows={rows} columns={columns} />;
|
|
61
92
|
}
|
|
62
93
|
}
|
|
@@ -32,7 +32,8 @@ import { isPublic } from "../../../config";
|
|
|
32
32
|
export let lifecycleIdURL = new URLParam("lifecycleid", "");
|
|
33
33
|
export let limitURL = new URLParam("lifecyclelimit", 16);
|
|
34
34
|
export let additionalSearchURL = new URLParam("lifecyclesearch", "");
|
|
35
|
-
export let
|
|
35
|
+
export let phase2AdditionalSearchURL = new URLParam("lifecyclephase2search", "");
|
|
36
|
+
export let lifecycleTableViewURL = new URLParam("lifecycletable", true);
|
|
36
37
|
|
|
37
38
|
export class LifeCyclePage extends qreact.Component {
|
|
38
39
|
controller = LifeCyclesController(SocketFunction.browserNodeId());
|
|
@@ -54,7 +55,7 @@ export class LifeCyclePage extends qreact.Component {
|
|
|
54
55
|
search = createLifeCycleSearch(this);
|
|
55
56
|
|
|
56
57
|
searchLifeCycle = (lifeCycleId: string) => {
|
|
57
|
-
return this.search.searchLifeCycle({ lifeCycleId, additionalSearch: additionalSearchURL.value.trim(), limit: limitURL.value });
|
|
58
|
+
return this.search.searchLifeCycle({ lifeCycleId, additionalSearch: additionalSearchURL.value.trim(), phase2AdditionalSearch: phase2AdditionalSearchURL.value.trim(), limit: limitURL.value });
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
componentDidMount() {
|
|
@@ -109,7 +110,7 @@ export class LifeCyclePage extends qreact.Component {
|
|
|
109
110
|
</div>
|
|
110
111
|
|
|
111
112
|
<InputLabelURL
|
|
112
|
-
label="Additional Search"
|
|
113
|
+
label="Additional Search (Phase 1)"
|
|
113
114
|
placeholder="Additional search filter..."
|
|
114
115
|
url={additionalSearchURL}
|
|
115
116
|
fillWidth
|
|
@@ -121,6 +122,19 @@ export class LifeCyclePage extends qreact.Component {
|
|
|
121
122
|
}}
|
|
122
123
|
/>
|
|
123
124
|
|
|
125
|
+
<InputLabelURL
|
|
126
|
+
label="Additional Search (Phase 2)"
|
|
127
|
+
placeholder="Additional search filter..."
|
|
128
|
+
url={phase2AdditionalSearchURL}
|
|
129
|
+
fillWidth
|
|
130
|
+
onKeyDown={(e) => {
|
|
131
|
+
if (e.key === "Enter" && lifecycleIdURL.value) {
|
|
132
|
+
phase2AdditionalSearchURL.value = e.currentTarget.value;
|
|
133
|
+
void this.searchLifeCycle(lifecycleIdURL.value);
|
|
134
|
+
}
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
|
|
124
138
|
<div className={css.hbox(12).wrap}>
|
|
125
139
|
<InputLabel
|
|
126
140
|
placeholder="Add new life cycle"
|
|
@@ -134,7 +148,7 @@ export class LifeCyclePage extends qreact.Component {
|
|
|
134
148
|
matchPattern: value,
|
|
135
149
|
groupByKeys: [],
|
|
136
150
|
isStart: true,
|
|
137
|
-
sourceType: "
|
|
151
|
+
sourceType: "info",
|
|
138
152
|
variables: {},
|
|
139
153
|
}],
|
|
140
154
|
};
|
|
@@ -188,7 +202,7 @@ export class LifeCyclePage extends qreact.Component {
|
|
|
188
202
|
{(this.state.phase1Searching || this.state.phase1Results.length > 0) && (
|
|
189
203
|
<div className={css.vbox(8)}>
|
|
190
204
|
<div className={css.boldStyle}>
|
|
191
|
-
Phase 1: Start Entries ({this.state.phase1Results.length} valid)
|
|
205
|
+
Phase 1: Start Entries ({this.state.phase1Results.length} valid{this.state.phase1Results.length >= limitURL.value && ", IMPORTANT! If recent events have an old start, we might miss them due to time filtering. Restrict your input with additional search until results < limit to ensure you don't miss any values"})
|
|
192
206
|
{this.state.phase1Searching && " - Searching..."}
|
|
193
207
|
</div>
|
|
194
208
|
{this.state.phase1Stats && (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
2
|
-
import { formatDateTime, formatTime } from "socket-function/src/formatting/format";
|
|
3
|
-
import { deepCloneJSON } from "socket-function/src/misc";
|
|
2
|
+
import { formatDateTime, formatDateTimeDetailed, formatTime } from "socket-function/src/formatting/format";
|
|
3
|
+
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";
|
|
@@ -78,6 +78,15 @@ export class LifeCycleRenderer extends qreact.Component<{
|
|
|
78
78
|
Pin
|
|
79
79
|
</Button>
|
|
80
80
|
)}
|
|
81
|
+
<Button hue={200} onClick={() => {
|
|
82
|
+
let newLifeCycle = deepCloneJSON(lifeCycle);
|
|
83
|
+
newLifeCycle.id = nextId();
|
|
84
|
+
Querysub.onCommitFinished(async () => {
|
|
85
|
+
await this.controller.setLifeCycle.promise(newLifeCycle);
|
|
86
|
+
});
|
|
87
|
+
}}>
|
|
88
|
+
Clone
|
|
89
|
+
</Button>
|
|
81
90
|
<Button
|
|
82
91
|
hue={0}
|
|
83
92
|
onClick={() => {
|
|
@@ -125,12 +134,11 @@ export class LifeCycleRenderer extends qreact.Component<{
|
|
|
125
134
|
onChangeValue={(value) => {
|
|
126
135
|
let matchPattern = value.trim();
|
|
127
136
|
if (matchPattern) {
|
|
128
|
-
let defaultGroupByKeys = lifeCycle.entries.length > 0 && lifeCycle.entries[0].groupByKeys && deepCloneJSON(lifeCycle.entries[0].groupByKeys) || [];
|
|
129
137
|
let newEntry: LifeCycleEntry = {
|
|
130
138
|
matchPattern,
|
|
131
139
|
sourceType: "info",
|
|
132
|
-
groupByKeys:
|
|
133
|
-
variables: {},
|
|
140
|
+
groupByKeys: deepCloneJSON(lifeCycle.entries[0]?.groupByKeys || []),
|
|
141
|
+
variables: deepCloneJSON(lifeCycle.entries[0]?.variables || {}),
|
|
134
142
|
};
|
|
135
143
|
let updatedLifeCycle = deepCloneJSON(lifeCycle);
|
|
136
144
|
let firstEndIndex = updatedLifeCycle.entries.findIndex(e => e.isEnd);
|
|
@@ -213,9 +221,9 @@ export class LifeCycleInstanceRenderer extends qreact.Component<{
|
|
|
213
221
|
>
|
|
214
222
|
{this.state.expanded && "▼" || "▶"}
|
|
215
223
|
</Button>
|
|
216
|
-
<span className={css.minWidth(200).hbox(12)}>
|
|
224
|
+
<span className={css.minWidth(200).hbox(12)} title={`${instance.startTime} to ${instance.endTime}`}>
|
|
217
225
|
<span className={css.colorhsl(220, 60, 50)}>
|
|
218
|
-
{
|
|
226
|
+
{formatDateTimeDetailed(instance.startTime)}
|
|
219
227
|
</span>
|
|
220
228
|
{instance.endTime !== undefined && (
|
|
221
229
|
<span className={css.colorhsl(220, 60, 50)}>
|