Skip to content

Commit

Permalink
🪟 🎉 Add connector builder logs viewer and improve page/slice state (#…
Browse files Browse the repository at this point in the history
…18949)

* change splitter to be single bar, and rename props

* add logs viewer to testing panel

* make log display height 100%

* remove comment

* clean up some styling, and add record count to tab title

* cleanup + only render paginator and slice selector when necessary

* move selected slice/page state into context and fix bug with state between streams

* fix tab keys

* pull LogsDisplay out into its own component to simplify ResultDisplay

* simplify ResultDisplay prop

Co-authored-by: Tim Roes <tim@airbyte.io>
  • Loading branch information
lmossman and timroes committed Nov 8, 2022
1 parent 77d22c5 commit 33f10d3
Show file tree
Hide file tree
Showing 18 changed files with 252 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@use "scss/colors";
@use "scss/variables";

.container {
padding-top: variables.$spacing-sm;
display: flex;
flex-direction: column;
height: 100%;
}

.header {
background-color: colors.$grey-50;
display: flex;
align-items: center;
gap: variables.$spacing-md;
padding: variables.$spacing-sm variables.$spacing-md;
}

.numLogsDisplay {
border-radius: variables.$border-radius-md;
background-color: colors.$blue;
padding: 1px variables.$spacing-sm;
color: colors.$white;
}

.logsDisplay {
overflow-y: auto;
height: 100%;
}
29 changes: 29 additions & 0 deletions airbyte-webapp/src/components/StreamTestingPanel/LogsDisplay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { FormattedMessage } from "react-intl";

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

import { StreamReadLogsItem } from "core/request/ConnectorBuilderClient";

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

interface LogsDisplayProps {
logs: StreamReadLogsItem[];
}

