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,14 +9,63 @@ 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" />
<Tabs value={authMode} onValueChange={handleModeChange} className="w-full">
<TabsList className="w-full">
<TabsTrigger value="connectionString">Connection String</TabsTrigger>
<TabsTrigger value="accountKey">Account Details</TabsTrigger>
</TabsList>
<TabsContent value="connectionString" className="flex flex-col gap-3">
<FormField
control={form.control}
name="config.connectionString"
render={({ field }) => (
<FormItem>
<FormLabel>Connection String *</FormLabel>
<FormControl>
<PasswordInput
{...field}
value={field.value ?? ""}
placeholder="e.g. DefaultEndpointsProtocol=https;..."
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TabsContent>
<TabsContent value="accountKey" className="flex flex-col gap-3">
<FormField <FormField
control={form.control} control={form.control}
name="config.accountName" name="config.accountName"
@@ -24,7 +73,11 @@ export const StorageBlobForm = ({ form }: StorageBlobFormProps) => {
<FormItem> <FormItem>
<FormLabel>Account Name *</FormLabel> <FormLabel>Account Name *</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="e.g. mystorageaccount" /> <Input
{...field}
value={field.value ?? ""}
placeholder="e.g. mystorageaccount"
/>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -35,35 +88,13 @@ export const StorageBlobForm = ({ form }: StorageBlobFormProps) => {
name="config.accountKey" name="config.accountKey"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Account Key</FormLabel> <FormLabel>Account Key *</FormLabel>
<FormControl> <FormControl>
<PasswordInput {...field} placeholder="e.g. base64-encoded-key" /> <PasswordInput
</FormControl> {...field}
<FormMessage /> value={field.value ?? ""}
</FormItem> placeholder="e.g. base64-encoded-key"
)}
/> />
<FormField
control={form.control}
name="config.connectionString"
render={({ field }) => (
<FormItem>
<FormLabel>Connection String</FormLabel>
<FormControl>
<PasswordInput {...field} placeholder="e.g. DefaultEndpointsProtocol=https;..." />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="config.containerName"
render={({ field }) => (
<FormItem>
<FormLabel>Container Name *</FormLabel>
<FormControl>
<Input {...field} placeholder="e.g. backups-prod" />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -76,7 +107,31 @@ export const StorageBlobForm = ({ form }: StorageBlobFormProps) => {
<FormItem> <FormItem>
<FormLabel>Endpoint URL</FormLabel> <FormLabel>Endpoint URL</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="e.g. https://myaccount.blob.core.windows.net" /> <Input
{...field}
value={field.value ?? ""}
placeholder="e.g. https://myaccount.blob.core.windows.net"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TabsContent>
</Tabs>
<FormField
control={form.control}
name="config.containerName"
render={({ field }) => (
<FormItem>
<FormLabel>Container Name *</FormLabel>
<FormControl>
<Input
{...field}
value={field.value ?? ""}
placeholder="e.g. backups-prod"
/>
</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",
});
}
}
});