fix: azure form (#341)

This commit is contained in:
Charles GTE
2026-06-27 20:52:43 +02:00
committed by GitHub
parent 8f44071069
commit f70d86f394
2 changed files with 136 additions and 58 deletions
@@ -9,53 +9,117 @@ import {
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { PasswordInput } from "@/components/ui/password-input"; import { PasswordInput } from "@/components/ui/password-input";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
type StorageBlobFormProps = { type StorageBlobFormProps = {
form: UseFormReturn<any, any, any>; form: UseFormReturn<any, any, any>;
}; };
export const StorageBlobForm = ({ form }: StorageBlobFormProps) => { export const StorageBlobForm = ({ form }: StorageBlobFormProps) => {
const storedMode = form.watch("config.authMode");
// Derive mode for legacy records saved before authMode existed: if no
// connection string but account credentials are present, open Account Details.
const derivedMode: "connectionString" | "accountKey" =
!form.watch("config.connectionString") &&
(form.watch("config.accountName") || form.watch("config.accountKey"))
? "accountKey"
: "connectionString";
const authMode: "connectionString" | "accountKey" = storedMode ?? derivedMode;
const handleModeChange = (value: string) => {
form.setValue("config.authMode", value, { shouldValidate: false });
// Clear errors of the now-inactive mode so stale messages don't linger.
if (value === "connectionString") {
form.clearErrors(["config.accountName", "config.accountKey"]);
} else {
form.clearErrors(["config.connectionString"]);
}
};
return ( return (
<> <>
<Separator className="my-1" /> <Separator className="my-1" />
<FormField <Tabs value={authMode} onValueChange={handleModeChange} className="w-full">
control={form.control} <TabsList className="w-full">
name="config.accountName" <TabsTrigger value="connectionString">Connection String</TabsTrigger>
render={({ field }) => ( <TabsTrigger value="accountKey">Account Details</TabsTrigger>
<FormItem> </TabsList>
<FormLabel>Account Name *</FormLabel>
<FormControl> <TabsContent value="connectionString" className="flex flex-col gap-3">
<Input {...field} placeholder="e.g. mystorageaccount" /> <FormField
</FormControl> control={form.control}
<FormMessage /> name="config.connectionString"
</FormItem> render={({ field }) => (
)} <FormItem>
/> <FormLabel>Connection String *</FormLabel>
<FormField <FormControl>
control={form.control} <PasswordInput
name="config.accountKey" {...field}
render={({ field }) => ( value={field.value ?? ""}
<FormItem> placeholder="e.g. DefaultEndpointsProtocol=https;..."
<FormLabel>Account Key</FormLabel> />
<FormControl> </FormControl>
<PasswordInput {...field} placeholder="e.g. base64-encoded-key" /> <FormMessage />
</FormControl> </FormItem>
<FormMessage /> )}
</FormItem> />
)} </TabsContent>
/>
<FormField <TabsContent value="accountKey" className="flex flex-col gap-3">
control={form.control} <FormField
name="config.connectionString" control={form.control}
render={({ field }) => ( name="config.accountName"
<FormItem> render={({ field }) => (
<FormLabel>Connection String</FormLabel> <FormItem>
<FormControl> <FormLabel>Account Name *</FormLabel>
<PasswordInput {...field} placeholder="e.g. DefaultEndpointsProtocol=https;..." /> <FormControl>
</FormControl> <Input
<FormMessage /> {...field}
</FormItem> value={field.value ?? ""}
)} placeholder="e.g. mystorageaccount"
/> />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="config.accountKey"
render={({ field }) => (
<FormItem>
<FormLabel>Account Key *</FormLabel>
<FormControl>
<PasswordInput
{...field}
value={field.value ?? ""}
placeholder="e.g. base64-encoded-key"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="config.endpointUrl"
render={({ field }) => (
<FormItem>
<FormLabel>Endpoint URL</FormLabel>
<FormControl>
<Input
{...field}
value={field.value ?? ""}
placeholder="e.g. https://myaccount.blob.core.windows.net"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TabsContent>
</Tabs>
<FormField <FormField
control={form.control} control={form.control}
name="config.containerName" name="config.containerName"
@@ -63,20 +127,11 @@ export const StorageBlobForm = ({ form }: StorageBlobFormProps) => {
<FormItem> <FormItem>
<FormLabel>Container Name *</FormLabel> <FormLabel>Container Name *</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="e.g. backups-prod" /> <Input
</FormControl> {...field}
<FormMessage /> value={field.value ?? ""}
</FormItem> placeholder="e.g. backups-prod"
)} />
/>
<FormField
control={form.control}
name="config.endpointUrl"
render={({ field }) => (
<FormItem>
<FormLabel>Endpoint URL</FormLabel>
<FormControl>
<Input {...field} placeholder="e.g. https://myaccount.blob.core.windows.net" />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1,7 +1,8 @@
import {z} from "zod"; import {z} from "zod";
export const BlobChannelConfigSchema = z.object({ export const BlobChannelConfigSchema = z.object({
accountName: z.string().min(1, "Account name is required"), authMode: z.enum(["connectionString", "accountKey"]).default("connectionString"),
accountName: z.string().optional(),
accountKey: z.string().optional(), accountKey: z.string().optional(),
connectionString: z.string().optional(), connectionString: z.string().optional(),
containerName: z.string().min(1, "Container name is required"), containerName: z.string().min(1, "Container name is required"),
@@ -9,7 +10,29 @@ export const BlobChannelConfigSchema = z.object({
(v) => (v === "" ? undefined : v), (v) => (v === "" ? undefined : v),
z.string().url("Endpoint URL must be a valid URL").optional(), z.string().url("Endpoint URL must be a valid URL").optional(),
), ),
}).refine( }).superRefine((data, ctx) => {
(data) => data.accountKey || data.connectionString, if (data.authMode === "connectionString") {
{message: "Either account key or connection string is required"} if (!data.connectionString) {
); ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["connectionString"],
message: "Connection string is required",
});
}
} else {
if (!data.accountName) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["accountName"],
message: "Account name is required",
});
}
if (!data.accountKey) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["accountKey"],
message: "Account key is required",
});
}
}
});