Skip to content

Commit

Permalink
[Connector Builder] Update view styles and add stream delete button (#…
Browse files Browse the repository at this point in the history
…20464)

* style view titles

* save progress on adding stream delete functionality

* fix delete behavior

* remove remaining console logs

* consolidate shared styles into BuilderConfigView component
  • Loading branch information
lmossman committed Dec 15, 2022
1 parent 3a8f47e commit e864e20
Show file tree
Hide file tree
Showing 10 changed files with 341 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,4 @@
.form {
flex: 1;
padding: variables.$spacing-xl;
display: flex;
flex-direction: column;
gap: variables.$spacing-xl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@use "scss/variables";
@use "scss/colors";

.container {
display: flex;
flex-direction: column;
gap: variables.$spacing-md;
}

.heading {
text-align: center;
font-size: 14px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

import { Heading } from "components/ui/Heading";

import styles from "./BuilderConfigView.module.scss";

interface BuilderConfigViewProps {
heading: string;
}

export const BuilderConfigView: React.FC<React.PropsWithChildren<BuilderConfigViewProps>> = ({ children, heading }) => {
return (
<div className={styles.container}>
<Heading className={styles.heading} as="h1">
{heading}
</Heading>
{children}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@use "scss/variables";
@use "scss/colors";

.container {
display: flex;
flex-direction: column;
align-items: center;
gap: variables.$spacing-sm;
}

.label {
color: colors.$grey;
}

.inputContainer {
max-width: 500px;
width: 70%;
background-color: colors.$grey-100;
border-color: colors.$grey-200;
border-radius: variables.$border-radius-md;

&:not(.disabled, .focused):hover {
border-color: colors.$blue;
}

&.md {
height: 43px;
}

&.lg {
height: 50px;
}
}

.input {
text-align: center;
height: 100%;
font-weight: 700;

&.md {
font-size: 19px;
}

&.lg {
font-size: 24px;
}
}

.error {
color: colors.$red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import classNames from "classnames";
import { useField } from "formik";
import { FormattedMessage } from "react-intl";

import { Input } from "components/ui/Input";
import { Text } from "components/ui/Text";

import styles from "./BuilderTitle.module.scss";

interface BuilderTitleProps {
// path to the location in the Connector Manifest schema which should be set by this component
path: string;
label: string;
size: "md" | "lg";
}

export const BuilderTitle: React.FC<BuilderTitleProps> = ({ path, label, size }) => {
const [field, meta] = useField(path);
const hasError = !!meta.error && meta.touched;

return (
<div className={styles.container}>
<Text className={styles.label} size="xs">
{label}
</Text>
<Input
containerClassName={classNames(styles.inputContainer, {
[styles.md]: size === "md",
[styles.lg]: size === "lg",
})}
className={classNames(styles.input, { [styles.md]: size === "md", [styles.lg]: size === "lg" })}
{...field}
type="text"
value={field.value ?? ""}
error={hasError}
/>
{hasError && (
<Text size="xs" className={styles.error}>
<FormattedMessage id={meta.error} />
</Text>
)}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { useIntl } from "react-intl";

import { BuilderCard } from "./BuilderCard";
import { BuilderConfigView } from "./BuilderConfigView";
import { BuilderField } from "./BuilderField";
import { BuilderTitle } from "./BuilderTitle";

export const GlobalConfigView: React.FC = () => {
const { formatMessage } = useIntl();

return (
<>
<BuilderConfigView heading={formatMessage({ id: "connectorBuilder.globalConfiguration" })}>
{/* Not using intl for the labels and tooltips in this component in order to keep maintainence simple */}
<BuilderCard>
<BuilderField
type="text"
path="global.connectorName"
label="Connector Name"
tooltip="Name of the connector being built"
/>
</BuilderCard>
<BuilderTitle path="global.connectorName" label="Connector Name" size="lg" />
<BuilderCard>
<BuilderField type="text" path="global.urlBase" label="API URL" tooltip="Base URL of the source API" />
</BuilderCard>
</>
</BuilderConfigView>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@use "scss/variables";
@use "scss/colors";

$deleteButtonWidth: 24px;

.controls {
display: flex;
justify-content: center;
}

.deleteButton {
border: none;
background-color: transparent;
color: colors.$grey;
border-radius: variables.$border-radius-xs;
width: $deleteButtonWidth;
height: $deleteButtonWidth;
padding: variables.$spacing-xs;
padding: 0;
cursor: pointer;
transition: variables.$transition;

&:hover {
color: colors.$white;
background-color: colors.$red;
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,78 @@
import { faTrashCan } from "@fortawesome/free-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useField } from "formik";
import { useIntl } from "react-intl";

import { useConfirmationModalService } from "hooks/services/ConfirmationModal";
import { BuilderView, useConnectorBuilderState } from "services/connectorBuilder/ConnectorBuilderStateService";

import { BuilderStream } from "../types";
import { BuilderCard } from "./BuilderCard";
import { BuilderConfigView } from "./BuilderConfigView";
import { BuilderField } from "./BuilderField";
import { BuilderTitle } from "./BuilderTitle";
import styles from "./StreamConfigView.module.scss";

interface StreamConfigViewProps {
streamNum: number;
}

export const StreamConfigView: React.FC<StreamConfigViewProps> = ({ streamNum }) => {
const streamPath = (path: string) => `streams[${streamNum}].${path}`;
const { formatMessage } = useIntl();
const [field, , helpers] = useField<BuilderStream[]>("streams");
const { openConfirmationModal, closeConfirmationModal } = useConfirmationModalService();
const { setSelectedView, setTestStreamIndex } = useConnectorBuilderState();

const streamPath = `streams[${streamNum}]`;
const streamFieldPath = (fieldPath: string) => `${streamPath}.${fieldPath}`;

const handleDelete = () => {
openConfirmationModal({
text: "connectorBuilder.deleteStreamModal.text",
title: "connectorBuilder.deleteStreamModal.title",
submitButtonText: "connectorBuilder.deleteStreamModal.submitButton",
onSubmit: () => {
const updatedStreams = field.value.filter((_, index) => index !== streamNum);
const streamToSelect = streamNum >= updatedStreams.length ? updatedStreams.length - 1 : streamNum;
const viewToSelect: BuilderView = updatedStreams.length === 0 ? "global" : streamToSelect;
helpers.setValue(updatedStreams);
setSelectedView(viewToSelect);
setTestStreamIndex(streamToSelect);
closeConfirmationModal();
},
});
};

return (
<BuilderCard>
<BuilderConfigView heading={formatMessage({ id: "connectorBuilder.stream" })}>
{/* Not using intl for the labels and tooltips in this component in order to keep maintainence simple */}
<BuilderField type="text" path={streamPath("name")} label="Stream Name" tooltip="Name of the stream" />
<BuilderField
type="text"
path={streamPath("urlPath")}
label="Path URL"
tooltip="Path of the endpoint that this stream represents."
/>
<BuilderField
type="array"
path={streamPath("fieldPointer")}
label="Field Pointer"
tooltip="Pointer into the response that should be extracted as the final record"
/>
<BuilderField
type="enum"
path={streamPath("httpMethod")}
options={["GET", "POST"]}
label="HTTP Method"
tooltip="HTTP method to use for requests sent to the API"
/>
</BuilderCard>
<BuilderTitle path={streamFieldPath("name")} label="Stream Name" size="md" />
<div className={styles.controls}>
<button className={styles.deleteButton} type="button" onClick={handleDelete}>
<FontAwesomeIcon icon={faTrashCan} />
</button>
</div>
<BuilderCard>
<BuilderField
type="text"
path={streamFieldPath("urlPath")}
label="Path URL"
tooltip="Path of the endpoint that this stream represents."
/>
<BuilderField
type="enum"
path={streamFieldPath("httpMethod")}
options={["GET", "POST"]}
label="HTTP Method"
tooltip="HTTP method to use for requests sent to the API"
/>
<BuilderField
type="array"
path={streamFieldPath("fieldPointer")}
label="Field Pointer"
tooltip="Pointer into the response that should be extracted as the final record"
/>
</BuilderCard>
</BuilderConfigView>
);
};
Loading

0 comments on commit e864e20

Please sign in to comment.