mirror of
https://github.com/moghtech/komodo.git
synced 2026-09-05 00:00:45 +00:00
filter updates by operation
This commit is contained in:
+27
-12
@@ -9,6 +9,7 @@ use types::{PermissionLevel, Update, UpdateTarget};
|
||||
|
||||
use crate::{
|
||||
auth::{RequestUser, RequestUserExtension},
|
||||
helpers::parse_comma_seperated_list,
|
||||
response,
|
||||
state::{State, StateExtension},
|
||||
};
|
||||
@@ -36,8 +37,18 @@ pub fn router() -> Router {
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let operations = value
|
||||
.get("operations")
|
||||
.map(|o| {
|
||||
let o = o.as_str().unwrap_or_default();
|
||||
if o.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
parse_comma_seperated_list::<String>(o).ok()
|
||||
})
|
||||
.flatten();
|
||||
let updates = state
|
||||
.list_updates(target, offset, show_builds, &user)
|
||||
.list_updates(target, offset, show_builds, operations, &user)
|
||||
.await
|
||||
.map_err(handle_anyhow_error)?;
|
||||
response!(Json(updates))
|
||||
@@ -92,9 +103,10 @@ impl State {
|
||||
target: Option<UpdateTarget>,
|
||||
offset: u64,
|
||||
show_builds: bool,
|
||||
operations: Option<Vec<String>>,
|
||||
user: &RequestUser,
|
||||
) -> anyhow::Result<Vec<Update>> {
|
||||
let filter = match target {
|
||||
let mut filter = match target {
|
||||
Some(target) => {
|
||||
if let (UpdateTarget::Deployment(id), true) = (&target, show_builds) {
|
||||
let deployment = self
|
||||
@@ -105,32 +117,32 @@ impl State {
|
||||
.get_build_check_permissions(build_id, user, PermissionLevel::Read)
|
||||
.await;
|
||||
if let Ok(_) = build {
|
||||
Some(doc! {
|
||||
doc! {
|
||||
"$or": [
|
||||
{"target": to_bson(&target).unwrap()},
|
||||
{"target": { "type": "Build", "id": build_id }, "operation": "build_build"}
|
||||
],
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Some(doc! {
|
||||
doc! {
|
||||
"target": to_bson(&target).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(doc! {
|
||||
doc! {
|
||||
"target": to_bson(&target).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.permission_on_update_target(&target, user).await?;
|
||||
Some(doc! {
|
||||
doc! {
|
||||
"target": to_bson(&target).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if user.is_admin {
|
||||
None
|
||||
doc! {}
|
||||
} else {
|
||||
let permissions_field = format!("permissions.{}", user.id);
|
||||
let target_filter = doc! {
|
||||
@@ -184,10 +196,13 @@ impl State {
|
||||
{ "target.type": "Procedure", "target.id": { "$in": &procedure_ids } }
|
||||
]
|
||||
};
|
||||
Some(filter)
|
||||
filter
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(operations) = operations {
|
||||
filter.insert("operation", doc! { "$in": operations });
|
||||
}
|
||||
let mut updates = self
|
||||
.db
|
||||
.updates
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use diff::{Diff, OptionDiff};
|
||||
|
||||
#[macro_export]
|
||||
@@ -25,3 +28,16 @@ where
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn parse_comma_seperated_list<T: FromStr>(comma_sep_list: &str) -> anyhow::Result<Vec<T>> {
|
||||
comma_sep_list
|
||||
.split(",")
|
||||
.filter(|item| item.len() > 0)
|
||||
.map(|item| {
|
||||
let item = item
|
||||
.parse()
|
||||
.map_err(|_| anyhow!("error parsing string {item} into type T"))?;
|
||||
Ok::<T, anyhow::Error>(item)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
+12
-2
@@ -101,7 +101,12 @@ impl State {
|
||||
|
||||
async fn check_cpu(&self, server: &Server, stats: &SystemStats) {
|
||||
let server_alert_status = self.server_alert_status.lock().await;
|
||||
if self.slack.is_none() || server_alert_status.get(&server.id).map(|s| s.cpu_alert).unwrap_or(false) {
|
||||
if self.slack.is_none()
|
||||
|| server_alert_status
|
||||
.get(&server.id)
|
||||
.map(|s| s.cpu_alert)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
drop(server_alert_status);
|
||||
@@ -175,7 +180,12 @@ impl State {
|
||||
|
||||
async fn check_mem(&self, server: &Server, stats: &SystemStats) {
|
||||
let server_alert_status = self.server_alert_status.lock().await;
|
||||
if self.slack.is_none() || server_alert_status.get(&server.id).map(|s| s.mem_alert).unwrap_or(false) {
|
||||
if self.slack.is_none()
|
||||
|| server_alert_status
|
||||
.get(&server.id)
|
||||
.map(|s| s.mem_alert)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
drop(server_alert_status);
|
||||
|
||||
@@ -23,7 +23,7 @@ const SummaryItem: Component<{
|
||||
}> = (p) => {
|
||||
return (
|
||||
<Flex
|
||||
class="card light shadow"
|
||||
class="card light shadow wrap"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
|
||||
@@ -1,15 +1,46 @@
|
||||
import { Component, For, Show } from "solid-js";
|
||||
import { Component, createEffect, createSignal, For, Show } from "solid-js";
|
||||
import { useAppState } from "../../../state/StateProvider";
|
||||
import { Operation } from "../../../types";
|
||||
import Flex from "../../shared/layout/Flex";
|
||||
import Grid from "../../shared/layout/Grid";
|
||||
import Loading from "../../shared/loading/Loading";
|
||||
import Selector from "../../shared/menu/Selector";
|
||||
import Update from "./Update";
|
||||
|
||||
const OPERATIONS = Object.values(Operation)
|
||||
.filter((e) => e !== "none" && !e.includes("user"))
|
||||
.map((e) => e.replaceAll("_", " "));
|
||||
|
||||
const Updates: Component<{}> = () => {
|
||||
const { updates } = useAppState();
|
||||
const [operation, setOperation] = createSignal<Operation>();
|
||||
createEffect(() => {
|
||||
if (operation()) {
|
||||
updates.load([operation()!]);
|
||||
} else {
|
||||
updates.load();
|
||||
}
|
||||
});
|
||||
return (
|
||||
<Grid class="card shadow" style={{ "flex-grow": 1 }}>
|
||||
<h1>updates</h1>
|
||||
<Flex alignItems="center" justifyContent="space-between">
|
||||
<h1>updates</h1>
|
||||
<Selector
|
||||
selected={operation() ? operation()! : "all"}
|
||||
items={["all", ...OPERATIONS]}
|
||||
onSelect={(o) =>
|
||||
o === "all"
|
||||
? setOperation(undefined)
|
||||
: setOperation(o.replaceAll(" ", "_") as Operation)
|
||||
}
|
||||
targetStyle={{ padding: "0" }}
|
||||
position="bottom right"
|
||||
searchStyle={{ width: "15rem" }}
|
||||
menuClass="scroller"
|
||||
menuStyle={{ "max-height": "50vh" }}
|
||||
useSearch
|
||||
/>
|
||||
</Flex>
|
||||
<Show
|
||||
when={updates.loaded()}
|
||||
fallback={
|
||||
|
||||
@@ -22,11 +22,14 @@ const Selector: Component<{
|
||||
position?: Position;
|
||||
targetClass?: string;
|
||||
targetStyle?: JSX.CSSProperties;
|
||||
menuClass?: string;
|
||||
menuStyle?: JSX.CSSProperties;
|
||||
containerStyle?: JSX.CSSProperties;
|
||||
disabled?: boolean;
|
||||
disabledClass?: string;
|
||||
disabledStyle?: JSX.CSSProperties;
|
||||
useSearch?: boolean;
|
||||
searchStyle?: JSX.CSSProperties;
|
||||
itemClass?: string;
|
||||
itemStyle?: JSX.CSSProperties;
|
||||
label?: JSXElement;
|
||||
@@ -35,7 +38,7 @@ const Selector: Component<{
|
||||
const [search, setSearch] = createSignal("");
|
||||
let ref: HTMLInputElement | undefined;
|
||||
createEffect(() => {
|
||||
if (show()) ref?.focus();
|
||||
if (show()) setTimeout(() => ref?.focus(), 200);
|
||||
});
|
||||
return (
|
||||
<Show
|
||||
@@ -69,7 +72,7 @@ const Selector: Component<{
|
||||
placeholder="search"
|
||||
value={search()}
|
||||
onEdit={setSearch}
|
||||
style={{ "text-align": "end" }}
|
||||
style={{ "text-align": "end", ...p.searchStyle }}
|
||||
onKeyDown={(e: any) => {
|
||||
if (e.key === "Escape") {
|
||||
toggle();
|
||||
@@ -104,6 +107,8 @@ const Selector: Component<{
|
||||
</For>
|
||||
</>
|
||||
}
|
||||
menuClass={p.menuClass}
|
||||
menuStyle={p.menuStyle}
|
||||
position={p.position}
|
||||
padding="0.25rem"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { Component, For, Show } from "solid-js";
|
||||
import { useAppState } from "../../state/StateProvider";
|
||||
import { Operation, Update as UpdateType, UpdateStatus } from "../../types";
|
||||
import { combineClasses, readableDuration, readableMonitorTimestamp } from "../../util/helpers";
|
||||
import {
|
||||
combineClasses,
|
||||
readableDuration,
|
||||
readableMonitorTimestamp,
|
||||
readableVersion,
|
||||
} from "../../util/helpers";
|
||||
import { useToggle } from "../../util/hooks";
|
||||
import Icon from "../shared/Icon";
|
||||
import Flex from "../shared/layout/Flex";
|
||||
@@ -10,7 +15,7 @@ import CenterMenu from "../shared/menu/CenterMenu";
|
||||
import s from "./update.module.scss";
|
||||
|
||||
const UpdateMenu: Component<{ update: UpdateType }> = (p) => {
|
||||
const { deployments, servers, builds } = useAppState();
|
||||
const { deployments, servers, builds } = useAppState();
|
||||
const name = () => {
|
||||
if (p.update.target.type === "Deployment" && deployments.loaded()) {
|
||||
return deployments.get(p.update.target.id!)?.deployment.name || "deleted";
|
||||
@@ -24,7 +29,7 @@ const UpdateMenu: Component<{ update: UpdateType }> = (p) => {
|
||||
};
|
||||
const operation = () => {
|
||||
if (p.update.operation === Operation.BuildBuild) {
|
||||
return "build"
|
||||
return "build";
|
||||
}
|
||||
return p.update.operation.replaceAll("_", " ");
|
||||
};
|
||||
@@ -38,9 +43,7 @@ const UpdateMenu: Component<{ update: UpdateType }> = (p) => {
|
||||
targetStyle={{ "place-self": "center end" }}
|
||||
targetClass="blue"
|
||||
padding="1rem 2rem"
|
||||
content={
|
||||
() => <UpdateMenuContent update={p.update} />
|
||||
}
|
||||
content={() => <UpdateMenuContent update={p.update} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -50,60 +53,88 @@ export default UpdateMenu;
|
||||
const UpdateMenuContent: Component<{ update: UpdateType }> = (p) => {
|
||||
const { usernames } = useAppState();
|
||||
return (
|
||||
<Grid class={s.LogContainer} gap="1rem">
|
||||
<Grid gap="0.5rem" class="card light shadow">
|
||||
<div>status: {p.update.status.replaceAll("_", " ")}</div>
|
||||
<div>operator: {usernames.get(p.update.operator)}</div>
|
||||
<div>started at: {readableMonitorTimestamp(p.update.start_ts)}</div>
|
||||
<Grid class={s.LogContainer}>
|
||||
<Grid
|
||||
gap="0.5rem"
|
||||
class="card light shadow"
|
||||
gridTemplateColumns="1fr 1fr"
|
||||
>
|
||||
<Flex gap="0.5rem" alignItems="center">
|
||||
status: <h2>{p.update.status.replaceAll("_", " ")}</h2>
|
||||
</Flex>
|
||||
<h2 style={{ "place-self": "center end" }}>
|
||||
{readableMonitorTimestamp(p.update.start_ts)}
|
||||
</h2>
|
||||
<Show when={p.update.end_ts}>
|
||||
<div>
|
||||
duration: {readableDuration(p.update.start_ts, p.update.end_ts!)}
|
||||
</div>
|
||||
<Flex gap="0.5rem" alignItems="center">
|
||||
duration:
|
||||
<h2>{readableDuration(p.update.start_ts, p.update.end_ts!)}</h2>
|
||||
</Flex>
|
||||
</Show>
|
||||
<Flex
|
||||
gap="0.5rem"
|
||||
alignItems="center"
|
||||
style={{ "place-self": "center end" }}
|
||||
>
|
||||
<Icon type="user" width="1.25rem" />
|
||||
<h2>{usernames.get(p.update.operator)}</h2>
|
||||
</Flex>
|
||||
<Show when={p.update.version}>
|
||||
<Flex gap="0.5rem" alignItems="center">
|
||||
version:
|
||||
<h2>{readableVersion(p.update.version!)}</h2>
|
||||
</Flex>
|
||||
</Show>
|
||||
</Grid>
|
||||
<For each={p.update.logs}>
|
||||
{(log, index) => {
|
||||
return (
|
||||
<Grid gap="0.5rem" class="card light shadow">
|
||||
<Flex alignItems="center" class="wrap">
|
||||
<h1>{log.stage}</h1>
|
||||
<div style={{ opacity: 0.7 }}>
|
||||
(stage {index() + 1} of {p.update.logs.length})
|
||||
</div>
|
||||
<div style={{ opacity: 0.7 }}>
|
||||
{readableDuration(log.start_ts, log.end_ts)}
|
||||
</div>
|
||||
</Flex>
|
||||
<Show when={log.command}>
|
||||
<div>command</div>
|
||||
<pre class={combineClasses(s.Log)}>{log.command}</pre>
|
||||
</Show>
|
||||
<Show when={log.stdout}>
|
||||
<div>stdout</div>
|
||||
<pre
|
||||
class={combineClasses(s.Log)}
|
||||
// style={{
|
||||
// "max-height": log.stderr ? "30vh" : "60vh",
|
||||
// }}
|
||||
>
|
||||
{log.stdout}
|
||||
</pre>
|
||||
</Show>
|
||||
<Show when={log.stderr}>
|
||||
<div>stderr</div>
|
||||
<pre
|
||||
class={combineClasses(s.Log)}
|
||||
// style={{
|
||||
// "max-height": log.stdout ? "30vh" : "60vh",
|
||||
// }}
|
||||
>
|
||||
{log.stderr}
|
||||
</pre>
|
||||
</Show>
|
||||
</Grid>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
<UpdateLogs update={p.update} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const UpdateLogs: Component<{ update: UpdateType }> = (p) => {
|
||||
return (
|
||||
<For each={p.update.logs}>
|
||||
{(log, index) => {
|
||||
return (
|
||||
<Grid gap="0.5rem" class="card light shadow">
|
||||
<Flex alignItems="center" class="wrap">
|
||||
<h1>{log.stage}</h1>
|
||||
<div style={{ opacity: 0.7 }}>
|
||||
(stage {index() + 1} of {p.update.logs.length})
|
||||
</div>
|
||||
<div style={{ opacity: 0.7 }}>
|
||||
{readableDuration(log.start_ts, log.end_ts)}
|
||||
</div>
|
||||
</Flex>
|
||||
<Show when={log.command}>
|
||||
<div>command</div>
|
||||
<pre class={combineClasses(s.Log)}>{log.command}</pre>
|
||||
</Show>
|
||||
<Show when={log.stdout}>
|
||||
<div>stdout</div>
|
||||
<pre
|
||||
class={combineClasses(s.Log)}
|
||||
// style={{
|
||||
// "max-height": log.stderr ? "30vh" : "60vh",
|
||||
// }}
|
||||
>
|
||||
{log.stdout}
|
||||
</pre>
|
||||
</Show>
|
||||
<Show when={log.stderr}>
|
||||
<div>stderr</div>
|
||||
<pre
|
||||
class={combineClasses(s.Log)}
|
||||
// style={{
|
||||
// "max-height": log.stdout ? "30vh" : "60vh",
|
||||
// }}
|
||||
>
|
||||
{log.stderr}
|
||||
</pre>
|
||||
</Show>
|
||||
</Grid>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createEffect, createResource, createSignal } from "solid-js";
|
||||
import { client } from "..";
|
||||
import { ServerStatus, SystemInformation, SystemStats, UpdateTarget } from "../types";
|
||||
import { Operation, ServerStatus, SystemInformation, SystemStats, UpdateTarget } from "../types";
|
||||
import {
|
||||
filterOutFromObj,
|
||||
getNestedEntry,
|
||||
@@ -152,7 +152,7 @@ export function useDeployments() {
|
||||
|
||||
export function useUpdates(target?: UpdateTarget, show_builds?: boolean) {
|
||||
const updates = useArrayWithId(
|
||||
() => client.list_updates(0, target, show_builds),
|
||||
(operations?: Operation[]) => client.list_updates(0, target, show_builds, operations),
|
||||
["_id", "$oid"]
|
||||
);
|
||||
const [noMore, setNoMore] = createSignal(false);
|
||||
@@ -173,10 +173,13 @@ export function useUpdates(target?: UpdateTarget, show_builds?: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
export function useArray<T>(query: () => Promise<T[]>) {
|
||||
export function useArray<T, O>(query: (options?: O) => Promise<T[]>, options?: O) {
|
||||
const [collection, set] = createSignal<T[]>();
|
||||
const load = (options?: O) => {
|
||||
query(options).then(set);
|
||||
}
|
||||
createEffect(() => {
|
||||
query().then(set);
|
||||
load(options);
|
||||
});
|
||||
const add = (item: T) => {
|
||||
set((items: T[] | undefined) => (items ? [item, ...items] : [item]));
|
||||
@@ -186,6 +189,7 @@ export function useArray<T>(query: () => Promise<T[]>) {
|
||||
};
|
||||
const loaded = () => (collection() ? true : false);
|
||||
return {
|
||||
load,
|
||||
collection,
|
||||
add,
|
||||
addManyToEnd,
|
||||
@@ -193,10 +197,13 @@ export function useArray<T>(query: () => Promise<T[]>) {
|
||||
};
|
||||
}
|
||||
|
||||
export function useArrayWithId<T>(query: () => Promise<T[]>, idPath: string[]) {
|
||||
export function useArrayWithId<T, O>(query: (options?: O) => Promise<T[]>, idPath: string[], options?: O) {
|
||||
const [collection, set] = createSignal<T[]>();
|
||||
const load = (options?: O) => {
|
||||
query(options).then(set);
|
||||
};
|
||||
createEffect(() => {
|
||||
query().then(set);
|
||||
load(options);
|
||||
});
|
||||
const addOrUpdate = (item: T) => {
|
||||
set((items: T[] | undefined) => {
|
||||
@@ -226,6 +233,7 @@ export function useArrayWithId<T>(query: () => Promise<T[]>, idPath: string[]) {
|
||||
};
|
||||
const loaded = () => (collection() ? true : false);
|
||||
return {
|
||||
load,
|
||||
collection,
|
||||
addOrUpdate,
|
||||
addManyToEnd,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
max-width: calc(1200px + 2rem);
|
||||
box-sizing: border-box;
|
||||
place-items: center;
|
||||
margin-bottom: 50vh;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
Group,
|
||||
HistoricalStatsQuery,
|
||||
Log,
|
||||
Operation,
|
||||
Procedure,
|
||||
Server,
|
||||
ServerActionState,
|
||||
@@ -233,7 +234,7 @@ export class Client {
|
||||
}
|
||||
|
||||
get_server_system_info(id: string): Promise<SystemInformation> {
|
||||
return this.get(`/api/server/${id}/system_information`)
|
||||
return this.get(`/api/server/${id}/system_information`);
|
||||
}
|
||||
|
||||
create_server(body: CreateServerBody): Promise<Server> {
|
||||
@@ -314,8 +315,11 @@ export class Client {
|
||||
get_build_action_state(id: string): Promise<BuildActionState> {
|
||||
return this.get(`/api/build/${id}/action_state`);
|
||||
}
|
||||
|
||||
get_build_versions(id: string, query?: BuildVersionsQuery): Promise<BuildVersionsReponse> {
|
||||
|
||||
get_build_versions(
|
||||
id: string,
|
||||
query?: BuildVersionsQuery
|
||||
): Promise<BuildVersionsReponse> {
|
||||
return this.get(`/api/build/${id}/versions${generateQuery(query as any)}`);
|
||||
}
|
||||
|
||||
@@ -405,13 +409,19 @@ export class Client {
|
||||
|
||||
// updates
|
||||
// show_builds is only relevant for Deployment targets, must pass show_builds = true to include build updates of attached build_id
|
||||
list_updates(offset: number, target?: UpdateTarget, show_builds?: boolean): Promise<Update[]> {
|
||||
list_updates(
|
||||
offset: number,
|
||||
target?: UpdateTarget,
|
||||
show_builds?: boolean,
|
||||
operations?: Operation[]
|
||||
): Promise<Update[]> {
|
||||
return this.get(
|
||||
`/api/update/list${generateQuery({
|
||||
offset,
|
||||
type: target && target.type,
|
||||
id: target && target.id,
|
||||
show_builds,
|
||||
operations: operations?.join(","),
|
||||
})}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { DockerContainerState, EnvironmentVar, ServerStatus, Timelength, Version } from "../types";
|
||||
import {
|
||||
DockerContainerState,
|
||||
EnvironmentVar,
|
||||
ServerStatus,
|
||||
Timelength,
|
||||
Version,
|
||||
} from "../types";
|
||||
|
||||
export function combineClasses(...classes: (string | false | undefined)[]) {
|
||||
return classes.filter((c) => (c ? true : false)).join(" ");
|
||||
@@ -48,8 +54,12 @@ export function readableDuration(start_ts: string, end_ts: string) {
|
||||
const start = new Date(start_ts);
|
||||
const end = new Date(end_ts);
|
||||
const durr = end.getTime() - start.getTime();
|
||||
const seconds = (durr / 1000).toFixed(1);
|
||||
return `${seconds} seconds`;
|
||||
const seconds = durr / 1000;
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remaining_seconds = seconds % 60;
|
||||
return `${
|
||||
minutes > 0 ? `${minutes} minute${minutes > 1 ? "s" : ""} ` : ""
|
||||
}${remaining_seconds.toFixed(minutes > 0 ? 0 : 1)} seconds`;
|
||||
}
|
||||
|
||||
const tzOffset = new Date().getTimezoneOffset() * 60;
|
||||
@@ -163,9 +173,7 @@ export function parseDotEnvToEnvVars(env: string): EnvironmentVar[] {
|
||||
.map(([variable, value]) => ({ variable, value }));
|
||||
}
|
||||
|
||||
export function deploymentHeaderStateClass(
|
||||
state: DockerContainerState,
|
||||
) {
|
||||
export function deploymentHeaderStateClass(state: DockerContainerState) {
|
||||
switch (state) {
|
||||
case DockerContainerState.Running:
|
||||
return "running";
|
||||
@@ -175,28 +183,28 @@ export function deploymentHeaderStateClass(
|
||||
}
|
||||
|
||||
export function version_to_string(version: Version) {
|
||||
return `${version.major}.${version.minor}.${version.patch}`
|
||||
return `${version.major}.${version.minor}.${version.patch}`;
|
||||
}
|
||||
|
||||
export function string_to_version(version: string): Version {
|
||||
const [major, minor, patch] = version.split(".")
|
||||
const [major, minor, patch] = version.split(".");
|
||||
return {
|
||||
major: Number(major),
|
||||
minor: Number(minor),
|
||||
patch: Number(patch),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function get_to_one_sec_divisor(timelength: Timelength) {
|
||||
// returns what the timelength needs to be divided to convert to per second values
|
||||
if (timelength === Timelength.OneSecond) {
|
||||
return 1
|
||||
return 1;
|
||||
} else if (timelength === Timelength.FiveSeconds) {
|
||||
return 5
|
||||
return 5;
|
||||
} else if (timelength === Timelength.ThirtySeconds) {
|
||||
return 30
|
||||
return 30;
|
||||
} else if (timelength === Timelength.OneMinute) {
|
||||
return 60
|
||||
return 60;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,14 +223,14 @@ export function convert_timelength_to_ms(timelength: Timelength) {
|
||||
|
||||
export function readableStorageAmount(gb: number) {
|
||||
if (gb > 512) {
|
||||
return `${(gb / 1024).toFixed(1)} TB`
|
||||
return `${(gb / 1024).toFixed(1)} TB`;
|
||||
} else if (gb < 1) {
|
||||
return `${(gb * 1024).toFixed()} MiB`
|
||||
return `${(gb * 1024).toFixed()} MiB`;
|
||||
} else {
|
||||
return `${gb.toFixed()} GiB`
|
||||
return `${gb.toFixed()} GiB`;
|
||||
}
|
||||
}
|
||||
|
||||
export function readableVersion(version: Version) {
|
||||
return `v${version.major}.${version.minor}.${version.patch}`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user