Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix enabling connection in refresh catalog mode #4527

Merged
merged 3 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 17 additions & 35 deletions airbyte-webapp/src/components/hooks/services/useConnectionHook.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useCallback, useEffect, useState } from "react";
import { useFetcher, useResource } from "rest-hooks";
import { useCallback } from "react";
import { useResource, useFetcher } from "rest-hooks";

import config from "config";
import FrequencyConfig from "config/FrequencyConfig.json";

import { AnalyticsService } from "core/analytics/AnalyticsService";
import { connectionService, Connection } from "core/domain/connection";

import ConnectionResource, {
Connection,
ScheduleProperties,
} from "core/resources/Connection";
import { SyncSchema } from "core/domain/catalog";
import { SourceDefinition } from "core/resources/SourceDefinition";
import FrequencyConfig from "config/FrequencyConfig.json";
import { Source } from "core/resources/Source";
import { Routes } from "pages/routes";
import useRouter from "../useRouterHook";
Expand Down Expand Up @@ -58,44 +60,25 @@ type UpdateStateConnection = {
sourceName: string;
prefix: string;
connectionConfiguration: ConnectionConfiguration;
schedule: {
units: number;
timeUnit: string;
} | null;
schedule: ScheduleProperties | null;
};

export const useConnectionLoad = (
connectionId: string,
withRefresh?: boolean
): { connection: Connection | null; isLoadingConnection: boolean } => {
const [connection, setConnection] = useState<null | Connection>(null);
const [isLoadingConnection, setIsLoadingConnection] = useState(false);

// TODO: change to useStatefulResource
const fetchConnection = useFetcher(ConnectionResource.detailShape(), false);
const baseConnection = useResource(ConnectionResource.detailShape(), {
connectionId: string
): {
connection: Connection;
refreshConnectionCatalog: () => Promise<Connection>;
} => {
const connection = useResource(ConnectionResource.detailShape(), {
connectionId,
});

useEffect(() => {
(async () => {
if (withRefresh) {
setIsLoadingConnection(true);
setConnection(
await fetchConnection({
connectionId,
withRefreshedCatalog: withRefresh,
})
);

setIsLoadingConnection(false);
}
})();
}, [connectionId, fetchConnection, withRefresh]);
const refreshConnectionCatalog = async () =>
await connectionService.getConnection(connectionId, true);

return {
connection: withRefresh ? connection : baseConnection,
isLoadingConnection,
connection,
refreshConnectionCatalog,
};
};

Expand Down Expand Up @@ -155,7 +138,6 @@ const useConnection = (): {
);

AnalyticsService.track("New Connection - Action", {
user_id: config.ui.workspaceId,
action: "Set up connection",
frequency: frequencyData?.text,
connector_source_definition: source?.sourceName,
Expand Down
22 changes: 22 additions & 0 deletions airbyte-webapp/src/core/domain/connection/ConnectionService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AirbyteRequestService } from "core/request/AirbyteRequestService";
import { Connection } from "./types";

class ConnectionService extends AirbyteRequestService {
get url() {
return "web_backend/connections";
}

public async getConnection(
connectionId: string,
withRefreshedCatalog?: boolean
): Promise<Connection> {
const rs = ((await this.fetch(`${this.url}/get`, {
connectionId,
withRefreshedCatalog,
})) as any) as Connection;

return rs;
}
}

export const connectionService = new ConnectionService();
3 changes: 3 additions & 0 deletions airbyte-webapp/src/core/domain/connection/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export * from "./types";
export * from "./operation";
export * from "./ConnectionService";
export * from "./OperationService";
32 changes: 32 additions & 0 deletions airbyte-webapp/src/core/domain/connection/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { SyncSchema } from "core/domain/catalog";
import { Source } from "core/resources/Source";
import { Destination } from "core/resources/Destination";
import { Operation } from "./operation";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ConnectionConfiguration = any;

Expand All @@ -14,3 +19,30 @@ export enum ConnectionNamespaceDefinition {
Destination = "destination",
CustomFormat = "customformat",
}

export type ScheduleProperties = {
units: number;
timeUnit: string;
};

export interface Connection {
connectionId: string;
name: string;
prefix: string;
sourceId: string;
destinationId: string;
status: string;
schedule: ScheduleProperties | null;
syncCatalog: SyncSchema;
latestSyncJobCreatedAt?: number | null;
namespaceDefinition: ConnectionNamespaceDefinition;
namespaceFormat: string;
isSyncing?: boolean;
latestSyncJobStatus: string | null;
operationIds: string[];

// WebBackend connection specific fields
source: Source;
destination: Destination;
operations: Operation[];
}
43 changes: 10 additions & 33 deletions airbyte-webapp/src/core/resources/Connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,18 @@ import {

import { SyncSchema } from "core/domain/catalog";
import { CommonRequestError } from "core/request/CommonRequestError";
import { Operation } from "core/domain/connection/operation";
import { Source } from "./Source";
import { Destination } from "./Destination";

import BaseResource from "./BaseResource";
import { ConnectionNamespaceDefinition } from "../domain/connection";

export type ScheduleProperties = {
units: number;
timeUnit: string;
};

export interface Connection {
connectionId: string;
name: string;
prefix: string;
sourceId: string;
destinationId: string;
status: string;
schedule: ScheduleProperties | null;
syncCatalog: SyncSchema;
latestSyncJobCreatedAt?: number | null;
namespaceDefinition: ConnectionNamespaceDefinition;
namespaceFormat: string;
isSyncing?: boolean;
latestSyncJobStatus: string | null;
operationIds: string[];

// WebBackend connection specific fields
source: Source;
destination: Destination;
operations: Operation[];
}
import {
ConnectionNamespaceDefinition,
Connection,
ScheduleProperties,
Operation,
} from "core/domain/connection";

export type { Connection, ScheduleProperties };

export default class ConnectionResource
extends BaseResource
Expand Down Expand Up @@ -83,10 +62,8 @@ export default class ConnectionResource
): ReadShape<SchemaDetail<Connection>> {
return {
...super.detailShape(),
getFetchKey: (params: {
connectionId: string;
withRefreshedCatalog?: boolean;
}) => "POST /web_backend/get" + JSON.stringify(params),
getFetchKey: (params: { connectionId: string }) =>
"POST /web_backend/get" + JSON.stringify(params),
fetch: async (
params: Readonly<Record<string, unknown>>
): Promise<Connection> =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ const Content = styled.div`

type IProps = {
connection: Connection;
disabled?: boolean;
frequencyText?: string;
};

const EnabledControl: React.FC<IProps> = ({ connection, frequencyText }) => {
const EnabledControl: React.FC<IProps> = ({
connection,
disabled,
frequencyText,
}) => {
const { updateConnection } = useConnection();

const onChangeStatus = async () => {
Expand All @@ -48,7 +53,7 @@ const EnabledControl: React.FC<IProps> = ({ connection, frequencyText }) => {

AnalyticsService.track("Source - Action", {
action:
connection.status === "active"
connection.status === Status.ACTIVE
? "Disable connection"
: "Reenable connection",
connector_source: connection.source?.sourceName,
Expand All @@ -65,15 +70,16 @@ const EnabledControl: React.FC<IProps> = ({ connection, frequencyText }) => {
<ToggleLabel htmlFor="toggle-enabled-source">
<FormattedMessage
id={
connection.status === "active"
connection.status === Status.ACTIVE
? "tables.enabled"
: "tables.disabled"
}
/>
</ToggleLabel>
<Toggle
disabled={disabled}
onChange={onChangeStatus}
checked={connection.status === "active"}
checked={connection.status === Status.ACTIVE}
id="toggle-enabled-source"
/>
</Content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { SourceDefinition } from "core/resources/SourceDefinition";
import { equal } from "utils/objects";
import EnabledControl from "./EnabledControl";
import { ConnectionNamespaceDefinition } from "core/domain/connection";
import { useAsyncFn } from "react-use";

type IProps = {
onAfterSaveSchema: () => void;
Expand Down Expand Up @@ -86,17 +87,13 @@ const SettingsView: React.FC<IProps> = ({
prefix: "",
syncCatalog: { streams: [] },
});

const {
updateConnection,
deleteConnection,
resetConnection,
} = useConnection();

const { connection, isLoadingConnection } = useConnectionLoad(
connectionId,
activeUpdatingSchemaMode
);

const onDelete = useCallback(() => deleteConnection({ connectionId }), [
deleteConnection,
connectionId,
Expand All @@ -107,13 +104,27 @@ const SettingsView: React.FC<IProps> = ({
connectionId,
]);

const {
connection: initialConnection,
refreshConnectionCatalog,
} = useConnectionLoad(connectionId);

const [
{ value: connectionWithRefreshCatalog, loading: isRefreshingCatalog },
refreshCatalog,
] = useAsyncFn(refreshConnectionCatalog, [connectionId]);

const connection = activeUpdatingSchemaMode
? connectionWithRefreshCatalog
: initialConnection;

const onSubmit = async (values: ValuesProps) => {
const initialSyncSchema = connection?.syncCatalog;

await updateConnection({
...values,
connectionId: connectionId,
status: connection?.status || "",
connectionId,
status: initialConnection.status || "",
withRefreshedCatalog: activeUpdatingSchemaMode,
});

Expand Down Expand Up @@ -141,10 +152,19 @@ const SettingsView: React.FC<IProps> = ({
}
};

const UpdateSchemaButton = () => {
const onEnterRefreshCatalogMode = async () => {
setActiveUpdatingSchemaMode(true);
await refreshCatalog();
};

const onExitRefreshCatalogMode = () => {
setActiveUpdatingSchemaMode(false);
};

const renderUpdateSchemaButton = () => {
if (!activeUpdatingSchemaMode) {
return (
<Button onClick={() => setActiveUpdatingSchemaMode(true)} type="button">
<Button onClick={onEnterRefreshCatalogMode} type="button">
<TryArrow icon={faRedoAlt} />
<FormattedMessage id="connection.updateSchema" />
</Button>
Expand All @@ -168,16 +188,15 @@ const SettingsView: React.FC<IProps> = ({
<TitleContainer hasButton={!activeUpdatingSchemaMode}>
<FormattedMessage id="connection.connectionSettings" />{" "}
</TitleContainer>
{connection && (
<EnabledControl
connection={connection}
frequencyText={frequencyText}
/>
)}
<EnabledControl
disabled={isRefreshingCatalog}
connection={initialConnection}
frequencyText={frequencyText}
/>
</Title>
}
>
{!isLoadingConnection && connection ? (
{!isRefreshingCatalog && connection ? (
<ConnectionForm
isEditMode
connection={connection}
Expand All @@ -186,9 +205,9 @@ const SettingsView: React.FC<IProps> = ({
successMessage={
saved && <FormattedMessage id="form.changesSaved" />
}
onCancel={() => setActiveUpdatingSchemaMode(false)}
onCancel={onExitRefreshCatalogMode}
editSchemeMode={activeUpdatingSchemaMode}
additionalSchemaControl={UpdateSchemaButton()}
additionalSchemaControl={renderUpdateSchemaButton()}
destinationIcon={destinationDefinition?.icon}
sourceIcon={sourceDefinition?.icon}
/>
Expand Down