From 4e4e210736924a8a320407013b9d524fef906df5 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Wed, 25 Jan 2023 22:53:27 +0000 Subject: [PATCH] implement build / deployment copy --- core/src/actions/build.rs | 3 +- frontend/public/icons/duplicate.svg | 12 +++ frontend/src/components/CopyMenu.tsx | 97 +++++++++++++++++++ frontend/src/components/build/Header.tsx | 34 ++++--- frontend/src/components/deployment/Header.tsx | 34 ++++--- frontend/src/components/shared/Icon.tsx | 3 +- .../src/components/shared/menu/Selector.tsx | 9 +- 7 files changed, 157 insertions(+), 35 deletions(-) create mode 100644 frontend/public/icons/duplicate.svg create mode 100644 frontend/src/components/CopyMenu.tsx diff --git a/core/src/actions/build.rs b/core/src/actions/build.rs index b8125a084..17aaea50e 100644 --- a/core/src/actions/build.rs +++ b/core/src/actions/build.rs @@ -5,7 +5,7 @@ use mungos::{doc, to_bson}; use types::{ monitor_timestamp, traits::{Busy, Permissioned}, - Build, Log, Operation, PermissionLevel, Update, UpdateStatus, UpdateTarget, + Build, Log, Operation, PermissionLevel, Update, UpdateStatus, UpdateTarget, Version, }; use crate::{ @@ -104,6 +104,7 @@ impl State { .await?; build.name = new_name; build.server_id = new_server_id; + build.version = Version::default(); let build = self.create_full_build(build, user).await?; Ok(build) } diff --git a/frontend/public/icons/duplicate.svg b/frontend/public/icons/duplicate.svg new file mode 100644 index 000000000..b8bbb2c3f --- /dev/null +++ b/frontend/public/icons/duplicate.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/frontend/src/components/CopyMenu.tsx b/frontend/src/components/CopyMenu.tsx new file mode 100644 index 000000000..1881b6877 --- /dev/null +++ b/frontend/src/components/CopyMenu.tsx @@ -0,0 +1,97 @@ +import { useNavigate } from "@solidjs/router"; +import { Component, createSignal } from "solid-js"; +import { client, pushNotification } from ".."; +import { useAppState } from "../state/StateProvider"; +import { Build, Deployment } from "../types"; +import { getId } from "../util/helpers"; +import { useToggle } from "../util/hooks"; +import ConfirmButton from "./shared/ConfirmButton"; +import Icon from "./shared/Icon"; +import Input from "./shared/Input"; +import Flex from "./shared/layout/Flex"; +import Grid from "./shared/layout/Grid"; +import CenterMenu from "./shared/menu/CenterMenu"; +import Selector from "./shared/menu/Selector"; + +const CopyMenu: Component<{ + type: "deployment" | "build"; + id: string; +}> = (p) => { + const navigate = useNavigate(); + const [show, toggleShow] = useToggle(); + const [newName, setNewName] = createSignal(""); + const { builds, deployments, servers } = useAppState(); + const [selectedId, setSelected] = createSignal(servers.ids()![0]); + const name = () => { + if (p.type === "build") { + return builds.get(p.id)?.name; + } else if (p.type === "deployment") { + return deployments.get(p.id)?.deployment.name; + } + }; + const copy = () => { + if (newName().length !== 0) { + let promise: Promise; + if (p.type === "build") { + promise = client.copy_build(p.id, { + name: newName(), + server_id: selectedId(), + }); + } else { + promise = client.copy_deployment(p.id, { + name: newName(), + server_id: selectedId(), + }); + } + toggleShow(); + promise.then((val) => { + navigate(`/${p.type}/${getId(val)}`); + }); + } else { + pushNotification("bad", "copy name cannot be empty"); + } + }; + return ( + } + targetClass="blue" + content={() => ( + + + + servers.get(id)!.server.name} + targetClass="blue" + targetStyle={{ display: "flex", gap: "0.5rem" }} + searchStyle={{ width: "12rem" }} + position="bottom right" + useSearch + /> + + + copy {p.type} + + + )} + position="center" + /> + ); +}; + +export default CopyMenu; diff --git a/frontend/src/components/build/Header.tsx b/frontend/src/components/build/Header.tsx index 2548732ca..2448eb464 100644 --- a/frontend/src/components/build/Header.tsx +++ b/frontend/src/components/build/Header.tsx @@ -13,6 +13,7 @@ import { A, useParams } from "@solidjs/router"; import { PermissionLevel } from "../../types"; import { client } from "../.."; import HoverMenu from "../shared/menu/HoverMenu"; +import CopyMenu from "../CopyMenu"; const Header: Component<{}> = (p) => { const { builds, servers } = useAppState(); @@ -43,21 +44,24 @@ const Header: Component<{}> = (p) => {

{build().name}

- { - client.delete_build(params.id); - }} - class="red" - > - - - } - content="delete build" - position="bottom center" - padding="0.5rem" - /> + + + { + client.delete_build(params.id); + }} + class="red" + > + + + } + content="delete build" + position="bottom center" + padding="0.5rem" + /> +
diff --git a/frontend/src/components/deployment/Header.tsx b/frontend/src/components/deployment/Header.tsx index 9e532f65b..18c7a0101 100644 --- a/frontend/src/components/deployment/Header.tsx +++ b/frontend/src/components/deployment/Header.tsx @@ -17,6 +17,7 @@ import Updates from "./Updates"; import { DockerContainerState, PermissionLevel } from "../../types"; import { A, useParams } from "@solidjs/router"; import { client } from "../.."; +import CopyMenu from "../CopyMenu"; const Header: Component<{}> = (p) => { const { deployments, servers } = useAppState(); @@ -53,21 +54,24 @@ const Header: Component<{}> = (p) => {

{deployment()!.deployment.name}

- { - client.delete_deployment(params.id); - }} - class="red" - > - - - } - content="delete deployment" - position="bottom center" - padding="0.5rem" - /> + + + { + client.delete_deployment(params.id); + }} + class="red" + > + + + } + content="delete deployment" + position="bottom center" + padding="0.5rem" + /> +
diff --git a/frontend/src/components/shared/Icon.tsx b/frontend/src/components/shared/Icon.tsx index 7e3ef3454..665e5c99c 100644 --- a/frontend/src/components/shared/Icon.tsx +++ b/frontend/src/components/shared/Icon.tsx @@ -45,7 +45,8 @@ export type IconType = | "cog" | "home" | "timeline-line-chart" - | "arrow-right"; + | "arrow-right" + | "duplicate"; const ICON_DIR = import.meta.env.VITE_ICON_DIR || "/assets/icons" diff --git a/frontend/src/components/shared/menu/Selector.tsx b/frontend/src/components/shared/menu/Selector.tsx index 3fbaf0762..5149c343c 100644 --- a/frontend/src/components/shared/menu/Selector.tsx +++ b/frontend/src/components/shared/menu/Selector.tsx @@ -33,10 +33,13 @@ const Selector: Component<{ itemClass?: string; itemStyle?: JSX.CSSProperties; label?: JSXElement; + itemMap?: (item: string) => string; }> = (p) => { const [show, toggle] = useToggle(); const [search, setSearch] = createSignal(""); let ref: HTMLInputElement | undefined; + const current = () => + p.itemMap ? p.itemMap(p.selected) : p.selected; createEffect(() => { if (show()) setTimeout(() => ref?.focus(), 200); }); @@ -46,7 +49,7 @@ const Selector: Component<{ fallback={
{p.label} - {p.selected} + {current()}
} > @@ -60,7 +63,7 @@ const Selector: Component<{ target={ } @@ -101,7 +104,7 @@ const Selector: Component<{ }} class={combineClasses(p.itemClass, s.SelectorItem)} > - {item} + {p.itemMap ? p.itemMap(item) : item} )}