forked from github-starred/komodo
standard update text menu
This commit is contained in:
@@ -92,7 +92,6 @@ export const Config = <T,>({
|
|||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
}) => {
|
}) => {
|
||||||
console.log(selector);
|
|
||||||
const [show, setShow] = useState(keys(components)[0]);
|
const [show, setShow] = useState(keys(components)[0]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import {
|
|||||||
ActionButton,
|
ActionButton,
|
||||||
ActionWithDialog,
|
ActionWithDialog,
|
||||||
ConfirmButton,
|
ConfirmButton,
|
||||||
|
TextUpdateMenu,
|
||||||
} from "@components/util";
|
} from "@components/util";
|
||||||
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
|
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
|
||||||
import { UsableResource } from "@types";
|
import { UsableResource } from "@types";
|
||||||
import { Button } from "@ui/button";
|
import { Button } from "@ui/button";
|
||||||
import { Card, CardHeader } from "@ui/card";
|
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
CommandEmpty,
|
CommandEmpty,
|
||||||
@@ -24,16 +24,8 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@ui/dialog";
|
} from "@ui/dialog";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
|
||||||
import { Textarea } from "@ui/textarea";
|
import { Check, ChevronsUpDown, Copy, SearchX, Trash } from "lucide-react";
|
||||||
import {
|
import { useState } from "react";
|
||||||
Check,
|
|
||||||
CheckCircle,
|
|
||||||
ChevronsUpDown,
|
|
||||||
Copy,
|
|
||||||
SearchX,
|
|
||||||
Trash,
|
|
||||||
} from "lucide-react";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { ResourceComponents } from ".";
|
import { ResourceComponents } from ".";
|
||||||
import { Input } from "@ui/input";
|
import { Input } from "@ui/input";
|
||||||
@@ -51,8 +43,6 @@ export const ResourceDescription = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const inv = useInvalidate();
|
const inv = useInvalidate();
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [description, setDescription] = useState<string>();
|
|
||||||
|
|
||||||
const resource = useRead(`Get${type}`, {
|
const resource = useRead(`Get${type}`, {
|
||||||
[type.toLowerCase()]: id,
|
[type.toLowerCase()]: id,
|
||||||
@@ -65,44 +55,18 @@ export const ResourceDescription = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(
|
|
||||||
() => setDescription(resource?.description),
|
|
||||||
[resource?.description]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<TextUpdateMenu
|
||||||
<DialogTrigger asChild>
|
title="Update Description"
|
||||||
<Card className="hover:bg-accent/50 transition-colors cursor-pointer">
|
value={resource?.description}
|
||||||
<CardHeader className="text-muted-foreground px-4 py-2 overflow-ellipsis">
|
onUpdate={(description) =>
|
||||||
{resource?.description || "Set description"}
|
update_description({
|
||||||
</CardHeader>
|
target: { type, id },
|
||||||
</Card>
|
description,
|
||||||
</DialogTrigger>
|
})
|
||||||
<DialogContent>
|
}
|
||||||
<DialogHeader>
|
triggerClassName="text-muted-foreground w-[300px]"
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import { useRead, useWrite } from "@lib/hooks";
|
import { useRead, useWrite } from "@lib/hooks";
|
||||||
import { Types } from "@monitor/client";
|
import { Types } from "@monitor/client";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import { AccountSelector, ConfigItem } from "@components/config/util";
|
||||||
AccountSelector,
|
|
||||||
ConfigInput,
|
|
||||||
ConfigItem,
|
|
||||||
} from "@components/config/util";
|
|
||||||
import { ImageConfig } from "./components/image";
|
import { ImageConfig } from "./components/image";
|
||||||
import { RestartModeSelector } from "./components/restart";
|
import { RestartModeSelector } from "./components/restart";
|
||||||
import { NetworkModeSelector } from "./components/network";
|
import { NetworkModeSelector } from "./components/network";
|
||||||
@@ -20,6 +16,7 @@ import {
|
|||||||
TerminationTimeout,
|
TerminationTimeout,
|
||||||
} from "./components/term-signal";
|
} from "./components/term-signal";
|
||||||
import { LabelsConfig, ResourceSelector } from "@components/resources/common";
|
import { LabelsConfig, ResourceSelector } from "@components/resources/common";
|
||||||
|
import { TextUpdateMenu } from "@components/util";
|
||||||
|
|
||||||
export const ServerSelector = ({
|
export const ServerSelector = ({
|
||||||
selected,
|
selected,
|
||||||
@@ -94,12 +91,14 @@ export const DeploymentConfig = ({ id }: { id: string }) => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
process_args: (value, set) => (
|
process_args: (value, set) => (
|
||||||
<ConfigInput
|
<ConfigItem label="Process Args">
|
||||||
label="Process Args"
|
<TextUpdateMenu
|
||||||
value={value}
|
title="Update Process Args"
|
||||||
onChange={(process_args) => set({ process_args })}
|
value={value}
|
||||||
disabled={disabled}
|
onUpdate={(process_args) => set({ process_args })}
|
||||||
/>
|
triggerClassName="max-w-[400px]"
|
||||||
|
/>
|
||||||
|
</ConfigItem>
|
||||||
),
|
),
|
||||||
network: (value, set) => (
|
network: (value, set) => (
|
||||||
<NetworkModeSelector
|
<NetworkModeSelector
|
||||||
|
|||||||
@@ -7,7 +7,14 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Check, Copy, Loader2, LogOut, Settings, User } from "lucide-react";
|
import {
|
||||||
|
Check,
|
||||||
|
CheckCircle,
|
||||||
|
Copy,
|
||||||
|
Loader2,
|
||||||
|
LogOut,
|
||||||
|
Settings,
|
||||||
|
} from "lucide-react";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -20,12 +27,9 @@ import {
|
|||||||
import { toast, useToast } from "@ui/use-toast";
|
import { toast, useToast } from "@ui/use-toast";
|
||||||
import { cn } from "@lib/utils";
|
import { cn } from "@lib/utils";
|
||||||
import { Link } 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 { AUTH_TOKEN_STORAGE_KEY } from "@main";
|
||||||
|
import { Textarea } from "@ui/textarea";
|
||||||
|
import { Card } from "@ui/card";
|
||||||
|
|
||||||
export const WithLoading = ({
|
export const WithLoading = ({
|
||||||
children,
|
children,
|
||||||
@@ -256,22 +260,6 @@ export const UserSettings = () => (
|
|||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const UserDropdown = () => {
|
|
||||||
// const user = useRead("GetUser", {}).data;
|
|
||||||
return (
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<Button variant="ghost" size="icon">
|
|
||||||
<User className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent>
|
|
||||||
<Logout />
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CopyButton = ({ content }: { content: string | undefined }) => {
|
export const CopyButton = ({ content }: { content: string | undefined }) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [copied, set] = useState(false);
|
const [copied, set] = useState(false);
|
||||||
@@ -302,3 +290,76 @@ export const CopyButton = ({ content }: { content: string | undefined }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const TextUpdateMenu = ({
|
||||||
|
title,
|
||||||
|
value = "",
|
||||||
|
triggerClassName,
|
||||||
|
onUpdate,
|
||||||
|
placeholder,
|
||||||
|
confirmButton,
|
||||||
|
}: {
|
||||||
|
title: string;
|
||||||
|
value: string | undefined;
|
||||||
|
onUpdate: (value: string) => void;
|
||||||
|
triggerClassName?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
confirmButton?: boolean;
|
||||||
|
}) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [_value, setValue] = useState(value);
|
||||||
|
useEffect(() => setValue(value), [value]);
|
||||||
|
const onClick = () => {
|
||||||
|
onUpdate(_value);
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Card className="px-3 py-2 hover:bg-accent/50 transition-colors cursor-pointer">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"text-sm text-nowrap overflow-hidden overflow-ellipsis",
|
||||||
|
triggerClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="min-w-[60vw]">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{title}</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<Textarea
|
||||||
|
value={_value}
|
||||||
|
onChange={(e) => setValue(e.target.value)}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") onClick();
|
||||||
|
}}
|
||||||
|
className="min-h-[200px]"
|
||||||
|
/>
|
||||||
|
<DialogFooter>
|
||||||
|
{confirmButton ? (
|
||||||
|
<ConfirmButton
|
||||||
|
title="Update"
|
||||||
|
icon={<CheckCircle className="w-4 h-4" />}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={onClick}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<CheckCircle className="w-4 h-4" />
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user