Skip to content

Commit 8d94c3a

Browse files
ambirdsallSofiiaZaitseva
authored andcommitted
🪟 🎉 Display service token validation errors in the UI (#19578)
Note: the backend returns a 500 status (should be 400, or at least 4xx), so the frontend has to remove the error message's unsightly "Internal Server Error: " prefix in post. In the future, we want to move this to a 400 error.
1 parent 1190fb0 commit 8d94c3a

File tree

4 files changed

+46
-16
lines changed

4 files changed

+46
-16
lines changed

airbyte-webapp/src/packages/cloud/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
"settings.integrationSettings.dbtCloudSettings.form.singleTenantUrl": "Single-tenant URL",
105105
"settings.integrationSettings.dbtCloudSettings.form.testConnection": "Test connection",
106106
"settings.integrationSettings.dbtCloudSettings.form.submit": "Save changes",
107+
"settings.integrationSettings.dbtCloudSettings.form.success": "Service Token saved successfully",
107108
"settings.generalSettings": "General Settings",
108109
"settings.generalSettings.changeWorkspace": "Change Workspace",
109110
"settings.generalSettings.form.name.label": "Workspace name",

airbyte-webapp/src/packages/cloud/services/dbtCloud.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
OperationRead,
1818
OperatorWebhookWebhookType,
1919
WebhookConfigRead,
20+
WorkspaceRead,
2021
} from "core/request/AirbyteClient";
2122
import { useWebConnectionService } from "hooks/services/useConnectionHook";
2223
import { useCurrentWorkspace } from "hooks/services/useWorkspace";
@@ -61,21 +62,26 @@ const isDbtCloudJob = (operation: OperationRead): boolean =>
6162
export const isSameJob = (remoteJob: DbtCloudJobInfo, savedJob: DbtCloudJob): boolean =>
6263
savedJob.accountId === remoteJob.accountId && savedJob.jobId === remoteJob.jobId;
6364

65+
type ServiceToken = string;
66+
6467
export const useSubmitDbtCloudIntegrationConfig = () => {
6568
const { workspaceId } = useCurrentWorkspace();
6669
const { mutateAsync: updateWorkspace } = useUpdateWorkspace();
6770

68-
return useMutation(async (authToken: string) => {
69-
await updateWorkspace({
70-
workspaceId,
71-
webhookConfigs: [
72-
{
73-
name: webhookConfigName,
74-
authToken,
75-
},
76-
],
77-
});
78-
});
71+
return useMutation<WorkspaceRead, Error, ServiceToken>(
72+
["submitWorkspaceDbtCloudToken", workspaceId],
73+
async (authToken: string) => {
74+
return await updateWorkspace({
75+
workspaceId,
76+
webhookConfigs: [
77+
{
78+
name: webhookConfigName,
79+
authToken,
80+
},
81+
],
82+
});
83+
}
84+
);
7985
};
8086

8187
export const useDbtIntegration = (connection: WebBackendConnectionRead) => {

airbyte-webapp/src/packages/cloud/views/settings/integrations/DbtCloudSettingsView.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Field, FieldProps, Form, Formik } from "formik";
2-
import React from "react";
3-
import { FormattedMessage } from "react-intl";
2+
import React, { useState } from "react";
3+
import { FormattedMessage, useIntl } from "react-intl";
44

55
import { LabeledInput } from "components/LabeledInput";
66
import { Button } from "components/ui/Button";
@@ -11,22 +11,43 @@ import { Content, SettingsCard } from "pages/SettingsPage/pages/SettingsComponen
1111
import styles from "./DbtCloudSettingsView.module.scss";
1212

1313
export const DbtCloudSettingsView: React.FC = () => {
14+
const { formatMessage } = useIntl();
1415
const { mutate: submitDbtCloudIntegrationConfig, isLoading } = useSubmitDbtCloudIntegrationConfig();
16+
const [hasValidationError, setHasValidationError] = useState(false);
17+
const [validationMessage, setValidationMessage] = useState("");
1518
return (
1619
<SettingsCard title={<FormattedMessage id="settings.integrationSettings.dbtCloudSettings" />}>
1720
<Content>
1821
<Formik
1922
initialValues={{
2023
serviceToken: "",
2124
}}
22-
onSubmit={({ serviceToken }) => submitDbtCloudIntegrationConfig(serviceToken)}
25+
onSubmit={({ serviceToken }, { resetForm }) => {
26+
setHasValidationError(false);
27+
setValidationMessage("");
28+
return submitDbtCloudIntegrationConfig(serviceToken, {
29+
onError: (e) => {
30+
setHasValidationError(true);
31+
32+
setValidationMessage(e.message.replace("Internal Server Error: ", ""));
33+
},
34+
onSuccess: () => {
35+
setValidationMessage(
36+
formatMessage({ id: "settings.integrationSettings.dbtCloudSettings.form.success" })
37+
);
38+
resetForm();
39+
},
40+
});
41+
}}
2342
>
2443
<Form>
2544
<Field name="serviceToken">
2645
{({ field }: FieldProps<string>) => (
2746
<LabeledInput
2847
{...field}
2948
label={<FormattedMessage id="settings.integrationSettings.dbtCloudSettings.form.serviceToken" />}
49+
error={hasValidationError}
50+
message={validationMessage}
3051
type="text"
3152
/>
3253
)}

airbyte-webapp/src/pages/ConnectionPage/pages/ConnectionItemPage/ConnectionTransformationTab/DbtCloudTransformationsCard.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ const DbtJobsList = ({ jobs, remove, dirty, isLoading }: DbtJobsListProps) => {
154154
<FormattedMessage id="connection.dbtCloudJobs.explanation" />
155155
</Text>
156156
{jobs.map((job, i) => (
157-
<JobsListItem key={i} job={job} removeJob={() => remove(i)} />
157+
<JobsListItem key={i} job={job} removeJob={() => remove(i)} isLoading={isLoading} />
158158
))}
159159
</>
160160
) : (
@@ -184,8 +184,9 @@ const DbtJobsList = ({ jobs, remove, dirty, isLoading }: DbtJobsListProps) => {
184184
interface JobsListItemProps {
185185
job: DbtCloudJob;
186186
removeJob: () => void;
187+
isLoading: boolean;
187188
}
188-
const JobsListItem = ({ job, removeJob }: JobsListItemProps) => {
189+
const JobsListItem = ({ job, removeJob, isLoading }: JobsListItemProps) => {
189190
const { formatMessage } = useIntl();
190191
// TODO if `job.jobName` is undefined, that means we failed to match any of the
191192
// dbt-Cloud-supplied jobs with the saved job. This means one of two things has
@@ -218,6 +219,7 @@ const JobsListItem = ({ job, removeJob }: JobsListItemProps) => {
218219
size="lg"
219220
className={styles.jobListItemDelete}
220221
onClick={removeJob}
222+
disabled={isLoading}
221223
aria-label={formatMessage({ id: "connection.dbtCloudJobs.job.deleteButton" })}
222224
>
223225
<FontAwesomeIcon icon={faXmark} height="21" width="21" />

0 commit comments

Comments
 (0)