Skip to content

Commit ae2aea8

Browse files
feat: connection name can be edited through UI (#12803)
* feat: connection name can be edited through UI * fix: changes requested by edmundito * 1. feat: Added connection name edit in connection settings 2. feat: Added connection name in listing connections page 3. fix: requested changes * chore: handle UI and e2e tests * chore: fix e2e tests for webapp * fix: UI margins * fix: webe2e tests * fix: input is not focused when clicked on name * fix: disable input while making API call * feat: added enter/esc functionality to connection name edit
1 parent 1d1476e commit ae2aea8

File tree

19 files changed

+458
-130
lines changed

19 files changed

+458
-130
lines changed

airbyte-webapp-e2e-tests/cypress/integration/connection.spec.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ describe("Connection main actions", () => {
2626
cy.get("button[type=submit]").first().click();
2727
cy.wait("@updateConnection");
2828
cy.get("span[data-id='success-result']").should("exist");
29-
30-
cy.get("div[data-id='status-step']").click();
31-
cy.get("div").contains("5 min").should("exist");
3229
});
3330

3431
it("Delete connection", () => {

airbyte-webapp-e2e-tests/cypress/support/commands/connection.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Cypress.Commands.add("createTestConnection", (sourceName, destinationName) => {
1111

1212
cy.wait("@discoverSchema");
1313

14+
cy.get("div[data-testid='connectionName']").type("Connection name");
1415
cy.get("div[data-testid='schedule']").click();
1516
cy.get("div[data-testid='manual']").click();
1617

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import styled from "styled-components";
2+
3+
import { ReleaseStageBadge } from "components/ReleaseStageBadge";
4+
5+
import { ReleaseStage } from "core/request/AirbyteClient";
6+
import { getIcon } from "utils/imageUtils";
7+
8+
type Props = {
9+
connectionName: string;
10+
icon?: string;
11+
connectorName: string;
12+
releaseStage?: ReleaseStage;
13+
};
14+
15+
const MainComponent = styled.div`
16+
display: flex;
17+
padding: 10px;
18+
width: 220px;
19+
align-items: center;
20+
`;
21+
22+
const Details = styled.div`
23+
width: 160px;
24+
margin-left: 10px;
25+
display: flex;
26+
flex-direction: column;
27+
font-weight: normal;
28+
`;
29+
30+
const EntityIcon = styled.div`
31+
height: 30px;
32+
width: 30px;
33+
`;
34+
35+
const ConnectionName = styled.div`
36+
font-size: 14px;
37+
color: #1a194d;
38+
text-align: left;
39+
margin-right: 10px;
40+
`;
41+
42+
const ConnectorDetails = styled.div`
43+
display: flex;
44+
justify-content: flex-start;
45+
align-items: center;
46+
`;
47+
48+
const ConnectorName = styled.div`
49+
font-size: 11px;
50+
margin-top: 1px;
51+
color: #afafc1;
52+
text-align: left;
53+
`;
54+
55+
function ConnectorCard(props: Props) {
56+
const { connectionName, connectorName, icon, releaseStage } = props;
57+
58+
return (
59+
<MainComponent>
60+
{icon && <EntityIcon>{getIcon(icon)}</EntityIcon>}
61+
<Details>
62+
<ConnectorDetails>
63+
<ConnectionName>{connectionName}</ConnectionName>
64+
{releaseStage && <ReleaseStageBadge stage={releaseStage} />}
65+
</ConnectorDetails>
66+
<ConnectorName>{connectorName} </ConnectorName>
67+
</Details>
68+
</MainComponent>
69+
);
70+
}
71+
72+
export default ConnectorCard;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import ConnectorCard from "./ConnectorCard";
2+
3+
export default ConnectorCard;

airbyte-webapp/src/components/EntityTable/ConnectionTable.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const ConnectionTable: React.FC<IProps> = ({ data, entity, onClickRow, onChangeS
3535
const { hasFeature } = useFeatureService();
3636
const allowSync = hasFeature(FeatureItem.AllowSync);
3737

38-
const sortBy = query.sortBy || "entity";
38+
const sortBy = query.sortBy || "entityName";
3939
const sortOrder = query.order || SortOrderEnum.ASC;
4040

4141
const onSortClick = useCallback(
@@ -61,7 +61,7 @@ const ConnectionTable: React.FC<IProps> = ({ data, entity, onClickRow, onChangeS
6161
if (sortBy === "lastSync") {
6262
result = b[sortBy] - a[sortBy];
6363
} else {
64-
result = a[`${sortBy}Name`].toLowerCase().localeCompare(b[`${sortBy}Name`].toLowerCase());
64+
result = a[sortBy].toLowerCase().localeCompare(b[sortBy].toLowerCase());
6565
}
6666

6767
if (sortOrder === SortOrderEnum.DESC) {
@@ -77,6 +77,24 @@ const ConnectionTable: React.FC<IProps> = ({ data, entity, onClickRow, onChangeS
7777

7878
const columns = React.useMemo(
7979
() => [
80+
{
81+
Header: (
82+
<>
83+
<FormattedMessage id="tables.name" />
84+
<SortButton
85+
wasActive={sortBy === "name"}
86+
lowToLarge={sortOrder === SortOrderEnum.ASC}
87+
onClick={() => onSortClick("name")}
88+
/>
89+
</>
90+
),
91+
headerHighlighted: true,
92+
accessor: "name",
93+
customWidth: 30,
94+
Cell: ({ cell, row }: CellProps<ITableDataItem>) => (
95+
<NameCell value={cell.value} enabled={row.original.enabled} status={row.original.lastSyncStatus} />
96+
),
97+
},
8098
{
8199
Header: (
82100
<>
@@ -86,20 +104,18 @@ const ConnectionTable: React.FC<IProps> = ({ data, entity, onClickRow, onChangeS
86104
<FormattedMessage id={`tables.${entity}ConnectionToName`} />
87105
)}
88106
<SortButton
89-
wasActive={sortBy === "entity"}
107+
wasActive={sortBy === "entityName"}
90108
lowToLarge={sortOrder === SortOrderEnum.ASC}
91-
onClick={() => onSortClick("entity")}
109+
onClick={() => onSortClick("entityName")}
92110
/>
93111
</>
94112
),
95113
headerHighlighted: true,
96114
accessor: "entityName",
97-
customWidth: 40,
98115
Cell: ({ cell, row }: CellProps<ITableDataItem>) => (
99116
<NameCell
100117
value={cell.value}
101118
enabled={row.original.enabled}
102-
status={row.original.lastSyncStatus}
103119
icon={entity === "connection"}
104120
img={row.original.entityIcon}
105121
/>
@@ -114,9 +130,9 @@ const ConnectionTable: React.FC<IProps> = ({ data, entity, onClickRow, onChangeS
114130
<FormattedMessage id="tables.connector" />
115131
)}
116132
<SortButton
117-
wasActive={sortBy === "connector"}
133+
wasActive={sortBy === "connectorName"}
118134
lowToLarge={sortOrder === SortOrderEnum.ASC}
119-
onClick={() => onSortClick("connector")}
135+
onClick={() => onSortClick("connectorName")}
120136
/>
121137
</>
122138
),

airbyte-webapp/src/components/EntityTable/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type EntityTableDataItem = {
1717

1818
type ITableDataItem = {
1919
connectionId: string;
20+
name: string;
2021
entityName: string;
2122
connectorName: string;
2223
enabled: boolean;

airbyte-webapp/src/components/EntityTable/utils.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export const getConnectionTableData = (
9090

9191
return {
9292
connectionId: connection.connectionId,
93+
name: connection.name,
9394
entityName:
9495
type === "connection"
9596
? `${connection.source?.sourceName} - ${connection.source?.name}`

airbyte-webapp/src/components/base/Input/Input.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons";
22
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3-
import React from "react";
3+
import React, { useEffect, useRef } from "react";
44
import { useIntl } from "react-intl";
55
import { useToggle } from "react-use";
66
import styled from "styled-components";
@@ -23,6 +23,7 @@ const getBackgroundColor = (props: IStyleProps) => {
2323
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
2424
error?: boolean;
2525
light?: boolean;
26+
defaultFocus?: boolean;
2627
}
2728

2829
const InputContainer = styled.div<InputProps>`
@@ -78,7 +79,10 @@ const VisibilityButton = styled(Button)`
7879
`;
7980

8081
const Input: React.FC<InputProps> = (props) => {
82+
const { defaultFocus = false } = props;
83+
8184
const { formatMessage } = useIntl();
85+
const inputRef = useRef<HTMLInputElement | null>(null);
8286
const [isContentVisible, setIsContentVisible] = useToggle(false);
8387
const [focused, toggleFocused] = useToggle(false);
8488

@@ -87,10 +91,17 @@ const Input: React.FC<InputProps> = (props) => {
8791
const type = isPassword ? (isContentVisible ? "text" : "password") : props.type;
8892
const onInputFocusChange = () => toggleFocused();
8993

94+
useEffect(() => {
95+
if (defaultFocus && inputRef.current !== null) {
96+
inputRef.current.focus();
97+
}
98+
}, [inputRef, defaultFocus]);
99+
90100
return (
91101
<InputContainer {...props} className={focused ? "input-container--focused" : undefined}>
92102
<InputComponent
93103
{...props}
104+
ref={inputRef}
94105
type={type}
95106
isPassword={isPassword}
96107
onFocus={onInputFocusChange}

airbyte-webapp/src/components/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ export * from "./Spinner";
1919
export * from "./StatusIcon";
2020
export * from "./TextWithHTML";
2121
export * from "./ProgressBar";
22+
export * from "./ConnectorCard";

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const connectionsKeys = {
3232
};
3333

3434
export type ValuesProps = {
35+
name?: string;
3536
schedule: ConnectionSchedule | null;
3637
prefix: string;
3738
syncCatalog: SyncSchema;

airbyte-webapp/src/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@
3232
"form.noConnectorFound": "No matching connector found",
3333
"form.sourceName.placeholder": "Your source name",
3434
"form.destinationName.placeholder": "Your destination name",
35+
"form.connectionName": "Name",
3536
"form.connectionName.placeholder": "Name",
3637
"form.name": "Name *",
3738
"form.sourceName.message": "Pick a name to help you identify this source in Airbyte",
3839
"form.destinationName.message": "Pick a name to help you identify this destination in Airbyte",
39-
"form.connectionName.message": "Pick a name to help you identify this source in Airbyte",
40+
"form.connectionName.message": "Pick a name to help you identify this connection",
4041
"form.sourceType": "Source type",
4142
"form.destinationType": "Destination type",
4243
"form.connectionType": "Connector type",

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Suspense } from "react";
1+
import React, { Suspense, useState } from "react";
22
import { Navigate, Route, Routes, useParams } from "react-router-dom";
33

44
import { LoadingPage, MainPageWithScroll } from "components";
@@ -26,6 +26,7 @@ const ConnectionItemPage: React.FC = () => {
2626
const connectionId = params.connectionId || "";
2727
const currentStep = params["*"] || ConnectionSettingsRoutes.STATUS;
2828
const connection = useGetConnection(connectionId);
29+
const [isStatusUpdating, setStatusUpdating] = useState(false);
2930

3031
const { source, destination } = connection;
3132

@@ -68,6 +69,7 @@ const ConnectionItemPage: React.FC = () => {
6869
destination={destination}
6970
connection={connection}
7071
currentStep={currentStep}
72+
onStatusUpdating={setStatusUpdating}
7173
/>
7274
}
7375
error={
@@ -80,7 +82,7 @@ const ConnectionItemPage: React.FC = () => {
8082
<Routes>
8183
<Route
8284
path={ConnectionSettingsRoutes.STATUS}
83-
element={<StatusView connection={connection} frequencyText={frequency?.text} />}
85+
element={<StatusView connection={connection} isStatusUpdating={isStatusUpdating} />}
8486
/>
8587
<Route
8688
path={ConnectionSettingsRoutes.REPLICATION}

0 commit comments

Comments
 (0)