Make basic Signal Digith work
This commit is contained in:
parent
bf5eb54932
commit
c0198d419f
15 changed files with 464 additions and 73 deletions
154
src/ui/Digith/Signal/SignalDigith.tsx
Normal file
154
src/ui/Digith/Signal/SignalDigith.tsx
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import { createEffect, createSignal, onCleanup, Show } from "solid-js";
|
||||
import { Digith } from "src/ui/Digith";
|
||||
import { useProgram } from "src/ui/ProgramProvider";
|
||||
import { CodeEditor } from "src/ui/Component/CodeEditor";
|
||||
import { sourceText } from "src/lang/parser/source_text";
|
||||
import { Program } from "src/lang/program";
|
||||
import { V, Validation, letValidate } from "src/ui/validation";
|
||||
import { validateSignalExprRaw } from "src/ui/validation/helpers";
|
||||
import { updateDigith } from "src/ui/Scrowl/scrowlStore";
|
||||
import { DigithError } from "src/ui/Digith/DigithError";
|
||||
import { Value } from "src/lang/eval/value";
|
||||
import { Val } from "src/ui/Component/Value";
|
||||
|
||||
type Input = {
|
||||
raw_body: string,
|
||||
}
|
||||
|
||||
const validator: Validation<Input, Program.UpdateSignal, DigithError> = letValidate(
|
||||
(input) => ({
|
||||
body: V.elseErr(validateSignalExprRaw(input.raw_body), err => ({
|
||||
payload: { tag: "Parse", field: "body", err, src: sourceText(input.raw_body) },
|
||||
ids: ["body"],
|
||||
tags: ["footer"],
|
||||
config: { title: "Signal Body" },
|
||||
})),
|
||||
}),
|
||||
(fields, input) => {
|
||||
return V.ok({
|
||||
body: fields.body,
|
||||
raw_body: input.raw_body
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export function SignalDigith(props: { signal: Digith.Signal }) {
|
||||
const program = useProgram();
|
||||
|
||||
const [value, setValue] = createSignal<Value | null>(null);
|
||||
|
||||
const [body, setBody] = createSignal(props.signal.raw_body);
|
||||
|
||||
const [errors, setErrors] = createSignal<DigithError[]>([]);
|
||||
|
||||
const isDirty = () =>
|
||||
body() !== props.signal.raw_body;
|
||||
|
||||
createEffect(() => {
|
||||
// TODO: Improve runtime error view
|
||||
try {
|
||||
const signal = Program.get_or_create_signal(program, props.signal.name);
|
||||
|
||||
// TODO: Not sure about this one. Setting a signal in `setValue` is discouraged.
|
||||
setTimeout(() => setValue(signal.read()), 0);
|
||||
// TODO: Handle cancelation...
|
||||
signal.subscribe((newValue) => {
|
||||
setValue(newValue);
|
||||
});
|
||||
onCleanup(() => {
|
||||
// TODO:
|
||||
});
|
||||
} catch (e) {
|
||||
// TODO: setErrors... but how? Shouldn't this be independent of `errors`?
|
||||
console.log("Failed to link Signal: ", e);
|
||||
}
|
||||
});
|
||||
|
||||
function handleRedefine() {
|
||||
setErrors([]);
|
||||
|
||||
const validRes = validator({ raw_body: body() });
|
||||
if (validRes.tag === "errors") {
|
||||
setErrors(validRes.errors);
|
||||
return;
|
||||
}
|
||||
const updateData = validRes.value;
|
||||
|
||||
const progRes = Program.updateSignal(program, props.signal.name, {
|
||||
body: updateData.body,
|
||||
raw_body: updateData.raw_body
|
||||
});
|
||||
|
||||
if (progRes.tag === "error") {
|
||||
setErrors([{
|
||||
payload: { tag: "Program", err: progRes.error },
|
||||
ids: ["program"],
|
||||
tags: ["footer"],
|
||||
config: { title: "Update Failed" },
|
||||
}]);
|
||||
return;
|
||||
}
|
||||
|
||||
// reloading the digith
|
||||
updateDigith(props.signal.id, {
|
||||
...props.signal,
|
||||
raw_body: updateData.raw_body
|
||||
});
|
||||
}
|
||||
// TODO
|
||||
return (
|
||||
<article>
|
||||
<header>
|
||||
<strong>Signal</strong>
|
||||
|
||||
{/* Dirty Indicator / Status */}
|
||||
<div>
|
||||
<Show when={isDirty()} fallback={<span style={{color: "var(--pico-muted-color)"}}>Synced</span>}>
|
||||
<span style={{color: "var(--pico-primary)"}}>● Unsaved Changes</span>
|
||||
</Show>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
Name
|
||||
<input
|
||||
type="text"
|
||||
value={props.signal.name}
|
||||
disabled
|
||||
style={{ opacity: 0.7, cursor: "not-allowed" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label>Body</label>
|
||||
<CodeEditor
|
||||
value={body()}
|
||||
onUpdate={setBody}
|
||||
onRun={handleRedefine}
|
||||
/>
|
||||
|
||||
<footer style={{ display: "flex", "align-items": "center", gap: "1rem" }}>
|
||||
<button
|
||||
onClick={handleRedefine}
|
||||
disabled={!isDirty()}
|
||||
>
|
||||
Redefine
|
||||
</button>
|
||||
|
||||
</footer>
|
||||
|
||||
<div style={{ "margin-top": "1rem" }}>
|
||||
<DigithError.ByTag errors={errors()} tag="footer" />
|
||||
</div>
|
||||
|
||||
<Show when={ value() } fallback={<div>Initializing...</div>}>
|
||||
{(value) => (
|
||||
<div>
|
||||
<label>Current Value</label>
|
||||
<Val value={ value() } />
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue