Skip to content

Commit

Permalink
implement oauth in UI (airbytehq#6385)
Browse files Browse the repository at this point in the history
* Implement auth

* Implement auth

* Fix wrong changes

* Place authenticate button in the proper place

* Finish oauth implementation

* Temporary ignore test

* Fix stories

* Fix react-widgets UI

* Remove unnecessary mock

* Add support for oneOf case

* Temporary disable test

* Fix path

* Fix lock file

* Do not flush values on auth

* Apply last auth changes

* Move button within section

* Leave comment about dirty tricks

* Call WebBackend endpoints for create instead of core one
  • Loading branch information
jamakase authored Sep 30, 2021
1 parent 8ed5eea commit 37542c0
Show file tree
Hide file tree
Showing 57 changed files with 3,387 additions and 749 deletions.
Binary file added airbyte-webapp/.storybook/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions airbyte-webapp/.storybook/manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { addons } from "@storybook/addons";
import theme from "./theme";

addons.setConfig({
panelPosition: "bottom",
theme
});
8 changes: 8 additions & 0 deletions airbyte-webapp/.storybook/theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { create } from "@storybook/theming/create";
import Image from "./logo.png";

export default create({
brandTitle: "Airbyte",
brandUrl: "https://airbyte.com",
brandImage: Image,
});
21 changes: 15 additions & 6 deletions airbyte-webapp/.storybook/withProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ThemeProvider } from "styled-components";
import { theme, Theme } from "../src/theme";
import GlobalStyle from "../src/global-styles";
import messages from "../src/locales/en.json";
import { FeatureService } from "../src/hooks/services/Feature";
import { ConfigServiceProvider, defaultConfig } from "../src/config";

