Compare commits

...

8 Commits

Author SHA1 Message Date
mbecker20
1374c26cd8 0.2.0 cleanup 2023-02-23 07:28:11 +00:00
mbecker20
5467b40b2e fix to git clone <TOKEN> splice 2023-02-23 07:22:32 +00:00
mbecker20
165b9012da improve users responsiveness 2023-02-23 07:17:18 +00:00
mbecker20
22630f665e update the manage users page 2023-02-23 07:09:33 +00:00
mbecker20
3d867084ba log poll default to false 2023-02-23 06:44:55 +00:00
mbecker20
171dd2d9e0 remove menu animation, change builder type to selector 2023-02-23 06:38:36 +00:00
mbecker20
9709239f88 build version h2 2023-02-22 22:45:05 +00:00
mbecker20
60d457b285 improve deployment in tree and display deployed version in header 2023-02-22 22:27:54 +00:00
31 changed files with 347 additions and 223 deletions

30
Cargo.lock generated
View File

@@ -743,7 +743,7 @@ dependencies = [
[[package]]
name = "core"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -760,7 +760,7 @@ dependencies = [
"hmac",
"jwt",
"monitor_helpers",
"monitor_types 0.1.17",
"monitor_types 0.2.0",
"mungos",
"periphery_client",
"serde",
@@ -995,10 +995,10 @@ checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "db_client"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"monitor_types 0.1.17",
"monitor_types 0.2.0",
"mungos",
]
@@ -1854,12 +1854,12 @@ dependencies = [
[[package]]
name = "monitor_client"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"envy",
"futures-util",
"monitor_types 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"monitor_types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest",
"serde",
"serde_derive",
@@ -1871,7 +1871,7 @@ dependencies = [
[[package]]
name = "monitor_helpers"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -1881,7 +1881,7 @@ dependencies = [
"bollard",
"futures",
"futures-util",
"monitor_types 0.1.17",
"monitor_types 0.2.0",
"periphery_client",
"rand",
"run_command",
@@ -1894,7 +1894,7 @@ dependencies = [
[[package]]
name = "monitor_periphery"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -1906,7 +1906,7 @@ dependencies = [
"envy",
"futures-util",
"monitor_helpers",
"monitor_types 0.1.17",
"monitor_types 0.2.0",
"run_command",
"serde",
"serde_derive",
@@ -1920,7 +1920,7 @@ dependencies = [
[[package]]
name = "monitor_types"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"bollard",
@@ -1937,9 +1937,9 @@ dependencies = [
[[package]]
name = "monitor_types"
version = "0.1.17"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cadc2581c18f79aa663ecdedceac23f8118a9c724c50458f593d3b1f40d182f"
checksum = "62e9379ee43474ebac60b639f9094343b92cc9cbee55d8a447a65cd46305feee"
dependencies = [
"anyhow",
"bollard",
@@ -2204,11 +2204,11 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "periphery_client"
version = "0.1.17"
version = "0.2.0"
dependencies = [
"anyhow",
"futures-util",
"monitor_types 0.1.17",
"monitor_types 0.2.0",
"reqwest",
"serde",
"serde_json",

View File

@@ -1,6 +1,6 @@
[package]
name = "core"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -33,6 +33,13 @@ struct ModifyUserCreateServerBody {
create_server_permissions: bool,
}
#[typeshare]
#[derive(Serialize, Deserialize)]
struct ModifyUserCreateBuildBody {
user_id: String,
create_build_permissions: bool,
}
pub fn router() -> Router {
Router::new()
.route(
@@ -62,6 +69,15 @@ pub fn router() -> Router {
response!(Json(update))
}),
)
.route(
"/modify_create_build",
post(|state, user, body| async {
let update = modify_user_create_build_permissions(state, user, body)
.await
.map_err(handle_anyhow_error)?;
response!(Json(update))
}),
)
}
async fn update_permissions(
@@ -309,3 +325,58 @@ async fn modify_user_create_server_permissions(
update.id = state.add_update(update.clone()).await?;
Ok(update)
}
async fn modify_user_create_build_permissions(
Extension(state): StateExtension,
Extension(user): RequestUserExtension,
Json(ModifyUserCreateBuildBody {
user_id,
create_build_permissions,
}): Json<ModifyUserCreateBuildBody>,
) -> anyhow::Result<Update> {
if !user.is_admin {
return Err(anyhow!(
"user does not have permissions for this action (not admin)"
));
}
let user = state
.db
.users
.find_one_by_id(&user_id)
.await
.context("failed at mongo query to find target user")?
.ok_or(anyhow!("did not find any user with user_id {user_id}"))?;
state
.db
.users
.update_one::<Document>(
&user_id,
mungos::Update::Set(doc! { "create_build_permissions": create_build_permissions }),
)
.await?;
let update_type = if create_build_permissions {
"enabled"
} else {
"disabled"
};
let ts = monitor_timestamp();
let mut update = Update {
target: UpdateTarget::System,
operation: Operation::ModifyUserCreateBuildPermissions,
logs: vec![Log::simple(
"modify user create build permissions",
format!(
"{update_type} create build permissions for {} (id: {})",
user.username, user.id
),
)],
start_ts: ts.clone(),
end_ts: Some(ts),
status: UpdateStatus::Complete,
success: true,
operator: user.id.clone(),
..Default::default()
};
update.id = state.add_update(update.clone()).await?;
Ok(update)
}

View File

@@ -11,6 +11,7 @@ import Input from "./shared/Input";
import Flex from "./shared/layout/Flex";
import Grid from "./shared/layout/Grid";
import CenterMenu from "./shared/menu/CenterMenu";
import HoverMenu from "./shared/menu/HoverMenu";
import Selector from "./shared/menu/Selector";
const CopyMenu: Component<{
@@ -58,47 +59,53 @@ const CopyMenu: Component<{
}
};
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}
/>
<Show when={p.type === "deployment"}>
<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: "100%" }}
position="bottom right"
useSearch
/>
</Show>
</Flex>
<ConfirmButton
class="green"
style={{ width: "100%" }}
onConfirm={copy}
>
copy {p.type}
</ConfirmButton>
</Grid>
)}
position="center"
<HoverMenu
target={
<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}
/>
<Show when={p.type === "deployment"}>
<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: "100%" }}
position="bottom right"
useSearch
/>
</Show>
</Flex>
<ConfirmButton
class="green"
style={{ width: "100%" }}
onConfirm={copy}
>
copy {p.type}
</ConfirmButton>
</Grid>
)}
position="center"
/>
}
content={`copy ${p.type}`}
position="bottom center"
/>
);
};

