export to toml work. log scroll button better

This commit is contained in:
mbecker20
2024-04-26 04:52:52 -07:00
parent 92ef0addd5
commit b5ea6d43f3
5 changed files with 84 additions and 18 deletions
+59
View File
@@ -0,0 +1,59 @@
import { useRead } from "@lib/hooks";
import { Types } from "@monitor/client";
import { Button } from "@ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@ui/dialog";
import { FileDown, Loader2 } from "lucide-react";
import { useState } from "react";
import { CopyButton } from "./util";
export const ExportButton = ({}: {
target?: Types.ResourceTarget;
user_group?: string;
}) => {
const [open, setOpen] = useState(false);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline" className="flex gap-2 items-center">
Export
<FileDown className="w-4 h-4" />
</Button>
</DialogTrigger>
<DialogContent className="min-w-[50vw]">
<DialogHeader>
<DialogTitle>Export to toml</DialogTitle>
</DialogHeader>
<ExportLoader />
</DialogContent>
</Dialog>
);
};
const ExportLoader = () => {
const { data, isPending } = useRead("ExportAllResourcesToToml", {});
return <ExportPre loading={isPending} content={data?.toml} />;
};
const ExportPre = ({
loading,
content,
}: {
loading: boolean;
content: string | undefined;
}) => {
return (
<div className="relative flex justify-center">
{loading && <Loader2 className="w-8 h-8 animate-spin" />}
<div className="overflow-y-scroll max-h-[80vh]">
<pre className="h-fit">{content}</pre>
</div>
<CopyButton content={content} className="absolute top-4 right-4" />
</div>
);
};
@@ -12,7 +12,7 @@ import {
DeleteDeployment,
RenameDeployment,
} from "./actions";
import { DeploymentLogs } from "./logs";
import { DeploymentLogs } from "./log";
import { snake_case_to_upper_space_case } from "@lib/formatting";
import {
bg_color_class_by_intention,
@@ -10,7 +10,7 @@ import {
ChevronDown,
X,
} from "lucide-react";
import { useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useDeployment } from ".";
import {
Select,
@@ -102,10 +102,8 @@ const DeploymentLogsInner = ({ id }: { id: string }) => {
</Button>
</div>
<TabsList>
<TabsTrigger value="stdout" onClick={to_bottom("stdout")}>
stdout
</TabsTrigger>
<TabsTrigger value="stderr" onClick={to_bottom("stderr")}>
<TabsTrigger value="stdout">stdout</TabsTrigger>
<TabsTrigger value="stderr">
stderr
{stderr && (
<AlertOctagon className="w-4 h-4 ml-2 stroke-red-500" />
@@ -175,18 +173,24 @@ const Log = ({
stream: "stdout" | "stderr";
}) => {
const _log = log?.[stream as keyof typeof log] as string | undefined;
const ref = useRef<HTMLDivElement>(null);
const scroll = () =>
ref.current?.scroll({
top: ref.current.scrollHeight,
behavior: "smooth",
});
useEffect(scroll, []);
return (
<>
<div className="h-[70vh] overflow-y-auto">
<div ref={ref} className="h-[70vh] overflow-y-auto">
<pre
id={stream}
dangerouslySetInnerHTML={{
__html: _log ? logToHtml(_log) : `no ${stream} logs`,
}}
className="-scroll-mt-24"
/>
</div>
<Button className="absolute bottom-4 right-4" onClick={to_bottom(stream)}>
<Button className="absolute bottom-4 right-4" onClick={scroll}>
<ChevronDown className="h-4 w-4" />
</Button>
</>
@@ -218,11 +222,6 @@ const TailLengthSelector = ({
</Select>
);
const to_bottom = (id: string) => () =>
document
.getElementById(id)
?.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
const convert = new Convert();
/**
* Converts the ansi colors in log to html.
+9 -3
View File
@@ -260,13 +260,19 @@ export const UserSettings = () => (
</Link>
);
export const CopyButton = ({ content }: { content: string | undefined }) => {
export const CopyButton = ({
content,
className,
}: {
content: string | undefined;
className?: string;
}) => {
const { toast } = useToast();
const [copied, set] = useState(false);
useEffect(() => {
if (copied) {
toast({ title: `Copied "${content}"` });
toast({ title: "Copied selection" });
const timeout = setTimeout(() => set(false), 3000);
return () => {
clearTimeout(timeout);
@@ -276,7 +282,7 @@ export const CopyButton = ({ content }: { content: string | undefined }) => {
return (
<Button
className="shrink-0"
className={cn("shrink-0", className)}
size="icon"
variant="outline"
onClick={() => {
+3 -1
View File
@@ -1,4 +1,5 @@
import { OpenAlerts } from "@components/alert";
import { ExportButton } from "@components/export";
import { Page, Section } from "@components/layouts";
import { ResourceComponents } from "@components/resources";
import { TagsFilter } from "@components/tags";
@@ -14,7 +15,8 @@ export const AllResources = () => {
title="Resources"
actions={
<div className="grid gap-4 justify-items-end">
<div className="flex gap-4">
<div className="flex gap-4 items-center">
<ExportButton />
<Input
value={search}
onChange={(e) => setSearch(e.target.value)}