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

Support passing environment variables to the runner #2

Merged
merged 1 commit into from
Aug 27, 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
127 changes: 118 additions & 9 deletions assets/runner_cell/src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import React, { useEffect, useRef, useState } from "react";
import { RiQuestionnaireLine, RiArrowDownSLine } from "@remixicon/react";
import {
RiQuestionnaireLine,
RiArrowDownSLine,
RiCloseLine,
} from "@remixicon/react";
import classNames from "classnames";

const FLY_CPU_KIND_OPTIONS = ["shared", "performance"].map((kind) => ({
Expand All @@ -16,13 +20,18 @@ const FLY_GPU_KIND_OPTIONS = [{ value: "", label: "None" }].concat(

export default function App({ ctx, payload }) {
const [fields, setFields] = useState(payload.fields);
const [allEnvs, setAllEnvs] = useState(payload.all_envs);
const [showHelpBox, setShowHelpBox] = useState(false);
const warning_type = payload.warning_type;

useEffect(() => {
ctx.handleEvent("update", ({ fields }) => {
setFields((currentFields) => ({ ...currentFields, ...fields }));
});

ctx.handleEvent("set_all_envs", ({ all_envs }) => {
setAllEnvs(all_envs);
});
}, []);

function pushUpdate(field, value) {
Expand All @@ -37,11 +46,7 @@ export default function App({ ctx, payload }) {
? event.target.checked
: event.target.value;

setFields({ ...fields, [field]: value });

if (push) {
pushUpdate(field, value);
}
handleFieldChange(field, value, push);
}

function handleBlur(event) {
Expand All @@ -50,6 +55,14 @@ export default function App({ ctx, payload }) {
pushUpdate(field, fields[field]);
}

function handleFieldChange(field, value, push = true) {
setFields({ ...fields, [field]: value });

if (push) {
pushUpdate(field, value);
}
}

return (
<div className="flex flex-col gap-4 font-sans">
{warning_type === "no_fly" && (
Expand Down Expand Up @@ -186,6 +199,16 @@ export default function App({ ctx, payload }) {
/>
</div>
</div>
<div className="w-full border-t border-gray-200" />
<div className="flex flex-wrap gap-2 p-4">
<MultiSelectField
name="fly_envs"
label="Env vars"
value={fields.fly_envs}
onChange={(value) => handleFieldChange("fly_envs", value)}
options={allEnvs.map((env) => ({ label: env, value: env }))}
/>
</div>
</div>
</div>
);
Expand All @@ -203,8 +226,8 @@ function HelpBox(_props) {
>
FLAME
</a>
pool that delegates computation to a separate machines. To learn
more about the configuration details, refer to{" "}
pool that delegates computation to a separate machines. To learn more
about the configuration details, refer to{" "}
<a
href="https://hexdocs.pm/flame"
target="_blank"
Expand All @@ -215,7 +238,8 @@ function HelpBox(_props) {
.
</p>
<p>
Once a pool is started, you can execute code on a separate machine as follows:
Once a pool is started, you can execute code on a separate machine as
follows:
<pre className="mt-2 p-4 bg-[#282c34] rounded-lg whitespace-pre-wrap">
<code className="text-[#c8ccd4]">
<span className="text-[#56b6c2]">FLAME</span>
Expand Down Expand Up @@ -315,6 +339,91 @@ function SelectField({
);
}

function MultiSelectField({
label = null,
value,
className,
options = [],
onChange,
...props
}) {
const availableOptions = options.filter(
(option) => !value.includes(option.value),
);

function labelForValue(value) {
const option = options.find((option) => option.value === value);

if (option) {
return option.label;
} else {
return value;
}
}

function handleSelectChange(event) {
const subvalue = event.target.value;
const newValue = value.concat([subvalue]).sort();
onChange && onChange(newValue);
}

function handleDelete(subvalue) {
const newValue = value.filter(
(otherSubvalue) => otherSubvalue !== subvalue,
);
onChange && onChange(newValue);
}

return (
<div className="flex flex-col min-w-36">
{label && (
<label className="color-gray-800 mb-0.5 block text-sm font-medium">
{label}
</label>
)}
<div
className={classNames([
"relative w-full min-h-[38px] flex rounded-lg border border-gray-200 bg-gray-50 px-3 py-1.5 pr-0 text-sm text-gray-600 placeholder-gray-400",
className,
])}
>
<div className="flex flex-wrap gap-1">
{value.map((value) => (
<div
key={value}
className="py-0.5 px-2 flex gap-1 items-center rounded-lg bg-gray-200"
>
<span>{labelForValue(value)}</span>
<button
className="rounded-lg hover:bg-gray-300"
onClick={() => handleDelete(value)}
>
<RiCloseLine size={12} />
</button>
</div>
))}
</div>
<select
{...props}
value=""
onChange={handleSelectChange}
className="grow min-w-8 w-0 opacity-0 appearance-none focus:outline-none"
>
<option value="" disabled></option>
{availableOptions.map((option) => (
<option key={option.value || ""} value={option.value || ""}>
{option.label}
</option>
))}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
<RiArrowDownSLine size={16} />
</div>
</div>
</div>
);
}

function FieldWrapper({ children }) {
return <div className="flex items-center gap-1.5">{children}</div>;
}
Expand Down
Loading
Loading