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

Add replicas slider, minor UI fixes #118

Merged
merged 6 commits into from
Dec 10, 2023
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
12,877 changes: 7,049 additions & 5,828 deletions package-lock.json

Large diffs are not rendered by default.

88 changes: 44 additions & 44 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,70 +39,70 @@
]
},
"dependencies": {
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@hookform/resolvers": "^2.9.3",
"@iconify/react": "^3.2.2",
"@mui/icons-material": "^5.11.16",
"@mui/lab": "^5.0.0-alpha.88",
"@mui/material": "^5.8.6",
"@mui/x-tree-view": "^6.0.0-alpha.3",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@hookform/resolvers": "^3.3.2",
"@iconify/react": "^4.1.1",
"@mui/icons-material": "^5.14.19",
"@mui/lab": "^5.0.0-alpha.155",
"@mui/material": "^5.14.20",
"@mui/x-tree-view": "^6.17.0",
"@react-keycloak/web": "^3.4.0",
"@react-three/drei": "^9.80.6",
"@react-three/fiber": "^8.13.7",
"@react-three/drei": "^9.90.0",
"@react-three/fiber": "^8.15.12",
"@sanity/eventsource": "^5.0.1",
"@testing-library/jest-dom": "^5.16.4",
"@types/three": "^0.155.0",
"apexcharts": "^3.35.3",
"change-case": "^4.1.2",
"crypto-js": "^4.1.1",
"date-fns": "^2.28.0",
"@testing-library/jest-dom": "^6.1.5",
"@types/three": "^0.159.0",
"apexcharts": "^3.44.2",
"change-case": "^5.3.0",
"crypto-js": "^4.2.0",
"date-fns": "^2.30.0",
"history": "^5.3.0",
"http-status-codes": "^2.2.0",
"i18next": "^23.6.0",
"i18next-browser-languagedetector": "^7.1.0",
"http-status-codes": "^2.3.0",
"i18next": "^23.7.8",
"i18next-browser-languagedetector": "^7.2.0",
"js-base64": "^3.7.5",
"keycloak-js": "^19.0.3",
"keycloak-js": "^23.0.1",
"lodash": "^4.17.21",
"notistack": "^3.0.1",
"numeral": "^2.0.6",
"prop-types": "^15.8.1",
"punycode": "^2.3.0",
"punycode": "^2.3.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.0",
"react-apexcharts": "^1.4.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-helmet-async": "^1.3.0",
"react-hook-form": "^7.33.1",
"react-i18next": "^13.3.1",
"react-router-dom": "^6.3.0",
"react-helmet-async": "^2.0.3",
"react-hook-form": "^7.48.2",
"react-i18next": "^13.5.0",
"react-router-dom": "^6.20.1",
"react-scripts": "^5.0.1",
"simplebar": "^5.3.8",
"simplebar-react": "^2.4.1",
"three": "^0.155.0",
"web-vitals": "^2.1.4",
"yaml": "^2.3.1",
"yup": "^0.32.11"
"simplebar": "^6.2.5",
"simplebar-react": "^3.2.4",
"three": "^0.159.0",
"web-vitals": "^3.5.0",
"yaml": "^2.3.4",
"yup": "^1.3.2"
},
"devDependencies": {
"@babel/core": "^7.18.6",
"@babel/eslint-parser": "^7.18.2",
"@babel/core": "^7.23.5",
"@babel/eslint-parser": "^7.23.3",
"@babel/plugin-proposal-private-property-in-object": "^7.21.0",
"@faker-js/faker": "^8.0.2",
"@svgr/webpack": "^6.2.1",
"eslint": "^8.19.0",
"@faker-js/faker": "^8.3.1",
"@svgr/webpack": "^8.1.0",
"eslint": "^8.55.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"prettier": "^2.7.1"
"prettier": "^3.1.0"
},
"overrides": {
"@svgr/webpack": "^6.2.1"
"@svgr/webpack": "^8.1.0"
}
}
3 changes: 1 addition & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// scroll bar
import "simplebar/src/simplebar.css";
import "simplebar/dist/simplebar.css"

import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
Expand Down
2 changes: 2 additions & 0 deletions src/layouts/dashboard/HelpButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const resolveURL = () => {
return base_url + "Using_Virtual_Machines";

if (path.startsWith("/profile")) return base_url + "Profile";
if (path.startsWith("/teams")) return base_url + "Teams";
if (path.startsWith("/inbox")) return base_url + "Inbox";

return "https://wiki.cloud.cbh.kth.se";
};
Expand Down
9 changes: 8 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,13 @@
"teams-subheader": "Teams are a way to organize your resources and collaborate with others. You can create a team and invite others to join.",
"create-team": "Create team",
"description": "Description",
"invite": "Invite"
"invite": "Invite",
"replicas": "Replicas",
"replicas-subheader": "Replicas are multiple instances of the same deployment. They are useful for load balancing and scaling.",
"replicas-shutdown": "Protip: By choosing 0 replicas, you can shut down this deployment without deleting it.",
"apply": "Apply",
"replicas-saving": "Saving replicas...",
"could-not-save-replicas": "Could not save replicas: ",
"replicas-shutdown-warning": "This will shut down your deployment. Are you sure?"
}
}
9 changes: 8 additions & 1 deletion src/locales/se.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,13 @@
"teams-subheader": "Grupper är ett sätt att organisera dina resurser och samarbeta med andra. Du kan skapa en grupp och bjuda in andra.",
"create-team": "Skapa grupp",
"description": "Beskrivning",
"invite": "Bjud in"
"invite": "Bjud in",
"replicas": "Kopior",
"replicas-subheader": "Kopior är en enkel form av skalning. Du kan skapa flera kopior av din app för att hantera mer trafik.",
"replicas-shutdown": "Tips från coachen: Genom att välja 0 kopior stängs appen av, men finns kvar i ditt konto.",
"apply": "Verkställ",
"replicas-saving": "Sparar antal kopior...",
"could-not-save-replicas": "Kunde inte uppdatera antal kopior: ",
"replicas-shutdown-warning": "Varning: Om du väljer 0 kopior kommer appen att stängas av."
}
}
4 changes: 4 additions & 0 deletions src/pages/edit/Edit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import ProxyManager from "./vms/ProxyManager";
import { HealthCheckRoute } from "./deployments/HealthCheckRoute";
import { useTranslation } from "react-i18next";
import DangerZone from "./DangerZone";
import { ReplicaManager } from "./deployments/ReplicaManager";