interface Props {
theme?: Theme;
Expand All @@ -24,12 +26,19 @@ class WithProviders extends React.Component<Props> {

return (
<Router history={createMemoryHistory()}>
<IntlProvider messages={messages} locale={"en"}>
<ThemeProvider theme={theme}>
<GlobalStyle />
{children}
</ThemeProvider>
</IntlProvider>
<FeatureService>
<IntlProvider messages={messages} locale={"en"}>
<ThemeProvider theme={theme}>
<ConfigServiceProvider
defaultConfig={defaultConfig}
providers={[]}
>
<GlobalStyle />
{children}
</ConfigServiceProvider>
</ThemeProvider>
</IntlProvider>
</FeatureService>
</Router>
);
}
Expand Down
2,915 changes: 2,363 additions & 552 deletions airbyte-webapp/package-lock.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions airbyte-webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
"@rest-hooks/legacy": "^2.0.5",
"@sentry/react": "^6.11.0",
"@sentry/tracing": "^6.11.0",
"@storybook/preset-create-react-app": "^3.2.0",
"@storybook/react": "^6.3.2",
"dayjs": "^1.8.35",
"firebase": "^9.0.1",
"flat": "^5.0.2",
Expand Down Expand Up @@ -57,6 +55,7 @@
"@storybook/addon-essentials": "^6.3.6",
"@storybook/preset-create-react-app": "^3.2.0",
"@storybook/react": "^6.3.2",
"@storybook/theming": "^6.3.8",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/react-hooks": "^7.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react";
import ContentCard from "./ContentCard";

export default {
title: "Example/ContentCard",
title: "Ui/ContentCard",
component: ContentCard,
} as ComponentMeta<typeof ContentCard>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react";
import Button from "./Button";

export default {
title: "Example/Button",
title: "Ui/Button",
component: Button,
argTypes: {
backgroundColor: { control: "color" },
Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/components/base/Card/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Card } from "./Card";

export default {
title: "Example/Card",
title: "Ui/Card",
component: Card,
} as ComponentMeta<typeof Card>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Multiselect as ReactMultiselect } from "react-widgets";
import styled from "styled-components";
import { MultiselectProps as WidgetMultiselectProps } from "react-widgets/lib/Multiselect";
import "react-widgets/dist/css/react-widgets.css";

type MultiselectProps = {
disabled?: boolean;
Expand Down
7 changes: 4 additions & 3 deletions airbyte-webapp/src/config/ConfigServiceProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ export function useConfig<T extends Config>(): T {

const ConfigServiceInner: React.FC<{
defaultConfig: Config;
providers: ValueProvider<Config>;
providers?: ValueProvider<Config>;
}> = ({ children, defaultConfig, providers }) => {
const { loading, value } = useAsync(
async () => applyProviders(defaultConfig, providers),
async () =>
providers ? applyProviders(defaultConfig, providers) : defaultConfig,
[providers]
);
const config: ConfigContext | null = useMemo(
Expand All @@ -38,7 +39,7 @@ const ConfigServiceInner: React.FC<{
);
return (
<configContext.Provider value={config}>
{loading ? <LoadingPage /> : children}
{loading && providers ? <LoadingPage /> : children}
</configContext.Provider>
);
};
Expand Down
1 change: 1 addition & 0 deletions airbyte-webapp/src/config/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const defaultConfig: Config = {
},
version: "",
apiUrl: `${window.location.protocol}//${window.location.hostname}:8001/api/v1/`,
oauthRedirectUrl: `${window.location.protocol}//${window.location.host}`,
isDemo: false,
};

Expand Down
1 change: 1 addition & 0 deletions airbyte-webapp/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type Config = {
openreplay: OpenReplayOptions;
fullstory: Fullstory.SnippetOptions;
apiUrl: string;
oauthRedirectUrl: string;
healthCheckInterval: number;
isDemo: boolean;
version?: string;
Expand Down
10 changes: 3 additions & 7 deletions airbyte-webapp/src/core/domain/connection/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@ import { SyncSchema } from "core/domain/catalog";
import { Source } from "core/resources/Source";
import { Destination } from "core/resources/Destination";
import { Operation } from "./operation";
import { AirbyteJSONSchema } from "core/jsonSchema";

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

type ConnectionSpecification = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
properties: any;
required: string[];
};
type ConnectionSpecification = AirbyteJSONSchema;

export type { ConnectionConfiguration, ConnectionSpecification };

Expand Down
30 changes: 30 additions & 0 deletions airbyte-webapp/src/core/domain/connector/DestinationAuthService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { AirbyteRequestService } from "core/request/AirbyteRequestService";
import { DestinationGetConsentPayload } from "./types";

class DestinationAuthService extends AirbyteRequestService {
get url(): string {
return "destination_oauths";
}

public getConsentUrl(
body: DestinationGetConsentPayload
): Promise<{ consentUrl: string }> {
return this.fetch<{ consentUrl: string }>(
`${this.url}/get_consent_url`,
body
);
}

public completeOauth(
body: DestinationGetConsentPayload & {
queryParams: Record<string, unknown>;
}
): Promise<Record<string, unknown>> {
return this.fetch<Record<string, unknown>>(
`${this.url}/complete_oauth`,
body
);
}
}

export { DestinationAuthService };
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { AirbyteRequestService } from "core/request/AirbyteRequestService";
import { DestinationDefinition } from "core/resources/DestinationDefinition";

class DestinationDefinitionService extends AirbyteRequestService {
get url() {
get url(): string {
return "destination_definitions";
}

public update(body: DestinationDefinition): Promise<DestinationDefinition> {
return this.fetch(`${this.url}/update`, body) as any;
return this.fetch<DestinationDefinition>(`${this.url}/update`, body);
}
}

Expand Down
30 changes: 30 additions & 0 deletions airbyte-webapp/src/core/domain/connector/SourceAuthService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { AirbyteRequestService } from "core/request/AirbyteRequestService";
import { SourceGetConsentPayload } from "./types";

class SourceAuthService extends AirbyteRequestService {
get url(): string {
return "source_oauths";
}

public getConsentUrl(
body: SourceGetConsentPayload
): Promise<{ consentUrl: string }> {
return this.fetch<{ consentUrl: string }>(
`${this.url}/get_consent_url`,
body
);
}

public completeOauth(
body: SourceGetConsentPayload & {
queryParams: Record<string, unknown>;
}
): Promise<Record<string, unknown>> {
return this.fetch<Record<string, unknown>>(
`${this.url}/complete_oauth`,
body
);
}
}

export { SourceAuthService };
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { AirbyteRequestService } from "core/request/AirbyteRequestService";
import { SourceDefinition } from "core/resources/SourceDefinition";

class SourceDefinitionService extends AirbyteRequestService {
get url() {
get url(): string {
return "source_definitions";
}

public update(body: SourceDefinition): Promise<SourceDefinition> {
return this.fetch(`${this.url}/update`, body) as any;
return this.fetch<SourceDefinition>(`${this.url}/update`, body);
}
}

Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/core/domain/connector/SourceService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AirbyteRequestService } from "core/request/AirbyteRequestService";

class SourceService extends AirbyteRequestService {
get url() {
get url(): string {
return "sources";
}
}
Expand Down
19 changes: 10 additions & 9 deletions airbyte-webapp/src/core/domain/connector/connector.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import { SourceDefinition } from "core/resources/SourceDefinition";
import { DestinationDefinition } from "core/resources/DestinationDefinition";
import { isSourceDefinition } from "./source";

export type ConnectorDefinition = SourceDefinition | DestinationDefinition;

export function isConnectorDeprecated(connector: ConnectorDefinition): boolean {
return !connector.latestDockerImageTag;
}
import { isSourceDefinition, isSourceDefinitionSpecification } from "./source";
import { ConnectorDefinition, ConnectorDefinitionSpecification } from "./types";

export class Connector {
static id(connector: ConnectorDefinition): string {
Expand All @@ -26,3 +19,11 @@ export class Connector {
);
}
}

export class ConnectorSpecification {
static id(connector: ConnectorDefinitionSpecification): string {
return isSourceDefinitionSpecification(connector)
? connector.sourceDefinitionId
: connector.destinationDefinitionId;
}
}
1 change: 1 addition & 0 deletions airbyte-webapp/src/core/domain/connector/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./connector";
export * from "./types";
15 changes: 14 additions & 1 deletion airbyte-webapp/src/core/domain/connector/source.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { SourceDefinition } from "core/resources/SourceDefinition";
import { ConnectorDefinition } from "./connector";
import {
ConnectorDefinition,
ConnectorDefinitionSpecification,
SourceDefinitionSpecification,
} from "./types";

export function isSourceDefinition(
connector: ConnectorDefinition
): connector is SourceDefinition {
return (connector as SourceDefinition).sourceDefinitionId !== undefined;
}

export function isSourceDefinitionSpecification(
connector: ConnectorDefinitionSpecification
): connector is SourceDefinitionSpecification {
return (
(connector as SourceDefinitionSpecification).sourceDefinitionId !==
undefined
);
}

// eslint-disable-next-line no-template-curly-in-string
export const SOURCE_NAMESPACE_TAG = "${SOURCE_NAMESPACE}";
48 changes: 48 additions & 0 deletions airbyte-webapp/src/core/domain/connector/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ConnectionSpecification } from "core/domain/connection";
import { DestinationSyncMode } from "core/domain/catalog";
import { SourceDefinition } from "core/resources/SourceDefinition";
import { DestinationDefinition } from "core/resources/DestinationDefinition";

export type ConnectorDefinition = SourceDefinition | DestinationDefinition;

interface ConnectorDefinitionSpecificationBase {
connectionSpecification: ConnectionSpecification;
documentationUrl: string;
authSpecification?: {
type: "oauth2.0";
oauth2Specification: {
rootObject?: string[];
oauthFlowInitParameters?: string[][];
oauthFlowOutputParameters?: string[][];
};
};
}

export type ConnectorDefinitionSpecification =
| DestinationDefinitionSpecification
| SourceDefinitionSpecification;

export interface DestinationDefinitionSpecification
extends ConnectorDefinitionSpecificationBase {
destinationDefinitionId: string;
supportedDestinationSyncModes: DestinationSyncMode[];
supportsDbt: boolean;
supportsNormalization: boolean;
}

export interface SourceDefinitionSpecification
extends ConnectorDefinitionSpecificationBase {
sourceDefinitionId: string;
}

export interface SourceGetConsentPayload {
redirectUrl: string;
sourceDefinitionId: string;
workspaceId: string;
}

export interface DestinationGetConsentPayload {
redirectUrl: string;
destinationDefinitionId: string;
workspaceId: string;
}
3 changes: 3 additions & 0 deletions airbyte-webapp/src/core/form/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ type FormItem = {
order?: number;
title?: string;
description?: string;

airbyte_hidden?: boolean;
};

export type FormBaseItem = {
Expand All @@ -23,6 +25,7 @@ type FormGroupItem = {
jsonSchema: AirbyteJSONSchema;
properties: FormBlock[];
isLoading?: boolean;
hasOauth?: boolean;
default?: JSONSchema7Type;
examples?: JSONSchema7Type;
} & FormItem;
Expand Down
1 change: 1 addition & 0 deletions airbyte-webapp/src/core/jsonSchema/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./types";
export * from "./schemaToUiWidget";
export * from "./schemaToYup";
export * from "./utils";
Loading

0 comments on commit 37542c0

Please sign in to comment.