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 @@ + + +
+
+
Authentication
+ + + {#if option.value === "connection_string"} + + {:else if option.value === "storage_key"} +
+ + +
+ {:else if option.value === "sas_token"} +
+ + +
+ {/if} +
+
+
+ + {#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({