forked from github-starred/komodo
implement description
This commit is contained in:
@@ -170,7 +170,7 @@ impl State {
|
||||
self.get_deployment_check_permissions(id, user, PermissionLevel::Update)
|
||||
.await?;
|
||||
self.db
|
||||
.builds
|
||||
.deployments
|
||||
.update_one::<()>(id, mungos::Update::Set(doc! { "description": description }))
|
||||
.await?;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ impl State {
|
||||
self.get_server_check_permissions(id, user, PermissionLevel::Update)
|
||||
.await?;
|
||||
self.db
|
||||
.builds
|
||||
.servers
|
||||
.update_one::<()>(id, mungos::Update::Set(doc! { "description": description }))
|
||||
.await?;
|
||||
}
|
||||
@@ -186,7 +186,7 @@ impl State {
|
||||
self.get_group_check_permissions(id, user, PermissionLevel::Update)
|
||||
.await?;
|
||||
self.db
|
||||
.builds
|
||||
.groups
|
||||
.update_one::<()>(id, mungos::Update::Set(doc! { "description": description }))
|
||||
.await?;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ impl State {
|
||||
self.get_procedure_check_permissions(id, user, PermissionLevel::Update)
|
||||
.await?;
|
||||
self.db
|
||||
.builds
|
||||
.procedures
|
||||
.update_one::<()>(id, mungos::Update::Set(doc! { "description": description }))
|
||||
.await?;
|
||||
}
|
||||
|
||||
125
frontend/src/components/Description.tsx
Normal file
125
frontend/src/components/Description.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import { Component, createSignal, onMount, Show } from "solid-js";
|
||||
import { client, pushNotification } from "..";
|
||||
import { useAppState } from "../state/StateProvider";
|
||||
import { UpdateTarget } from "../types";
|
||||
import { useToggle } from "../util/hooks";
|
||||
import ConfirmButton from "./shared/ConfirmButton";
|
||||
import Flex from "./shared/layout/Flex";
|
||||
import Grid from "./shared/layout/Grid";
|
||||
import Loading from "./shared/loading/Loading";
|
||||
import CenterMenu from "./shared/menu/CenterMenu";
|
||||
import TextArea from "./shared/TextArea";
|
||||
|
||||
const Description: Component<{
|
||||
name: string;
|
||||
target: UpdateTarget;
|
||||
description?: string;
|
||||
userCanUpdate: boolean;
|
||||
}> = (p) => {
|
||||
const [show, toggleShow] = useToggle();
|
||||
const description = () => {
|
||||
if (p.description) {
|
||||
return p.description;
|
||||
} else {
|
||||
return "add a description";
|
||||
}
|
||||
};
|
||||
const [width, setWidth] = createSignal<number>();
|
||||
onMount(() => {
|
||||
setWidth(ref!?.clientWidth);
|
||||
});
|
||||
let ref: HTMLDivElement;
|
||||
return (
|
||||
<CenterMenu
|
||||
show={show}
|
||||
toggleShow={toggleShow}
|
||||
title={`description | ${p.name}`}
|
||||
targetClass="card grey"
|
||||
targetStyle={{ width: "100%", "justify-content": "flex-start" }}
|
||||
target={
|
||||
<div
|
||||
ref={ref! as any}
|
||||
class="ellipsis"
|
||||
style={{
|
||||
opacity: 0.7,
|
||||
width: width() ? `${width()}px` : "100%",
|
||||
"box-sizing": "border-box",
|
||||
"text-align": "left"
|
||||
}}
|
||||
>
|
||||
{width() ? description() : ""}
|
||||
</div>
|
||||
}
|
||||
content={() => (
|
||||
<DescriptionMenu
|
||||
target={p.target}
|
||||
description={p.description}
|
||||
userCanUpdate={p.userCanUpdate}
|
||||
toggleShow={toggleShow}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const DescriptionMenu: Component<{
|
||||
target: UpdateTarget;
|
||||
description?: string;
|
||||
userCanUpdate: boolean;
|
||||
toggleShow: () => void;
|
||||
}> = (p) => {
|
||||
const { builds, servers, deployments } = useAppState();
|
||||
let ref: HTMLTextAreaElement;
|
||||
onMount(() => {
|
||||
ref?.focus();
|
||||
});
|
||||
const [desc, setDesc] = createSignal(p.description);
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
const update_description = () => {
|
||||
setLoading(true);
|
||||
client
|
||||
.update_description({ target: p.target, description: desc() || "" })
|
||||
.then(() => {
|
||||
if (p.target.type === "Build") {
|
||||
builds.update({ ...builds.get(p.target.id)!, description: desc() });
|
||||
} else if (p.target.type === "Deployment") {
|
||||
const deployment = deployments.get(p.target.id)!;
|
||||
deployments.update({
|
||||
...deployment,
|
||||
deployment: { ...deployment.deployment, description: desc() },
|
||||
});
|
||||
} else if (p.target.type === "Server") {
|
||||
const server = servers.get(p.target.id)!;
|
||||
servers.update({
|
||||
...server,
|
||||
server: { ...server.server, description: desc() },
|
||||
});
|
||||
}
|
||||
p.toggleShow();
|
||||
})
|
||||
.catch(() => {
|
||||
pushNotification("bad", "failed to update description");
|
||||
p.toggleShow();
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Grid placeItems="center">
|
||||
<TextArea
|
||||
ref={ref! as any}
|
||||
placeholder="add a description"
|
||||
value={desc()}
|
||||
onEdit={setDesc}
|
||||
onEnter={update_description}
|
||||
style={{ width: "700px", "max-width": "90vw", padding: "1rem" }}
|
||||
disabled={!p.userCanUpdate}
|
||||
/>
|
||||
<Show when={!loading()} fallback={<Loading />}>
|
||||
<button class="green" onClick={update_description}>
|
||||
update
|
||||
</button>
|
||||
</Show>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Description;
|
||||
@@ -1,19 +1,24 @@
|
||||
import { Component } from "solid-js";
|
||||
import { Component, Show } from "solid-js";
|
||||
import Grid from "./shared/layout/Grid";
|
||||
import Loading from "./shared/loading/Loading";
|
||||
|
||||
const NotFound: Component<{ type: "deployment" | "server" | "build" }> = (p) => {
|
||||
return (
|
||||
<Grid
|
||||
placeItems="center"
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
>
|
||||
<Grid placeItems="center" style={{ width: "fit-content", height: "fit-content" }}>
|
||||
<h2>{p.type} at id not found</h2>
|
||||
const NotFound: Component<{
|
||||
type: "deployment" | "server" | "build";
|
||||
loaded: boolean;
|
||||
}> = (p) => {
|
||||
return (
|
||||
<Grid placeItems="center" style={{ height: "100%", width: "100%" }}>
|
||||
<Grid
|
||||
placeItems="center"
|
||||
style={{ width: "fit-content", height: "fit-content" }}
|
||||
>
|
||||
<Show when={p.loaded} fallback={<h2>loading {p.type}...</h2>}>
|
||||
<h2>{p.type} at id not found</h2>
|
||||
</Show>
|
||||
<Loading type="sonar" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default NotFound;
|
||||
export default NotFound;
|
||||
|
||||
@@ -2,7 +2,9 @@ import { useNavigate, useParams } from "@solidjs/router";
|
||||
import { Component, createEffect, onCleanup, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { Operation } from "../../types";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { Operation, PermissionLevel } from "../../types";
|
||||
import Description from "../Description";
|
||||
import NotFound from "../NotFound";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
import Actions from "./Actions";
|
||||
@@ -12,6 +14,7 @@ import BuildTabs from "./tabs/Tabs";
|
||||
import Updates from "./Updates";
|
||||
|
||||
const Build: Component<{}> = (p) => {
|
||||
const { user, user_id } = useUser();
|
||||
const { builds, ws } = useAppState();
|
||||
const navigate = useNavigate();
|
||||
const params = useParams();
|
||||
@@ -31,8 +34,11 @@ const Build: Component<{}> = (p) => {
|
||||
});
|
||||
});
|
||||
onCleanup(() => unsub);
|
||||
const userCanUpdate = () =>
|
||||
user().admin ||
|
||||
build()?.permissions![user_id()] === PermissionLevel.Update;
|
||||
return (
|
||||
<Show when={build()} fallback={<NotFound type="build" />}>
|
||||
<Show when={build()} fallback={<NotFound type="build" loaded={builds.loaded()} />}>
|
||||
<ActionStateProvider build_id={params.id}>
|
||||
<Grid
|
||||
style={{
|
||||
@@ -44,8 +50,14 @@ const Build: Component<{}> = (p) => {
|
||||
style={{ width: "100%" }}
|
||||
gridTemplateColumns={isSemiMobile() ? "1fr" : "1fr 1fr"}
|
||||
>
|
||||
<Grid style={{ "flex-grow": 1, "grid-auto-rows": "auto 1fr" }}>
|
||||
<Grid style={{ "flex-grow": 1, "grid-auto-rows": "auto auto 1fr" }}>
|
||||
<Header />
|
||||
<Description
|
||||
target={{ type: "Build", id: params.id }}
|
||||
name={build()?.name!}
|
||||
description={build()?.description}
|
||||
userCanUpdate={userCanUpdate()}
|
||||
/>
|
||||
<Actions />
|
||||
</Grid>
|
||||
<Show when={!isSemiMobile()}>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { Component, onCleanup, Show } from "solid-js";
|
||||
import { client } from "../..";
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { ServerStatus } from "../../types";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { PermissionLevel } from "../../types";
|
||||
import Description from "../Description";
|
||||
import NotFound from "../NotFound";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
import Actions from "./Actions";
|
||||
@@ -16,12 +17,16 @@ const POLLING_RATE = 10000;
|
||||
// let interval = -1;
|
||||
|
||||
const Deployment: Component<{}> = (p) => {
|
||||
const { user, user_id } = useUser();
|
||||
const { servers, deployments } = useAppState();
|
||||
const { isSemiMobile } = useAppDimensions();
|
||||
const params = useParams();
|
||||
const deployment = () => deployments.get(params.id);
|
||||
const server = () =>
|
||||
deployment() && servers.get(deployment()!.deployment.server_id);
|
||||
const userCanUpdate = () =>
|
||||
user().admin ||
|
||||
deployment()?.deployment.permissions![user_id()] === PermissionLevel.Update;
|
||||
// clearInterval(interval);
|
||||
// interval = setInterval(async () => {
|
||||
// if (server()?.status === ServerStatus.Ok) {
|
||||
@@ -33,7 +38,7 @@ const Deployment: Component<{}> = (p) => {
|
||||
return (
|
||||
<Show
|
||||
when={deployment() && server()}
|
||||
fallback={<NotFound type="deployment" />}
|
||||
fallback={<NotFound type="deployment" loaded={deployments.loaded()} />}
|
||||
>
|
||||
<ActionStateProvider>
|
||||
<Grid
|
||||
@@ -46,8 +51,14 @@ const Deployment: Component<{}> = (p) => {
|
||||
style={{ width: "100%" }}
|
||||
gridTemplateColumns={isSemiMobile() ? "1fr" : "1fr 1fr"}
|
||||
>
|
||||
<Grid style={{ "flex-grow": 1, "grid-auto-rows": "auto 1fr" }}>
|
||||
<Grid style={{ "flex-grow": 1, "grid-auto-rows": "auto auto 1fr" }}>
|
||||
<Header />
|
||||
<Description
|
||||
target={{ type: "Deployment", id: params.id }}
|
||||
name={deployment()?.deployment.name!}
|
||||
description={deployment()?.deployment.description}
|
||||
userCanUpdate={userCanUpdate()}
|
||||
/>
|
||||
<Actions />
|
||||
</Grid>
|
||||
<Show when={!isSemiMobile()}>
|
||||
|
||||
@@ -2,6 +2,9 @@ import { useParams } from "@solidjs/router";
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAppDimensions } from "../../state/DimensionProvider";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { useUser } from "../../state/UserProvider";
|
||||
import { PermissionLevel } from "../../types";
|
||||
import Description from "../Description";
|
||||
import NotFound from "../NotFound";
|
||||
import ServerChildren from "../server_children/ServerChildren";
|
||||
import Grid from "../shared/layout/Grid";
|
||||
@@ -12,15 +15,16 @@ import ServerTabs from "./tabs/Tabs";
|
||||
import Updates from "./Updates";
|
||||
|
||||
const Server: Component<{}> = (p) => {
|
||||
const { user, user_id } = useUser();
|
||||
const { servers } = useAppState();
|
||||
const params = useParams();
|
||||
const server = () => servers.get(params.id)!;
|
||||
const { isSemiMobile } = useAppDimensions();
|
||||
// const userCanUpdate = () =>
|
||||
// user().admin ||
|
||||
// server()!.server.permissions![getId(user())] === PermissionLevel.Update;
|
||||
const userCanUpdate = () =>
|
||||
user().admin ||
|
||||
server()?.server.permissions![user_id()] === PermissionLevel.Update;
|
||||
return (
|
||||
<Show when={server()} fallback={<NotFound type="server" />}>
|
||||
<Show when={server()} fallback={<NotFound type="server" loaded={servers.loaded()} />}>
|
||||
<ActionStateProvider>
|
||||
<Grid
|
||||
style={{
|
||||
@@ -32,8 +36,14 @@ const Server: Component<{}> = (p) => {
|
||||
style={{ width: "100%" }}
|
||||
gridTemplateColumns={isSemiMobile() ? "1fr" : "1fr 1fr"}
|
||||
>
|
||||
<Grid style={{ "flex-grow": 1, "grid-auto-rows": "auto 1fr" }}>
|
||||
<Grid style={{ "flex-grow": 1, "grid-auto-rows": "auto auto 1fr" }}>
|
||||
<Header />
|
||||
<Description
|
||||
target={{ type: "Server", id: params.id }}
|
||||
name={server().server.name}
|
||||
description={server().server.description}
|
||||
userCanUpdate={userCanUpdate()}
|
||||
/>
|
||||
<Actions />
|
||||
</Grid>
|
||||
<Show when={!isSemiMobile()}>
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { useParams } from "@solidjs/router";
|
||||
import { Component, createResource, For, Show } from "solid-js";
|
||||
import { client } from "../../..";
|
||||
import { useAppDimensions } from "../../../state/DimensionProvider";
|
||||
import { useAppState } from "../../../state/StateProvider";
|
||||
import { readableStorageAmount } from "../../../util/helpers";
|
||||
import Flex from "../../shared/layout/Flex";
|
||||
import Grid from "../../shared/layout/Grid";
|
||||
import Loading from "../../shared/loading/Loading";
|
||||
import HoverMenu from "../../shared/menu/HoverMenu";
|
||||
|
||||
const Info: Component<{}> = (p) => {
|
||||
const { isMobile } = useAppDimensions();
|
||||
const { serverInfo } = useAppState();
|
||||
const params = useParams();
|
||||
const [stats] = createResource(() => client.get_server_stats(params.id, { disks: true }));
|
||||
@@ -74,8 +77,17 @@ const Info: Component<{}> = (p) => {
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Flex alignItems="center">
|
||||
<div>mount point:</div>
|
||||
<h2>{disk.mount}</h2>
|
||||
<div style={{ "white-space": "nowrap" }}>
|
||||
mount point:
|
||||
</div>
|
||||
<h2
|
||||
class="ellipsis"
|
||||
style={{
|
||||
"max-width": isMobile() ? "50px" : "200px",
|
||||
}}
|
||||
>
|
||||
{disk.mount}
|
||||
</h2>
|
||||
</Flex>
|
||||
<Flex alignItems="center">
|
||||
<div>{readableStorageAmount(disk.used_gb)} used</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ const TextArea: Component<
|
||||
onBlur={(e) => p.onConfirm && p.onConfirm(e.currentTarget.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && p.onEnter) {
|
||||
e.preventDefault();
|
||||
p.onEnter(e.currentTarget.value);
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -38,7 +38,7 @@ h1 {
|
||||
h2 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 450;
|
||||
user-select: none;
|
||||
// user-select: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,6 @@ svg {
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
Reference in New Issue
Block a user