Skip to content

Commit

Permalink
🪟 Add catalog changes modal on schema refresh (#14074)
Browse files Browse the repository at this point in the history
* WIP - types, props, components

* logic tweaks

* moving around

* begin styling and content

* modal formatting, section header

* client update, add/removed streams works

* theme tweaks

* WIP -- adding accordion

* hook for modal display logic

* display logic, row/accordion progress

* fix atrocities of table rendering, move header to own component

* headers cleanup

* headers cleanup

* imageblock more flexible

* progress on table todo: consolidate, complete

* styling good, animation TODO

* self review pt. 1

* cleanup

* note

* note

* accessibility and i18n improvements

* fix typo in scss

* missig i18l things

* move icon to /icons

* Update airbyte-webapp/src/views/Connection/CatalogDiffModal/CatalogDiffModal.tsx

Co-authored-by: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com>

* Update airbyte-webapp/src/views/Connection/CatalogDiffModal/components/DiffAccordion.tsx

Co-authored-by: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com>

* spacing, use ModalFooter

* Update airbyte-webapp/src/views/Connection/CatalogDiffModal/components/StreamRow.tsx

Co-authored-by: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com>

* begin moving to memoized reducer function

* memoize diff sorter and remove extra divs

* cleanup

* modal body padding

* up0date to use modal service

* move calculated string mode out of component

* respond to review

* add accordionheader component

* catalog can be undefined

* cleanup cell rendering

* cleanup and make storybook work again

* move table styles within a parent class

* subheading alignment consistency

* more padding/spacing adjustments

* cleanup from review

* mixup from rebase

* set width on modal level not content level

* Update airbyte-webapp/src/views/Connection/CatalogDiffModal/utils.tsx

Co-authored-by: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com>

* Update airbyte-webapp/src/views/Connection/CatalogDiffModal/utils.tsx

Co-authored-by: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com>

* linting and unused class cleanup

Co-authored-by: Edmundo Ruiz Ghanem <168664+edmundito@users.noreply.github.com>
  • Loading branch information
teallarson and edmundito authored Aug 3, 2022
1 parent d3d60c1 commit a4ccaee
Show file tree
Hide file tree
Showing 34 changed files with 901 additions and 21 deletions.
16 changes: 5 additions & 11 deletions airbyte-webapp/.storybook/withProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@ import { FeatureService } from "../src/hooks/services/Feature";
import { ConfigServiceProvider, defaultConfig } from "../src/config";
import { DocumentationPanelProvider } from "../src/views/Connector/ConnectorDocumentationLayout/DocumentationPanelContext";
import { ServicesProvider } from "../src/core/servicesProvider";
import {
analyticsServiceContext,
AnalyticsServiceProviderValue,
} from "../src/hooks/services/Analytics";
import { analyticsServiceContext, AnalyticsServiceProviderValue } from "../src/hooks/services/Analytics";

const AnalyticsContextMock: AnalyticsServiceProviderValue = ({
const AnalyticsContextMock: AnalyticsServiceProviderValue = {
analyticsContext: {},
setContext: () => {},
addContextProps: () => {},
removeContextProps: () => {},
service: {
track: () => {},
},
} as unknown) as AnalyticsServiceProviderValue;
} as unknown as AnalyticsServiceProviderValue;

const queryClient = new QueryClient({
defaultOptions: {
Expand All @@ -45,12 +42,9 @@ export const withProviders = (getStory) => (
<MemoryRouter>
<IntlProvider messages={messages} locale={"en"}>
<ThemeProvider theme={theme}>
<ConfigServiceProvider
defaultConfig={defaultConfig}
providers={[]}
>
<ConfigServiceProvider defaultConfig={defaultConfig} providers={[]}>
<DocumentationPanelProvider>
<FeatureService>
<FeatureService features={[]}>
<GlobalStyle />
{getStory()}
</FeatureService>
Expand Down
19 changes: 19 additions & 0 deletions airbyte-webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions airbyte-webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.1.18",
"@fullstory/browser": "^1.5.1",
"@headlessui/react": "^1.6.5",
"@monaco-editor/react": "^4.4.5",
"@sentry/react": "^6.19.6",
"@sentry/tracing": "^6.19.6",
Expand Down
18 changes: 18 additions & 0 deletions airbyte-webapp/src/components/ImageBlock/ImageBlock.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@
&.darkBlue {
background: colors.$dark-blue-100;
}
&.green {
background: colors.$green;
color: colors.$white;
}

&.red {
background: colors.$red;
color: colors.$white;
}

&.blue {
background: colors.$blue;
color: colors.$white;
}
}

.small {
Expand All @@ -39,4 +53,8 @@
font-size: 10px;
color: colors.$white;
padding: 3px 0 3px;

&.light {
font-weight: 500;
}
}
18 changes: 14 additions & 4 deletions airbyte-webapp/src/components/ImageBlock/ImageBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@ interface ImageBlockProps {
img?: string;
num?: number;
small?: boolean;
color?: string;
light?: boolean;
ariaLabel?: string;
}

export const ImageBlock: React.FC<ImageBlockProps> = ({ img, num, small }) => {
export const ImageBlock: React.FC<ImageBlockProps> = ({ img, num, small, color, light, ariaLabel }) => {
const imageCircleClassnames = classnames({
[styles.circle]: num,
[styles.iconContainer]: !num || num === undefined,
[styles.small]: small && !num,
[styles.darkBlue]: !small && num,
[styles.darkBlue]: !small && num && !color,
[styles.green]: color === "green",
[styles.red]: color === "red",
[styles.blue]: color === "blue",
[styles.light]: light,
});

const numberStyles = classnames(styles.number, { [styles.light]: light });

return (
<div className={imageCircleClassnames}>
{num ? <div className={styles.number}>{num}</div> : <div className={styles.icon}>{getIcon(img)}</div>}
<div className={imageCircleClassnames} aria-label={ariaLabel}>
{num ? <div className={numberStyles}>{num}</div> : <div className={styles.icon}>{getIcon(img)}</div>}
</div>
);
};
Expand Down
3 changes: 3 additions & 0 deletions airbyte-webapp/src/components/Modal/ModalBody.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@
padding: variables.$spacing-lg variables.$spacing-xl;
overflow: auto;
max-width: 100%;
&.paddingNone {
padding: 0;
}
}
10 changes: 8 additions & 2 deletions airbyte-webapp/src/components/Modal/ModalBody.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import classnames from "classnames";

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

interface ModalBodyProps {
maxHeight?: number | string;
padded?: boolean;
}

export const ModalBody: React.FC<ModalBodyProps> = ({ children, maxHeight }) => {
export const ModalBody: React.FC<ModalBodyProps> = ({ children, maxHeight, padded = true }) => {
const modalStyles = classnames(styles.modalBody, {
[styles.paddingNone]: !padded,
});
return (
<div className={styles.modalBody} style={{ maxHeight }}>
<div className={modalStyles} style={{ maxHeight }}>
{children}
</div>
);
Expand Down
18 changes: 18 additions & 0 deletions airbyte-webapp/src/components/icons/ModificationIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const ModificationIcon: React.FC = () => {
return (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.8332 9.16663L14.1665 6.66663L10.8332 4.16663V5.83329H4.1665V7.49996H10.8332V9.16663Z"
fill="#CBC8FF"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.16683 15.8334L5.8335 13.3334L9.16683 10.8334V12.5H15.8335V14.1667H9.16683V15.8334Z"
fill="#CBC8FF"
/>
</svg>
);
};
2 changes: 1 addition & 1 deletion airbyte-webapp/src/hooks/services/Modal/ModalService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const ModalServiceProvider: React.FC = ({ children }) => {
<Modal
title={modalOptions.title}
size={modalOptions.size}
onClose={() => resultSubjectRef.current?.next({ type: "canceled" })}
onClose={modalOptions.preventCancel ? undefined : () => resultSubjectRef.current?.next({ type: "canceled" })}
>
<modalOptions.content
onCancel={() => resultSubjectRef.current?.next({ type: "canceled" })}
Expand Down
1 change: 1 addition & 0 deletions airbyte-webapp/src/hooks/services/Modal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ModalProps } from "components/Modal/Modal";
export interface ModalOptions<T> {
title: ModalProps["title"];
size?: ModalProps["size"];
preventCancel?: boolean;
content: React.ComponentType<ModalContentProps<T>>;
}

Expand Down
11 changes: 11 additions & 0 deletions airbyte-webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,17 @@
"connection.sourceTestAgain": "Test source connection again",
"connection.resetData": "Reset your data",
"connection.updateSchema": "Refresh source schema",
"connection.updateSchema.completed": "Refreshed source schema",
"connection.updateSchema.confirm": "Confirm",
"connection.updateSchema.new": "{value} new {item}",
"connection.updateSchema.removed": "{value} removed {item}",
"connection.updateSchema.changed": "{value} {item} with changes",
"connection.updateSchema.stream": "{count, plural, one {table} other {tables}}",
"connection.updateSchema.field": "{count, plural, one {field} other {fields}}",
"connection.updateSchema.streamName": "Stream name",
"connection.updateSchema.namespace": "Namespace",
"connection.updateSchema.dataType": "Data type",

"connection.newConnection": "+ New connection",
"connection.newConnectionTitle": "New connection",
"connection.noConnections": "Connection list is empty",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
ValuesProps,
} from "hooks/services/useConnectionHook";
import { equal } from "utils/objects";
import { CatalogDiffModal } from "views/Connection/CatalogDiffModal/CatalogDiffModal";
import ConnectionForm from "views/Connection/ConnectionForm";
import { ConnectionFormSubmitResult } from "views/Connection/ConnectionForm/ConnectionForm";
import { FormikConnectionFormValues } from "views/Connection/ConnectionForm/formConfig";
Expand Down Expand Up @@ -87,7 +88,6 @@ export const ReplicationView: React.FC<ReplicationViewProps> = ({ onAfterSaveSch
const [saved, setSaved] = useState(false);
const [connectionFormValues, setConnectionFormValues] = useState<FormikConnectionFormValues>();
const connectionService = useConnectionService();

const { mutateAsync: updateConnection } = useUpdateConnection();

const { connection: initialConnection, refreshConnectionCatalog } = useConnectionLoad(connectionId);
Expand Down Expand Up @@ -177,7 +177,16 @@ export const ReplicationView: React.FC<ReplicationViewProps> = ({ onAfterSaveSch
const onRefreshSourceSchema = async () => {
setSaved(false);
setActiveUpdatingSchemaMode(true);
await refreshCatalog();
const { catalogDiff, syncCatalog } = await refreshCatalog();
if (catalogDiff?.transforms && catalogDiff.transforms.length > 0) {
await openModal<void>({
title: formatMessage({ id: "connection.updateSchema.completed" }),
preventCancel: true,
content: ({ onClose }) => (
<CatalogDiffModal catalogDiff={catalogDiff} catalog={syncCatalog} onClose={onClose} />
),
});
}
};

const onCancelConnectionFormEdit = () => {
Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/scss/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ $green-800: #007c84;
$green-900: #005959;
$green: $green-200;

$red-50: #ffbac6;
$red-50: #ffe4e8;
$red-100: #ffbac6;
$red-200: #ff8da1;
$red-300: #ff5e7b;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@use "../../../scss/variables";

.modalContent {
display: flex;
flex-direction: column;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useMemo } from "react";
import { FormattedMessage } from "react-intl";

import { Button } from "components";

import { AirbyteCatalog, CatalogDiff } from "core/request/AirbyteClient";

import { ModalBody, ModalFooter } from "../../../components/Modal";
import styles from "./CatalogDiffModal.module.scss";
import { DiffSection } from "./components/DiffSection";
import { FieldSection } from "./components/FieldSection";
import { getSortedDiff } from "./utils";

interface CatalogDiffModalProps {
catalogDiff: CatalogDiff;
catalog: AirbyteCatalog;
onClose: () => void;
}

export const CatalogDiffModal: React.FC<CatalogDiffModalProps> = ({ catalogDiff, catalog, onClose }) => {
const { newItems, removedItems, changedItems } = useMemo(
() => getSortedDiff(catalogDiff.transforms),
[catalogDiff.transforms]
);

return (
<>
<ModalBody maxHeight={400} padded={false}>
<div className={styles.modalContent}>
{removedItems.length > 0 && <DiffSection streams={removedItems} diffVerb="removed" catalog={catalog} />}
{newItems.length > 0 && <DiffSection streams={newItems} diffVerb="new" />}
{changedItems.length > 0 && <FieldSection streams={changedItems} diffVerb="changed" />}
</div>
</ModalBody>
<ModalFooter>
<Button onClick={() => onClose()}>
<FormattedMessage id="connection.updateSchema.confirm" />
</Button>
</ModalFooter>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@use "../../../../scss/variables";
@forward "../components/StreamRow.module.scss";
@forward "../components/DiffSection.module.scss";

.accordionContainer {
width: 100%;
}

.accordionButton {
width: 100%;
background: none;
border: none;
height: 40px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: variables.$spacing-sm;
font-weight: 400;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Disclosure } from "@headlessui/react";
import { useMemo } from "react";

import { StreamTransform } from "core/request/AirbyteClient";

import { getSortedDiff } from "../utils";
import styles from "./DiffAccordion.module.scss";
import { DiffAccordionHeader } from "./DiffAccordionHeader";
import { DiffFieldTable } from "./DiffFieldTable";

interface DiffAccordionProps {
streamTransform: StreamTransform;
}

export const DiffAccordion: React.FC<DiffAccordionProps> = ({ streamTransform }) => {
const { newItems, removedItems, changedItems } = useMemo(
() => getSortedDiff(streamTransform.updateStream),
[streamTransform.updateStream]
);

return (
<div className={styles.accordionContainer}>
<Disclosure>
{({ open }) => (
<>
<Disclosure.Button className={styles.accordionButton}>
<DiffAccordionHeader
streamDescriptor={streamTransform.streamDescriptor}
removedCount={removedItems.length}
newCount={newItems.length}
changedCount={changedItems.length}
open={open}
/>
</Disclosure.Button>
<Disclosure.Panel>
{removedItems.length > 0 && <DiffFieldTable fieldTransforms={removedItems} diffVerb="removed" />}
{newItems.length > 0 && <DiffFieldTable fieldTransforms={newItems} diffVerb="new" />}
{changedItems.length > 0 && <DiffFieldTable fieldTransforms={changedItems} diffVerb="changed" />}
</Disclosure.Panel>
</>
)}
</Disclosure>
</div>
);
};
Loading

0 comments on commit a4ccaee

Please sign in to comment.