Skip to content

Commit af22211

Browse files
committed
Merge branch 'master' into grubberr/11566-source-github-reviews
2 parents b81e8a1 + 39107bf commit af22211

File tree

29 files changed

+290
-211
lines changed

29 files changed

+290
-211
lines changed

airbyte-config/init/src/main/resources/seed/destination_definitions.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@
203203
- name: S3
204204
destinationDefinitionId: 4816b78f-1489-44c1-9060-4b19d5fa9362
205205
dockerRepository: airbyte/destination-s3
206-
dockerImageTag: 0.2.12
206+
dockerImageTag: 0.2.13
207207
documentationUrl: https://docs.airbyte.io/integrations/destinations/s3
208208
icon: s3.svg
209209
resourceRequirements:

airbyte-config/init/src/main/resources/seed/destination_specs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3469,7 +3469,7 @@
34693469
supported_destination_sync_modes:
34703470
- "append"
34713471
- "overwrite"
3472-
- dockerImage: "airbyte/destination-s3:0.2.12"
3472+
- dockerImage: "airbyte/destination-s3:0.2.13"
34733473
spec:
34743474
documentationUrl: "https://docs.airbyte.io/integrations/destinations/s3"
34753475
connectionSpecification:

airbyte-webapp/src/config/ConfigServiceProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type ConfigContext<T extends Config = Config> = {
1010
config: T;
1111
};
1212

13-
const configContext = React.createContext<ConfigContext | null>(null);
13+
export const configContext = React.createContext<ConfigContext | null>(null);
1414

