Skip to content

Commit

Permalink
Merge pull request #2984 from quantified-uncertainty/refactorings-and…
Browse files Browse the repository at this point in the history
…-empty-results

SquiggleOutputViewer refactorings and empty results
  • Loading branch information
OAGr authored Jan 19, 2024
2 parents 6dfbfd6 + bf69e56 commit 0baa7f7
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 244 deletions.
23 changes: 10 additions & 13 deletions packages/components/src/components/SquiggleChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
StandaloneExecutionProps,
useSquiggle,
} from "../lib/hooks/useSquiggle.js";
import { getResultValue, getResultVariables } from "../lib/utility.js";
import { MessageAlert } from "./Alert.js";
import { PartialPlaygroundSettings } from "./PlaygroundSettings.js";
import { SquiggleErrorAlert } from "./SquiggleErrorAlert.js";
Expand Down Expand Up @@ -52,23 +51,21 @@ export const SquiggleChart: FC<SquiggleChartProps> = memo(
}

if (rootPathOverride) {
const { output } = squiggleOutput;
if (!output.ok) {
return <SquiggleErrorAlert error={output.value} />;
}
const rootValue =
rootPathOverride.root === "result"
? getResultValue(squiggleOutput)
: getResultVariables(squiggleOutput);
if (!rootValue) {
return <MessageAlert heading="Value is not defined" />;
}
if (!rootValue.ok) {
return <SquiggleErrorAlert error={rootValue.value} />;
}
? output.value.result
: output.value.bindings.asValue();

const value = getSubvalueByPath(rootValue.value, rootPathOverride);
if (!value) {
const value = getSubvalueByPath(rootValue, rootPathOverride);
if (value) {
return <SquiggleViewer value={value} />;
} else {
return <MessageAlert heading="Value is not defined" />;
}

return <SquiggleViewer value={value} />;
} else {
return (
<SquiggleOutputViewer
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/components/SquiggleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const SquiggleEditor: FC<SquiggleEditorProps> = ({
onSubmit={() => runnerState.run()}
/>
</div>
{hideViewer || !squiggleOutput?.code ? null : (
{hideViewer || !squiggleOutput ? null : (
<SquiggleOutputViewer
squiggleOutput={squiggleOutput}
isRunning={isRunning}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { FC } from "react";

import { SqValue } from "@quri/squiggle-lang";

import { SqOutputResult } from "../../../../squiggle-lang/src/public/types.js";
import { ErrorBoundary } from "../ErrorBoundary.js";
import { SquiggleErrorAlert } from "../SquiggleErrorAlert.js";
import { SquiggleViewer } from "../SquiggleViewer/index.js";
import { ViewerMode } from "./index.js";

type Props = {
mode: ViewerMode;
output: SqOutputResult;
isRunning: boolean;
};

export const ViewerBody: FC<Props> = ({ output, mode, isRunning }) => {
if (!output.ok) {
return <SquiggleErrorAlert error={output.value} />;
}

const sqOutput = output.value;
let usedValue: SqValue | undefined;
switch (mode) {
case "Result":
usedValue = output.value.result;
break;
case "Variables":
usedValue = sqOutput.bindings.asValue();
break;
case "Imports":
usedValue = sqOutput.imports.asValue();
break;
case "Exports":
usedValue = sqOutput.exports.asValue();
}

if (!usedValue) {
return null;
}

return (
<div className="relative">
{isRunning && (
// `opacity-0 squiggle-semi-appear` would be better, but won't work reliably until we move Squiggle evaluation to Web Workers
<div className="absolute z-10 inset-0 bg-white opacity-50" />
)}
<ErrorBoundary>
{/* we don't pass settings or editor here because they're already configured in `<ViewerProvider>`; hopefully `<SquiggleViewer>` itself won't need to rely on settings, otherwise things might break */}
<SquiggleViewer value={usedValue} />
</ErrorBoundary>
</div>
);
};
115 changes: 115 additions & 0 deletions packages/components/src/components/SquiggleOutputViewer/ViewerMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import clsx from "clsx";
import { FC } from "react";

import {
Button,
CodeBracketIcon,
Dropdown,
DropdownMenu,
DropdownMenuActionItem,
TriangleIcon,
} from "@quri/ui";

import { SqOutputResult } from "../../../../squiggle-lang/src/public/types.js";
import { ViewerMode } from "./index.js";

const MenuItemTitle: FC<{ title: string; type: string | null }> = ({
title,
type,
}) => {
const isEmpty = type === null;
return (
<div className="flex justify-between">
<span className={clsx(isEmpty && "text-slate-400")}>{title}</span>
{isEmpty ? (
<span className="text-slate-300">Empty</span>
) : (
<span className="text-blue-800">{type}</span>
)}
</div>
);
};

type Props = {
mode: ViewerMode;
setMode: (mode: ViewerMode) => void;
output: SqOutputResult;
};

export const ViewerMenu: FC<Props> = ({ mode, setMode, output }) => {
const hasResult = output.ok && output.value.result.tag !== "Void";
const variablesCount = output.ok ? output.value.bindings.size() : 0;
const importsCount = output.ok ? output.value.imports.size() : 0;
const exportsCount = output.ok ? output.value.exports.size() : 0;

return (
<Dropdown
render={({ close }) => (
<DropdownMenu>
{Boolean(importsCount) && (
<DropdownMenuActionItem
icon={CodeBracketIcon}
title={
<MenuItemTitle
title="Imports"
type={importsCount ? `{}${importsCount}` : null}
/>
}
onClick={() => {
setMode("Imports");
close();
}}
/>
)}
{Boolean(variablesCount) && (
<DropdownMenuActionItem
icon={CodeBracketIcon}
title={
<MenuItemTitle
title="Variables"
type={variablesCount ? `{}${variablesCount}` : null}
/>
}
onClick={() => {
setMode("Variables");
close();
}}
/>
)}
{Boolean(exportsCount) && (
<DropdownMenuActionItem
icon={CodeBracketIcon}
title={
<MenuItemTitle
title="Exports"
type={exportsCount ? `{}${exportsCount}` : null}
/>
}
onClick={() => {
setMode("Exports");
close();
}}
/>
)}
<DropdownMenuActionItem
icon={CodeBracketIcon}
title={
<MenuItemTitle title="Result" type={hasResult ? "" : null} />
}
onClick={() => {
setMode("Result");
close();
}}
/>
</DropdownMenu>
)}
>
<Button size="small">
<div className="flex items-center space-x-1.5">
<span>{mode}</span>
<TriangleIcon className="rotate-180 text-slate-400" size={10} />
</div>
</Button>
</Dropdown>
);
};
Loading

0 comments on commit 0baa7f7

Please sign in to comment.