export const LogsDisplay: React.FC<LogsDisplayProps> = ({ logs }) => {
return (
<div className={styles.container}>
<div className={styles.header}>
<Text size="sm" bold>
<FormattedMessage id="connectorBuilder.connectorLogs" />
</Text>
<Text className={styles.numLogsDisplay} size="xs" bold>
{logs.length}
</Text>
</div>
<div className={styles.logsDisplay}>
<pre>{JSON.stringify(logs, null, 2)}</pre>
</div>
</div>
);
};
21 changes: 16 additions & 5 deletions airbyte-webapp/src/components/StreamTestingPanel/PageDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,36 @@ interface PageDisplayProps {

interface TabData {
title: string;
key: string;
content: StreamReadSlicesItemPagesItemRecordsItem[] | HttpRequest | HttpResponse;
}

export const PageDisplay: React.FC<PageDisplayProps> = ({ page, className }) => {
const { formatMessage } = useIntl();
const tabs: TabData[] = [{ title: formatMessage({ id: "connectorBuilder.recordsTab" }), content: page.records }];
const tabs: TabData[] = [
{
title: `${formatMessage({ id: "connectorBuilder.recordsTab" })} (${page.records.length})`,
key: "records",
content: page.records,
},
];
if (page.request) {
tabs.push({ title: formatMessage({ id: "connectorBuilder.requestTab" }), content: page.request });
tabs.push({ title: formatMessage({ id: "connectorBuilder.requestTab" }), key: "request", content: page.request });
}
if (page.response) {
tabs.push({ title: formatMessage({ id: "connectorBuilder.responseTab" }), content: page.response });
tabs.push({
title: formatMessage({ id: "connectorBuilder.responseTab" }),
key: "response",
content: page.response,
});
}

return (
<div className={classNames(className)}>
<Tab.Group>
<Tab.List className={styles.tabList}>
{tabs.map((tab) => (
<Tab className={styles.tab}>
<Tab className={styles.tab} key={tab.key}>
{({ selected }) => (
<Text className={classNames(styles.tabTitle, { [styles.selected]: selected })}>{tab.title}</Text>
)}
Expand All @@ -47,7 +58,7 @@ export const PageDisplay: React.FC<PageDisplayProps> = ({ page, className }) =>
</Tab.List>
<Tab.Panels className={styles.tabPanelContainer}>
{tabs.map((tab) => (
<Tab.Panel className={styles.tabPanel}>
<Tab.Panel className={styles.tabPanel} key={tab.key}>
<pre>{JSON.stringify(tab.content, null, 2)}</pre>
</Tab.Panel>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
display: flex;
flex-direction: column;
gap: variables.$spacing-lg;
padding-bottom: variables.$spacing-md;
height: 100%;
}

.sliceSelector {
Expand All @@ -21,7 +23,7 @@

.paginator {
display: flex;
gap: variables.$spacing-sm;
gap: 2px;
align-self: center;
justify-self: flex-end;
margin-top: auto;
Expand Down
41 changes: 20 additions & 21 deletions airbyte-webapp/src/components/StreamTestingPanel/ResultDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
import classNames from "classnames";
import { useState } from "react";

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

import { StreamRead } from "core/request/ConnectorBuilderClient";
import { StreamReadSlicesItem } from "core/request/ConnectorBuilderClient";
import { useConnectorBuilderState } from "services/connectorBuilder/ConnectorBuilderStateService";

import { PageDisplay } from "./PageDisplay";
import styles from "./ResultDisplay.module.scss";
import { SliceSelector } from "./SliceSelector";

interface ResultDisplayProps {
streamRead: StreamRead;
slices: StreamReadSlicesItem[];
className?: string;
}

export const ResultDisplay: React.FC<ResultDisplayProps> = ({ streamRead, className }) => {
const [selectedSliceIndex, setSelectedSliceIndex] = useState(0);
const [selectedPage, setSelectedPage] = useState(0);
export const ResultDisplay: React.FC<ResultDisplayProps> = ({ slices, className }) => {
const { selectedSlice, selectedPage, setSelectedSlice, setSelectedPage } = useConnectorBuilderState();

const handlePageChange = (selectedPageIndex: number) => {
setSelectedPage(selectedPageIndex);
};

const slice = streamRead.slices[selectedSliceIndex];
const slice = slices[selectedSlice];
const numPages = slice.pages.length;
const page = slice.pages[selectedPage];

return (
<div className={classNames(className, styles.container)}>
<SliceSelector
className={styles.sliceSelector}
slices={streamRead.slices}
selectedSliceIndex={selectedSliceIndex}
onSelect={setSelectedSliceIndex}
/>
{slices.length > 1 && (
<SliceSelector
className={styles.sliceSelector}
slices={slices}
selectedSliceIndex={selectedSlice}
onSelect={setSelectedSlice}
/>
)}
<PageDisplay className={styles.pageDisplay} page={page} />
<div className={styles.paginator}>
<Text className={styles.pageLabel}>Page:</Text>
<Paginator numPages={numPages} onPageChange={handlePageChange} selectedPage={selectedPage} />
</div>
{slice.pages.length > 1 && (
<div className={styles.paginator}>
<Text className={styles.pageLabel}>Page:</Text>
<Paginator numPages={numPages} onPageChange={setSelectedPage} selectedPage={selectedPage} />
</div>
)}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
@use "scss/variables";

.container {
padding: variables.$spacing-xl;
padding: variables.$spacing-xl variables.$spacing-md variables.$spacing-md variables.$spacing-md;
display: flex;
flex-direction: column;
height: 100%;
gap: variables.$spacing-xl;
gap: variables.$spacing-lg;
}

.streamSelector {
Expand All @@ -16,9 +16,12 @@
flex: 0 0 auto;
}

.resultDisplay {
.resizablePanelsContainer {
flex: 1;
min-height: 0;

// required to hide the connector logs splitter underneath the resizable panel overlay
z-index: 0;
}

.placeholder {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useIntl } from "react-intl";

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

import { useReadStream } from "services/connectorBuilder/ConnectorBuilderApiService";
import { useConnectorBuilderState } from "services/connectorBuilder/ConnectorBuilderStateService";

import { LogsDisplay } from "./LogsDisplay";
import { ResultDisplay } from "./ResultDisplay";
import { StreamSelector } from "./StreamSelector";
import styles from "./StreamTestingPanel.module.scss";
Expand All @@ -27,7 +30,21 @@ export const StreamTestingPanel: React.FC<unknown> = () => {
}}
/>
{streamReadData && streamReadData.slices.length !== 0 ? (
<ResultDisplay className={styles.resultDisplay} streamRead={streamReadData} />
<ResizablePanels
className={styles.resizablePanelsContainer}
orientation="horizontal"
firstPanel={{
children: <ResultDisplay slices={streamReadData.slices} />,
minWidth: 120,
}}
secondPanel={{
className: styles.logsContainer,
children: <LogsDisplay logs={streamReadData.logs} />,
minWidth: 30,
flex: 0,
}}
hideSecondPanel={streamReadData.logs.length === 0}
/>
) : (
<div className={styles.placeholder}>{formatMessage({ id: "connectorBuilder.resultsPlaceholder" })}</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
$testIconHeight: 17px;

.container {
margin: variables.$spacing-lg 0;
display: flex;
gap: variables.$spacing-md;
height: 36px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
right: 0;
left: 0;
width: 100%;
z-index: 1;
}

.option {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $containerHeight: 23px;
height: $containerHeight;
width: 80%;
display: flex;
gap: variables.$spacing-sm;
gap: 2px;
font-size: 10px;
margin: 0;
}
Expand Down
41 changes: 20 additions & 21 deletions airbyte-webapp/src/components/ui/Paginator/Paginator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,23 @@ function pageRangeDisplayed(numPages: number, selectedPageIndex: number): number
return 3;
}

export const Paginator: React.FC<PaginatorProps> = ({ className, numPages, onPageChange, selectedPage }) => {
return (
<ReactPaginate
pageCount={numPages}
onPageChange={(event) => {
onPageChange(event.selected);
}}
breakLabel="…"
nextLabel=">"
previousLabel="<"
pageRangeDisplayed={pageRangeDisplayed(numPages, selectedPage)}
marginPagesDisplayed={2}
containerClassName={classNames(className, styles.container)}
pageClassName={classNames(styles.button, styles.page)}
breakClassName={classNames(styles.button, styles.break)}
activeClassName={styles.active}
previousClassName={classNames(styles.button, styles.previous)}
nextClassName={classNames(styles.button, styles.next)}
/>
);
};
export const Paginator: React.FC<PaginatorProps> = ({ className, numPages, onPageChange, selectedPage }) => (
<ReactPaginate
pageCount={numPages}
onPageChange={(event) => {
onPageChange(event.selected);
}}
forcePage={selectedPage}
breakLabel="…"
nextLabel=">"
previousLabel="<"
pageRangeDisplayed={pageRangeDisplayed(numPages, selectedPage)}
marginPagesDisplayed={2}
containerClassName={classNames(className, styles.container)}
pageClassName={classNames(styles.button, styles.page)}
breakClassName={classNames(styles.button, styles.break)}
activeClassName={styles.active}
previousClassName={classNames(styles.button, styles.previous)}
nextClassName={classNames(styles.button, styles.next)}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,35 @@
transform: rotate(180deg);
}

.panelGrabber {
.panelGrabberVertical {
height: 100vh;
padding: variables.$spacing-sm;
width: 10px;
display: flex;
flex-direction: row;
}

.grabberHandleIcon {
margin: auto;
height: 25px;
color: colors.$grey-100;
.panelGrabberHorizontal {
width: 100%;
height: 10px;
display: flex;
flex-direction: column;
}

.handleIcon {
background-color: colors.$grey-100;
border-radius: variables.$border-radius-sm;
}

.handleIconVertical {
margin: auto 0 auto auto;
height: 30px;
width: 3px;
}

.handleIconHorizontal {
margin: 0 auto auto;
width: 30px;
height: 3px;
}

.splitter {
Expand Down
Loading

0 comments on commit 33f10d3

Please sign in to comment.