improve updates

This commit is contained in:
karamvir
2023-07-25 16:06:37 -07:00
parent 9a3b160e62
commit 082a76bfb7
5 changed files with 207 additions and 202 deletions

View File

@@ -6,7 +6,7 @@ import {
DropdownMenuTrigger,
} from "@ui/dropdown";
import { Bell } from "lucide-react";
import { SingleUpdate } from "./updates";
import { SingleUpdate } from "./update";
import { Button } from "@ui/button";
export const DesktopUpdates = () => {
@@ -22,7 +22,7 @@ export const DesktopUpdates = () => {
<DropdownMenuContent className="w-[500px]">
<DropdownMenuGroup>
{updates?.map((update) => (
<div className="p-2 hover:bg-muted transition-colors border-b last:border-none">
<div className="px-2 py-4 hover:bg-muted transition-colors border-b last:border-none">
<SingleUpdate update={update} />
</div>
))}

View File

@@ -0,0 +1,172 @@
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@ui/sheet";
import { Update } from "@monitor/client/dist/types";
import {
readableDuration,
readableVersion,
version_to_string,
} from "@util/helpers";
import {
Calendar,
Clock,
Hammer,
Milestone,
Rocket,
Server,
User,
} from "lucide-react";
// import { UpdateUser } from ".";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@ui/card";
import { ReactNode } from "react";
import { useNavigate } from "react-router-dom";
import { ServerName } from "@resources/server/util";
import { DeploymentName } from "@resources/deployment/util";
import { BuildName } from "@resources/build/util";
// import { useRead } from "@hooks";
export const UpdateUser = ({ userId }: { userId: string }) => {
// const { data } = useRead({ type: "GetUser", params: {} });
if (userId === "github") return <>GitHub</>;
if (userId === "auto redeploy") return <>Auto Redeploy</>;
return <>{userId.slice(0, 10)}...</>;
};
export const UpdateDetails = ({
update,
children,
}: {
update: Update;
children: ReactNode;
}) => {
const nav = useNavigate();
return (
<Sheet>
<SheetTrigger asChild>{children}</SheetTrigger>
<SheetContent position="right" size="lg">
<SheetHeader className="mb-4">
<SheetTitle>
{update.operation
.split("_")
.map((s) => s[0].toUpperCase() + s.slice(1))
.join(" ")}{" "}
{version_to_string(update.version)}
</SheetTitle>
<SheetDescription className="flex flex-col gap-2">
<div className="flex items-center gap-2">
<User className="w-4 h-4" />
<UpdateUser userId={update.operator} />
</div>
<div className="flex gap-4">
<div
className="flex items-center gap-2 cursor-pointer"
onClick={() => {
update.target.id
? nav(
`/${update.target.type.toLowerCase()}s/${
update.target.id
}`
)
: null;
}}
>
{update.target.type === "Server" && (
<>
<Server className="w-4 h-4" />
<ServerName serverId={update.target.id} />
</>
)}
{update.target.type === "Deployment" && (
<>
<Rocket className="w-4 h-4" />
<DeploymentName deploymentId={update.target.id} />
</>
)}
{update.target.type === "Build" && (
<>
<Hammer className="w-4 h-4" />
<BuildName id={update.target.id} />
</>
)}
</div>
{update.version && (
<div className="flex items-center gap-2">
<Milestone className="w-4 h-4" />
{readableVersion(update.version)}
</div>
)}
</div>
<div className="flex gap-4">
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4" />
{new Date(update.start_ts).toLocaleString()}
</div>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4" />
{update.end_ts
? readableDuration(update.start_ts, update.end_ts)
: "ongoing"}
</div>
</div>
</SheetDescription>
</SheetHeader>
<div className="grid gap-2">
{update.logs.map((log, i) => (
<Card>
<CardHeader>
<CardTitle>{log.stage}</CardTitle>
<CardDescription className="flex gap-2">
<span>
Stage {i + 1} of {update.logs.length}
</span>
<span>|</span>
<span className="flex items-center gap-2">
<Clock className="w-4 h-4" />
{readableDuration(log.start_ts, log.end_ts)}
</span>
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-2">
{log.command && (
<div>
<CardDescription>command</CardDescription>
<pre className="max-h-[500px] overflow-y-auto">
{log.command}
</pre>
</div>
)}
{log.stdout && (
<div>
<CardDescription>stdout</CardDescription>
<pre className="max-h-[500px] overflow-y-auto">
{log.stdout}
</pre>
</div>
)}
{log.stderr && (
<div>
<CardDescription>stdout</CardDescription>
<pre className="max-h-[500px] overflow-y-auto">
{log.stderr}
</pre>
</div>
)}
</CardContent>
</Card>
))}
</div>
</SheetContent>
</Sheet>
);
};

View File

@@ -1,168 +1,33 @@
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@ui/sheet";
import { version_to_string } from "@util/helpers";
import { Calendar, User } from "lucide-react";
import { UpdateDetails, UpdateUser } from "./details";
import { Update } from "@monitor/client/dist/types";
import {
readableDuration,
readableVersion,
version_to_string,
} from "@util/helpers";
import {
Calendar,
Clock,
Hammer,
Milestone,
Rocket,
Server,
User,
} from "lucide-react";
// import { UpdateUser } from ".";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@ui/card";
import { ReactNode } from "react";
import { useNavigate } from "react-router-dom";
import { ServerName } from "@resources/server/util";
import { DeploymentName } from "@resources/deployment/util";
import { BuildName } from "@resources/build/util";
// import { useRead } from "@hooks";
export const UpdateUser = ({ userId }: { userId: string }) => {
// const { data } = useRead({ type: "GetUser", params: {} });
if (userId === "github") return <>GitHub</>;
if (userId === "auto redeploy") return <>Auto Redeploy</>;
return <>{userId.slice(0, 10)}...</>;
};
const fmt_date = (d: Date) =>
`${d.getDate()}/${d.getMonth()} @ ${d.getHours()}:${d.getMinutes()}`;
export const UpdateDetails = ({
update,
children,
}: {
update: Update;
children: ReactNode;
}) => {
const nav = useNavigate();
return (
<Sheet>
<SheetTrigger asChild>{children}</SheetTrigger>
<SheetContent position="right" size="lg">
<SheetHeader className="mb-4">
<SheetTitle>
{update.operation
.split("_")
.map((s) => s[0].toUpperCase() + s.slice(1))
.join(" ")}{" "}
{version_to_string(update.version)}
</SheetTitle>
<SheetDescription className="flex flex-col gap-2">
<div
className="flex items-center gap-2 cursor-pointer"
onClick={() => {
update.target.id
? nav(
`/${update.target.type.toLowerCase()}s/${
update.target.id
}`
)
: null;
}}
>
{update.target.type === "Server" && (
<>
<Server className="w-4 h-4" />
<ServerName serverId={update.target.id} />
</>
)}
{update.target.type === "Deployment" && (
<>
<Rocket className="w-4 h-4" />
<DeploymentName deploymentId={update.target.id} />
</>
)}
{update.target.type === "Build" && (
<>
<Hammer className="w-4 h-4" />
<BuildName id={update.target.id} />
</>
)}
</div>
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4" />
{new Date(update.start_ts).toLocaleString()}
</div>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4" />
{update.end_ts
? readableDuration(update.start_ts, update.end_ts)
: "ongoing"}
</div>
<div className="flex items-center gap-2">
<User className="w-4 h-4" />
<UpdateUser userId={update.operator} />
</div>
{update.version && (
<div className="flex items-center gap-2">
<Milestone className="w-4 h-4" />
{readableVersion(update.version)}
</div>
)}
</SheetDescription>
</SheetHeader>
<div className="max-h-[80vh] overflow-y-auto grid gap-2">
{update.logs.map((log, i) => (
<Card>
<CardHeader>
<CardTitle>{log.stage}</CardTitle>
<CardDescription className="flex gap-2">
<span>
Stage {i + 1} of {update.logs.length}
</span>
<span>|</span>
<span className="flex items-center gap-2">
<Clock className="w-4 h-4" />
{readableDuration(log.start_ts, log.end_ts)}
</span>
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-2">
{log.command && (
<div>
<CardDescription>command</CardDescription>
<pre className="max-h-[500px] overflow-y-auto">
{log.command}
</pre>
</div>
)}
{log.stdout && (
<div>
<CardDescription>stdout</CardDescription>
<pre className="max-h-[500px] overflow-y-auto">
{log.stdout}
</pre>
</div>
)}
{log.stderr && (
<div>
<CardDescription>stdout</CardDescription>
<pre className="max-h-[500px] overflow-y-auto">
{log.stderr}
</pre>
</div>
)}
</CardContent>
</Card>
))}
export const SingleUpdate = ({ update }: { update: Update }) => (
<UpdateDetails update={update}>
<div
className="grid gap-4 justify-start items-center cursor-pointer"
style={{ gridTemplateColumns: "1fr 1.75fr 1fr" }}
>
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4" />
<div className="text-xs">
{update.end_ts ? fmt_date(new Date(update.end_ts)) : "ongoing"}
</div>
</SheetContent>
</Sheet>
);
};
</div>
<div className="text-sm w-full">
{update.operation.match(/[A-Z][a-z]+|[0-9]+/g)?.join(" ")}{" "}
{version_to_string(update.version)}
</div>
<div className="flex items-center gap-2 text-sm">
<User className="w-4 h-4" />
<UpdateUser userId={update.operator} />
</div>
</div>
</UpdateDetails>
);

View File

@@ -1,36 +0,0 @@
import { version_to_string } from "@util/helpers";
import { Calendar, User } from "lucide-react";
import { UpdateDetails, UpdateUser } from "./update";
import { Update } from "@monitor/client/dist/types";
const fmt_date = (d: Date) =>
`${d.getDate()}/${d.getMonth()} @ ${d.getHours()}:${d.getMinutes()}`;
export const SingleUpdate = ({ update }: { update: Update }) => (
<UpdateDetails update={update}>
<div
className="grid gap-4 justify-start items-center cursor-pointer"
style={{ gridTemplateColumns: "1fr 1.75fr 1fr" }}
>
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4" />
<div className="text-xs">
{update.end_ts ? fmt_date(new Date(update.end_ts)) : "ongoing"}
</div>
</div>
<div className="text-sm w-full">
{update.operation
.split("_")
.map((s) => s[0].toUpperCase() + s.slice(1))
.join(" ")}{" "}
{version_to_string(update.version)}
</div>
<div className="flex items-center gap-2 text-sm">
<User className="w-4 h-4" />
<UpdateUser userId={update.operator} />
</div>
</div>
</UpdateDetails>
);

View File

@@ -196,8 +196,12 @@ export function deploymentHeaderStateClass(state: Types.DockerContainerState) {
}
}
export const keys = <T extends object>(o: T): (keyof T)[] =>
Object.keys(o) as (keyof T)[];
export function version_to_string(version: Types.Version | undefined) {
if (!version) return;
if (!keys(version).some((k) => !!version[k])) return;
return `v${version.major}.${version.minor}.${version.patch}`;
}