Skip to content

Commit

Permalink
Add tooltips to overflow text on streams table (#21253)
Browse files Browse the repository at this point in the history
* WIP

* styling wip

* Simple implementation

* Calculated tooltips based on field length

* Use default dark tooltip

* Cleaned up code and fixed a bug. The existing cursor & PK selects have their own tooltips.

* console.log cleanup and re-adding commented fields

* Snapshot tests

* source defined primary key was causing issues

* Handle encoded text

* Fix encoded html error
  • Loading branch information
krishnaglick authored Jan 19, 2023
1 parent 8a96a7c commit a50ae01
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ $large: 200px;
.tableCell {
flex: 1 0 $medium;
min-width: $medium;
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;

[data-type="text"] {
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

&.xsmall {
flex-basis: $xsmall;
Expand All @@ -25,3 +29,7 @@ $large: 200px;
min-width: $large;
}
}

.noEllipsis > * {
overflow: visible;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import classNames from "classnames";
import React from "react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { useWindowSize } from "react-use";

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

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

Expand All @@ -8,6 +11,7 @@ type Sizes = "xsmall" | "small" | "medium" | "large";
interface CatalogTreeTableCellProps {
size?: Sizes;
className?: string;
withTooltip?: boolean;
}

// This lets us avoid the eslint complaint about unused styles
Expand All @@ -18,10 +22,63 @@ const sizeMap: Record<Sizes, string> = {
large: styles.large,
};

const TooltipText: React.FC<{ textNodes: Element[] }> = ({ textNodes }) => {
if (!textNodes.length) {
return null;
}
const text = textNodes.map((t) => decodeURIComponent(t.innerHTML)).join(" | ");
return <div dangerouslySetInnerHTML={{ __html: text }} />;
};

export const CatalogTreeTableCell: React.FC<React.PropsWithChildren<CatalogTreeTableCellProps>> = ({
size = "medium",
withTooltip,
className,
children,
}) => {
return <div className={classNames(styles.tableCell, className, sizeMap[size])}>{children}</div>;
const [tooltipDisabled, setTooltipDisabled] = useState(true);
const [textNodes, setTextNodes] = useState<Element[]>([]);
const cell = useRef<HTMLDivElement | null>(null);

const { width: windowWidth } = useWindowSize();

const getTextNodes = useCallback(() => {
if (withTooltip && cell.current) {
setTextNodes(Array.from(cell.current.querySelectorAll(`[data-type="text"]`)));
}
}, [withTooltip]);

useEffect(() => {
// windowWidth is only here so this functionality changes based on window width
if (textNodes.length && windowWidth) {
const [scrollWidths, clientWidths] = textNodes.reduce(
([scrollWidths, clientWidths], textNode) => {
if (textNode) {
scrollWidths += textNode.scrollWidth;
clientWidths += textNode.clientWidth;
}
return [scrollWidths, clientWidths];
},
[0, 0]
);

if (scrollWidths > clientWidths) {
setTooltipDisabled(false);
} else {
setTooltipDisabled(true);
}
}
}, [textNodes, windowWidth]);

return (
<div ref={cell} className={classNames(styles.tableCell, className, sizeMap[size])} onMouseEnter={getTextNodes}>
{withTooltip ? (
<Tooltip className={styles.noEllipsis} control={children} placement="bottom-start" disabled={tooltipDisabled}>
<TooltipText textNodes={textNodes} />
</Tooltip>
) : (
children
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,17 @@ export const CatalogTreeTableRow: React.FC<StreamHeaderProps> = ({
<Switch size="sm" checked={stream.config?.selected} onChange={onSelectStream} disabled={disabled} />
</CatalogTreeTableCell>
{/* <Cell>{fieldCount}</Cell> */}
<CatalogTreeTableCell>
<CatalogTreeTableCell withTooltip>
<Text size="md" className={styles.cellText}>
{stream.stream?.namespace || <FormattedMessage id="form.noNamespace" />}
</Text>
</CatalogTreeTableCell>
<CatalogTreeTableCell>
<CatalogTreeTableCell withTooltip>
<Text size="md" className={styles.cellText}>
{stream.stream?.name}
</Text>
</CatalogTreeTableCell>
<CatalogTreeTableCell size="large">
<CatalogTreeTableCell size="large" withTooltip>
{disabled ? (
<Text size="md" className={styles.cellText}>
{syncSchema.syncMode}
Expand All @@ -104,7 +104,7 @@ export const CatalogTreeTableRow: React.FC<StreamHeaderProps> = ({
/>
)}
</CatalogTreeTableCell>
<CatalogTreeTableCell>
<CatalogTreeTableCell withTooltip={pkType === "sourceDefined"}>
{pkType && (
<StreamPathSelect
pathType={pkType}
Expand All @@ -120,12 +120,12 @@ export const CatalogTreeTableRow: React.FC<StreamHeaderProps> = ({
<CatalogTreeTableCell size="xsmall">
<ArrowRightIcon />
</CatalogTreeTableCell>
<CatalogTreeTableCell>
<CatalogTreeTableCell withTooltip>
<Text size="md" className={styles.cellText}>
{destNamespace}
</Text>
</CatalogTreeTableCell>
<CatalogTreeTableCell>
<CatalogTreeTableCell withTooltip>
<Text size="md" className={styles.cellText}>
{destName}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ exports[`<BulkEditPanel /> should render 1`] = `
>
<span
class="<removed-for-snapshot-test>"
data-type="text"
/>
</div>
<svg
Expand Down Expand Up @@ -146,6 +147,7 @@ exports[`<BulkEditPanel /> should render 1`] = `
>
<span
class="<removed-for-snapshot-test>"
data-type="text"
>
Not available
</span>
Expand Down Expand Up @@ -210,6 +212,7 @@ exports[`<BulkEditPanel /> should render 1`] = `
>
<span
class="<removed-for-snapshot-test>"
data-type="text"
>
Not available
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ exports[`SchemaChangesBackdrop renders if there are non-breaking changes and pre
</div>
<p
class="text md text"
data-type="text"
>
Please review the schema updates before making changes to the connection
</p>
Expand Down Expand Up @@ -181,6 +182,7 @@ exports[`SchemaChangesBackdrop renders with breaking changes and prevents backgr
</div>
<p
class="text md text"
data-type="text"
>
Please review the schema updates before making changes to the connection
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ exports[`CreateConnectionForm should render 1`] = `
</span>
<p
class="<removed-for-snapshot-test>"
data-type="text"
>
Optional
</p>
Expand Down Expand Up @@ -1072,11 +1073,13 @@ exports[`CreateConnectionForm should render with an error 1`] = `
</div>
<p
class="<removed-for-snapshot-test>"
data-type="text"
>
Failed to fetch schema. Please try again
</p>
<p
class="<removed-for-snapshot-test>"
data-type="text"
>
Error: Test Error
</p>
Expand Down
1 change: 1 addition & 0 deletions airbyte-webapp/src/components/ui/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const Text: React.FC<React.PropsWithChildren<TextProps>> = React.memo(

return React.createElement(as, {
...remainingProps,
"data-type": "text",
className,
children,
});
Expand Down
15 changes: 8 additions & 7 deletions airbyte-webapp/src/components/ui/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable jsx-a11y/mouse-events-have-key-events */
import { autoUpdate, flip, offset, shift, useFloating, UseFloatingProps } from "@floating-ui/react-dom";
import classNames from "classnames";
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useMemo } from "react";
import { createPortal } from "react-dom";

import { tooltipContext } from "./context";
Expand Down Expand Up @@ -54,7 +54,7 @@ export const Tooltip: React.FC<React.PropsWithChildren<TooltipProps>> = (props)
};
}, [isMouseOver]);

const canShowTooltip = isVisible && !disabled;
const canShowTooltip = useMemo(() => isVisible && !disabled, [disabled, isVisible]);

const onMouseOver = () => {
setIsMouseOver(true);
Expand All @@ -75,8 +75,8 @@ export const Tooltip: React.FC<React.PropsWithChildren<TooltipProps>> = (props)
>
{control}
</span>
{canShowTooltip &&
createPortal(
{createPortal(
canShowTooltip ? (
<div
role="tooltip"
ref={floating}
Expand All @@ -90,9 +90,10 @@ export const Tooltip: React.FC<React.PropsWithChildren<TooltipProps>> = (props)
onMouseOut={onMouseOut}
>
<tooltipContext.Provider value={props}>{children}</tooltipContext.Provider>
</div>,
document.body
)}
</div>
) : null,
document.body
)}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ exports[`ConnectionReplicationPage should render 1`] = `
</span>
<p
class="<removed-for-snapshot-test>"
data-type="text"
>
Optional
</p>
Expand Down Expand Up @@ -883,6 +884,7 @@ exports[`ConnectionReplicationPage should show an error if there is a schemaErro
</div>
<p
class="<removed-for-snapshot-test>"
data-type="text"
>
Failed to fetch schema. Please try again
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exports[`<mockFrequentlyUsedConnectors /> should renders with mock data without
>
<p
class="<removed-for-snapshot-test>"
data-type="text"
>
Most frequently used destinations
</p>
Expand Down

0 comments on commit a50ae01

Please sign in to comment.