mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
fix: azure form (#341)
This commit is contained in:
@@ -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",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user