1515
export function useConfig<T extends Config>(): T {
1616
const configService = useContext(configContext);

airbyte-webapp/src/core/domain/catalog/api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export type SyncSchemaStream = {
2828
stream: AirbyteStream;
2929
config: AirbyteStreamConfiguration;
3030

31+
/**
32+
* This field is not returned from API and is used to track unique objects
33+
*/
3134
id: string;
3235
};
3336

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { AirbyteRequestService } from "core/request/AirbyteRequestService";
2+
import { NotificationStatus } from "./types";
3+
4+
class NotificationService extends AirbyteRequestService {
5+
get url(): string {
6+
return "notifications";
7+
}
8+
9+
public try(payload: {
10+
notificationType: "slack";
11+
sendOnSuccess: boolean;
12+
sendOnFailure: boolean;
13+
slackConfiguration: {
14+
webhook: string;
15+
};
16+
}): Promise<NotificationStatus> {
17+
return this.fetch<NotificationStatus>(`${this.url}/try`, payload);
18+
}
19+
}
20+
21+
export { NotificationService };
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface NotificationStatus {
2+
status: string;
3+
message: string;
4+
}

airbyte-webapp/src/core/resources/Notifications.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

airbyte-webapp/src/hooks/services/useWorkspace.tsx

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
import { useFetcher } from "rest-hooks";
2+
import { useMutation } from "react-query";
23

34
import WorkspaceResource from "core/resources/Workspace";
4-
import NotificationsResource, {
5-
Notifications,
6-
} from "core/resources/Notifications";
75

86
import { useAnalyticsService } from "hooks/services/Analytics";
97
import { useCurrentWorkspace } from "services/workspaces/WorkspacesService";
108
import { Destination, Source } from "core/domain/connector";
119
import { Workspace } from "core/domain/workspace/Workspace";
10+
import { NotificationStatus } from "core/domain/notification/types";
11+
import { useConfig } from "config";
12+
import { useDefaultRequestMiddlewares } from "services/useDefaultRequestMiddlewares";
13+
import { useInitService } from "services/useInitService";
14+
import { NotificationService } from "core/domain/notification/NotificationService";
1215

1316
export type WebhookPayload = {
1417
webhook: string;
1518
sendOnSuccess: boolean;
1619
sendOnFailure: boolean;
1720
};
1821

22+
function useGetNotificationService(): NotificationService {
23+
const { apiUrl } = useConfig();
24+
25+
const requestAuthMiddleware = useDefaultRequestMiddlewares();
26+
27+
return useInitService(
28+
() => new NotificationService(apiUrl, requestAuthMiddleware),
29+
[apiUrl, requestAuthMiddleware]
30+
);
31+
}
32+
1933
const useWorkspace = (): {
2034
workspace: Workspace;
2135
updatePreferences: (data: {
@@ -25,7 +39,7 @@ const useWorkspace = (): {
2539
securityUpdates: boolean;
2640
}) => Promise<Workspace>;
2741
updateWebhook: (data: WebhookPayload) => Promise<Workspace>;
28-
testWebhook: (data: WebhookPayload) => Promise<Notifications>;
42+
testWebhook: (data: WebhookPayload) => Promise<NotificationStatus>;
2943
setInitialSetupConfig: (data: {
3044
email: string;
3145
anonymousDataCollection: boolean;
@@ -43,8 +57,9 @@ const useWorkspace = (): {
4357
destination: Destination;
4458
}) => Promise<void>;
4559
} => {
60+
const notificationService = useGetNotificationService();
4661
const updateWorkspace = useFetcher(WorkspaceResource.updateShape());
47-
const tryWebhookUrl = useFetcher(NotificationsResource.tryShape());
62+
4863
const workspace = useCurrentWorkspace();
4964

5065
const analyticsService = useAnalyticsService();
@@ -130,19 +145,6 @@ const useWorkspace = (): {
130145
}
131146
);
132147

133-
const testWebhook = async (data: WebhookPayload) =>
134-
await tryWebhookUrl(
135-
{
136-
notificationType: "slack",
137-
sendOnSuccess: data.sendOnSuccess,
138-
sendOnFailure: data.sendOnFailure,
139-
slackConfiguration: {
140-
webhook: data.webhook,
141-
},
142-
},
143-
{}
144-
);
145-
146148
const updateWebhook = async (data: WebhookPayload) =>
147149
await updateWorkspace(
148150
{},
@@ -166,13 +168,24 @@ const useWorkspace = (): {
166168
}
167169
);
168170

171+
const tryWebhookUrl = useMutation((data: WebhookPayload) =>
172+
notificationService.try({
173+
notificationType: "slack",
174+
sendOnSuccess: data.sendOnSuccess,
175+
sendOnFailure: data.sendOnFailure,
176+
slackConfiguration: {
177+
webhook: data.webhook,
178+
},
179+
})
180+
);
181+
169182
return {
170183
workspace,
171184
finishOnboarding,
172185
setInitialSetupConfig,
173186
updatePreferences,
174187
updateWebhook,
175-
testWebhook,
188+
testWebhook: tryWebhookUrl.mutateAsync,
176189
sendFeedback,
177190
};
178191
};

airbyte-webapp/src/pages/SettingsPage/pages/NotificationPage/NotificationPage.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ const NotificationPage: React.FC = () => {
4747
successMessage,
4848
} = useAsyncWithTimeout(async (data: WebhookPayload) => updateWebhook(data));
4949

50-
const onTestWebhook = async (data: WebhookPayload) => {
51-
await testWebhook(data);
52-
};
53-
5450
const firstNotification = workspace.notifications?.[0];
5551

5652
const initialValues = useMemo(
@@ -74,7 +70,7 @@ const NotificationPage: React.FC = () => {
7470
<WebHookForm
7571
webhook={initialValues}
7672
onSubmit={onSubmitWebhook}
77-
onTest={onTestWebhook}
73+
onTest={testWebhook}
7874
errorMessage={errorMessage}
7975
successMessage={successMessage}
8076
/>

airbyte-webapp/src/utils/testutils.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { IntlProvider } from "react-intl";
77

88
import en from "locales/en.json";
99
import { FeatureService } from "hooks/services/Feature";
10-
import { ConfigServiceProvider, defaultConfig } from "config";
10+
import { configContext, defaultConfig } from "config";
1111

1212
export type RenderOptions = {
1313
// optionally pass in a history object to control routes in the test
@@ -27,11 +27,11 @@ export function render(
2727
return (
2828
<ThemeProvider theme={{}}>
2929
<IntlProvider locale="en" messages={en}>
30-
<ConfigServiceProvider defaultConfig={defaultConfig}>
30+
<configContext.Provider value={{ config: defaultConfig }}>
3131
<FeatureService>
3232
<MemoryRouter>{children}</MemoryRouter>
3333
</FeatureService>
34-
</ConfigServiceProvider>
34+
</configContext.Provider>
3535
</IntlProvider>
3636
</ThemeProvider>
3737
);

airbyte-webapp/src/views/Connection/CatalogTree/StreamHeader.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ export const StreamHeader: React.FC<StreamHeaderProps> = ({
7171
cursorField,
7272
destinationSyncMode,
7373
} = stream.config;
74+
75+
const { defaultCursorField } = stream.stream;
7476
const syncSchema = useMemo(
7577
() => ({
7678
syncMode,
@@ -126,9 +128,11 @@ export const StreamHeader: React.FC<StreamHeaderProps> = ({
126128
<PathPopout
127129
pathType={cursorType}
128130
paths={paths}
129-
path={cursorField}
131+
path={
132+
cursorType === "sourceDefined" ? defaultCursorField : cursorField
133+
}
130134
placeholder={
131-
<FormattedMessage id="connectionForm.primaryKey.searchPlaceholder" />
135+
<FormattedMessage id="connectionForm.cursor.searchPlaceholder" />
132136
}
133137
onPathChange={onCursorChange}
134138
/>

airbyte-webapp/src/views/Connection/CatalogTree/components/PathPopout.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ type PathProps = {
4242

4343
export const PathPopout: React.FC<PathPopoutProps> = (props) => {
4444
if (props.pathType === "sourceDefined") {
45+
if (props.path) {
46+
const text = props.path
47+
? props.isMulti
48+
? props.path.map(pathDisplayName).join(", ")
49+
: pathDisplayName(props.path)
50+
: "";
51+
52+
return <>{text}</>;
53+
}
4554
return <>{"<sourceDefined>"}</>;
4655
}
4756

airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionForm.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,10 @@ const ConnectionForm: React.FC<ConnectionFormProps> = ({
140140
const onFormSubmit = useCallback(
141141
async (values: FormikConnectionFormValues) => {
142142
const formValues: ConnectionFormValues = (connectionValidationSchema.cast(
143-
values
143+
values,
144+
{
145+
context: { isRequest: true },
146+
}
144147
) as unknown) as ConnectionFormValues;
145148

146149
formValues.operations = mapFormPropsToOperation(

airbyte-webapp/src/views/Connection/ConnectionForm/formConfig.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@ const connectionValidationSchema = yup
9898
id: yup
9999
.string()
100100
// This is required to get rid of id fields we are using to detect stream for edition
101-
.strip(true),
101+
.when(
102+
"$isRequest",
103+
(isRequest: boolean, schema: yup.StringSchema) =>
104+
isRequest ? schema.strip(true) : schema
105+
),
102106
stream: yup.object(),
103107
config: yup
104108
.object({

airbyte-webapp/src/views/Connector/ServiceForm/ServiceForm.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ jest.mock("hooks/services/useWorkspace", () => ({
108108
}),
109109
}));
110110

111-
describe.skip("Service Form", () => {
111+
describe("Service Form", () => {
112112
describe("should display json schema specs", () => {
113113
let container: HTMLElement;
114114
beforeEach(() => {

airbyte-webapp/src/views/Connector/ServiceForm/ServiceForm.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import React, { useCallback, useEffect, useMemo, useState } from "react";
1+
import React, {
2+
useCallback,
3+
useEffect,
4+
useMemo,
5+
useRef,
6+
useState,
7+
} from "react";
28
import { Formik, getIn, setIn, useFormikContext } from "formik";
39
import { JSONSchema7 } from "json-schema";
410
import { useToggle } from "react-use";
@@ -25,6 +31,7 @@ import {
2531
ConnectorDefinitionSpecification,
2632
} from "core/domain/connector";
2733
import { isDefined } from "utils/common";
34+
import { ConnectionConfiguration } from "../../../core/domain/connection";
2835

2936
export type ServiceFormProps = {
3037
formType: "source" | "destination";
@@ -54,17 +61,20 @@ const FormikPatch: React.FC = () => {
5461
* @param schema
5562
* @constructor
5663
*/
57-
const PatchInitialValuesWithWidgetConfig: React.FC<{ schema: JSONSchema7 }> = ({
58-
schema,
59-
}) => {
64+
const PatchInitialValuesWithWidgetConfig: React.FC<{
65+
schema: JSONSchema7;
66+
}> = ({ schema }) => {
6067
const { widgetsInfo } = useServiceForm();
61-
const { values, setValues } = useFormikContext();
68+
const { values, setFieldValue } = useFormikContext<ServiceFormValues>();
69+
70+
const valueRef = useRef<ConnectionConfiguration>();
71+
valueRef.current = values.connectionConfiguration;
6272

6373
useEffect(() => {
6474
// set all const fields to form field values, so we could send form
6575
const constPatchedValues = Object.entries(widgetsInfo)
6676
.filter(([_, v]) => isDefined(v.const))
67-
.reduce((acc, [k, v]) => setIn(acc, k, v.const), values);
77+
.reduce((acc, [k, v]) => setIn(acc, k, v.const), valueRef.current);
6878

6979
// set default fields as current values, so values could be populated correctly
7080
// fix for https://github.com/airbytehq/airbyte/issues/6791
@@ -75,7 +85,7 @@ const PatchInitialValuesWithWidgetConfig: React.FC<{ schema: JSONSchema7 }> = ({
7585
)
7686
.reduce((acc, [k, v]) => setIn(acc, k, v.default), constPatchedValues);
7787

78-
setValues(defaultPatchedValues);
88+
setFieldValue("connectionConfiguration", defaultPatchedValues);
7989

8090
// eslint-disable-next-line react-hooks/exhaustive-deps
8191
}, [schema]);
@@ -92,12 +102,11 @@ const SetDefaultName: React.FC = () => {
92102
const { selectedService } = useServiceForm();
93103

94104
useEffect(() => {
95-
// Formik has an issue, that prevents us from setting a field value directly in code here
96-
// It won't change the value at all, unless we push it one execution slot further with setTimeout
97-
setTimeout(() => {
98-
setFieldValue("name", selectedService?.name ?? "");
99-
});
100-
}, [selectedService, setFieldValue]);
105+
if (selectedService) {
106+
setFieldValue("name", selectedService.name);
107+
}
108+
// eslint-disable-next-line react-hooks/exhaustive-deps
109+
}, [selectedService]);
101110

102111
return null;
103112
};

0 commit comments

Comments
 (0)