diff --git a/airbyte-webapp-e2e-tests/cypress/integration/connection.spec.ts b/airbyte-webapp-e2e-tests/cypress/integration/connection.spec.ts index 81a0aaa95841b..9050fed19b919 100644 --- a/airbyte-webapp-e2e-tests/cypress/integration/connection.spec.ts +++ b/airbyte-webapp-e2e-tests/cypress/integration/connection.spec.ts @@ -28,7 +28,7 @@ describe("Connection main actions", () => { cy.get("div[data-id='replication-step']").click(); cy.get("div[data-testid='schedule']").click(); - cy.get("div[data-testid='Every 5 minutes']").click(); + cy.get("div[data-testid='Every hour']").click(); cy.get("button[type=submit]").first().click(); cy.wait("@updateConnection"); cy.get("span[data-id='success-result']").should("exist"); diff --git a/airbyte-webapp/src/components/EntityTable/hooks.tsx b/airbyte-webapp/src/components/EntityTable/hooks.tsx index 46d6091d24827..37819f268f987 100644 --- a/airbyte-webapp/src/components/EntityTable/hooks.tsx +++ b/airbyte-webapp/src/components/EntityTable/hooks.tsx @@ -1,4 +1,4 @@ -import { getFrequencyConfig } from "config/utils"; +import { getFrequencyType } from "config/utils"; import { Action, Namespace } from "core/analytics"; import { buildConnectionUpdate } from "core/domain/connection"; import { useAnalyticsService } from "hooks/services/Analytics"; @@ -21,14 +21,12 @@ const useSyncActions = (): { }) ); - const frequency = getFrequencyConfig(connection.schedule); - const enabledStreams = connection.syncCatalog.streams.filter((stream) => stream.config?.selected).length; const trackableAction = connection.status === ConnectionStatus.active ? Action.DISABLE : Action.REENABLE; analyticsService.track(Namespace.CONNECTION, trackableAction, { - frequency: frequency?.type, + frequency: getFrequencyType(connection.schedule), connector_source: connection.source?.sourceName, connector_source_definition_id: connection.source?.sourceDefinitionId, connector_destination: connection.destination?.destinationName, diff --git a/airbyte-webapp/src/config/FrequencyConfig.json b/airbyte-webapp/src/config/FrequencyConfig.json deleted file mode 100644 index 491c96d876c41..0000000000000 --- a/airbyte-webapp/src/config/FrequencyConfig.json +++ /dev/null @@ -1,76 +0,0 @@ -[ - { - "type": "manual", - "config": null - }, - { - "type": "5 min", - "config": { - "units": 5, - "timeUnit": "minutes" - } - }, - { - "type": "15 min", - "config": { - "units": 15, - "timeUnit": "minutes" - } - }, - { - "type": "30 min", - "config": { - "units": 30, - "timeUnit": "minutes" - } - }, - { - "type": "1 hour", - "config": { - "units": 1, - "timeUnit": "hours" - } - }, - { - "type": "2 hours", - "config": { - "units": 2, - "timeUnit": "hours" - } - }, - { - "type": "3 hours", - "config": { - "units": 3, - "timeUnit": "hours" - } - }, - { - "type": "6 hours", - "config": { - "units": 6, - "timeUnit": "hours" - } - }, - { - "type": "8 hours", - "config": { - "units": 8, - "timeUnit": "hours" - } - }, - { - "type": "12 hours", - "config": { - "units": 12, - "timeUnit": "hours" - } - }, - { - "type": "24 hours", - "config": { - "units": 24, - "timeUnit": "hours" - } - } -] diff --git a/airbyte-webapp/src/config/frequencyConfig.ts b/airbyte-webapp/src/config/frequencyConfig.ts new file mode 100644 index 0000000000000..9cfc913e1ed6e --- /dev/null +++ b/airbyte-webapp/src/config/frequencyConfig.ts @@ -0,0 +1,33 @@ +import { ConnectionSchedule } from "core/request/AirbyteClient"; + +export const frequencyConfig: Array = [ + null, // manual + { + units: 1, + timeUnit: "hours", + }, + { + units: 2, + timeUnit: "hours", + }, + { + units: 3, + timeUnit: "hours", + }, + { + units: 6, + timeUnit: "hours", + }, + { + units: 8, + timeUnit: "hours", + }, + { + units: 12, + timeUnit: "hours", + }, + { + units: 24, + timeUnit: "hours", + }, +]; diff --git a/airbyte-webapp/src/config/utils.ts b/airbyte-webapp/src/config/utils.ts index 6699f864bd230..46dec71bada37 100644 --- a/airbyte-webapp/src/config/utils.ts +++ b/airbyte-webapp/src/config/utils.ts @@ -1,6 +1,4 @@ -import FrequencyConfig from "config/FrequencyConfig.json"; import { ConnectionSchedule } from "core/request/AirbyteClient"; -import { equal } from "utils/objects"; -export const getFrequencyConfig = (schedule?: ConnectionSchedule) => - FrequencyConfig.find((item) => (!schedule && !item.config) || equal(item.config, schedule)); +export const getFrequencyType = (schedule?: ConnectionSchedule) => + schedule ? `${schedule.units} ${schedule.timeUnit}` : "manual"; diff --git a/airbyte-webapp/src/hooks/services/useConnectionHook.tsx b/airbyte-webapp/src/hooks/services/useConnectionHook.tsx index 9e2c640f624b6..e0db3dbbc7482 100644 --- a/airbyte-webapp/src/hooks/services/useConnectionHook.tsx +++ b/airbyte-webapp/src/hooks/services/useConnectionHook.tsx @@ -1,6 +1,6 @@ import { QueryClient, useMutation, useQueryClient } from "react-query"; -import { getFrequencyConfig } from "config/utils"; +import { getFrequencyType } from "config/utils"; import { Action, Namespace } from "core/analytics"; import { SyncSchema } from "core/domain/catalog"; import { WebBackendConnectionService } from "core/domain/connection"; @@ -92,15 +92,13 @@ export const useSyncConnection = () => { const analyticsService = useAnalyticsService(); return useMutation((connection: WebBackendConnectionRead) => { - const frequency = getFrequencyConfig(connection.schedule); - analyticsService.track(Namespace.CONNECTION, Action.SYNC, { actionDescription: "Manual triggered sync", connector_source: connection.source?.sourceName, connector_source_definition_id: connection.source?.sourceDefinitionId, connector_destination: connection.destination?.destinationName, connector_destination_definition_id: connection.destination?.destinationDefinitionId, - frequency: frequency?.type, + frequency: getFrequencyType(connection.schedule), }); return service.sync(connection.connectionId); @@ -143,11 +141,9 @@ const useCreateConnection = () => { const enabledStreams = values.syncCatalog.streams.filter((stream) => stream.config?.selected).length; - const frequencyData = getFrequencyConfig(values.schedule); - analyticsService.track(Namespace.CONNECTION, Action.CREATE, { actionDescription: "New connection created", - frequency: frequencyData?.type || "", + frequency: getFrequencyType(values.schedule), connector_source_definition: source?.sourceName, connector_source_definition_id: sourceDefinition?.sourceDefinitionId, connector_destination_definition: destination?.destinationName, diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx index bfd9fb03dddb5..10467d09d9ba8 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionItemPage.tsx @@ -4,7 +4,7 @@ import { Navigate, Route, Routes, useParams } from "react-router-dom"; import { LoadingPage, MainPageWithScroll } from "components"; import HeadTitle from "components/HeadTitle"; -import { getFrequencyConfig } from "config/utils"; +import { getFrequencyType } from "config/utils"; import { Action, Namespace } from "core/analytics"; import { ConnectionStatus } from "core/request/AirbyteClient"; import { useAnalyticsService } from "hooks/services/Analytics"; @@ -30,8 +30,6 @@ const ConnectionItemPage: React.FC = () => { const { source, destination } = connection; - const frequency = getFrequencyConfig(connection.schedule); - const onAfterSaveSchema = () => { analyticsService.track(Namespace.CONNECTION, Action.EDIT_SCHEMA, { actionDescription: "Connection saved with catalog changes", @@ -39,7 +37,7 @@ const ConnectionItemPage: React.FC = () => { connector_source_definition_id: source.sourceDefinitionId, connector_destination: destination.destinationName, connector_destination_definition_id: destination.destinationDefinitionId, - frequency: frequency?.type, + frequency: getFrequencyType(connection.schedule), }); }; diff --git a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/components/StatusMainInfo.tsx b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/components/StatusMainInfo.tsx index 66c67affbae27..2c48279a42a1f 100644 --- a/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/components/StatusMainInfo.tsx +++ b/airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/components/StatusMainInfo.tsx @@ -5,7 +5,7 @@ import { Link } from "react-router-dom"; import ConnectorCard from "components/ConnectorCard"; -import { getFrequencyConfig } from "config/utils"; +import { getFrequencyType } from "config/utils"; import { ConnectionStatus, SourceRead, DestinationRead, WebBackendConnectionRead } from "core/request/AirbyteClient"; import { FeatureItem, useFeature } from "hooks/services/Feature"; import { RoutePaths } from "pages/routePaths"; @@ -32,7 +32,6 @@ export const StatusMainInfo: React.FC = ({ const destinationDefinition = useDestinationDefinition(destination.destinationDefinitionId); const allowSync = useFeature(FeatureItem.AllowSync); - const frequency = getFrequencyConfig(connection.schedule); const sourceConnectionPath = `../../${RoutePaths.Source}/${source.sourceId}`; const destinationConnectionPath = `../../${RoutePaths.Destination}/${destination.destinationId}`; @@ -64,7 +63,7 @@ export const StatusMainInfo: React.FC = ({ onStatusUpdating={onStatusUpdating} disabled={!allowSync} connection={connection} - frequencyType={frequency?.type} + frequencyType={getFrequencyType(connection.schedule)} /> )} diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionForm.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionForm.tsx index 63b6b0a0e6949..f3cb2d553b8e5 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionForm.tsx +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionForm.tsx @@ -185,7 +185,7 @@ const ConnectionForm: React.FC = ({ ); const errorMessage = submitError ? createFormErrorMessage(submitError) : null; - const frequencies = useFrequencyDropdownData(); + const frequencies = useFrequencyDropdownData(connection.schedule); return ( { + it("should return only default frequencies when no additional frequency is provided", () => { + const { result } = renderHook(() => useFrequencyDropdownData(undefined), { wrapper }); + expect(result.current.map((item) => item.value)).toEqual(frequencyConfig); + }); + + it("should return only default frequencies when additional frequency is already present", () => { + const additionalFrequency = { + units: 1, + timeUnit: ConnectionScheduleTimeUnit["hours"], + }; + const { result } = renderHook(() => useFrequencyDropdownData(additionalFrequency), { wrapper }); + expect(result.current.map((item) => item.value)).toEqual(frequencyConfig); + }); + + it("should include additional frequency when provided and unique", () => { + const additionalFrequency = { + units: 7, + timeUnit: ConnectionScheduleTimeUnit["minutes"], + }; + const { result } = renderHook(() => useFrequencyDropdownData(additionalFrequency), { wrapper }); + + expect(result.current.length).toEqual(frequencyConfig.length + 1); + expect(result.current).toContainEqual({ label: "Every 7 minutes", value: { units: 7, timeUnit: "minutes" } }); + }); +}); diff --git a/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx b/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx index 2e6f6e3e568fc..5c500f6d0fba4 100644 --- a/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx +++ b/airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx @@ -4,7 +4,7 @@ import * as yup from "yup"; import { DropDownRow } from "components"; -import FrequencyConfig from "config/FrequencyConfig.json"; +import { frequencyConfig } from "config/frequencyConfig"; import { SyncSchema } from "core/domain/catalog"; import { isDbtTransformation, @@ -254,24 +254,35 @@ const useInitialValues = ( }, [initialSchema, connection, isEditMode, destDefinition]); }; -const useFrequencyDropdownData = (): DropDownRow.IDataItem[] => { +const useFrequencyDropdownData = ( + additionalFrequency: WebBackendConnectionRead["schedule"] +): DropDownRow.IDataItem[] => { const { formatMessage } = useIntl(); - return useMemo( - () => - FrequencyConfig.map((item) => ({ - value: item.config, - label: item.config - ? formatMessage( - { - id: `form.every.${item.config.timeUnit}`, - }, - { value: item.config.units } - ) - : formatMessage({ id: "frequency.manual" }), - })), - [formatMessage] - ); + return useMemo(() => { + const frequencies = [...frequencyConfig]; + if (additionalFrequency) { + const additionalFreqAlreadyPresent = frequencies.some( + (frequency) => + frequency?.timeUnit === additionalFrequency.timeUnit && frequency?.units === additionalFrequency.units + ); + if (!additionalFreqAlreadyPresent) { + frequencies.push(additionalFrequency); + } + } + + return frequencies.map((frequency) => ({ + value: frequency, + label: frequency + ? formatMessage( + { + id: `form.every.${frequency.timeUnit}`, + }, + { value: frequency.units } + ) + : formatMessage({ id: "frequency.manual" }), + })); + }, [formatMessage, additionalFrequency]); }; export type { ConnectionFormValues, FormikConnectionFormValues };