forked from github-starred/komodo
consolidate Resource components
This commit is contained in:
@@ -2,17 +2,18 @@ module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
ignorePatterns: ["dist", ".eslintrc.cjs"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["react-refresh"],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Section } from "@components/layouts";
|
||||
import { ResourceComponents } from "@components/resources";
|
||||
import { ResourceLink } from "@components/util";
|
||||
import { ResourceLink } from "@components/resources/common";
|
||||
import {
|
||||
alert_level_intention,
|
||||
text_color_class_by_intention,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
import { useRead } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
import {
|
||||
Select,
|
||||
@@ -11,15 +11,7 @@ import {
|
||||
import { Button } from "@ui/button";
|
||||
import { Input } from "@ui/input";
|
||||
import { Switch } from "@ui/switch";
|
||||
import {
|
||||
CheckCircle,
|
||||
ChevronsUpDown,
|
||||
MinusCircle,
|
||||
PlusCircle,
|
||||
Save,
|
||||
SearchX,
|
||||
Trash,
|
||||
} from "lucide-react";
|
||||
import { CheckCircle, MinusCircle, PlusCircle, Save } from "lucide-react";
|
||||
import { ReactNode, useState } from "react";
|
||||
import { cn } from "@lib/utils";
|
||||
import {
|
||||
@@ -30,19 +22,8 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@ui/dialog";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@ui/command";
|
||||
import { snake_case_to_upper_space_case } from "@lib/formatting";
|
||||
import { ActionWithDialog, ConfirmButton } from "@components/util";
|
||||
import { UsableResource } from "@types";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ConfirmButton } from "@components/util";
|
||||
|
||||
export const ConfigItem = ({
|
||||
label,
|
||||
@@ -175,70 +156,6 @@ export const DoubleInput = <
|
||||
);
|
||||
};
|
||||
|
||||
type UsableResources = Exclude<Types.ResourceTarget["type"], "System">;
|
||||
|
||||
export const ResourceSelector = ({
|
||||
type,
|
||||
selected,
|
||||
onSelect,
|
||||
disabled,
|
||||
}: {
|
||||
type: UsableResources;
|
||||
selected: string | undefined;
|
||||
onSelect?: (id: string) => void;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [input, setInput] = useState("");
|
||||
|
||||
const resources = useRead(`List${type}s`, {}).data;
|
||||
const name = resources?.find((r) => r.id === selected)?.name;
|
||||
|
||||
if (!resources) return null;
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="secondary" className="flex gap-2" disabled={disabled}>
|
||||
{name ?? `Select ${type}`}
|
||||
{!disabled && <ChevronsUpDown className="w-3 h-3" />}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] max-h-[200px] p-0" sideOffset={12}>
|
||||
<Command>
|
||||
<CommandInput
|
||||
placeholder={`Search ${type}s`}
|
||||
className="h-9"
|
||||
value={input}
|
||||
onValueChange={setInput}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty className="flex justify-evenly items-center">
|
||||
{`No ${type}s Found`}
|
||||
<SearchX className="w-3 h-3" />
|
||||
</CommandEmpty>
|
||||
|
||||
<CommandGroup>
|
||||
{resources.map((resource) => (
|
||||
<CommandItem
|
||||
key={resource.id}
|
||||
onSelect={() => {
|
||||
onSelect && onSelect(resource.id);
|
||||
setOpen(false);
|
||||
}}
|
||||
className="flex items-center justify-between cursor-pointer"
|
||||
>
|
||||
<div className="p-1">{resource.name}</div>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export const AccountSelector = ({
|
||||
id,
|
||||
type,
|
||||
@@ -403,34 +320,3 @@ export const SystemCommand = ({
|
||||
</ConfigItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const DeleteResource = ({
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
id: string;
|
||||
}) => {
|
||||
const nav = useNavigate();
|
||||
const resource = useRead(`Get${type}`, { [type.toLowerCase()]: id } as any).data;
|
||||
const { mutateAsync, isPending } = useWrite(`Delete${type}`);
|
||||
|
||||
if (!resource) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="w-full">Delete {type}</div>
|
||||
<ActionWithDialog
|
||||
name={resource.name}
|
||||
title="Delete"
|
||||
icon={<Trash className="h-4 w-4" />}
|
||||
onClick={async () => {
|
||||
await mutateAsync({ id });
|
||||
nav(`/${type.toLowerCase()}s`);
|
||||
}}
|
||||
disabled={isPending}
|
||||
loading={isPending}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,9 +17,8 @@ import { DataTable } from "@ui/data-table";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "@ui/card";
|
||||
import { AlerterConfig } from "./config";
|
||||
import { CopyResource, ResourceLink } from "@components/util";
|
||||
import { TagsWithBadge, useTagsFilter } from "@components/tags";
|
||||
import { DeleteResource } from "@components/config/util";
|
||||
import { CopyResource, DeleteResource, ResourceLink } from "../common";
|
||||
|
||||
const useAlerter = (id?: string) =>
|
||||
useRead("ListAlerters", {}).data?.find((d) => d.id === id);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Config } from "@components/config";
|
||||
import {
|
||||
AccountSelector,
|
||||
ConfigItem,
|
||||
ResourceSelector,
|
||||
SystemCommand,
|
||||
} from "@components/config/util";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
@@ -20,6 +19,7 @@ import {
|
||||
import { Textarea } from "@ui/textarea";
|
||||
import { MinusCircle, PlusCircle } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ResourceSelector } from "../common";
|
||||
|
||||
export const BuildConfig = ({ id }: { id: string }) => {
|
||||
const config = useRead("GetBuild", { build: id }).data?.config;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NewResource, Section } from "@components/layouts";
|
||||
import { ConfirmButton, CopyResource, ResourceLink } from "@components/util";
|
||||
import { ConfirmButton } from "@components/util";
|
||||
import { useExecute, useRead, useWrite } from "@lib/hooks";
|
||||
import { RequiredResourceComponents } from "@types";
|
||||
import { Input } from "@ui/input";
|
||||
@@ -11,7 +11,7 @@ import { fill_color_class_by_intention } from "@lib/color";
|
||||
import { BuildChart } from "./dashboard";
|
||||
import { BuildTable } from "./table";
|
||||
import { fmt_version } from "@lib/formatting";
|
||||
import { DeleteResource } from "@components/config/util";
|
||||
import { CopyResource, DeleteResource, ResourceLink } from "../common";
|
||||
|
||||
const useBuild = (id?: string) =>
|
||||
useRead("ListBuilds", {}).data?.find((d) => d.id === id);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Config } from "@components/config";
|
||||
import { InputList, ResourceSelector } from "@components/config/util";
|
||||
import { InputList } from "@components/config/util";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
import { useState } from "react";
|
||||
import { ResourceSelector } from "../common";
|
||||
|
||||
export const BuilderConfig = ({ id }: { id: string }) => {
|
||||
const config = useRead("GetBuilder", { builder: id }).data?.config;
|
||||
|
||||
@@ -18,8 +18,7 @@ import { Cloud, Bot, Factory, AlertTriangle } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BuilderConfig } from "./config";
|
||||
import { CopyResource, ResourceLink } from "@components/util";
|
||||
import { DeleteResource } from "@components/config/util";
|
||||
import { CopyResource, DeleteResource, ResourceLink } from "../common";
|
||||
|
||||
const useBuilder = (id?: string) =>
|
||||
useRead("ListBuilders", {}).data?.find((d) => d.id === id);
|
||||
|
||||
253
frontend/src/components/resources/common.tsx
Normal file
253
frontend/src/components/resources/common.tsx
Normal file
@@ -0,0 +1,253 @@
|
||||
import { ActionButton, ActionWithDialog, ConfirmButton } from "@components/util";
|
||||
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
|
||||
import { UsableResource } from "@types";
|
||||
import { Button } from "@ui/button";
|
||||
import { Card, CardContent } from "@ui/card";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@ui/command";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@ui/dialog";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
|
||||
import { Textarea } from "@ui/textarea";
|
||||
import { Check, CheckCircle, ChevronsUpDown, Copy, SearchX, Trash } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { ResourceComponents } from ".";
|
||||
import { Input } from "@ui/input";
|
||||
|
||||
export const ResourceDescription = ({
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
id: string;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [description, setDescription] = useState<string>();
|
||||
|
||||
const { mutate: update_description } = useWrite("UpdateDescription");
|
||||
|
||||
const resource = useRead(`Get${type}`, {
|
||||
[type.toLowerCase()]: id,
|
||||
} as any).data;
|
||||
|
||||
useEffect(
|
||||
() => setDescription(resource?.description),
|
||||
[resource?.description]
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Card>
|
||||
<CardContent className="text-muted-foreground">
|
||||
{resource?.description}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Update Description</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
/>
|
||||
<DialogFooter>
|
||||
<ConfirmButton
|
||||
title="Update"
|
||||
icon={<CheckCircle className="w-4 h-4" />}
|
||||
onClick={() => {
|
||||
update_description({
|
||||
target: { type, id },
|
||||
description: description!,
|
||||
});
|
||||
setOpen(false);
|
||||
}}
|
||||
disabled={description !== undefined}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const ResourceSelector = ({
|
||||
type,
|
||||
selected,
|
||||
onSelect,
|
||||
disabled,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
selected: string | undefined;
|
||||
onSelect?: (id: string) => void;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [input, setInput] = useState("");
|
||||
|
||||
const resources = useRead(`List${type}s`, {}).data;
|
||||
const name = resources?.find((r) => r.id === selected)?.name;
|
||||
|
||||
if (!resources) return null;
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="secondary" className="flex gap-2" disabled={disabled}>
|
||||
{name ?? `Select ${type}`}
|
||||
{!disabled && <ChevronsUpDown className="w-3 h-3" />}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] max-h-[200px] p-0" sideOffset={12}>
|
||||
<Command>
|
||||
<CommandInput
|
||||
placeholder={`Search ${type}s`}
|
||||
className="h-9"
|
||||
value={input}
|
||||
onValueChange={setInput}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty className="flex justify-evenly items-center">
|
||||
{`No ${type}s Found`}
|
||||
<SearchX className="w-3 h-3" />
|
||||
</CommandEmpty>
|
||||
|
||||
<CommandGroup>
|
||||
{resources.map((resource) => (
|
||||
<CommandItem
|
||||
key={resource.id}
|
||||
onSelect={() => {
|
||||
onSelect && onSelect(resource.id);
|
||||
setOpen(false);
|
||||
}}
|
||||
className="flex items-center justify-between cursor-pointer"
|
||||
>
|
||||
<div className="p-1">{resource.name}</div>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export const ResourceLink = ({
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
id: string;
|
||||
}) => {
|
||||
const Components = ResourceComponents[type];
|
||||
return (
|
||||
<Link to={`/${type.toLowerCase()}s/${id}`}>
|
||||
<Button variant="link" className="flex gap-2 items-center p-0">
|
||||
<Components.Icon id={id} />
|
||||
<Components.Name id={id} />
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export const CopyResource = ({
|
||||
id,
|
||||
disabled,
|
||||
type,
|
||||
}: {
|
||||
id: string;
|
||||
disabled?: boolean;
|
||||
type: Exclude<UsableResource, "Server">;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [name, setName] = useState("");
|
||||
|
||||
const nav = useNavigate();
|
||||
const inv = useInvalidate();
|
||||
const { mutate } = useWrite(`Copy${type}`, {
|
||||
onSuccess: (res) => {
|
||||
inv([`List${type}s`]);
|
||||
nav(`/${type.toLowerCase()}s/${res._id?.$oid}`);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<ActionButton
|
||||
title="Copy"
|
||||
icon={<Copy className="w-4 h-4" />}
|
||||
disabled={disabled}
|
||||
onClick={() => setOpen(true)}
|
||||
/>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Copy {type}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4 my-4">
|
||||
<p>Provide a name for the newly created {type.toLowerCase()}.</p>
|
||||
<Input value={name} onChange={(e) => setName(e.target.value)} />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<ConfirmButton
|
||||
title="Copy"
|
||||
icon={<Check className="w-4 h-4" />}
|
||||
disabled={!name}
|
||||
onClick={() => {
|
||||
mutate({ id, name });
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const DeleteResource = ({
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
id: string;
|
||||
}) => {
|
||||
const nav = useNavigate();
|
||||
const resource = useRead(`Get${type}`, {
|
||||
[type.toLowerCase()]: id,
|
||||
} as any).data;
|
||||
const { mutateAsync, isPending } = useWrite(`Delete${type}`);
|
||||
|
||||
if (!resource) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="w-full">Delete {type}</div>
|
||||
<ActionWithDialog
|
||||
name={resource.name}
|
||||
title="Delete"
|
||||
icon={<Trash className="h-4 w-4" />}
|
||||
onClick={async () => {
|
||||
await mutateAsync({ id });
|
||||
nav(`/${type.toLowerCase()}s`);
|
||||
}}
|
||||
disabled={isPending}
|
||||
loading={isPending}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ConfigItem, ResourceSelector } from "@components/config/util";
|
||||
import { ConfigItem } from "@components/config/util";
|
||||
import { ResourceSelector } from "@components/resources/common";
|
||||
import { fmt_version } from "@lib/formatting";
|
||||
import { useRead } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
AccountSelector,
|
||||
ConfigInput,
|
||||
ConfigItem,
|
||||
ResourceSelector,
|
||||
} from "@components/config/util";
|
||||
import { ImageConfig } from "./components/image";
|
||||
import { RestartModeSelector } from "./components/restart";
|
||||
@@ -20,6 +19,7 @@ import {
|
||||
TermSignalLabels,
|
||||
TerminationTimeout,
|
||||
} from "./components/term-signal";
|
||||
import { ResourceSelector } from "@components/resources/common";
|
||||
|
||||
export const ServerSelector = ({
|
||||
selected,
|
||||
|
||||
@@ -24,8 +24,8 @@ import {
|
||||
text_color_class_by_intention,
|
||||
} from "@lib/color";
|
||||
import { DeploymentTable } from "./table";
|
||||
import { CopyResource, ResourceLink } from "@components/util";
|
||||
import { DeploymentsChart } from "./dashboard";
|
||||
import { CopyResource, ResourceLink } from "../common";
|
||||
|
||||
export const useDeployment = (id?: string) =>
|
||||
useRead("ListDeployments", {}, { refetchInterval: 5000 }).data?.find(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ConfigLayout } from "@components/config";
|
||||
import { ResourceSelector } from "@components/config/util";
|
||||
import { ConfirmButton } from "@components/util";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
@@ -40,6 +39,7 @@ import {
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { ResourceSelector } from "../common";
|
||||
|
||||
export const ProcedureConfig = ({ id }: { id: string }) => {
|
||||
const procedure = useRead("GetProcedure", { procedure: id }).data;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NewResource, Section } from "@components/layouts";
|
||||
import { ConfirmButton, CopyResource, ResourceLink } from "@components/util";
|
||||
import { ConfirmButton } from "@components/util";
|
||||
import { useExecute, useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
import { RequiredResourceComponents } from "@types";
|
||||
@@ -17,7 +17,7 @@ import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { ProcedureConfig } from "./config";
|
||||
import { ProcedureTable } from "./table";
|
||||
import { DeleteResource } from "@components/config/util";
|
||||
import { CopyResource, DeleteResource, ResourceLink } from "../common";
|
||||
|
||||
const useProcedure = (id?: string) =>
|
||||
useRead("ListProcedures", {}).data?.find((d) => d.id === id);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Config } from "@components/config";
|
||||
import {
|
||||
ConfigItem,
|
||||
ResourceSelector,
|
||||
SystemCommand,
|
||||
} from "@components/config/util";
|
||||
import { useRead, useWrite } from "@lib/hooks";
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
SelectValue,
|
||||
} from "@ui/select";
|
||||
import { useState } from "react";
|
||||
import { ResourceSelector } from "../common";
|
||||
|
||||
export const RepoConfig = ({ id }: { id: string }) => {
|
||||
const config = useRead("GetRepo", { repo: id }).data?.config;
|
||||
|
||||
@@ -6,12 +6,11 @@ import { DataTable } from "@ui/data-table";
|
||||
import { AlertTriangle, GitBranch } from "lucide-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { RepoConfig } from "./config";
|
||||
import { CopyResource, ResourceLink } from "@components/util";
|
||||
import { useState } from "react";
|
||||
import { NewResource, Section } from "@components/layouts";
|
||||
import { Input } from "@ui/input";
|
||||
import { CloneRepo, PullRepo } from "./actions";
|
||||
import { DeleteResource } from "@components/config/util";
|
||||
import { CopyResource, DeleteResource, ResourceLink } from "../common";
|
||||
|
||||
const useRepo = (id?: string) =>
|
||||
useRead("ListRepos", {}).data?.find((d) => d.id === id);
|
||||
|
||||
@@ -16,10 +16,9 @@ import { ServerConfig } from "./config";
|
||||
import { DeploymentTable } from "../deployment/table";
|
||||
import { ServerTable } from "./table";
|
||||
import { ServersChart } from "./dashboard";
|
||||
import { ResourceLink } from "@components/util";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Button } from "@ui/button";
|
||||
import { DeleteResource } from "@components/config/util";
|
||||
import { DeleteResource, ResourceLink } from "../common";
|
||||
|
||||
export const useServer = (id?: string) =>
|
||||
useRead("ListServers", {}).data?.find((d) => d.id === id);
|
||||
|
||||
@@ -19,16 +19,13 @@ import {
|
||||
} from "@ui/dialog";
|
||||
import { toast, useToast } from "@ui/use-toast";
|
||||
import { cn } from "@lib/utils";
|
||||
import { useInvalidate, useWrite } from "@lib/hooks";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from "@ui/dropdown-menu";
|
||||
import { AUTH_TOKEN_STORAGE_KEY } from "@main";
|
||||
import { UsableResource } from "@types";
|
||||
import { ResourceComponents } from "./resources";
|
||||
|
||||
export const WithLoading = ({
|
||||
children,
|
||||
@@ -166,61 +163,6 @@ export const ActionWithDialog = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const CopyResource = ({
|
||||
id,
|
||||
disabled,
|
||||
type,
|
||||
}: {
|
||||
id: string;
|
||||
disabled?: boolean;
|
||||
type: Exclude<UsableResource, "Server">;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [name, setName] = useState("");
|
||||
|
||||
const nav = useNavigate();
|
||||
const inv = useInvalidate();
|
||||
const { mutate } = useWrite(`Copy${type}`, {
|
||||
onSuccess: (res) => {
|
||||
inv([`List${type}s`]);
|
||||
nav(`/${type.toLowerCase()}s/${res._id?.$oid}`);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<ActionButton
|
||||
title="Copy"
|
||||
icon={<Copy className="w-4 h-4" />}
|
||||
disabled={disabled}
|
||||
onClick={() => setOpen(true)}
|
||||
/>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Copy {type}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4 my-4">
|
||||
<p>Provide a name for the newly created {type.toLowerCase()}.</p>
|
||||
<Input value={name} onChange={(e) => setName(e.target.value)} />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<ConfirmButton
|
||||
title="Copy"
|
||||
icon={<Check className="w-4 h-4" />}
|
||||
disabled={!name}
|
||||
onClick={() => {
|
||||
mutate({ id, name });
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConfirmButton = ({
|
||||
variant,
|
||||
size,
|
||||
@@ -336,21 +278,3 @@ export const CopyButton = ({ content }: { content: string | undefined }) => {
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export const ResourceLink = ({
|
||||
type,
|
||||
id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
id: string;
|
||||
}) => {
|
||||
const Components = ResourceComponents[type];
|
||||
return (
|
||||
<Link to={`/${type.toLowerCase()}s/${id}`}>
|
||||
<Button variant="link" className="flex gap-2 items-center p-0">
|
||||
<Components.Icon id={id} />
|
||||
<Components.Name id={id} />
|
||||
</Button>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ApiKeysSummary } from "@components/dashboard/api-keys";
|
||||
import { ResourceComponents } from "@components/resources";
|
||||
import { OpenAlerts } from "@components/alert";
|
||||
import { useUser } from "@lib/hooks";
|
||||
import { ResourceLink } from "@components/util";
|
||||
import { ResourceLink } from "@components/resources/common";
|
||||
|
||||
export const Dashboard = () => {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Page, Section } from "@components/layouts";
|
||||
import { ConfirmButton, ResourceLink } from "@components/util";
|
||||
import { ResourceLink } from "@components/resources/common";
|
||||
import { ConfirmButton } from "@components/util";
|
||||
import { text_color_class_by_intention } from "@lib/color";
|
||||
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
|
||||
import { Types } from "@monitor/client";
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": false,
|
||||
|
||||
/* Paths */
|
||||
"baseUrl": "./src",
|
||||
|
||||
Reference in New Issue
Block a user