diff --git a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml index 6c38b7ce2d6c3..4fae97dc66ee2 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml +++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml @@ -199,6 +199,37 @@ paths: security: - OAuth2PasswordBearer: [] - HTTPBearer: [] + /ui/connections/hook_meta/{connection_type}: + get: + tags: + - Connection + summary: Hook Meta Data For Type + description: Return full metadata (standard_fields, extra_fields) for a single + connection type. + operationId: hook_meta_data_for_type + security: + - OAuth2PasswordBearer: [] + - HTTPBearer: [] + parameters: + - name: connection_type + in: path + required: true + schema: + type: string + title: Connection Type + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/ConnectionHookMetaData' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' /ui/connections/hook_meta: get: tags: diff --git a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/connections.py b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/connections.py index 2ce95265e0420..36dd31b30dc26 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/connections.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/connections.py @@ -16,7 +16,7 @@ # under the License. from __future__ import annotations -from fastapi import Depends +from fastapi import Depends, HTTPException from airflow.api_fastapi.common.router import AirflowRouter from airflow.api_fastapi.core_api.datamodels.connections import ConnectionHookMetaData @@ -26,6 +26,18 @@ connections_router = AirflowRouter(tags=["Connection"], prefix="/connections") +@connections_router.get( + "/hook_meta/{connection_type}", + dependencies=[Depends(requires_access_connection(method="GET"))], +) +def hook_meta_data_for_type(connection_type: str) -> ConnectionHookMetaData: + """Return full metadata (standard_fields, extra_fields) for a single connection type.""" + result = HookMetaService.hook_meta_for_type(connection_type) + if result is None: + raise HTTPException(status_code=404, detail=f"Connection type '{connection_type}' not found") + return result + + @connections_router.get( "/hook_meta", dependencies=[Depends(requires_access_connection(method="GET"))], diff --git a/airflow-core/src/airflow/api_fastapi/core_api/services/ui/connections.py b/airflow-core/src/airflow/api_fastapi/core_api/services/ui/connections.py index 4568eb0727827..89f90039088eb 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/services/ui/connections.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/services/ui/connections.py @@ -238,3 +238,80 @@ def hook_meta_data() -> list[ConnectionHookMetaData]: ) result.append(hook_meta) return result + + @staticmethod + def hook_meta_for_type(connection_type: str) -> ConnectionHookMetaData | None: + """ + Return full metadata for a single connection type. + + Only imports the requested hook class (via lazy dict lookup), not all hooks. + """ + from unittest import mock + + from airflow.providers_manager import ProvidersManager + + def mock_lazy_gettext(txt: str) -> str: + return txt + + def mock_any_of(allowed_values: list) -> HookMetaService.MockEnum: + return HookMetaService.MockEnum(allowed_values) + + import sys + from importlib.util import find_spec + from unittest.mock import MagicMock + + for mod_name in [ + "wtforms", + "wtforms.csrf", + "wtforms.fields", + "wtforms.fields.simple", + "wtforms.validators", + "flask_babel", + "flask_appbuilder", + "flask_appbuilder.fieldwidgets", + ]: + try: + if not find_spec(mod_name): + raise ModuleNotFoundError + except ModuleNotFoundError: + sys.modules[mod_name] = MagicMock() + with ( + mock.patch("wtforms.StringField", HookMetaService.MockStringField), + mock.patch("wtforms.fields.StringField", HookMetaService.MockStringField), + mock.patch("wtforms.fields.simple.StringField", HookMetaService.MockStringField), + mock.patch("wtforms.IntegerField", HookMetaService.MockIntegerField), + mock.patch("wtforms.fields.IntegerField", HookMetaService.MockIntegerField), + mock.patch("wtforms.PasswordField", HookMetaService.MockPasswordField), + mock.patch("wtforms.BooleanField", HookMetaService.MockBooleanField), + mock.patch("wtforms.fields.BooleanField", HookMetaService.MockBooleanField), + mock.patch("wtforms.fields.simple.BooleanField", HookMetaService.MockBooleanField), + mock.patch("flask_babel.lazy_gettext", mock_lazy_gettext), + mock.patch("flask_appbuilder.fieldwidgets.BS3TextFieldWidget", HookMetaService.MockAnyWidget), + mock.patch("flask_appbuilder.fieldwidgets.BS3TextAreaFieldWidget", HookMetaService.MockAnyWidget), + mock.patch("flask_appbuilder.fieldwidgets.BS3PasswordFieldWidget", HookMetaService.MockAnyWidget), + mock.patch("wtforms.validators.Optional", HookMetaService.MockOptional), + mock.patch("wtforms.validators.any_of", mock_any_of), + ): + pm = ProvidersManager() + pm.initialize_providers_hooks() + + if connection_type not in pm._hooks_lazy_dict: + return None + hook_info = pm._hooks_lazy_dict[connection_type] + if not hook_info: + return None + + prefix = f"extra__{connection_type}__" + filtered_widgets = {k: v for k, v in pm._connection_form_widgets.items() if k.startswith(prefix)} + widgets = HookMetaService._convert_extra_fields(filtered_widgets) + + return ConnectionHookMetaData( + connection_type=connection_type, + hook_class_name=hook_info.hook_class_name, + default_conn_name=None, + hook_name=hook_info.hook_name, + standard_fields=HookMetaService._make_standard_fields( + pm._field_behaviours.get(connection_type) + ), + extra_fields=widgets.get(connection_type), + ) diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts index d74622f5a8ca2..96636910a0fc9 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts @@ -122,6 +122,12 @@ export const UseConnectionServiceGetConnectionsKeyFn = ({ connectionIdPattern, l offset?: number; orderBy?: string[]; } = {}, queryKey?: Array) => [useConnectionServiceGetConnectionsKey, ...(queryKey ?? [{ connectionIdPattern, limit, offset, orderBy }])]; +export type ConnectionServiceHookMetaDataForTypeDefaultResponse = Awaited>; +export type ConnectionServiceHookMetaDataForTypeQueryResult = UseQueryResult; +export const useConnectionServiceHookMetaDataForTypeKey = "ConnectionServiceHookMetaDataForType"; +export const UseConnectionServiceHookMetaDataForTypeKeyFn = ({ connectionType }: { + connectionType: string; +}, queryKey?: Array) => [useConnectionServiceHookMetaDataForTypeKey, ...(queryKey ?? [{ connectionType }])]; export type ConnectionServiceHookMetaDataDefaultResponse = Awaited>; export type ConnectionServiceHookMetaDataQueryResult = UseQueryResult; export const useConnectionServiceHookMetaDataKey = "ConnectionServiceHookMetaData"; diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts index 8ccaf76a47a83..1db515754a92e 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts @@ -225,6 +225,17 @@ export const ensureUseConnectionServiceGetConnectionsData = (queryClient: QueryC orderBy?: string[]; } = {}) => queryClient.ensureQueryData({ queryKey: Common.UseConnectionServiceGetConnectionsKeyFn({ connectionIdPattern, limit, offset, orderBy }), queryFn: () => ConnectionService.getConnections({ connectionIdPattern, limit, offset, orderBy }) }); /** +* Hook Meta Data For Type +* Return full metadata (standard_fields, extra_fields) for a single connection type. +* @param data The data for the request. +* @param data.connectionType +* @returns ConnectionHookMetaData Successful Response +* @throws ApiError +*/ +export const ensureUseConnectionServiceHookMetaDataForTypeData = (queryClient: QueryClient, { connectionType }: { + connectionType: string; +}) => queryClient.ensureQueryData({ queryKey: Common.UseConnectionServiceHookMetaDataForTypeKeyFn({ connectionType }), queryFn: () => ConnectionService.hookMetaDataForType({ connectionType }) }); +/** * Hook Meta Data * Retrieve information about available connection types (hook classes) and their parameters. * @returns ConnectionHookMetaData Successful Response diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts index 57c4174683dfa..b13d5cbcb0f67 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts @@ -225,6 +225,17 @@ export const prefetchUseConnectionServiceGetConnections = (queryClient: QueryCli orderBy?: string[]; } = {}) => queryClient.prefetchQuery({ queryKey: Common.UseConnectionServiceGetConnectionsKeyFn({ connectionIdPattern, limit, offset, orderBy }), queryFn: () => ConnectionService.getConnections({ connectionIdPattern, limit, offset, orderBy }) }); /** +* Hook Meta Data For Type +* Return full metadata (standard_fields, extra_fields) for a single connection type. +* @param data The data for the request. +* @param data.connectionType +* @returns ConnectionHookMetaData Successful Response +* @throws ApiError +*/ +export const prefetchUseConnectionServiceHookMetaDataForType = (queryClient: QueryClient, { connectionType }: { + connectionType: string; +}) => queryClient.prefetchQuery({ queryKey: Common.UseConnectionServiceHookMetaDataForTypeKeyFn({ connectionType }), queryFn: () => ConnectionService.hookMetaDataForType({ connectionType }) }); +/** * Hook Meta Data * Retrieve information about available connection types (hook classes) and their parameters. * @returns ConnectionHookMetaData Successful Response diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts index 33a5ca388165a..3803c2771eb92 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts @@ -225,6 +225,17 @@ export const useConnectionServiceGetConnections = , "queryKey" | "queryFn">) => useQuery({ queryKey: Common.UseConnectionServiceGetConnectionsKeyFn({ connectionIdPattern, limit, offset, orderBy }, queryKey), queryFn: () => ConnectionService.getConnections({ connectionIdPattern, limit, offset, orderBy }) as TData, ...options }); /** +* Hook Meta Data For Type +* Return full metadata (standard_fields, extra_fields) for a single connection type. +* @param data The data for the request. +* @param data.connectionType +* @returns ConnectionHookMetaData Successful Response +* @throws ApiError +*/ +export const useConnectionServiceHookMetaDataForType = = unknown[]>({ connectionType }: { + connectionType: string; +}, queryKey?: TQueryKey, options?: Omit, "queryKey" | "queryFn">) => useQuery({ queryKey: Common.UseConnectionServiceHookMetaDataForTypeKeyFn({ connectionType }, queryKey), queryFn: () => ConnectionService.hookMetaDataForType({ connectionType }) as TData, ...options }); +/** * Hook Meta Data * Retrieve information about available connection types (hook classes) and their parameters. * @returns ConnectionHookMetaData Successful Response diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts index 2d01abdb58f4f..cdb1665e74f21 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts @@ -225,6 +225,17 @@ export const useConnectionServiceGetConnectionsSuspense = , "queryKey" | "queryFn">) => useSuspenseQuery({ queryKey: Common.UseConnectionServiceGetConnectionsKeyFn({ connectionIdPattern, limit, offset, orderBy }, queryKey), queryFn: () => ConnectionService.getConnections({ connectionIdPattern, limit, offset, orderBy }) as TData, ...options }); /** +* Hook Meta Data For Type +* Return full metadata (standard_fields, extra_fields) for a single connection type. +* @param data The data for the request. +* @param data.connectionType +* @returns ConnectionHookMetaData Successful Response +* @throws ApiError +*/ +export const useConnectionServiceHookMetaDataForTypeSuspense = = unknown[]>({ connectionType }: { + connectionType: string; +}, queryKey?: TQueryKey, options?: Omit, "queryKey" | "queryFn">) => useSuspenseQuery({ queryKey: Common.UseConnectionServiceHookMetaDataForTypeKeyFn({ connectionType }, queryKey), queryFn: () => ConnectionService.hookMetaDataForType({ connectionType }) as TData, ...options }); +/** * Hook Meta Data * Retrieve information about available connection types (hook classes) and their parameters. * @returns ConnectionHookMetaData Successful Response diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts index d36012e372c2a..1fb571fd117ef 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise'; import { OpenAPI } from './core/OpenAPI'; import { request as __request } from './core/request'; -import type { GetAssetsData, GetAssetsResponse, GetAssetAliasesData, GetAssetAliasesResponse, GetAssetAliasData, GetAssetAliasResponse, GetAssetEventsData, GetAssetEventsResponse, CreateAssetEventData, CreateAssetEventResponse, MaterializeAssetData, MaterializeAssetResponse, GetAssetQueuedEventsData, GetAssetQueuedEventsResponse, DeleteAssetQueuedEventsData, DeleteAssetQueuedEventsResponse, GetAssetData, GetAssetResponse, GetDagAssetQueuedEventsData, GetDagAssetQueuedEventsResponse, DeleteDagAssetQueuedEventsData, DeleteDagAssetQueuedEventsResponse, GetDagAssetQueuedEventData, GetDagAssetQueuedEventResponse, DeleteDagAssetQueuedEventData, DeleteDagAssetQueuedEventResponse, NextRunAssetsData, NextRunAssetsResponse, ListBackfillsData, ListBackfillsResponse, CreateBackfillData, CreateBackfillResponse, GetBackfillData, GetBackfillResponse, PauseBackfillData, PauseBackfillResponse, UnpauseBackfillData, UnpauseBackfillResponse, CancelBackfillData, CancelBackfillResponse, CreateBackfillDryRunData, CreateBackfillDryRunResponse, ListBackfillsUiData, ListBackfillsUiResponse, DeleteConnectionData, DeleteConnectionResponse, GetConnectionData, GetConnectionResponse, PatchConnectionData, PatchConnectionResponse, GetConnectionsData, GetConnectionsResponse, PostConnectionData, PostConnectionResponse, BulkConnectionsData, BulkConnectionsResponse, TestConnectionData, TestConnectionResponse, CreateDefaultConnectionsResponse, HookMetaDataResponse, GetDagRunData, GetDagRunResponse, DeleteDagRunData, DeleteDagRunResponse, PatchDagRunData, PatchDagRunResponse, GetUpstreamAssetEventsData, GetUpstreamAssetEventsResponse, ClearDagRunData, ClearDagRunResponse, GetDagRunsData, GetDagRunsResponse, TriggerDagRunData, TriggerDagRunResponse, WaitDagRunUntilFinishedData, WaitDagRunUntilFinishedResponse, GetListDagRunsBatchData, GetListDagRunsBatchResponse, GetDagSourceData, GetDagSourceResponse, GetDagStatsData, GetDagStatsResponse, GetConfigData, GetConfigResponse, GetConfigValueData, GetConfigValueResponse, GetConfigsResponse, ListDagWarningsData, ListDagWarningsResponse, GetDagsData, GetDagsResponse, PatchDagsData, PatchDagsResponse, GetDagData, GetDagResponse, PatchDagData, PatchDagResponse, DeleteDagData, DeleteDagResponse, GetDagDetailsData, GetDagDetailsResponse, FavoriteDagData, FavoriteDagResponse, UnfavoriteDagData, UnfavoriteDagResponse, GetDagTagsData, GetDagTagsResponse, GetDagsUiData, GetDagsUiResponse, GetLatestRunInfoData, GetLatestRunInfoResponse, GetEventLogData, GetEventLogResponse, GetEventLogsData, GetEventLogsResponse, GetExtraLinksData, GetExtraLinksResponse, GetTaskInstanceData, GetTaskInstanceResponse, PatchTaskInstanceData, PatchTaskInstanceResponse, DeleteTaskInstanceData, DeleteTaskInstanceResponse, GetMappedTaskInstancesData, GetMappedTaskInstancesResponse, GetTaskInstanceDependenciesByMapIndexData, GetTaskInstanceDependenciesByMapIndexResponse, GetTaskInstanceDependenciesData, GetTaskInstanceDependenciesResponse, GetTaskInstanceTriesData, GetTaskInstanceTriesResponse, GetMappedTaskInstanceTriesData, GetMappedTaskInstanceTriesResponse, GetMappedTaskInstanceData, GetMappedTaskInstanceResponse, PatchTaskInstanceByMapIndexData, PatchTaskInstanceByMapIndexResponse, GetTaskInstancesData, GetTaskInstancesResponse, BulkTaskInstancesData, BulkTaskInstancesResponse, GetTaskInstancesBatchData, GetTaskInstancesBatchResponse, GetTaskInstanceTryDetailsData, GetTaskInstanceTryDetailsResponse, GetMappedTaskInstanceTryDetailsData, GetMappedTaskInstanceTryDetailsResponse, PostClearTaskInstancesData, PostClearTaskInstancesResponse, PatchTaskInstanceDryRunByMapIndexData, PatchTaskInstanceDryRunByMapIndexResponse, PatchTaskInstanceDryRunData, PatchTaskInstanceDryRunResponse, GetLogData, GetLogResponse, GetExternalLogUrlData, GetExternalLogUrlResponse, UpdateHitlDetailData, UpdateHitlDetailResponse, GetHitlDetailData, GetHitlDetailResponse, GetHitlDetailTryDetailData, GetHitlDetailTryDetailResponse, GetHitlDetailsData, GetHitlDetailsResponse, GetImportErrorData, GetImportErrorResponse, GetImportErrorsData, GetImportErrorsResponse, GetJobsData, GetJobsResponse, GetPluginsData, GetPluginsResponse, ImportErrorsResponse, DeletePoolData, DeletePoolResponse, GetPoolData, GetPoolResponse, PatchPoolData, PatchPoolResponse, GetPoolsData, GetPoolsResponse, PostPoolData, PostPoolResponse, BulkPoolsData, BulkPoolsResponse, GetProvidersData, GetProvidersResponse, GetXcomEntryData, GetXcomEntryResponse, UpdateXcomEntryData, UpdateXcomEntryResponse, DeleteXcomEntryData, DeleteXcomEntryResponse, GetXcomEntriesData, GetXcomEntriesResponse, CreateXcomEntryData, CreateXcomEntryResponse, GetTasksData, GetTasksResponse, GetTaskData, GetTaskResponse, DeleteVariableData, DeleteVariableResponse, GetVariableData, GetVariableResponse, PatchVariableData, PatchVariableResponse, GetVariablesData, GetVariablesResponse, PostVariableData, PostVariableResponse, BulkVariablesData, BulkVariablesResponse, ReparseDagFileData, ReparseDagFileResponse, GetDagVersionData, GetDagVersionResponse, GetDagVersionsData, GetDagVersionsResponse, GetHealthResponse, GetVersionResponse, LoginData, LoginResponse, LogoutResponse, GetAuthMenusResponse, GetCurrentUserInfoResponse, GenerateTokenData, GenerateTokenResponse2, GetPartitionedDagRunsData, GetPartitionedDagRunsResponse, GetPendingPartitionedDagRunData, GetPendingPartitionedDagRunResponse, GetDependenciesData, GetDependenciesResponse, HistoricalMetricsData, HistoricalMetricsResponse, DagStatsResponse2, GetDagRunDeadlinesData, GetDagRunDeadlinesResponse, StructureDataData, StructureDataResponse2, GetDagStructureData, GetDagStructureResponse, GetGridRunsData, GetGridRunsResponse, GetGridTiSummariesData, GetGridTiSummariesResponse, GetGanttDataData, GetGanttDataResponse, GetCalendarData, GetCalendarResponse, ListTeamsData, ListTeamsResponse } from './types.gen'; +import type { GetAssetsData, GetAssetsResponse, GetAssetAliasesData, GetAssetAliasesResponse, GetAssetAliasData, GetAssetAliasResponse, GetAssetEventsData, GetAssetEventsResponse, CreateAssetEventData, CreateAssetEventResponse, MaterializeAssetData, MaterializeAssetResponse, GetAssetQueuedEventsData, GetAssetQueuedEventsResponse, DeleteAssetQueuedEventsData, DeleteAssetQueuedEventsResponse, GetAssetData, GetAssetResponse, GetDagAssetQueuedEventsData, GetDagAssetQueuedEventsResponse, DeleteDagAssetQueuedEventsData, DeleteDagAssetQueuedEventsResponse, GetDagAssetQueuedEventData, GetDagAssetQueuedEventResponse, DeleteDagAssetQueuedEventData, DeleteDagAssetQueuedEventResponse, NextRunAssetsData, NextRunAssetsResponse, ListBackfillsData, ListBackfillsResponse, CreateBackfillData, CreateBackfillResponse, GetBackfillData, GetBackfillResponse, PauseBackfillData, PauseBackfillResponse, UnpauseBackfillData, UnpauseBackfillResponse, CancelBackfillData, CancelBackfillResponse, CreateBackfillDryRunData, CreateBackfillDryRunResponse, ListBackfillsUiData, ListBackfillsUiResponse, DeleteConnectionData, DeleteConnectionResponse, GetConnectionData, GetConnectionResponse, PatchConnectionData, PatchConnectionResponse, GetConnectionsData, GetConnectionsResponse, PostConnectionData, PostConnectionResponse, BulkConnectionsData, BulkConnectionsResponse, TestConnectionData, TestConnectionResponse, CreateDefaultConnectionsResponse, HookMetaDataForTypeData, HookMetaDataForTypeResponse, HookMetaDataResponse, GetDagRunData, GetDagRunResponse, DeleteDagRunData, DeleteDagRunResponse, PatchDagRunData, PatchDagRunResponse, GetUpstreamAssetEventsData, GetUpstreamAssetEventsResponse, ClearDagRunData, ClearDagRunResponse, GetDagRunsData, GetDagRunsResponse, TriggerDagRunData, TriggerDagRunResponse, WaitDagRunUntilFinishedData, WaitDagRunUntilFinishedResponse, GetListDagRunsBatchData, GetListDagRunsBatchResponse, GetDagSourceData, GetDagSourceResponse, GetDagStatsData, GetDagStatsResponse, GetConfigData, GetConfigResponse, GetConfigValueData, GetConfigValueResponse, GetConfigsResponse, ListDagWarningsData, ListDagWarningsResponse, GetDagsData, GetDagsResponse, PatchDagsData, PatchDagsResponse, GetDagData, GetDagResponse, PatchDagData, PatchDagResponse, DeleteDagData, DeleteDagResponse, GetDagDetailsData, GetDagDetailsResponse, FavoriteDagData, FavoriteDagResponse, UnfavoriteDagData, UnfavoriteDagResponse, GetDagTagsData, GetDagTagsResponse, GetDagsUiData, GetDagsUiResponse, GetLatestRunInfoData, GetLatestRunInfoResponse, GetEventLogData, GetEventLogResponse, GetEventLogsData, GetEventLogsResponse, GetExtraLinksData, GetExtraLinksResponse, GetTaskInstanceData, GetTaskInstanceResponse, PatchTaskInstanceData, PatchTaskInstanceResponse, DeleteTaskInstanceData, DeleteTaskInstanceResponse, GetMappedTaskInstancesData, GetMappedTaskInstancesResponse, GetTaskInstanceDependenciesByMapIndexData, GetTaskInstanceDependenciesByMapIndexResponse, GetTaskInstanceDependenciesData, GetTaskInstanceDependenciesResponse, GetTaskInstanceTriesData, GetTaskInstanceTriesResponse, GetMappedTaskInstanceTriesData, GetMappedTaskInstanceTriesResponse, GetMappedTaskInstanceData, GetMappedTaskInstanceResponse, PatchTaskInstanceByMapIndexData, PatchTaskInstanceByMapIndexResponse, GetTaskInstancesData, GetTaskInstancesResponse, BulkTaskInstancesData, BulkTaskInstancesResponse, GetTaskInstancesBatchData, GetTaskInstancesBatchResponse, GetTaskInstanceTryDetailsData, GetTaskInstanceTryDetailsResponse, GetMappedTaskInstanceTryDetailsData, GetMappedTaskInstanceTryDetailsResponse, PostClearTaskInstancesData, PostClearTaskInstancesResponse, PatchTaskInstanceDryRunByMapIndexData, PatchTaskInstanceDryRunByMapIndexResponse, PatchTaskInstanceDryRunData, PatchTaskInstanceDryRunResponse, GetLogData, GetLogResponse, GetExternalLogUrlData, GetExternalLogUrlResponse, UpdateHitlDetailData, UpdateHitlDetailResponse, GetHitlDetailData, GetHitlDetailResponse, GetHitlDetailTryDetailData, GetHitlDetailTryDetailResponse, GetHitlDetailsData, GetHitlDetailsResponse, GetImportErrorData, GetImportErrorResponse, GetImportErrorsData, GetImportErrorsResponse, GetJobsData, GetJobsResponse, GetPluginsData, GetPluginsResponse, ImportErrorsResponse, DeletePoolData, DeletePoolResponse, GetPoolData, GetPoolResponse, PatchPoolData, PatchPoolResponse, GetPoolsData, GetPoolsResponse, PostPoolData, PostPoolResponse, BulkPoolsData, BulkPoolsResponse, GetProvidersData, GetProvidersResponse, GetXcomEntryData, GetXcomEntryResponse, UpdateXcomEntryData, UpdateXcomEntryResponse, DeleteXcomEntryData, DeleteXcomEntryResponse, GetXcomEntriesData, GetXcomEntriesResponse, CreateXcomEntryData, CreateXcomEntryResponse, GetTasksData, GetTasksResponse, GetTaskData, GetTaskResponse, DeleteVariableData, DeleteVariableResponse, GetVariableData, GetVariableResponse, PatchVariableData, PatchVariableResponse, GetVariablesData, GetVariablesResponse, PostVariableData, PostVariableResponse, BulkVariablesData, BulkVariablesResponse, ReparseDagFileData, ReparseDagFileResponse, GetDagVersionData, GetDagVersionResponse, GetDagVersionsData, GetDagVersionsResponse, GetHealthResponse, GetVersionResponse, LoginData, LoginResponse, LogoutResponse, GetAuthMenusResponse, GetCurrentUserInfoResponse, GenerateTokenData, GenerateTokenResponse2, GetPartitionedDagRunsData, GetPartitionedDagRunsResponse, GetPendingPartitionedDagRunData, GetPendingPartitionedDagRunResponse, GetDependenciesData, GetDependenciesResponse, HistoricalMetricsData, HistoricalMetricsResponse, DagStatsResponse2, GetDagRunDeadlinesData, GetDagRunDeadlinesResponse, StructureDataData, StructureDataResponse2, GetDagStructureData, GetDagStructureResponse, GetGridRunsData, GetGridRunsResponse, GetGridTiSummariesData, GetGridTiSummariesResponse, GetGanttDataData, GetGanttDataResponse, GetCalendarData, GetCalendarResponse, ListTeamsData, ListTeamsResponse } from './types.gen'; export class AssetService { /** @@ -811,6 +811,27 @@ export class ConnectionService { }); } + /** + * Hook Meta Data For Type + * Return full metadata (standard_fields, extra_fields) for a single connection type. + * @param data The data for the request. + * @param data.connectionType + * @returns ConnectionHookMetaData Successful Response + * @throws ApiError + */ + public static hookMetaDataForType(data: HookMetaDataForTypeData): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/ui/connections/hook_meta/{connection_type}', + path: { + connection_type: data.connectionType + }, + errors: { + 422: 'Validation Error' + } + }); + } + /** * Hook Meta Data * Retrieve information about available connection types (hook classes) and their parameters. diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts index 038c02ee2cd0b..8d29ad827f5ae 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts @@ -2494,6 +2494,12 @@ export type TestConnectionResponse = ConnectionTestResponse; export type CreateDefaultConnectionsResponse = void; +export type HookMetaDataForTypeData = { + connectionType: string; +}; + +export type HookMetaDataForTypeResponse = ConnectionHookMetaData; + export type HookMetaDataResponse = Array; export type GetDagRunData = { @@ -4489,6 +4495,21 @@ export type $OpenApiTs = { }; }; }; + '/ui/connections/hook_meta/{connection_type}': { + get: { + req: HookMetaDataForTypeData; + res: { + /** + * Successful Response + */ + 200: ConnectionHookMetaData; + /** + * Validation Error + */ + 422: HTTPValidationError; + }; + }; + }; '/ui/connections/hook_meta': { get: { res: { diff --git a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py index a63a171d3ad6c..6427534df0f8c 100644 --- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py +++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py @@ -136,3 +136,32 @@ def test_should_respond_401(self, unauthenticated_test_client): def test_should_respond_403(self, unauthorized_test_client): response = unauthorized_test_client.get("/connections/hook_meta") assert response.status_code == 403 + + +class TestHookMetaDataForType: + @skip_if_force_lowest_dependencies_marker + def test_hook_meta_data_for_type(self, test_client): + response = test_client.get("/connections/hook_meta/fs") + assert response.status_code == 200 + data = response.json() + assert data["connection_type"] == "fs" + assert data["hook_name"] == "File (path)" + + @skip_if_force_lowest_dependencies_marker + def test_hook_meta_data_for_type_generic(self, test_client): + response = test_client.get("/connections/hook_meta/generic") + assert response.status_code == 200 + data = response.json() + assert data["connection_type"] == "generic" + + def test_hook_meta_data_for_type_not_found(self, test_client): + response = test_client.get("/connections/hook_meta/nonexistent_type_xyz") + assert response.status_code == 404 + + def test_hook_meta_data_for_type_401(self, unauthenticated_test_client): + response = unauthenticated_test_client.get("/connections/hook_meta/fs") + assert response.status_code == 401 + + def test_hook_meta_data_for_type_403(self, unauthorized_test_client): + response = unauthorized_test_client.get("/connections/hook_meta/fs") + assert response.status_code == 403