Skip to content

Commit

Permalink
added pages for other instances
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Paulen committed Jan 19, 2025
1 parent a547224 commit adecdfb
Show file tree
Hide file tree
Showing 74 changed files with 3,696 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

# production
/build
dist/
dist*/

# misc
.DS_Store
Expand Down
9 changes: 9 additions & 0 deletions c9088/data/formData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const images = {
simple: {
"cerit.io/hubs/rstudio:4.3.1-snakemake": "RStudio with R 4.3.1 and Snakemake",
},
}

export const sectionTitles = {
simple: "Simple Jupyter Images",
};
35 changes: 35 additions & 0 deletions c9088/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JupyterHub</title>
</head>

<body>
{% block main %} {% set named_spawners =
user.all_spawners(include_default=False)|list %}
<div id="root"></div>
<script>
const appConfig = {
spawners: {
{% for spawner in named_spawners %}
"{{ spawner.name }}": {
last_activity: {% if spawner.last_activity %} "{{ spawner.last_activity.isoformat() + 'Z' }}"{% else %} null{% endif %},
url: {% if spawner.ready %} "{{ user.server_url(spawner.name) }}"{% else %} null{% endif %},
active: {{ "true" if spawner.active else "false" }},
ready: {{ "true" if spawner.ready else "false" }},
} {% if not loop.last %}, {% endif %}
{% endfor %}
},
default_server_active: {{ "true" if default_server.active else "false" }},
url: "{{ url }}",
userName: "{{ user.name }}",
xsrf: "{{ xsrf_token }}",
};
</script>
<script type="module" src="/js/home.jsx"></script>
{% endblock main %}
</body>
</html>
39 changes: 39 additions & 0 deletions c9088/js/Form.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.wrapper {
display: flex;
flex-direction: column;
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 50%;
background: rgba(255, 255, 255, 0.5);
padding: 50px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
min-height: 100vh;
}

.GPU-wrapper {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
align-items: center;
}

.GPU-stats {
border: none;
}

@media (max-width: 768px) {
.wrapper {
display: flex;
flex-direction: column;
position: absolute;
width: 90%;
padding: 5%;
background: rgba(255, 255, 255, 0.5);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
min-height: 80vh;
}
}
202 changes: 202 additions & 0 deletions c9088/js/FormPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import "./Form.css";
import React, { useState, useEffect } from "react";
import ProgressiveForm from "../../src/components/Form/ProgressiveForm";
import { EinfraFooter } from "../../src/components/FooterAndHeader/EinfraFooter";
import { FieldHeader } from "../../src/components/FieldHeader/FieldHeader";
import { SliderCheckBox } from "../../src/components/SliderCheckBox/SliderCheckBox";
import { TileSelector } from "../../src/components/TileSelector/TileSelector";
import JupyterHubHeader from "../../src/components/FooterAndHeader/JupyterHubHeader";
import {
DropDownButton,
DropDownOption,
} from "../../src/components/DropDownButton/DropDownButton";
import {
images,
sectionTitles,
} from "../data/formData";

const StepOne = ({ setFormData }) => {
const [activeDropdownIndex, setActiveDropdownIndex] = useState(null);
const [selectedDropdownIndex, setSelectedDropdownIndex] = useState(null);
const [activeDropdownOptionIndex, setActiveDropdownOptionIndex] = useState(null);

const handleErase = (checked) => {
setFormData((prev) => {
const updatedFormData = { ...prev };

if (checked) {
updatedFormData.delhome = "delete";
} else {
delete updatedFormData.delhome;
}

return updatedFormData;
});
};

const handleSelect = (key, image, index, dindex) => {
setSelectedDropdownIndex(dindex);
setActiveDropdownOptionIndex(index);
setFormData((prev) => ({
...prev,
dockerimage: image,
}));
};

const isActiveIndex = (index) => {
return activeDropdownIndex === index;
};

const isSelectedIndex = (index) => {
return selectedDropdownIndex === index;
};

let dropDownIndex = 0;

return (
<div className="form-wrap">
<h2>Choosing Image</h2>
{Object.entries(images).map(([key, options], dropdownIndex) => (
<DropDownButton
key={dropdownIndex}
isActive={true}
onActivate={() => setActiveDropdownIndex(dropdownIndex)}
isSelected={isSelectedIndex(dropdownIndex)}
title={sectionTitles[key]}
>
{Object.entries(options).map(([value, label]) => {
const currentIndex = dropDownIndex++;
return (
<DropDownOption
index={currentIndex}
activeIndex={activeDropdownOptionIndex}
title={label}
onSelect={() =>
handleSelect(key, value, currentIndex, dropdownIndex)
}
/>
);
})}
</DropDownButton>
))}
<h2>Choosing storage</h2>
<FieldHeader
title="Persistent Notebook Home"
infoText="Persistent home means that even when notebook is deleted, the data will persist and can be used again."
>
<DropDownButton
key={0}
isActive={true}
primary={false}
title="New"
>
<SliderCheckBox
title="Erase if home exists"
onChange={handleErase}
id="phCheckId"
></SliderCheckBox>
<div>
Mounted to
<code>/home/jovyan</code>
</div>
</DropDownButton>
</FieldHeader>
</div>
);
};


const StepThree = ({ setFormData }) => {

const handleCPUSelect = (value) => {
setFormData((prev) => ({
...prev,
cpuselection: value,
}));
};

const handleMemSelect = (value) => {
setFormData((prev) => ({
...prev,
memselection: value,
}));
};

return (
<div className="form-wrap">
<h2>Resources</h2>
<p>
The notebook is spawned only when one node fulfills <b>all</b> your
requirements.
</p>
<TileSelector
setFormData={handleCPUSelect}
title="CPU"
selectionText="Select CPU limit:"
numberOptions={[1, 4, 6, 8, 10, 16, 24, 32]}
></TileSelector>
<TileSelector
setFormData={handleMemSelect}
title="Memory"
selectionText={"Select memory limit (in GB):"}
numberOptions={[4, 8, 16, 32, 64, 128, 256]}
></TileSelector>
</div>
);
};

function FormPage() {

const [formData, setFormData] = useState({
memselection: 4,
cpuselection: 1,
dockerimage: "cerit.io/hubs/rstudio:4.3.1-snakemake",
});

const submitForm = () => {
const formDataToSend = new FormData();

Object.entries(formData).forEach(([key, value]) => {
formDataToSend.append(key, value);
});

fetch(appConfig.postUrl, {
method: "POST",
body: formDataToSend,
})
.then((response) => {
if (response.ok) {
const pendingUrl = appConfig.postUrl.replace(
"/spawn/",
"/spawn-pending/",
);
window.location.href = pendingUrl;
} else {
console.error("Error submitting form:", response.statusText);
}
})
.catch((error) => {
console.error("Network error:", error);
});
};

const steps = [
<StepOne key={0} formData={formData} setFormData={setFormData} />,
<StepThree key={1} formData={formData} setFormData={setFormData} />,
];

return (
<>
<JupyterHubHeader userName={appConfig.userName}></JupyterHubHeader>
<div className="wrapper">
<ProgressiveForm
steps={steps}
submitForm={submitForm}
></ProgressiveForm>
<EinfraFooter></EinfraFooter>
</div>
</>
);
}

export default FormPage;
Loading

0 comments on commit adecdfb

Please sign in to comment.