View File

@@ -2,6 +2,7 @@ import { Component, Show } from "solid-js";
import { useAppState } from "../../../../state/StateProvider";
import Flex from "../../../shared/layout/Flex";
import Grid from "../../../shared/layout/Grid";
import Selector from "../../../shared/menu/Selector";
import { useConfig } from "../Provider";
const BuilderType: Component<{}> = (p) => {
@@ -24,34 +25,25 @@ const BuilderType: Component<{}> = (p) => {
>
<h1>builder type</h1>
<Show when={userCanUpdate()} fallback={<h2>{builderType()}</h2>}>
<Grid gap="0" gridTemplateColumns="1fr 1fr">
<button
class={builderType() === "server" ? "blue" : "grey"}
style={{ width: "100%" }}
onClick={() => {
if (builderType() !== "server") {
<Selector
targetClass="blue"
selected={builderType() || "select type"}
items={["aws", "server"]}
position="bottom right"
onSelect={(type) => {
if (type !== builderType()) {
if (type === "server") {
const server_id =
servers.ids()?.length || 0 > 0
? servers.ids()![0]
: undefined;
setBuild({ server_id, aws_config: undefined });
}
}}
>
server
</button>
<button
class={builderType() === "aws" ? "blue" : "grey"}
style={{ width: "100%" }}
onClick={() => {
if (builderType() !== "aws") {
} else if (type === "aws") {
setBuild({ server_id: undefined, aws_config: {} });
}
}}
>
aws
</button>
</Grid>
}
}}
/>
</Show>
</Flex>
);

View File

@@ -1,10 +1,11 @@
import { Component, Show } from "solid-js";
import { Component, createResource, Show } from "solid-js";
import { useAppState } from "../../state/StateProvider";
import { useUser } from "../../state/UserProvider";
import {
combineClasses,
deploymentHeaderStateClass,
getId,
readableVersion,
} from "../../util/helpers";
import Icon from "../shared/Icon";
import Flex from "../shared/layout/Flex";
@@ -20,7 +21,7 @@ import CopyMenu from "../CopyMenu";
import ConfirmMenuButton from "../shared/ConfirmMenuButton";
const Header: Component<{}> = (p) => {
const { deployments, servers } = useAppState();
const { deployments, servers, builds } = useAppState();
const params = useParams();
const deployment = () => deployments.get(params.id)!;
const { user } = useUser();
@@ -37,6 +38,27 @@ const Header: Component<{}> = (p) => {
deployment().deployment.permissions![getId(user())] ===
PermissionLevel.Update;
const server = () => servers.get(deployment().deployment.server_id);
const [deployed_version] = createResource(() =>
client.get_deployment_deployed_version(params.id)
);
const image = () => {
if (deployment().deployment.build_id) {
const build = builds.get(deployment().deployment.build_id!)!;
if (deployment().state === DockerContainerState.NotDeployed) {
const version = deployment().deployment.build_version
? readableVersion(deployment().deployment.build_version!).replaceAll(
"v",
""
)
: "latest";
return `${build.name}:${version}`;
} else {
return deployed_version() && `${build.name}:${deployed_version()}`;
}
} else {
return deployment().deployment.docker_run_args.image || "unknown";
}
};
return (
<>
<Grid
@@ -52,7 +74,10 @@ const Header: Component<{}> = (p) => {
}}
>
<Flex alignItems="center" justifyContent="space-between">
<h1>{deployment()!.deployment.name}</h1>
<Flex alignItems="center">
<h1>{deployment()!.deployment.name}</h1>
<div style={{ opacity: 0.7 }}>{image()}</div>
</Flex>
<Show when={userCanUpdate()}>
<Flex alignItems="center">
<CopyMenu type="deployment" id={params.id} />

View File

@@ -49,9 +49,9 @@ const Config: Component<{}> = () => {
</Show>
<Network />
<Restart />
<Env />
<Ports />
<Mounts />
<Env />
<ExtraArgs />
<PostImage />
<Show when={isMobile()}>

View File

@@ -17,7 +17,7 @@ const Env: Component<{}> = (p) => {
<Grid class={combineClasses("config-item shadow")}>
<Flex alignItems="center" justifyContent="space-between">
<h1>environment</h1>
<Flex alignItems="center" gap="0.2rem">
<Flex alignItems="center">
<Show
when={
!deployment.docker_run_args.environment ||

View File

@@ -22,21 +22,11 @@ const ExtraArgs: Component<{}> = (p) => {
<Grid class="config-item shadow">
<Flex justifyContent="space-between" alignItems="center">
<h1>extra args</h1>
<Flex alignItems="center">
<Show
when={
!deployment.docker_run_args.extra_args ||
deployment.docker_run_args.extra_args.length === 0
}
>
<div>none</div>
</Show>
<Show when={userCanUpdate()}>
<button class="green" onClick={onAdd}>
<Icon type="plus" />
</button>
</Show>
</Flex>
<Show when={userCanUpdate()}>
<button class="green" onClick={onAdd}>
<Icon type="plus" />
</button>
</Show>
</Flex>
<For each={[...deployment.docker_run_args.extra_args!.keys()]}>
{(_, index) => (

View File

@@ -20,6 +20,7 @@ const Network: Component<{}> = (p) => {
onSelect={(network) => setDeployment("docker_run_args", { network })}
position="bottom right"
disabled={!userCanUpdate()}
searchStyle={{ width: "100%", "min-width": "12rem" }}
useSearch
/>
</Flex>

View File

@@ -23,21 +23,11 @@ const Volumes: Component<{}> = (p) => {
<Grid class={combineClasses("config-item shadow")}>
<Flex justifyContent="space-between" alignItems="center">
<h1>volumes</h1>
<Flex alignItems="center">
<Show
when={
!deployment.docker_run_args.volumes ||
deployment.docker_run_args.volumes.length === 0
}
>
<div>none</div>
</Show>
<Show when={userCanUpdate()}>
<button class="green" onClick={onAdd}>
<Icon type="plus" />
</button>
</Show>
</Flex>
<Show when={userCanUpdate()}>
<button class="green" onClick={onAdd}>
<Icon type="plus" />
</button>
</Show>
</Flex>
<For each={deployment.docker_run_args.volumes}>
{({ local, container }, index) => (

View File

@@ -70,7 +70,7 @@ const Log: Component<{
const buffer = useBuffer(scrolled, 250);
const [poll, togglePoll] = useLocalStorageToggle(
"deployment-log-polling",
true
false
);
clearInterval(interval);
interval = setInterval(() => {

View File

@@ -134,7 +134,7 @@ const Build: Component<{ id: string }> = (p) => {
<Show when={isAwsBuild()}>
<div style={{ opacity: 0.7 }}>aws build</div>
</Show>
<div>{version()}</div>
<h2>{version()}</h2>
<Show when={!isMobile()}>
<div style={{ opacity: 0.7 }}>{lastBuiltAt()}</div>
</Show>

View File

@@ -11,6 +11,7 @@ import {
} from "../../util/helpers";
import Circle from "../shared/Circle";
import Flex from "../shared/layout/Flex";
import Grid from "../shared/layout/Grid";
import s from "./serverchildren.module.scss";
const Deployment: Component<{ id: string }> = (p) => {
@@ -40,9 +41,11 @@ const Deployment: Component<{ id: string }> = (p) => {
return (
<Show when={deployment()}>
<A href={`/deployment/${p.id}`} class={combineClasses(s.DropdownItem)}>
<h2>{deployment().deployment.name}</h2>
<Flex alignItems="center">
<Grid gap="0">
<h2>{deployment().deployment.name}</h2>
<div style={{ opacity: 0.7 }}>{image()}</div>
</Grid>
<Flex alignItems="center">
<div style={{ opacity: 0.7 }}>{deployments.status(p.id)}</div>
<Circle
size={1}

View File

@@ -1,8 +1,6 @@
import {
Accessor,
Component,
createEffect,
createSignal,
JSX,
JSXElement,
Show,
@@ -27,16 +25,16 @@ const CenterMenu: Component<{
style?: JSX.CSSProperties;
position?: "top" | "center";
}> = (p) => {
const [buffer, set] = createSignal(p.show());
createEffect(() => {
if (p.show()) {
set(true);
} else {
setTimeout(() => {
set(false);
}, 350);
}
});
// const [buffer, set] = createSignal(p.show());
// createEffect(() => {
// if (p.show()) {
// set(true);
// } else {
// setTimeout(() => {
// set(false);
// }, 350);
// }
// });
return (
<>
<button
@@ -49,7 +47,7 @@ const CenterMenu: Component<{
>
{p.target}
</button>
<Show when={buffer()}>
<Show when={p.show()}>
<Child {...p} show={p.show} toggleShow={p.toggleShow} />
</Show>
</>
@@ -69,7 +67,7 @@ const Child: Component<{
useKeyDown("Escape", p.toggleShow);
return (
<Grid
class={combineClasses(s.CenterMenuContainer, p.show() ? s.Enter : s.Exit)}
class={combineClasses(s.CenterMenuContainer)}
onClick={(e) => {
e.stopPropagation();
p.toggleShow();

View File

@@ -22,18 +22,18 @@ const HoverMenu: Component<{
containerStyle?: JSX.CSSProperties;
}> = (p) => {
const [show, set] = createSignal(false);
const [buffer, setBuffer] = createSignal(false);
let timeout: number;
createEffect(() => {
clearTimeout(timeout);
if (show()) {
setBuffer(true);
} else {
timeout = setTimeout(() => {
setBuffer(false);
}, 350);
}
});
// const [buffer, setBuffer] = createSignal(false);
// let timeout: number;
// createEffect(() => {
// clearTimeout(timeout);
// if (show()) {
// setBuffer(true);
// } else {
// timeout = setTimeout(() => {
// setBuffer(false);
// }, 350);
// }
// });
return (
<Flex
class={s.HoverMenuTarget}
@@ -44,13 +44,13 @@ const HoverMenu: Component<{
alignItems="center"
>
{p.target}
<Show when={buffer()}>
<Show when={show()}>
<div
class={combineClasses(
p.contentClass,
getPositionClass(p.position),
s.HoverMenu,
show() ? s.Enter : s.Exit,
// show() ? s.Enter : s.Exit,
)}
onMouseOut={() => {
set(false);
@@ -59,7 +59,7 @@ const HoverMenu: Component<{
set(false)
e.stopPropagation();
}}
style={{ ...p.contentStyle, padding: p.padding }}
style={{ ...p.contentStyle, padding: p.padding || "0.5rem" }}
>
{p.content}
</div>

View File

@@ -1,7 +1,5 @@
import {
Component,
createEffect,
createSignal,
JSX,
JSXElement,
Show,
@@ -22,20 +20,20 @@ const Menu: Component<{
containerStyle?: JSX.CSSProperties;
backgroundColor?: string;
}> = (p) => {
const [buffer, set] = createSignal(p.show);
createEffect(() => {
if (p.show) {
set(true);
} else {
setTimeout(() => {
set(false);
}, 350);
}
});
// const [buffer, set] = createSignal(p.show);
// createEffect(() => {
// if (p.show) {
// set(true);
// } else {
// setTimeout(() => {
// set(false);
// }, 350);
// }
// });
return (
<div class={s.MenuContainer} style={p.containerStyle}>
{p.target}
<Show when={buffer()}>
<Show when={p.show}>
<div
class={s.MenuBackground}
style={{ "background-color": p.backgroundColor }}
@@ -47,7 +45,7 @@ const Menu: Component<{
s.Menu,
"shadow",
getPositionClass(p.position),
p.show ? s.Enter : s.Exit
// p.show ? s.Enter : s.Exit
)}
style={{ padding: p.padding as any, ...p.menuStyle }}
onClick={(e) => e.stopPropagation()}

View File

@@ -16,7 +16,6 @@ const Account: Component<{ close: () => void }> = (p) => {
<Show when={isMobile()}>
<Flex justifyContent="center">{user().username}</Flex>
</Show>
<Flex justifyContent="center">admin: {user().admin.toString()}</Flex>
<Show when={user().admin}>
<A
href="/users"
@@ -27,12 +26,12 @@ const Account: Component<{ close: () => void }> = (p) => {
manage users
</A>
</Show>
<Show when={!user().admin}>
{/* <Show when={!user().admin}>
<Flex justifyContent="center">
create server permissions:{" "}
{user().create_server_permissions.toString()}
{user().create_server_permissions?.toString()}
</Flex>
</Show>
</Show> */}
<A
href="/account"
class="grey"

View File

@@ -17,7 +17,7 @@ import { ControlledTabs } from "../../shared/tabs/Tabs";
import { useAppDimensions } from "../../../state/DimensionProvider";
import Grid from "../../shared/layout/Grid";
import { A, useNavigate } from "@solidjs/router";
import { ServerStatus } from "../../../types";
import { Build, ServerStatus } from "../../../types";
const mobileStyle: JSX.CSSProperties = {
// position: "fixed",
@@ -191,8 +191,10 @@ const Builds: Component<{ close: () => void }> = (p) => {
gap="0.2rem"
style={{ opacity: 0.6, "font-size": "0.9rem" }}
>
{servers.get(build.server_id)?.server.name}
<Icon type="caret-right" width="0.7rem" />
<Show when={build.server_id}>
{build.server_id && servers.get(build.server_id)?.server.name}
<Icon type="caret-right" width="0.7rem" />
</Show>
build
</Flex>
</Grid>

View File

@@ -8,6 +8,7 @@ import {
Show,
} from "solid-js";
import { client } from "../..";
import { useAppDimensions } from "../../state/DimensionProvider";
import { useAppState } from "../../state/StateProvider";
import { Operation } from "../../types";
import { combineClasses, getId } from "../../util/helpers";
@@ -18,9 +19,19 @@ import Loading from "../shared/loading/Loading";
import s from "./users.module.scss";
const Users: Component<{}> = (p) => {
const { isMobile } = useAppDimensions();
const { ws } = useAppState();
const [users, { refetch }] = createResource(() => client.list_users());
onCleanup(ws.subscribe([Operation.ModifyUserEnabled], refetch));
onCleanup(
ws.subscribe(
[
Operation.ModifyUserEnabled,
Operation.ModifyUserCreateServerPermissions,
Operation.ModifyUserCreateBuildPermissions,
],
refetch
)
);
const [search, setSearch] = createSignal("");
const filteredUsers = createMemo(() =>
users()?.filter((user) => user.username.includes(search()))
@@ -34,55 +45,78 @@ const Users: Component<{}> = (p) => {
</Grid>
}
>
<Grid class={s.UsersContent}>
<Grid class={combineClasses(s.Users, "card shadow")}>
<Flex justifyContent="space-between">
<h1>users</h1>
<Input
class="lightgrey"
placeholder="search"
value={search()}
onEdit={setSearch}
/>
</Flex>
<For each={filteredUsers()}>
{(user) => (
<Flex class={combineClasses(s.User, "shadow")}>
<div class={s.Username}>{user.username}</div>
<Flex alignItems="center">
<button
class={user.enabled ? "green" : "red"}
onClick={() => {
client.modify_user_enabled({
user_id: getId(user),
enabled: !user.enabled,
});
}}
>
{user.enabled ? "enabled" : "disabled"}
</button>
<button
class={user.create_server_permissions ? "green" : "red"}
onClick={() => {
client.modify_user_create_server_permissions({
user_id: getId(user),
create_server_permissions: !user.create_server_permissions,
});
}}
>
{user.create_server_permissions ? "can create servers" : "cannot create servers"}
</button>
{/* <ConfirmButton
<Grid
class="card shadow"
style={{ width: "100%", "box-sizing": "border-box" }}
>
<Flex justifyContent="space-between">
<h1>users</h1>
<Input
class="lightgrey"
placeholder="search"
value={search()}
onEdit={setSearch}
/>
</Flex>
<For each={filteredUsers()}>
{(user) => (
<Flex class={combineClasses(s.User, "shadow")}>
<div class={s.Username}>{user.username}</div>
<Grid
placeItems="center end"
gridTemplateColumns={!isMobile() ? "1fr 1fr 1fr" : undefined}
>
<button
class={user.enabled ? "green" : "red"}
style={{ width: isMobile() ? "11rem" : "6rem" }}
onClick={() => {
client.modify_user_enabled({
user_id: getId(user),
enabled: !user.enabled,
});
}}
>
{user.enabled ? "enabled" : "disabled"}
</button>
<button
class={user.create_server_permissions ? "green" : "red"}
style={{ width: "11rem" }}
onClick={() => {
client.modify_user_create_server_permissions({
user_id: getId(user),
create_server_permissions:
!user.create_server_permissions,
});
}}
>
{user.create_server_permissions
? "can create servers"
: "cannot create servers"}
</button>
<button
class={user.create_build_permissions ? "green" : "red"}
style={{ width: "11rem" }}
onClick={() => {
client.modify_user_create_build_permissions({
user_id: getId(user),
create_build_permissions: !user.create_build_permissions,
});
}}
>
{user.create_build_permissions
? "can create builds"
: "cannot create builds"}
</button>
{/* <ConfirmButton
class="red"
onConfirm={() => deleteUser(user._id!)}
>
<Icon type="trash" />
</ConfirmButton> */}
</Flex>
</Flex>
)}
</For>
</Grid>
</Grid>
</Flex>
)}
</For>
</Grid>
</Show>
);

View File

@@ -432,6 +432,7 @@ export enum Operation {
DeleteGroup = "delete_group",
ModifyUserEnabled = "modify_user_enabled",
ModifyUserCreateServerPermissions = "modify_user_create_server_permissions",
ModifyUserCreateBuildPermissions = "modify_user_create_build_permissions",
ModifyUserPermissions = "modify_user_permissions",
AutoBuild = "auto_build",
AutoPull = "auto_pull",

View File

@@ -39,6 +39,7 @@ import {
CreateSecretBody,
CreateServerBody,
LoginOptions,
ModifyUserCreateBuildBody,
ModifyUserCreateServerBody,
ModifyUserEnabledBody,
PermissionsUpdateBody,
@@ -463,6 +464,12 @@ export class Client {
return this.post("/api/permissions/modify_create_server", body);
}
modify_user_create_build_permissions(
body: ModifyUserCreateBuildBody
): Promise<Update> {
return this.post("/api/permissions/modify_create_build", body);
}
async get<R = any>(url: string): Promise<R> {
return await axios({
method: "get",

View File

@@ -54,6 +54,11 @@ export interface ModifyUserCreateServerBody {
create_server_permissions: boolean;
}
export interface ModifyUserCreateBuildBody {
user_id: string;
create_build_permissions: boolean;
}
export interface CreateProcedureBody {
name: string;
}

View File

@@ -1,6 +1,6 @@
[package]
name = "db_client"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_helpers"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
authors = ["MoghTech"]
description = "helpers used as dependency for mogh tech monitor"

View File

@@ -83,7 +83,7 @@ async fn clone(
access_token: Option<GithubToken>,
) -> Log {
let _ = std::fs::remove_dir_all(destination);
let access_token = match access_token {
let access_token_at = match &access_token {
Some(token) => format!("{token}@"),
None => String::new(),
};
@@ -91,12 +91,12 @@ async fn clone(
Some(branch) => format!(" -b {branch}"),
None => String::new(),
};
let repo_url = format!("https://{access_token}github.com/{repo}.git");
let repo_url = format!("https://{access_token_at}github.com/{repo}.git");
let command = format!("git clone {repo_url} {destination}{branch}");
let start_ts = monitor_timestamp();
let output = async_run_command(&command).await;
let command = if access_token.len() > 0 {
command.replace(&access_token, "<TOKEN>")
let command = if access_token_at.len() > 0 {
command.replace(&access_token.unwrap(), "<TOKEN>")
} else {
command
};

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_client"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
authors = ["MoghTech"]
description = "a client to interact with the monitor system"
@@ -9,7 +9,7 @@ license = "GPL-3.0-or-later"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
monitor_types = "0.1.17"
monitor_types = "0.2.0"
# monitor_types = { path = "../types" }
reqwest = { version = "0.11", features = ["json"] }
tokio-tungstenite = { version = "0.18", features=["native-tls"] }

View File

@@ -1,6 +1,6 @@
[package]
name = "periphery_client"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_types"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
authors = ["MoghTech"]
description = "types for the mogh tech monitor"

View File

@@ -131,6 +131,7 @@ pub enum Operation {
// user
ModifyUserEnabled,
ModifyUserCreateServerPermissions,
ModifyUserCreateBuildPermissions,
ModifyUserPermissions,
// github webhook automation

View File

@@ -1,6 +1,6 @@
[package]
name = "monitor_periphery"
version = "0.1.17"
version = "0.2.0"
edition = "2021"
authors = ["MoghTech"]
description = "monitor periphery binary | run monitor periphery as system daemon"