@checkstack/ui 1.8.2 → 1.9.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/CHANGELOG.md +69 -0
- package/package.json +6 -2
- package/scripts/generate-stdlib-types.ts +90 -0
- package/src/components/CodeEditor/CodeEditor.tsx +7 -0
- package/src/components/CodeEditor/MonacoEditor.tsx +203 -117
- package/src/components/CodeEditor/generateTypeDefinitions.ts +19 -26
- package/src/components/CodeEditor/generated/stdlib-types.json +1 -0
- package/src/components/CodeEditor/index.ts +7 -0
- package/src/components/CodeEditor/monacoStdlib.ts +62 -0
- package/src/components/CodeEditor/monacoWorkers.ts +118 -0
- package/src/components/CodeEditor/scriptContext.test.ts +280 -0
- package/src/components/CodeEditor/scriptContext.ts +467 -0
- package/src/components/CodeEditor/shellEnvVarMatcher.test.ts +95 -0
- package/src/components/CodeEditor/shellEnvVarMatcher.ts +70 -0
- package/src/components/DynamicForm/DynamicForm.tsx +6 -0
- package/src/components/DynamicForm/FormField.tsx +15 -0
- package/src/components/DynamicForm/MultiTypeEditorField.tsx +111 -6
- package/src/components/DynamicForm/index.ts +2 -0
- package/src/components/DynamicForm/starterTemplateSelector.test.ts +96 -0
- package/src/components/DynamicForm/starterTemplateSelector.ts +32 -0
- package/src/components/DynamicForm/types.ts +34 -1
- package/src/components/LinksEditor.tsx +69 -34
- package/src/hooks/useInitOnceForKey.test.ts +127 -0
- package/src/hooks/useInitOnceForKey.ts +87 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure decision function powering {@link useInitOnceForKey}. Extracted so
|
|
5
|
+
* it can be unit-tested without a DOM (the hook itself wraps this with
|
|
6
|
+
* a `useRef` + `useEffect`).
|
|
7
|
+
*
|
|
8
|
+
* Returns `true` iff the caller should run their initialiser:
|
|
9
|
+
*
|
|
10
|
+
* - `value` is defined (the query has finished loading), AND
|
|
11
|
+
* - `key` is defined (we have a discriminator to track init-per-record),
|
|
12
|
+
* AND
|
|
13
|
+
* - we haven't yet initialised for this key (i.e. `initialisedKey !== key`).
|
|
14
|
+
*
|
|
15
|
+
* Background refetches of the same record produce a new `value` reference
|
|
16
|
+
* but the same `key`, so the function returns `false` for them — that's
|
|
17
|
+
* the whole point.
|
|
18
|
+
*/
|
|
19
|
+
export function shouldInitForKey({
|
|
20
|
+
value,
|
|
21
|
+
key,
|
|
22
|
+
initialisedKey,
|
|
23
|
+
}: {
|
|
24
|
+
value: unknown;
|
|
25
|
+
key: string | number | null | undefined;
|
|
26
|
+
initialisedKey: string | number | null | undefined;
|
|
27
|
+
}): boolean {
|
|
28
|
+
if (value === undefined || value === null) return false;
|
|
29
|
+
if (key === undefined || key === null) return false;
|
|
30
|
+
return initialisedKey !== key;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Run a one-shot initialiser exactly once per `key`, ignoring subsequent
|
|
35
|
+
* `value` changes that keep the same key.
|
|
36
|
+
*
|
|
37
|
+
* Built for forms that need to seed local state from a react-query result
|
|
38
|
+
* but **must not** reset that state when the query refetches in the
|
|
39
|
+
* background. The canonical use case is the healthcheck editor: a realtime
|
|
40
|
+
* `HEALTH_CHECK_RUN_COMPLETED` signal invalidates the configuration query
|
|
41
|
+
* on every run, which would otherwise wipe the user's in-progress edits
|
|
42
|
+
* via a naive `useEffect([data], () => setState(data))`.
|
|
43
|
+
*
|
|
44
|
+
* Behaviour:
|
|
45
|
+
* - Calls `onInit(value)` the first time `value` is defined for a given
|
|
46
|
+
* `key`.
|
|
47
|
+
* - **Does NOT** call it again if `value` changes but `key` stays the
|
|
48
|
+
* same. Background refetches keep the same key (= the same record's
|
|
49
|
+
* primary id) and therefore don't re-run the initialiser.
|
|
50
|
+
* - **Does** call it again when `key` changes — e.g. when the user
|
|
51
|
+
* navigates to a different record without unmounting the page.
|
|
52
|
+
* - Skips initialisation entirely while either `value` or `key` is
|
|
53
|
+
* `undefined`/`null`.
|
|
54
|
+
*
|
|
55
|
+
* `onInit` is read from a ref so callers can safely pass a fresh closure
|
|
56
|
+
* each render without re-firing the effect.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* useInitOnceForKey(existingConfig, existingConfig?.id, (config) => {
|
|
60
|
+
* setFormState({
|
|
61
|
+
* name: config.name,
|
|
62
|
+
* collectors: config.collectors ?? [],
|
|
63
|
+
* });
|
|
64
|
+
* });
|
|
65
|
+
*/
|
|
66
|
+
export function useInitOnceForKey<T>(
|
|
67
|
+
value: T | undefined | null,
|
|
68
|
+
key: string | number | null | undefined,
|
|
69
|
+
onInit: (value: T) => void,
|
|
70
|
+
): void {
|
|
71
|
+
const initialisedKeyRef = useRef<string | number | null | undefined>(undefined);
|
|
72
|
+
const onInitRef = useRef(onInit);
|
|
73
|
+
|
|
74
|
+
// Keep the latest callback in a ref so a fresh closure each render doesn't
|
|
75
|
+
// re-trigger the effect; only `value` and `key` should drive it.
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
onInitRef.current = onInit;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (!shouldInitForKey({ value, key, initialisedKey: initialisedKeyRef.current })) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
initialisedKeyRef.current = key;
|
|
85
|
+
onInitRef.current(value as T);
|
|
86
|
+
}, [value, key]);
|
|
87
|
+
}
|
package/src/index.ts
CHANGED