diff --git a/runtime/drivers/azure/azure.go b/runtime/drivers/azure/azure.go
index dbfd51ffd90..9ec149214ce 100644
--- a/runtime/drivers/azure/azure.go
+++ b/runtime/drivers/azure/azure.go
@@ -23,6 +23,14 @@ var spec = drivers.Spec{
Description: "Connect to Azure Blob Storage.",
DocsURL: "https://docs.rilldata.com/build/connectors/data-source/azure",
ConfigProperties: []*drivers.PropertySpec{
+ {
+ Key: "azure_storage_connection_string",
+ Type: drivers.StringPropertyType,
+ DisplayName: "Azure Connection String",
+ Description: "Azure connection string for storage account",
+ Placeholder: "Paste your Azure connection string here",
+ Secret: true,
+ },
{
Key: "azure_storage_account",
Type: drivers.StringPropertyType,
@@ -38,13 +46,7 @@ var spec = drivers.Spec{
Type: drivers.StringPropertyType,
Secret: true,
},
- {
- Key: "azure_storage_connection_string",
- Type: drivers.StringPropertyType,
- Secret: true,
- },
},
- // Important: Any edits to the below properties must be accompanied by changes to the client-side form validation schemas.
SourceProperties: []*drivers.PropertySpec{
{
Key: "path",
diff --git a/web-common/src/features/sources/modal/AddDataForm.svelte b/web-common/src/features/sources/modal/AddDataForm.svelte
index 697c5def71e..15bdd9b8b7f 100644
--- a/web-common/src/features/sources/modal/AddDataForm.svelte
+++ b/web-common/src/features/sources/modal/AddDataForm.svelte
@@ -22,6 +22,7 @@
import { connectorStepStore } from "./connectorStepStore";
import FormRenderer from "./FormRenderer.svelte";
import YamlPreview from "./YamlPreview.svelte";
+ import AzureMultiStepForm from "./AzureMultiStepForm.svelte";
import GCSMultiStepForm from "./GCSMultiStepForm.svelte";
import { AddDataFormManager } from "./AddDataFormManager";
import { hasOnlyDsn } from "./utils";
@@ -383,13 +384,30 @@
enhance={paramsEnhance}
onSubmit={paramsSubmit}
>
-
+ {#if connector.name === "gcs"}
+
+ {:else if connector.name === "azure"}
+
+ {:else}
+
+ {/if}
{:else}
diff --git a/web-common/src/features/sources/modal/AddDataFormManager.ts b/web-common/src/features/sources/modal/AddDataFormManager.ts
index c81956ffeaa..a82adadd1a7 100644
--- a/web-common/src/features/sources/modal/AddDataFormManager.ts
+++ b/web-common/src/features/sources/modal/AddDataFormManager.ts
@@ -89,12 +89,18 @@ export class AddDataFormManager {
const isSourceForm = formType === "source";
const isConnectorForm = formType === "connector";
+ const isMultiStep = MULTI_STEP_CONNECTORS.includes(connector.name ?? "");
// Base properties
+ // For multi-step connectors (e.g., gcs, azure), step 1 always configures the connector,
+ // even when the overall formType is "source". So prefer configProperties here.
this.properties =
- (isSourceForm
- ? connector.sourceProperties
- : connector.configProperties?.filter((p) => p.key !== "dsn")) ?? [];
+ (isMultiStep
+ ? connector.configProperties
+ : isSourceForm
+ ? connector.sourceProperties
+ : connector.configProperties
+ )?.filter((p) => p.key !== "dsn") ?? [];
// Filter properties based on connector type
this.filteredParamsProperties = (() => {
diff --git a/web-common/src/features/sources/modal/AddDataModal.svelte b/web-common/src/features/sources/modal/AddDataModal.svelte
index 42c8289d1b1..968edca0183 100644
--- a/web-common/src/features/sources/modal/AddDataModal.svelte
+++ b/web-common/src/features/sources/modal/AddDataModal.svelte
@@ -71,6 +71,8 @@
});
function goToConnectorForm(connector: V1ConnectorDriver) {
+ // Ensure multi-step connectors always start on the connector step
+ resetConnectorStep();
const state = {
step: 2,
selectedConnector: connector,
diff --git a/web-common/src/features/sources/modal/AzureMultiStepForm.svelte b/web-common/src/features/sources/modal/AzureMultiStepForm.svelte
new file mode 100644
index 00000000000..06c04baef85
--- /dev/null
+++ b/web-common/src/features/sources/modal/AzureMultiStepForm.svelte
@@ -0,0 +1,164 @@
+
+
+
+
+
+ {#each filteredParamsProperties as property (property.key)}
+ {@const propertyKey = property.key ?? ""}
+ {#if propertyKey !== "path" && propertyKey !== "azure_storage_connection_string" && propertyKey !== "azure_storage_account" && propertyKey !== "azure_storage_key" && propertyKey !== "azure_storage_sas_token"}
+
+ {#if property.type === ConnectorDriverPropertyType.TYPE_STRING || property.type === ConnectorDriverPropertyType.TYPE_NUMBER}
+ onStringInputChange(e)}
+ alwaysShowError
+ />
+ {:else if property.type === ConnectorDriverPropertyType.TYPE_BOOLEAN}
+
+ {:else if property.type === ConnectorDriverPropertyType.TYPE_INFORMATIONAL}
+
+ {/if}
+
+ {/if}
+ {/each}
+
diff --git a/web-common/src/features/sources/modal/constants.ts b/web-common/src/features/sources/modal/constants.ts
index 4bffc52825d..36871354e42 100644
--- a/web-common/src/features/sources/modal/constants.ts
+++ b/web-common/src/features/sources/modal/constants.ts
@@ -18,6 +18,11 @@ export const CONNECTION_TAB_OPTIONS: { value: string; label: string }[] = [
];
export type GCSAuthMethod = "credentials" | "hmac";
+export type AzureAuthMethod =
+ | "connection_string"
+ | "storage_key"
+ | "sas_token"
+ | "public";
export const GCS_AUTH_OPTIONS: {
value: GCSAuthMethod;
@@ -39,6 +44,29 @@ export const GCS_AUTH_OPTIONS: {
},
];
+export const AZURE_AUTH_OPTIONS: {
+ value: AzureAuthMethod;
+ label: string;
+ description: string;
+ hint?: string;
+}[] = [
+ {
+ value: "connection_string",
+ label: "Connection String",
+ description: "Alternative for cloud deployment",
+ },
+ {
+ value: "storage_key",
+ label: "Storage Account Key",
+ description: "Recommended for cloud deployment",
+ },
+ {
+ value: "sas_token",
+ label: "Shared Access Signature (SAS) Token",
+ description: "Most secure, fine-grained control",
+ },
+];
+
// pre-defined order for sources
export const SOURCES = [
"athena",
@@ -67,7 +95,7 @@ export const OLAP_ENGINES = [
export const ALL_CONNECTORS = [...SOURCES, ...OLAP_ENGINES];
// Connectors that support multi-step forms (connector -> source)
-export const MULTI_STEP_CONNECTORS = ["gcs"];
+export const MULTI_STEP_CONNECTORS = ["gcs", "azure"];
export const FORM_HEIGHT_TALL = "max-h-[38.5rem] min-h-[38.5rem]";
export const FORM_HEIGHT_DEFAULT = "max-h-[34.5rem] min-h-[34.5rem]";
diff --git a/web-common/src/features/sources/modal/yupSchemas.ts b/web-common/src/features/sources/modal/yupSchemas.ts
index b12ec332eae..091459dcf0f 100644
--- a/web-common/src/features/sources/modal/yupSchemas.ts
+++ b/web-common/src/features/sources/modal/yupSchemas.ts
@@ -66,18 +66,21 @@ export const getYupSchema = {
}),
azure: yup.object().shape({
+ azure_storage_connection_string: yup.string(),
+ azure_storage_account: yup.string(),
+ azure_storage_key: yup.string(),
+ azure_storage_sas_token: yup.string(),
path: yup
.string()
.matches(
/^azure:\/\//,
"Must be an Azure URI (e.g. azure://container/path)",
)
- .required("Path is required"),
- azure_storage_account: yup.string(),
+ .optional(),
name: yup
.string()
.matches(VALID_NAME_PATTERN, INVALID_NAME_MESSAGE)
- .required("Source name is required"),
+ .optional(),
}),
postgres: yup.object().shape({