implement build / deployment copy

This commit is contained in:
mbecker20
2023-01-25 22:53:27 +00:00
parent 09dfc8faa3
commit 4e4e210736
7 changed files with 157 additions and 35 deletions

View File

@@ -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)
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Rounded_Rectangle_2_1_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<g id="Rounded_Rectangle_2">
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#fceade" d="M15,4H1C0.45,4,0,4.45,0,5v14c0,0.55,0.45,1,1,1h14c0.55,0,1-0.45,1-1V5
C16,4.45,15.55,4,15,4z M14,18H2V6h12V18z M19,0H5C4.45,0,4,0.45,4,1v2h2V2h12v12h-1v2h2c0.55,0,1-0.45,1-1V1
C20,0.45,19.55,0,19,0z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 679 B

View File

@@ -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<Build | Deployment>;
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 (
<CenterMenu
show={show}
toggleShow={toggleShow}
title={`copy ${p.type} | ${name()}`}
target={<Icon type="duplicate" />}
targetClass="blue"
content={() => (
<Grid placeItems="center">
<Flex alignItems="center">
<Input
placeholder="copy name"
class="card dark"
style={{ padding: "0.5rem" }}
value={newName()}
onEdit={setNewName}
/>
<Selector
label="target: "
selected={selectedId()}
items={servers.ids()!}
onSelect={setSelected}
itemMap={(id) => servers.get(id)!.server.name}
targetClass="blue"
targetStyle={{ display: "flex", gap: "0.5rem" }}
searchStyle={{ width: "12rem" }}
position="bottom right"
useSearch
/>
</Flex>
<ConfirmButton
class="green"
onConfirm={copy}
>
copy {p.type}
</ConfirmButton>
</Grid>
)}
position="center"
/>
);
};
export default CopyMenu;

View File

@@ -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) => {
<Flex alignItems="center" justifyContent="space-between">
<h1>{build().name}</h1>
<Show when={userCanUpdate()}>
<HoverMenu
target={
<ConfirmButton
onConfirm={() => {
client.delete_build(params.id);
}}
class="red"
>
<Icon type="trash" />
</ConfirmButton>
}
content="delete build"
position="bottom center"
padding="0.5rem"
/>
<Flex alignItems="center">
<CopyMenu type="build" id={params.id} />
<HoverMenu
target={
<ConfirmButton
onConfirm={() => {
client.delete_build(params.id);
}}
class="red"
>
<Icon type="trash" />
</ConfirmButton>
}
content="delete build"
position="bottom center"
padding="0.5rem"
/>
</Flex>
</Show>
</Flex>
<Flex alignItems="center" justifyContent="space-between">

View File

@@ -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) => {
<Flex alignItems="center" justifyContent="space-between">
<h1>{deployment()!.deployment.name}</h1>
<Show when={userCanUpdate()}>
<HoverMenu
target={
<ConfirmButton
onConfirm={() => {
client.delete_deployment(params.id);
}}
class="red"
>
<Icon type="trash" />
</ConfirmButton>
}
content="delete deployment"
position="bottom center"
padding="0.5rem"
/>
<Flex alignItems="center">
<CopyMenu type="deployment" id={params.id} />
<HoverMenu
target={
<ConfirmButton
onConfirm={() => {
client.delete_deployment(params.id);
}}
class="red"
>
<Icon type="trash" />
</ConfirmButton>
}
content="delete deployment"
position="bottom center"
padding="0.5rem"
/>
</Flex>
</Show>
</Flex>
<Flex alignItems="center" justifyContent="space-between">

View File

@@ -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"

View File

@@ -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={
<div class={p.disabledClass} style={p.disabledStyle}>
<Show when={p.label}>{p.label}</Show>
{p.selected}
{current()}
</div>
}
>
@@ -60,7 +63,7 @@ const Selector: Component<{
target={
<button class={p.targetClass} onClick={toggle} style={p.targetStyle}>
<Show when={p.label}>{p.label}</Show>
{p.selected}
{current()}
<Icon type="chevron-down" />
</button>
}
@@ -101,7 +104,7 @@ const Selector: Component<{
}}
class={combineClasses(p.itemClass, s.SelectorItem)}
>
{item}
{p.itemMap ? p.itemMap(item) : item}
</button>
)}
</For>