1
This commit is contained in:
parent
a6d4d9cc5a
commit
70f19f230d
56
frontend/package-lock.json
generated
56
frontend/package-lock.json
generated
@ -31,6 +31,7 @@
|
|||||||
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||||
"@radix-ui/react-label": "^2.1.1",
|
"@radix-ui/react-label": "^2.1.1",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.3",
|
"@radix-ui/react-navigation-menu": "^1.2.3",
|
||||||
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
"@radix-ui/react-progress": "^1.1.1",
|
"@radix-ui/react-progress": "^1.1.1",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-select": "^2.1.4",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
@ -45,6 +46,7 @@
|
|||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
"antd": "^5.22.2",
|
"antd": "^5.22.2",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
|
"cmdk": "^1.0.4",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
"form-render": "^2.5.1",
|
"form-render": "^2.5.1",
|
||||||
"less": "^4.2.1",
|
"less": "^4.2.1",
|
||||||
@ -2096,6 +2098,7 @@
|
|||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
|
||||||
"integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
|
"integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/primitive": "1.1.1",
|
"@radix-ui/primitive": "1.1.1",
|
||||||
"@radix-ui/react-compose-refs": "1.1.1",
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
@ -2352,6 +2355,43 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@radix-ui/react-popover/-/react-popover-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-aUACAkXx8LaFymDma+HQVji7WhvEhpFJ7+qPz17Nf4lLZqtreGOFRiNQWQmhzp7kEWg9cOyyQJpdIMUMPc/CPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-context": "1.1.1",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.1.3",
|
||||||
|
"@radix-ui/react-focus-guards": "1.1.1",
|
||||||
|
"@radix-ui/react-focus-scope": "1.1.1",
|
||||||
|
"@radix-ui/react-id": "1.1.0",
|
||||||
|
"@radix-ui/react-popper": "1.2.1",
|
||||||
|
"@radix-ui/react-portal": "1.1.3",
|
||||||
|
"@radix-ui/react-presence": "1.1.2",
|
||||||
|
"@radix-ui/react-primitive": "2.0.1",
|
||||||
|
"@radix-ui/react-slot": "1.1.1",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
|
"aria-hidden": "^1.1.1",
|
||||||
|
"react-remove-scroll": "^2.6.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-popper": {
|
"node_modules/@radix-ui/react-popper": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
|
||||||
@ -4397,6 +4437,22 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cmdk": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/cmdk/-/cmdk-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-AnsjfHyHpQ/EFeAnG216WY7A5LiYCoZzCSygiLvfXC3H3LFGCprErteUcszaVluGOhuOTbJS3jWHrSDYPBBygg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
|
"@radix-ui/react-id": "^1.1.0",
|
||||||
|
"@radix-ui/react-primitive": "^2.0.0",
|
||||||
|
"use-sync-external-store": "^1.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18 || ^19 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||||
"@radix-ui/react-label": "^2.1.1",
|
"@radix-ui/react-label": "^2.1.1",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.3",
|
"@radix-ui/react-navigation-menu": "^1.2.3",
|
||||||
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
"@radix-ui/react-progress": "^1.1.1",
|
"@radix-ui/react-progress": "^1.1.1",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||||
"@radix-ui/react-select": "^2.1.4",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
@ -47,6 +48,7 @@
|
|||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
"antd": "^5.22.2",
|
"antd": "^5.22.2",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
|
"cmdk": "^1.0.4",
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
"form-render": "^2.5.1",
|
"form-render": "^2.5.1",
|
||||||
"less": "^4.2.1",
|
"less": "^4.2.1",
|
||||||
|
|||||||
152
frontend/src/components/ui/command.tsx
Normal file
152
frontend/src/components/ui/command.tsx
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { Command as CommandPrimitive } from "cmdk"
|
||||||
|
import { Search } from "lucide-react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||||
|
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||||
|
|
||||||
|
const Command = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
Command.displayName = CommandPrimitive.displayName
|
||||||
|
|
||||||
|
interface CommandDialogProps extends DialogProps {}
|
||||||
|
|
||||||
|
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||||
|
return (
|
||||||
|
<Dialog {...props}>
|
||||||
|
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||||
|
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||||
|
{children}
|
||||||
|
</Command>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CommandInput = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||||
|
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
<CommandPrimitive.Input
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||||
|
|
||||||
|
const CommandList = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.List>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.List
|
||||||
|
ref={ref}
|
||||||
|
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandList.displayName = CommandPrimitive.List.displayName
|
||||||
|
|
||||||
|
const CommandEmpty = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||||
|
>((props, ref) => (
|
||||||
|
<CommandPrimitive.Empty
|
||||||
|
ref={ref}
|
||||||
|
className="py-6 text-center text-sm"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||||
|
|
||||||
|
const CommandGroup = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Group
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||||
|
|
||||||
|
const CommandSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 h-px bg-border", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
const CommandItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CommandPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const CommandShortcut = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CommandShortcut.displayName = "CommandShortcut"
|
||||||
|
|
||||||
|
export {
|
||||||
|
Command,
|
||||||
|
CommandDialog,
|
||||||
|
CommandInput,
|
||||||
|
CommandList,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandItem,
|
||||||
|
CommandShortcut,
|
||||||
|
CommandSeparator,
|
||||||
|
}
|
||||||
29
frontend/src/components/ui/popover.tsx
Normal file
29
frontend/src/components/ui/popover.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Popover = PopoverPrimitive.Root
|
||||||
|
|
||||||
|
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||||
|
|
||||||
|
const PopoverContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||||
|
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||||
|
<PopoverPrimitive.Portal>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
align={align}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</PopoverPrimitive.Portal>
|
||||||
|
))
|
||||||
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||||
|
|
||||||
|
export { Popover, PopoverTrigger, PopoverContent }
|
||||||
@ -35,6 +35,11 @@ import {useForm} from "react-hook-form";
|
|||||||
import {zodResolver} from "@hookform/resolvers/zod";
|
import {zodResolver} from "@hookform/resolvers/zod";
|
||||||
import {applicationFormSchema, type ApplicationFormValues} from "../schema";
|
import {applicationFormSchema, type ApplicationFormValues} from "../schema";
|
||||||
import {Textarea} from "@/components/ui/textarea";
|
import {Textarea} from "@/components/ui/textarea";
|
||||||
|
import {Command, CommandEmpty, CommandGroup, CommandInput, CommandItem} from "@/components/ui/command";
|
||||||
|
import {ScrollArea} from "@/components/ui/scroll-area";
|
||||||
|
import {Check} from "lucide-react";
|
||||||
|
import {cn} from "@/lib/utils";
|
||||||
|
import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover";
|
||||||
|
|
||||||
interface ApplicationModalProps {
|
interface ApplicationModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -165,221 +170,258 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={(open) => !open && onCancel()}>
|
<Dialog open={open} onOpenChange={(open) => !open && onCancel()}>
|
||||||
<DialogContent className="sm:max-w-[600px]">
|
<DialogContent className="sm:max-w-[600px] h-[90vh]">
|
||||||
<DialogHeader>
|
<DialogHeader className="pb-4">
|
||||||
<DialogTitle>{isEdit ? '编辑' : '新建'}应用</DialogTitle>
|
<DialogTitle>{isEdit ? '编辑' : '新建'}应用</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Form {...form}>
|
<ScrollArea className="flex-1 -mx-6">
|
||||||
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
|
<div className="px-6">
|
||||||
<FormField
|
<Form {...form}>
|
||||||
control={form.control}
|
<form id="applicationForm" onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
|
||||||
name="appCode"
|
<FormField
|
||||||
render={({field}) => (
|
control={form.control}
|
||||||
<FormItem>
|
name="appCode"
|
||||||
<FormLabel>应用编码</FormLabel>
|
render={({field}) => (
|
||||||
<FormControl>
|
<FormItem>
|
||||||
<Input
|
<FormLabel>应用编码</FormLabel>
|
||||||
{...field}
|
<FormControl>
|
||||||
disabled={isEdit}
|
<Input
|
||||||
placeholder="请输入应用编码"
|
{...field}
|
||||||
/>
|
disabled={isEdit}
|
||||||
</FormControl>
|
placeholder="请输入应用编码"
|
||||||
<FormMessage/>
|
/>
|
||||||
</FormItem>
|
</FormControl>
|
||||||
)}
|
<FormMessage/>
|
||||||
/>
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="appName"
|
name="appName"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>应用名称</FormLabel>
|
<FormLabel>应用名称</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
placeholder="请输入应用名称"
|
placeholder="请输入应用名称"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="language"
|
name="language"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>开发语言</FormLabel>
|
<FormLabel>开发语言</FormLabel>
|
||||||
<Select
|
<Select
|
||||||
disabled={isEdit}
|
disabled={isEdit}
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="请选择开发语言"/>
|
<SelectValue placeholder="请选择开发语言"/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value={DevelopmentLanguageTypeEnum.JAVA}>Java</SelectItem>
|
<SelectItem value={DevelopmentLanguageTypeEnum.JAVA}>Java</SelectItem>
|
||||||
<SelectItem value={DevelopmentLanguageTypeEnum.NODE_JS}>NodeJS</SelectItem>
|
<SelectItem value={DevelopmentLanguageTypeEnum.NODE_JS}>NodeJS</SelectItem>
|
||||||
<SelectItem value={DevelopmentLanguageTypeEnum.PYTHON}>Python</SelectItem>
|
<SelectItem value={DevelopmentLanguageTypeEnum.PYTHON}>Python</SelectItem>
|
||||||
<SelectItem value={DevelopmentLanguageTypeEnum.GO}>Go</SelectItem>
|
<SelectItem value={DevelopmentLanguageTypeEnum.GO}>Go</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="gitInstanceId"
|
name="gitInstanceId"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Git实例</FormLabel>
|
<FormLabel>Git实例</FormLabel>
|
||||||
<Select
|
<Select
|
||||||
disabled={isEdit}
|
disabled={isEdit}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
field.onChange(Number(value));
|
field.onChange(Number(value));
|
||||||
handleGitInstanceChange(Number(value));
|
handleGitInstanceChange(Number(value));
|
||||||
}}
|
}}
|
||||||
value={field.value?.toString()}
|
value={field.value?.toString()}
|
||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="请选择Git实例"/>
|
<SelectValue placeholder="请选择Git实例"/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{gitInstances.map(instance => (
|
{gitInstances.map(instance => (
|
||||||
<SelectItem key={instance.id} value={instance.id.toString()}>
|
<SelectItem key={instance.id} value={instance.id.toString()}>
|
||||||
{instance.name}
|
{instance.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="repositoryGroupId"
|
name="repositoryGroupId"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>代码仓库组</FormLabel>
|
<FormLabel>代码仓库组</FormLabel>
|
||||||
<Select
|
<Popover>
|
||||||
onValueChange={(value) => field.onChange(Number(value))}
|
<PopoverTrigger asChild>
|
||||||
value={field.value?.toString()}
|
<FormControl>
|
||||||
disabled={!form.watch('gitInstanceId')}
|
<Button
|
||||||
>
|
variant="outline"
|
||||||
<FormControl>
|
role="combobox"
|
||||||
<SelectTrigger>
|
disabled={!form.watch('gitInstanceId')}
|
||||||
<SelectValue placeholder="请选择代码仓库组"/>
|
className={cn(
|
||||||
</SelectTrigger>
|
"w-full justify-between",
|
||||||
</FormControl>
|
!field.value && "text-muted-foreground"
|
||||||
<SelectContent>
|
)}
|
||||||
{repositoryGroups.map((group) => (
|
>
|
||||||
<SelectItem key={group.id} value={group.id.toString()}>
|
{field.value
|
||||||
{group.name}
|
? repositoryGroups.find(
|
||||||
</SelectItem>
|
(group) => group.id === field.value
|
||||||
))}
|
)?.name
|
||||||
</SelectContent>
|
: "请选择代码仓库组"}
|
||||||
</Select>
|
</Button>
|
||||||
<FormMessage/>
|
</FormControl>
|
||||||
</FormItem>
|
</PopoverTrigger>
|
||||||
)}
|
<PopoverContent className="w-full p-0">
|
||||||
/>
|
<Command>
|
||||||
|
<CommandInput placeholder="搜索代码仓库组..." />
|
||||||
|
<CommandEmpty>未找到代码仓库组</CommandEmpty>
|
||||||
|
<CommandGroup>
|
||||||
|
<ScrollArea className="h-60">
|
||||||
|
{repositoryGroups.map((group) => (
|
||||||
|
<CommandItem
|
||||||
|
value={group.name}
|
||||||
|
key={group.id}
|
||||||
|
onSelect={() => {
|
||||||
|
form.setValue("repositoryGroupId", group.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Check
|
||||||
|
className={cn(
|
||||||
|
"mr-2 h-4 w-4",
|
||||||
|
group.id === field.value
|
||||||
|
? "opacity-100"
|
||||||
|
: "opacity-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{group.name}
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</ScrollArea>
|
||||||
|
</CommandGroup>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
<FormMessage/>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="repoUrl"
|
name="repoUrl"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>仓库地址</FormLabel>
|
<FormLabel>仓库地址</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
placeholder={selectedGitInstance ? `例如: ${selectedGitInstance.url}/your-project.git` : "请先选择Git实例"}
|
placeholder={selectedGitInstance ? `例如: ${selectedGitInstance.url}/your-project.git` : "请先选择Git实例"}
|
||||||
disabled={!selectedGitInstance}
|
disabled={!selectedGitInstance}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="appDesc"
|
name="appDesc"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>应用描述</FormLabel>
|
<FormLabel>应用描述</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Textarea
|
<Textarea
|
||||||
{...field}
|
{...field}
|
||||||
placeholder="请输入应用描述"
|
placeholder="请输入应用描述"
|
||||||
rows={4}
|
rows={4}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="enabled"
|
name="enabled"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
|
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
<FormLabel>状态</FormLabel>
|
<FormLabel>状态</FormLabel>
|
||||||
</div>
|
</div>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch
|
<Switch
|
||||||
checked={field.value}
|
checked={field.value}
|
||||||
onCheckedChange={field.onChange}
|
onCheckedChange={field.onChange}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="sort"
|
name="sort"
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>排序</FormLabel>
|
<FormLabel>排序</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
type="number"
|
type="number"
|
||||||
min={0}
|
min={0}
|
||||||
onChange={(e) => field.onChange(Number(e.target.value))}
|
onChange={(e) => field.onChange(Number(e.target.value))}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage/>
|
<FormMessage/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DialogFooter>
|
<div className="h-4" />
|
||||||
<Button type="button" variant="outline" onClick={onCancel}>
|
</form>
|
||||||
取消
|
</Form>
|
||||||
</Button>
|
</div>
|
||||||
<Button type="submit">
|
</ScrollArea>
|
||||||
确定
|
<DialogFooter className="pt-4">
|
||||||
</Button>
|
<Button type="button" variant="outline" onClick={onCancel}>
|
||||||
</DialogFooter>
|
取消
|
||||||
</form>
|
</Button>
|
||||||
</Form>
|
<Button type="submit" form="applicationForm">
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user