querysub 0.252.0 → 0.253.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 +2 -2
- package/src/3-path-functions/PathFunctionRunner.ts +1 -0
- package/src/4-deploy/git.ts +34 -1
- package/src/deployManager/MachinesPage.tsx +7 -10
- package/src/deployManager/components/MachineDetailPage.tsx +13 -21
- package/src/deployManager/components/MachinesListPage.tsx +59 -48
- package/src/deployManager/components/ServiceDetailPage.tsx +7 -9
- package/src/deployManager/components/ServicesListPage.tsx +41 -31
- package/src/deployManager/components/deployButtons.tsx +212 -0
- package/src/deployManager/machineApplyMainCode.ts +10 -4
- package/src/deployManager/machineController.ts +31 -4
- package/src/deployManager/machineSchema.ts +134 -45
- package/src/deployManager/spec.txt +3 -62
- package/src/deployManager/urlParams.ts +0 -1
- package/src/diagnostics/errorLogs/ErrorLogController.ts +1 -0
- package/src/diagnostics/errorLogs/LogClassifiers.tsx +6 -0
- package/src/library-components/SyncedController.ts +91 -31
- package/src/misc/formatJSX.tsx +6 -0
|
@@ -2,7 +2,6 @@ import { URLParam } from "../library-components/URLParam";
|
|
|
2
2
|
|
|
3
3
|
export type ViewType = "services" | "machines" | "service-detail" | "machine-detail";
|
|
4
4
|
|
|
5
|
-
// URL Parameters for navigation state
|
|
6
5
|
export const currentViewParam = new URLParam<ViewType>("machineview", "machines");
|
|
7
6
|
export const selectedServiceIdParam = new URLParam("serviceId", "");
|
|
8
7
|
export const selectedMachineIdParam = new URLParam("machineId", "");
|
|
@@ -140,6 +140,7 @@ let ensureBlocksFlushing = lazy(() => {
|
|
|
140
140
|
let pendingLogs: { log: LogRaw; type: LogType }[] = [];
|
|
141
141
|
let logClassifier: ((log: LogRaw, typeHint: LogType) => LogClass) | undefined;
|
|
142
142
|
let initLogClassifier = lazy(async () => {
|
|
143
|
+
if (!isNode()) return null as never;
|
|
143
144
|
let logClasses = await new ErrorLogControllerBase().getClasses();
|
|
144
145
|
logClassifier = getLogClassCategorizer(logClasses);
|
|
145
146
|
if (pendingLogs.length > 0) {
|
|
@@ -284,6 +284,12 @@ export class SuppressUntil extends qreact.Component<{
|
|
|
284
284
|
</>
|
|
285
285
|
)}
|
|
286
286
|
</div>
|
|
287
|
+
{type !== "info" && <Button
|
|
288
|
+
onClick={() => updateClass({ suppressUntil: changeTime })}
|
|
289
|
+
class={css.hsl(infoColor.h, infoColor.s, infoColor.l)}
|
|
290
|
+
>
|
|
291
|
+
Fixed
|
|
292
|
+
</Button>}
|
|
287
293
|
{type !== "info" && <Button
|
|
288
294
|
onClick={() => updateClass({ type: "info" })}
|
|
289
295
|
class={css.hsl(infoColor.h, infoColor.s, infoColor.l)}
|
|
@@ -8,12 +8,16 @@ import { formatTime } from "socket-function/src/formatting/format";
|
|
|
8
8
|
import { nextId } from "socket-function/src/misc";
|
|
9
9
|
import { getCallObj } from "socket-function/src/nodeProxy";
|
|
10
10
|
import { MaybePromise } from "socket-function/src/types";
|
|
11
|
+
import { isNode } from "typesafecss";
|
|
11
12
|
|
|
12
13
|
// IMPORTANT! See cacheAsyncSynced if you just want to run promise functions
|
|
13
14
|
|
|
14
15
|
let controllerIds = new Set<string>();
|
|
15
16
|
|
|
16
17
|
module.hotreload = false;
|
|
18
|
+
// NOTE: Most SyncedController are defined in files we don't hotreload anyways, so the page will refresh on changes. And if they aren't... they should be.
|
|
19
|
+
// - And if we reload all the calls on hot reload, it makes iterating on the UI extremely annoying. So... we don't anymore.
|
|
20
|
+
/*
|
|
17
21
|
onHotReload(() => {
|
|
18
22
|
Querysub.commitLocal(() => {
|
|
19
23
|
let root = syncedData();
|
|
@@ -31,14 +35,15 @@ onHotReload(() => {
|
|
|
31
35
|
}
|
|
32
36
|
});
|
|
33
37
|
});
|
|
38
|
+
*/
|
|
34
39
|
|
|
35
40
|
export function syncedIsAnyLoading() {
|
|
36
41
|
return Querysub.fastRead(() => {
|
|
37
42
|
for (let controllerId in syncedData()) {
|
|
38
|
-
for (let
|
|
39
|
-
for (let fnc
|
|
40
|
-
for (let
|
|
41
|
-
if (atomic(
|
|
43
|
+
for (let fncs of Object.values(syncedData()[controllerId])) {
|
|
44
|
+
for (let fnc of Object.values(fncs)) {
|
|
45
|
+
for (let obj of Object.values(fnc)) {
|
|
46
|
+
if (atomic(obj.promise)) {
|
|
42
47
|
return true;
|
|
43
48
|
}
|
|
44
49
|
}
|
|
@@ -103,6 +108,58 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
103
108
|
refreshAll(): void;
|
|
104
109
|
isAnyLoading(): boolean;
|
|
105
110
|
} {
|
|
111
|
+
if (isNode()) {
|
|
112
|
+
let result = cache((nodeId: string) => {
|
|
113
|
+
let proxy = new Proxy({}, {
|
|
114
|
+
get: (target, fncNameUntyped) => {
|
|
115
|
+
if (typeof fncNameUntyped !== "string") return undefined;
|
|
116
|
+
if (fncNameUntyped === "resetAll" || fncNameUntyped === "refreshAll" || fncNameUntyped === "isAnyLoading") {
|
|
117
|
+
return notAllowedOnServer;
|
|
118
|
+
}
|
|
119
|
+
let fncName = fncNameUntyped;
|
|
120
|
+
function call(...args: any[]) {
|
|
121
|
+
notAllowedOnServer();
|
|
122
|
+
}
|
|
123
|
+
call.promise = (...args: any[]) => {
|
|
124
|
+
return controller.nodes[nodeId][fncName](...args);
|
|
125
|
+
};
|
|
126
|
+
call.reset = (...args: any[]) => {
|
|
127
|
+
notAllowedOnServer();
|
|
128
|
+
};
|
|
129
|
+
call.resetAll = () => {
|
|
130
|
+
notAllowedOnServer();
|
|
131
|
+
};
|
|
132
|
+
call.refresh = (...args: any[]) => {
|
|
133
|
+
notAllowedOnServer();
|
|
134
|
+
};
|
|
135
|
+
call.refreshAll = () => {
|
|
136
|
+
notAllowedOnServer();
|
|
137
|
+
};
|
|
138
|
+
call.isAnyLoading = () => {
|
|
139
|
+
notAllowedOnServer();
|
|
140
|
+
};
|
|
141
|
+
call.setCache = (config: { args: any[], result: any }) => {
|
|
142
|
+
notAllowedOnServer();
|
|
143
|
+
};
|
|
144
|
+
return call;
|
|
145
|
+
}
|
|
146
|
+
}) as any;
|
|
147
|
+
return proxy;
|
|
148
|
+
}) as any;
|
|
149
|
+
function notAllowedOnServer() {
|
|
150
|
+
throw new Error(`Syncing with getSyncedController is not allowed on the server. If we absolutely need this we can support it, but... you should just be using raw synced state anyways.`);
|
|
151
|
+
}
|
|
152
|
+
result.resetAll = () => {
|
|
153
|
+
notAllowedOnServer();
|
|
154
|
+
};
|
|
155
|
+
result.refreshAll = () => {
|
|
156
|
+
notAllowedOnServer();
|
|
157
|
+
};
|
|
158
|
+
result.isAnyLoading = () => {
|
|
159
|
+
notAllowedOnServer();
|
|
160
|
+
};
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
106
163
|
let id = nextId();
|
|
107
164
|
controllerIds.add(id);
|
|
108
165
|
|
|
@@ -151,9 +208,9 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
151
208
|
if (fncNameUntyped === "refreshAll") {
|
|
152
209
|
return () => {
|
|
153
210
|
return Querysub.commitLocal(() => {
|
|
154
|
-
for (let fnc
|
|
155
|
-
for (let
|
|
156
|
-
|
|
211
|
+
for (let fnc of Object.values(syncedData()[id][nodeId])) {
|
|
212
|
+
for (let obj of Object.values(fnc)) {
|
|
213
|
+
obj.invalidated = true;
|
|
157
214
|
}
|
|
158
215
|
}
|
|
159
216
|
});
|
|
@@ -162,9 +219,9 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
162
219
|
if (fncNameUntyped === "isAnyLoading") {
|
|
163
220
|
return () => {
|
|
164
221
|
return Querysub.commitLocal(() => {
|
|
165
|
-
for (let fnc
|
|
166
|
-
for (let
|
|
167
|
-
if (atomic(
|
|
222
|
+
for (let fnc of Object.values(syncedData()[id][nodeId])) {
|
|
223
|
+
for (let obj of Object.values(fnc)) {
|
|
224
|
+
if (atomic(obj.promise)) {
|
|
168
225
|
return true;
|
|
169
226
|
}
|
|
170
227
|
}
|
|
@@ -195,14 +252,13 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
195
252
|
doAtomicWrites(() => {
|
|
196
253
|
obj.promise = promise;
|
|
197
254
|
});
|
|
198
|
-
function
|
|
255
|
+
function invalidateReaders() {
|
|
199
256
|
let root = syncedData();
|
|
200
257
|
for (let writesTo of config?.writes?.[fncName] || []) {
|
|
201
258
|
for (let watcher of writeWatchers.get(writesTo) || []) {
|
|
202
|
-
for (let
|
|
203
|
-
for (let fnc
|
|
204
|
-
for (let
|
|
205
|
-
let obj = root[watcher.controllerId][nodeId][fnc][argsHash];
|
|
259
|
+
for (let fncs of Object.values(root[watcher.controllerId])) {
|
|
260
|
+
for (let fnc of Object.values(fncs)) {
|
|
261
|
+
for (let obj of Object.values(fnc)) {
|
|
206
262
|
obj.invalidated = true;
|
|
207
263
|
}
|
|
208
264
|
}
|
|
@@ -216,7 +272,7 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
216
272
|
Querysub.commitLocal(() => {
|
|
217
273
|
obj.result = atomicObjectWriteNoFreeze({ result });
|
|
218
274
|
obj.promise = undefined;
|
|
219
|
-
|
|
275
|
+
invalidateReaders();
|
|
220
276
|
});
|
|
221
277
|
},
|
|
222
278
|
error => {
|
|
@@ -224,7 +280,7 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
224
280
|
Querysub.commitLocal(() => {
|
|
225
281
|
obj.result = atomicObjectWriteNoFreeze({ error });
|
|
226
282
|
obj.promise = undefined;
|
|
227
|
-
|
|
283
|
+
invalidateReaders();
|
|
228
284
|
});
|
|
229
285
|
}
|
|
230
286
|
);
|
|
@@ -243,9 +299,13 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
243
299
|
}
|
|
244
300
|
call.promise = (...args: any[]) => {
|
|
245
301
|
return Querysub.fastRead(() => {
|
|
246
|
-
call(...args);
|
|
247
302
|
let argsHash = JSON.stringify(args);
|
|
248
|
-
let
|
|
303
|
+
let obj = syncedData()[id][nodeId][fncName][argsHash];
|
|
304
|
+
// Reset promise, to force it to not use the cache, as promise functions should never be cached. This might result in the results being set out of order, but... generally functions called with promise and accessed inside a watcher, so this should be fine.
|
|
305
|
+
obj.promise = undefined;
|
|
306
|
+
obj.invalidated = true;
|
|
307
|
+
call(...args);
|
|
308
|
+
let promise = atomic(obj.promise);
|
|
249
309
|
if (!promise) {
|
|
250
310
|
debugger;
|
|
251
311
|
throw new Error(`Impossible, called function, but promise is not found for ${fncName}`);
|
|
@@ -279,15 +339,15 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
279
339
|
};
|
|
280
340
|
call.refreshAll = () => {
|
|
281
341
|
return Querysub.commitLocal(() => {
|
|
282
|
-
for (let
|
|
283
|
-
|
|
342
|
+
for (let obj of Object.values(syncedData()[id][nodeId][fncName])) {
|
|
343
|
+
obj.invalidated = true;
|
|
284
344
|
}
|
|
285
345
|
});
|
|
286
346
|
};
|
|
287
347
|
call.isAnyLoading = () => {
|
|
288
348
|
return Querysub.commitLocal(() => {
|
|
289
|
-
for (let
|
|
290
|
-
if (atomic(
|
|
349
|
+
for (let obj of Object.values(syncedData()[id][nodeId][fncName])) {
|
|
350
|
+
if (atomic(obj.promise)) {
|
|
291
351
|
return true;
|
|
292
352
|
}
|
|
293
353
|
}
|
|
@@ -320,10 +380,10 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
320
380
|
};
|
|
321
381
|
result.refreshAll = () => {
|
|
322
382
|
return Querysub.commitLocal(() => {
|
|
323
|
-
for (let
|
|
324
|
-
for (let fnc
|
|
325
|
-
for (let
|
|
326
|
-
|
|
383
|
+
for (let fncs of Object.values(syncedData()[id])) {
|
|
384
|
+
for (let fnc of Object.values(fncs)) {
|
|
385
|
+
for (let obj of Object.values(fnc)) {
|
|
386
|
+
obj.invalidated = true;
|
|
327
387
|
}
|
|
328
388
|
}
|
|
329
389
|
}
|
|
@@ -331,10 +391,10 @@ export function getSyncedController<T extends SocketRegistered>(
|
|
|
331
391
|
};
|
|
332
392
|
result.isAnyLoading = () => {
|
|
333
393
|
return Querysub.commitLocal(() => {
|
|
334
|
-
for (let
|
|
335
|
-
for (let fnc
|
|
336
|
-
for (let
|
|
337
|
-
if (atomic(
|
|
394
|
+
for (let fncs of Object.values(syncedData()[id])) {
|
|
395
|
+
for (let fnc of Object.values(fncs)) {
|
|
396
|
+
for (let obj of Object.values(fnc)) {
|
|
397
|
+
if (atomic(obj.promise)) {
|
|
338
398
|
return true;
|
|
339
399
|
}
|
|
340
400
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { qreact } from "../4-dom/qreact";
|
|
2
|
+
import { formatTime, formatVeryNiceDateTime } from "socket-function/src/formatting/format";
|
|
3
|
+
|
|
4
|
+
export function formatTimeJSX(time: number) {
|
|
5
|
+
return <span title={formatVeryNiceDateTime(time)}>({formatTime(Date.now() - time)})</span>;
|
|
6
|
+
}
|