Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create templates in script editors #151

Merged
merged 7 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gui/src/app/FileEditor/StanFileEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ const StanFileEditor: FunctionComponent<Props> = ({
readOnly={!isCompiling ? readOnly : true}
toolbarItems={toolbarItems}
codeMarkers={stancErrorsToCodeMarkers(stancErrors)}
hintTextOnEmpty="Begin editing or select an example from the left panel"
contentOnEmpty="Begin editing or select an example from the left panel"
/>
{window}
</Splitter>
Expand Down
20 changes: 12 additions & 8 deletions gui/src/app/FileEditor/TextEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type Props = {
toolbarItems?: ToolbarItem[];
label: string;
codeMarkers?: CodeMarker[];
hintTextOnEmpty?: string;
contentOnEmpty?: string | HTMLSpanElement;
};

export type ToolbarItem =
Expand Down Expand Up @@ -55,7 +55,7 @@ const TextEditor: FunctionComponent<Props> = ({
language,
label,
codeMarkers,
hintTextOnEmpty,
contentOnEmpty,
}) => {
const handleChange = useCallback(
(value: string | undefined) => {
Expand Down Expand Up @@ -104,16 +104,16 @@ const TextEditor: FunctionComponent<Props> = ({

useEffect(() => {
if (!editorInstance) return;
if (!hintTextOnEmpty) return;
if (!contentOnEmpty) return;
if (text || editedText) {
return;
}
const contentWidget = createHintTextContentWidget(hintTextOnEmpty);
const contentWidget = createHintTextContentWidget(contentOnEmpty);
editorInstance.addContentWidget(contentWidget);
return () => {
editorInstance.removeContentWidget(contentWidget);
};
}, [text, editorInstance, editedText, hintTextOnEmpty]);
}, [text, editorInstance, editedText, contentOnEmpty]);

/////////////////////////////////////////////////

Expand Down Expand Up @@ -242,14 +242,18 @@ const NotSelectable: FunctionComponent<PropsWithChildren> = ({ children }) => {
return <div className="NotSelectable">{children}</div>;
};

const createHintTextContentWidget = (hintText: string) => {
const createHintTextContentWidget = (content: string | HTMLSpanElement) => {
return {
getDomNode: () => {
const node = document.createElement("div");
node.style.width = "max-content";
node.style.pointerEvents = "none";
node.className = "EditorHintText";
node.textContent = hintText;
const spanElement =
typeof content === "string" ? document.createElement("span") : content;
if (typeof content === "string") {
spanElement.textContent = content;
}
node.appendChild(spanElement);
return node;
},
getId: () => "hintText",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ const DataPyFileEditor: FunctionComponent<Props> = ({
[fileContent, editedFileContent, handleRun, status, handleHelp],
);

const contentOnEmpty = useMemo(() => {
const spanElement = document.createElement("span");
const t1 = document.createTextNode(
"Define a dictionary called data to update the data.json. ",
);
const a1 = document.createElement("a");
a1.onclick = () => {
setEditedFileContent(dataPyTemplate);
};
a1.textContent = "Click here to generate an example";
spanElement.appendChild(t1);
spanElement.appendChild(a1);
return spanElement;
}, [setEditedFileContent]);
Comment on lines +90 to +103
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to do this as a React component? No worries if not, it just seems like it'd be more straightforward than having to assemble it manually.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice, but I don't think it's possible.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just looked into a few options, all the supported ways of turning a JSX element into a actual DOM element are in react-dom/server and therefore don't persist the onClick in a meaningful way. Too bad


return (
<TextEditor
language="python"
Expand All @@ -97,8 +112,13 @@ const DataPyFileEditor: FunctionComponent<Props> = ({
onSetEditedText={setEditedFileContent}
readOnly={readOnly}
toolbarItems={toolbarItems}
contentOnEmpty={contentOnEmpty}
/>
);
};

const dataPyTemplate = `data = {
"a": [1, 2, 3]
}`;

export default DataPyFileEditor;
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,21 @@ if (typeof(data) != "list") {
[fileContent, editedFileContent, handleRun, status, handleHelp],
);

const contentOnEmpty = useMemo(() => {
const spanElement = document.createElement("span");
const t1 = document.createTextNode(
"Define a list called data to update the data.json. ",
);
const a1 = document.createElement("a");
a1.onclick = () => {
setEditedFileContent(dataRTemplate);
};
a1.textContent = "Click here to generate an example";
spanElement.appendChild(t1);
spanElement.appendChild(a1);
return spanElement;
}, [setEditedFileContent]);

return (
<TextEditor
language="r"
Expand All @@ -131,8 +146,13 @@ if (typeof(data) != "list") {
onSetEditedText={setEditedFileContent}
readOnly={readOnly}
toolbarItems={toolbarItems}
contentOnEmpty={contentOnEmpty}
/>
);
};

const dataRTemplate = `data <- list(
a = c(1, 2, 3)
)`;

export default DataRFileEditor;
32 changes: 32 additions & 0 deletions gui/src/app/pyodide/AnalysisPyFileEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,21 @@ const AnalysisPyFileEditor: FunctionComponent<Props> = ({
return ret;
}, [fileContent, editedFileContent, imagesRef, hasData, status, handleRun]);

const contentOnEmpty = useMemo(() => {
const spanElement = document.createElement("span");
const t1 = document.createTextNode(
"Use the draws object to access the samples. ",
);
const a1 = document.createElement("a");
a1.onclick = () => {
setEditedFileContent(analysisPyTemplate);
};
a1.textContent = "Click here to generate an example";
spanElement.appendChild(t1);
spanElement.appendChild(a1);
return spanElement;
}, [setEditedFileContent]);

WardBrian marked this conversation as resolved.
Show resolved Hide resolved
return (
<TextEditor
language="python"
Expand All @@ -168,10 +183,27 @@ const AnalysisPyFileEditor: FunctionComponent<Props> = ({
onSetEditedText={setEditedFileContent}
readOnly={readOnly}
toolbarItems={toolbarItems}
contentOnEmpty={contentOnEmpty}
/>
);
};

const analysisPyTemplate = `import matplotlib.pyplot as plt
WardBrian marked this conversation as resolved.
Show resolved Hide resolved

# Print the draws object
print(draws)

# Print parameter names
print(draws.parameter_names)

# plot the lp parameter
samples = draws.get("lp__")
print(samples.shape)
plt.hist(samples.ravel(), bins=30)
plt.title("lp__")
plt.show()
`;

type ConsoleOutType = "stdout" | "stderr";

export const writeConsoleOutToDiv = (
Expand Down
9 changes: 8 additions & 1 deletion gui/src/localStyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,11 @@ span.EditorTitle {
.EditorHintText {
font-style: italic;
color: #aaa;
}
pointer-events: none;
}

.EditorHintText a {
color: gray;
text-decoration: underline;
pointer-events: all;
}