Skip to content

Commit

Permalink
Merge pull request #90 from yuvipanda/default-to-HEAD
Browse files Browse the repository at this point in the history
Default to head
  • Loading branch information
yuvipanda authored Nov 14, 2024
2 parents a386195 + c373443 commit a0eecb8
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 227 deletions.
53 changes: 16 additions & 37 deletions src/ImageBuilder.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useEffect, useState, useRef, useContext } from "react";
import Select from "react-select";
import { TextField } from "./components/form/fields";
import { SpawnerFormContext } from "./state";
import useRepositoryField from "./hooks/useRepositoryField";
import useRefField from "./hooks/useRefField";

async function buildImage(repo, ref, term, fitAddon) {
const { BinderRepository } = await import("@jupyterhub/binderhub-client");
Expand Down Expand Up @@ -93,12 +92,9 @@ export function ImageBuilder({ name, isActive }) {
ref: repoRef,
setCustomOption,
} = useContext(SpawnerFormContext);
const { repo, repoId, repoFieldProps, repoError, repoIsValidating } =
const { repo, repoId, repoFieldProps, repoError } =
useRepositoryField(binderRepo);
const { ref, refError, refFieldProps, refIsLoading } = useRefField(
repoId,
repoRef,
);
const [ref, setRef] = useState(repoRef || "HEAD");
const repoFieldRef = useRef();
const branchFieldRef = useRef();

Expand All @@ -117,7 +113,6 @@ export function ImageBuilder({ name, isActive }) {
useEffect(() => {
if (setCustomOption) {
repoFieldRef.current.setAttribute("value", binderRepo);
branchFieldRef.current.value = repoRef;
}
}, [binderRepo, repoRef, setCustomOption]);

Expand Down Expand Up @@ -173,41 +168,25 @@ export function ImageBuilder({ name, isActive }) {
{...repoFieldProps}
aria-invalid={!!repoError}
/>
{repoIsValidating && (
<div className="profile-option-control-info">
Validating repository...
</div>
)}
{repoError && (
<div className="profile-option-control-error">{repoError}</div>
)}
</div>
</div>

<div
className={`profile-option-container ${repoError ? "has-error" : ""}`}
>
<div className="profile-option-label-container">
<label>Git Ref</label>
</div>
<div className="profile-option-control-container">
<Select
aria-label="Git Ref"
ref={branchFieldRef}
{...refFieldProps}
aria-invalid={!!refError}
isDisabled={!refFieldProps.options}
/>
{refIsLoading && !refIsLoading && (
<div className="profile-option-control-info">
Loading Git ref options...
</div>
)}
{refError && (
<div className="profile-option-control-error">{refError}</div>
)}
</div>
</div>
<TextField
ref={branchFieldRef}
id={`${name}--ref`}
label="Git Ref"
value={ref}
validate={
isActive && {
required: "Enter a git ref.",
}
}
onChange={(e) => setRef(e.target.value)}
tabIndex={isActive ? "0" : "-1"}
/>

<div className="right-button">
<button
Expand Down
112 changes: 27 additions & 85 deletions src/ImageBuilder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import ProfileForm from "./ProfileForm";
import { SpawnerFormProvider } from "./state";

test("select repository by org/repo", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));
const user = userEvent.setup();

render(
Expand All @@ -31,19 +27,14 @@ test("select repository by org/repo", async () => {
await user.type(repoField, "org/repo");
await user.click(document.body);

const branchField = await screen.getByLabelText("Git Ref");
await user.click(branchField);
await user.click(screen.getByText("main"));
expect(fetch.mock.calls[0][0]).toEqual(
"https://api.github.com/repos/org/repo",
);
expect(
screen.queryByText(
"Provide the repository as the format 'organization/repository'.",
),
).not.toBeInTheDocument();
});

test("select repository by https://github.com/org/repo", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));
const user = userEvent.setup();

render(
Expand All @@ -65,19 +56,14 @@ test("select repository by https://github.com/org/repo", async () => {
await user.type(repoField, "https://github.com/org/repo");
await user.click(document.body);

const branchField = await screen.getByLabelText("Git Ref");
await user.click(branchField);
await user.click(screen.getByText("main"));
expect(fetch.mock.calls[0][0]).toEqual(
"https://api.github.com/repos/org/repo",
);
expect(
screen.queryByText(
"Provide the repository as the format 'organization/repository'.",
),
).not.toBeInTheDocument();
});

test("select repository by https://www.github.com/org/repo", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));
const user = userEvent.setup();

render(
Expand All @@ -99,19 +85,14 @@ test("select repository by https://www.github.com/org/repo", async () => {
await user.type(repoField, "https://www.github.com/org/repo");
await user.click(document.body);

const branchField = await screen.getByLabelText("Git Ref");
await user.click(branchField);
await user.click(screen.getByText("main"));
expect(fetch.mock.calls[0][0]).toEqual(
"https://api.github.com/repos/org/repo",
);
expect(
screen.queryByText(
"Provide the repository as the format 'organization/repository'.",
),
).not.toBeInTheDocument();
});

test("select repository by github.com/org/repo", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));
const user = userEvent.setup();

render(
Expand All @@ -133,19 +114,14 @@ test("select repository by github.com/org/repo", async () => {
await user.type(repoField, "github.com/org/repo");
await user.click(document.body);

const branchField = await screen.getByLabelText("Git Ref");
await user.click(branchField);
await user.click(screen.getByText("main"));
expect(fetch.mock.calls[0][0]).toEqual(
"https://api.github.com/repos/org/repo",
);
expect(
screen.queryByText(
"Provide the repository as the format 'organization/repository'.",
),
).not.toBeInTheDocument();
});

test("select repository by www.github.com/org/repo", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));
const user = userEvent.setup();

render(
Expand All @@ -166,13 +142,11 @@ test("select repository by www.github.com/org/repo", async () => {
const repoField = screen.getByLabelText("Repository");
await user.type(repoField, "www.github.com/org/repo");
await user.click(document.body);

const branchField = await screen.getByLabelText("Git Ref");
await user.click(branchField);
await user.click(screen.getByText("main"));
expect(fetch.mock.calls[0][0]).toEqual(
"https://api.github.com/repos/org/repo",
);
expect(
screen.queryByText(
"Provide the repository as the format 'organization/repository'.",
),
).not.toBeInTheDocument();
});

test("invalid org/repo string (not matching pattern)", async () => {
Expand Down Expand Up @@ -202,7 +176,6 @@ test("invalid org/repo string (not matching pattern)", async () => {
"Provide the repository as the format 'organization/repository'.",
),
);
expect(screen.queryByLabelText("Git Ref")).toHaveAttribute("disabled");
});

test("invalid org/repo string (wrong base URL)", async () => {
Expand Down Expand Up @@ -232,33 +205,6 @@ test("invalid org/repo string (wrong base URL)", async () => {
"Provide the repository as the format 'organization/repository'.",
),
);
expect(screen.queryByLabelText("Git Ref")).toHaveAttribute("disabled");
});

test("repo not found", async () => {
fetch.mockResponseOnce("", { status: 400 });
const user = userEvent.setup();

render(
<SpawnerFormProvider>
<ProfileForm />
</SpawnerFormProvider>,
);
const radio = screen.getByRole("radio", {
name: "CPU only No GPU, only CPU",
});
await user.click(radio);

const select = screen.getByLabelText("Image - dynamic image building");
await user.click(select);

await user.click(screen.getByText("Build your own image"));

const repoField = screen.getByLabelText("Repository");
await user.type(repoField, "https://github.com/org/repo");
await user.click(document.body);

expect(screen.queryByLabelText("Git Ref")).toHaveAttribute("disabled");
});

test("no org/repo provided", async () => {
Expand Down Expand Up @@ -288,10 +234,6 @@ test("no org/repo provided", async () => {
});

test("no branch selected", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));
const user = userEvent.setup();

render(
Expand All @@ -313,8 +255,8 @@ test("no branch selected", async () => {
await user.type(repoField, "org/repo");
await user.click(document.body);

expect(screen.queryByLabelText("Git Ref")).toBeInTheDocument();
await user.clear(screen.queryByLabelText("Git Ref"));
await user.click(screen.getByRole("button", { name: "Build image" }));

expect(screen.getByText("Select a git ref."));
expect(screen.getByText("Enter a git ref."));
});
15 changes: 2 additions & 13 deletions src/ProfileForm.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, test, beforeEach } from "@jest/globals";
import { render, screen, waitFor } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import ProfileForm from "./ProfileForm";
Expand Down Expand Up @@ -220,11 +220,6 @@ describe("Profile form with URL Params", () => {
});

test("preselects values", async () => {
fetch
.mockResponseOnce("")
.mockResponseOnce(JSON.stringify([{ name: "main" }, { name: "develop" }]))
.mockResponseOnce(JSON.stringify([{ name: "v1.0" }]));

render(
<SpawnerFormProvider>
<ProfileForm />
Expand All @@ -237,12 +232,6 @@ describe("Profile form with URL Params", () => {
expect(radio.checked).toBeTruthy();

expect(screen.getByLabelText("Repository").value).toEqual("org/repo");
await waitFor(() =>
expect(fetch.mock.calls[2][0]).toEqual(
"https://api.github.com/repos/org/repo/tags",
),
);

await waitFor(() => expect(screen.getByText("v1.0")).toBeInTheDocument());
expect(screen.getByLabelText("Git Ref").value).toEqual("v1.0");
});
});
17 changes: 8 additions & 9 deletions src/components/form/fields.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { forwardRef, useState } from "react";

import { CustomizedSelect } from "./CustomSelect";

Expand Down Expand Up @@ -73,14 +73,10 @@ export function SelectField({
);
}

export function TextField({
id,
label,
value,
validate = {},
onChange,
tabIndex,
}) {
function _TextField(
{ id, label, value, validate = {}, onChange, tabIndex },
ref,
) {
const [touched, setTouched] = useState(false);
const onBlur = () => setTouched(true);

Expand All @@ -91,6 +87,7 @@ export function TextField({
return (
<Field id={id} label={label} error={touched && error}>
<input
ref={ref}
type="text"
id={id}
name={id}
Expand All @@ -106,3 +103,5 @@ export function TextField({
</Field>
);
}

export const TextField = forwardRef(_TextField);
Loading

0 comments on commit a0eecb8

Please sign in to comment.