export function Edit() {
const { t } = useTranslation();
Expand Down Expand Up @@ -200,6 +201,9 @@ export function Edit() {
<GHActions resource={resource} />
)}

{resource.type === "deployment" && (
<ReplicaManager deployment={resource} />
)}
{resource.type === "deployment" && (
<LogsView deployment={resource} />
)}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/edit/deployments/GHActions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const GHActions = ({ resource }) => {
</Stack>

<Button
variant={showSecrets ? "contained" : "outlined"}
variant={"contained"}
onClick={() => setShowSecrets(!showSecrets)}
startIcon={
<Iconify icon={showSecrets ? "mdi:eye-off" : "mdi:eye"} />
Expand Down
134 changes: 134 additions & 0 deletions src/pages/edit/deployments/ReplicaManager.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {
Button,
Card,
CardContent,
CardHeader,
Grid,
Slider,
Stack,
Typography,
} from "@mui/material";

import { enqueueSnackbar } from "notistack";
import { useEffect, useState } from "react";
import { useKeycloak } from "@react-keycloak/web";
import useResource from "src/hooks/useResource";
import { updateDeployment } from "src/api/deploy/deployments";
import { errorHandler } from "src/utils/errorHandler";
import { useTranslation } from "react-i18next";

export const ReplicaManager = ({ deployment }) => {
const { t } = useTranslation();
const { initialized, keycloak } = useKeycloak();
const { queueJob, user } = useResource();

const [loading, setLoading] = useState(false);
const [max, setMax] = useState(0);
const [count, _setCount] = useState(deployment.replicas);

useEffect(() => {
if (!(initialized && user)) return;
if (user.admin) {
setMax(100);
return;
}

setMax(user.quota.deployments - user.usage.deployments);

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const applyChanges = async (r) => {
if (!initialized) return;
setLoading(true);

try {
const res = await updateDeployment(
deployment.id,
{ replicas: r },
keycloak.token
);

queueJob(res);
enqueueSnackbar(t("replicas-saving"), { variant: "info" });
} catch (error) {
errorHandler(error).forEach((e) =>
enqueueSnackbar(t("could-not-save-replicas") + e, {
variant: "error",
})
);
} finally {
setLoading(false);
}
};

const setCount = (v) => {
if (v > max) {
enqueueSnackbar(t("max-replicas") + max, { variant: "warning" });
return;
}

_setCount(v);
};

return (
<Card sx={{ boxShadow: 20 }}>
<CardHeader title={t("replicas")} subheader={t("replicas-subheader")} />

<CardContent>
<Typography gutterBottom variant="body2">
{t("replicas-shutdown")}
</Typography>

<Grid container spacing={2} alignItems="center">
<Grid item xs>
<Slider
aria-labelledby="input-slider"
value={count}
onChange={(e, v) => setCount(v)}
min={0}
max={max}
step={1}
marks
aria-label={t("replicas")}
valueLabelDisplay="auto"
disabled={loading}
/>
</Grid>
<Grid item>
<Typography gutterBottom style={{ fontFamily: "monospace" }}>
<span style={{ opacity: 0 }}>{count < 10 ? "0" : ""}</span>
{count}/{max}
</Typography>
</Grid>
</Grid>

{count === 0 && (
<Typography gutterBottom variant="body2">
{t("replicas-shutdown-warning")}
</Typography>
)}

{count !== deployment.replicas && (
<Stack direction="row" spacing={2} alignItems="center" useFlexGap>
<Button
variant="contained"
color="primary"
onClick={() => applyChanges(count)}
disabled={loading}
>
{t("apply")}
</Button>

<Button
onClick={() => setCount(deployment.replicas)}
disabled={loading}
>
{t("cancel")}
</Button>
</Stack>
)}
</CardContent>
</Card>
);
};
4 changes: 2 additions & 2 deletions src/pages/edit/vms/GPUManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ export const GPUManager = ({ vm }) => {
{t("gpu-drivers-1")}
<br />
{t("gpu-drivers-2")}
<CopyToClipboard text="sudo ubuntu-drivers install --gpgpu">
<CopyToClipboard text="apt install nvidia-driver-535-server nvidia-utils-535-server -y">
<Tooltip enterTouchDelay={10} title="Copy to clipboard">
<span
style={{
Expand All @@ -440,7 +440,7 @@ export const GPUManager = ({ vm }) => {
cursor: "pointer",
}}
>
sudo ubuntu-drivers install --gpgpu
apt install nvidia-driver-535-server nvidia-utils-535-server -y
</span>
</Tooltip>
</CopyToClipboard>
Expand Down
1 change: 1 addition & 0 deletions src/pages/teams/Teams.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ const Teams = () => {
spacing={2}
alignItems={"center"}
useFlexGap
key={team.id+" "+member.username}
>
<Typography variant="body1">
{member.email || member.username}
Expand Down