mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-08 09:19:53 +00:00
🚧 wip
This commit is contained in:
@@ -40,7 +40,12 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ChevronsUpDown, ExternalLink } from "lucide-react";
|
||||
import {
|
||||
ArrowDownIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronsUpDown,
|
||||
ExternalLink
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
@@ -50,7 +55,7 @@ import {
|
||||
formatMultiSitesSelectorLabel
|
||||
} from "./multi-site-selector";
|
||||
import type { Selectedsite } from "./site-selector";
|
||||
import { CaretSortIcon } from "@radix-ui/react-icons";
|
||||
|
||||
import { MachinesSelector } from "./machines-selector";
|
||||
import DomainPicker from "@app/components/DomainPicker";
|
||||
import { SwitchInput } from "@app/components/SwitchInput";
|
||||
@@ -155,7 +160,7 @@ export type InternalResourceData = {
|
||||
const tagSchema = z.object({ id: z.string(), text: z.string() });
|
||||
|
||||
function buildSelectedSitesForResource(
|
||||
resource: InternalResourceData,
|
||||
resource: InternalResourceData
|
||||
): Selectedsite[] {
|
||||
return resource.siteIds.map((siteId, idx) => ({
|
||||
name: resource.siteNames[idx] ?? "",
|
||||
@@ -608,9 +613,7 @@ export function InternalResourceForm({
|
||||
users: [],
|
||||
clients: []
|
||||
});
|
||||
setSelectedSites(
|
||||
buildSelectedSitesForResource(resource)
|
||||
);
|
||||
setSelectedSites(buildSelectedSitesForResource(resource));
|
||||
setTcpPortMode(
|
||||
getPortModeFromString(resource.tcpPortRangeString)
|
||||
);
|
||||
@@ -877,7 +880,9 @@ export function InternalResourceForm({
|
||||
field.value ??
|
||||
"http"
|
||||
}
|
||||
disabled={httpSectionDisabled}
|
||||
disabled={
|
||||
httpSectionDisabled
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger className="w-full">
|
||||
@@ -918,7 +923,10 @@ export function InternalResourceForm({
|
||||
<Input
|
||||
{...field}
|
||||
className="w-full"
|
||||
disabled={isHttpMode && httpSectionDisabled}
|
||||
disabled={
|
||||
isHttpMode &&
|
||||
httpSectionDisabled
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -974,7 +982,9 @@ export function InternalResourceForm({
|
||||
field.value ??
|
||||
""
|
||||
}
|
||||
disabled={httpSectionDisabled}
|
||||
disabled={
|
||||
httpSectionDisabled
|
||||
}
|
||||
onChange={(e) => {
|
||||
const raw =
|
||||
e.target
|
||||
@@ -1009,7 +1019,9 @@ export function InternalResourceForm({
|
||||
</div>
|
||||
|
||||
{isHttpMode && (
|
||||
<PaidFeaturesAlert tiers={tierMatrix.httpPrivateResources} />
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix.httpPrivateResources}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isHttpMode ? (
|
||||
@@ -1022,55 +1034,61 @@ export function InternalResourceForm({
|
||||
{t(httpConfigurationDescriptionKey)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={httpSectionDisabled ? "pointer-events-none opacity-50" : undefined}>
|
||||
<DomainPicker
|
||||
key={
|
||||
variant === "edit" && siteResourceId
|
||||
? `http-domain-${siteResourceId}`
|
||||
: "http-domain-create"
|
||||
<div
|
||||
className={
|
||||
httpSectionDisabled
|
||||
? "pointer-events-none opacity-50"
|
||||
: undefined
|
||||
}
|
||||
orgId={orgId}
|
||||
cols={2}
|
||||
hideFreeDomain
|
||||
defaultSubdomain={
|
||||
httpConfigSubdomain ?? undefined
|
||||
}
|
||||
defaultDomainId={
|
||||
httpConfigDomainId ?? undefined
|
||||
}
|
||||
defaultFullDomain={
|
||||
httpConfigFullDomain ?? undefined
|
||||
}
|
||||
onDomainChange={(res) => {
|
||||
if (res === null) {
|
||||
>
|
||||
<DomainPicker
|
||||
key={
|
||||
variant === "edit" && siteResourceId
|
||||
? `http-domain-${siteResourceId}`
|
||||
: "http-domain-create"
|
||||
}
|
||||
orgId={orgId}
|
||||
cols={2}
|
||||
hideFreeDomain
|
||||
defaultSubdomain={
|
||||
httpConfigSubdomain ?? undefined
|
||||
}
|
||||
defaultDomainId={
|
||||
httpConfigDomainId ?? undefined
|
||||
}
|
||||
defaultFullDomain={
|
||||
httpConfigFullDomain ?? undefined
|
||||
}
|
||||
onDomainChange={(res) => {
|
||||
if (res === null) {
|
||||
form.setValue(
|
||||
"httpConfigSubdomain",
|
||||
null
|
||||
);
|
||||
form.setValue(
|
||||
"httpConfigDomainId",
|
||||
null
|
||||
);
|
||||
form.setValue(
|
||||
"httpConfigFullDomain",
|
||||
null
|
||||
);
|
||||
return;
|
||||
}
|
||||
form.setValue(
|
||||
"httpConfigSubdomain",
|
||||
null
|
||||
res.subdomain ?? null
|
||||
);
|
||||
form.setValue(
|
||||
"httpConfigDomainId",
|
||||
null
|
||||
res.domainId
|
||||
);
|
||||
form.setValue(
|
||||
"httpConfigFullDomain",
|
||||
null
|
||||
res.fullDomain
|
||||
);
|
||||
return;
|
||||
}
|
||||
form.setValue(
|
||||
"httpConfigSubdomain",
|
||||
res.subdomain ?? null
|
||||
);
|
||||
form.setValue(
|
||||
"httpConfigDomainId",
|
||||
res.domainId
|
||||
);
|
||||
form.setValue(
|
||||
"httpConfigFullDomain",
|
||||
res.fullDomain
|
||||
);
|
||||
}}
|
||||
/>
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -1088,7 +1106,9 @@ export function InternalResourceForm({
|
||||
onCheckedChange={
|
||||
field.onChange
|
||||
}
|
||||
disabled={httpSectionDisabled}
|
||||
disabled={
|
||||
httpSectionDisabled
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -1511,7 +1531,7 @@ export function InternalResourceForm({
|
||||
role="combobox"
|
||||
className={cn(
|
||||
"justify-between w-full",
|
||||
"text-muted-foreground pl-1.5"
|
||||
"text-muted-foreground pl-1.5 cursor-text"
|
||||
)}
|
||||
>
|
||||
<span
|
||||
@@ -1548,7 +1568,7 @@ export function InternalResourceForm({
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<ChevronDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useMemo, useState } from "react";
|
||||
import { useDebounce } from "use-debounce";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { MultiSelectTags } from "./multi-select-tags";
|
||||
import { MultiSelectTags } from "./multi-select/multi-select-tags";
|
||||
|
||||
export type SelectedMachine = Pick<
|
||||
ListClientsResponse["clients"][number],
|
||||
|
||||
61
src/components/multi-select/multi-select-input.tsx
Normal file
61
src/components/multi-select/multi-select-input.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@app/components/ui/popover";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
import {
|
||||
type TagValue,
|
||||
type MultiSelectTagsProps,
|
||||
MultiSelectTags
|
||||
} from "./multi-select-tags";
|
||||
|
||||
export interface MultiSelectInputProps<
|
||||
T extends TagValue
|
||||
> extends MultiSelectTagsProps<T> {
|
||||
buttonText?: string;
|
||||
}
|
||||
|
||||
export function MultiSelectInput<T extends TagValue>({
|
||||
buttonText,
|
||||
...props
|
||||
}: MultiSelectInputProps<T>) {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<div
|
||||
className={cn(
|
||||
"justify-between w-full",
|
||||
"text-muted-foreground pl-1.5 cursor-text"
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1",
|
||||
"overflow-x-auto"
|
||||
)}
|
||||
>
|
||||
{/* {(field.value ?? []).map((client) => (
|
||||
<span
|
||||
key={client.clientId}
|
||||
className={cn(
|
||||
"bg-muted-foreground/20 font-normal text-foreground rounded-sm",
|
||||
"py-1 px-1.5 text-xs"
|
||||
)}
|
||||
>
|
||||
{client.name}
|
||||
</span>
|
||||
))} */}
|
||||
<span className="pl-1 font-normal">{buttonText}</span>
|
||||
</span>
|
||||
<ChevronDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0">
|
||||
<MultiSelectTags {...props} />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from "./ui/command";
|
||||
} from "../ui/command";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { CheckIcon } from "lucide-react";
|
||||
|
||||
Reference in New Issue
Block a user