Fix Datagrid links regression (#3548)
* Add Datagrid hack anchor * Add tabIndex=-1 and aria-hidden * Use react-router-dom `navigate` for smoother experience * Remove debug * Code review * Add comment * Typo
This commit is contained in:
parent
6acf43bab5
commit
2d0f40c021
5 changed files with 73 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
|||
import "@glideapps/glide-data-grid/dist/index.css";
|
||||
|
||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||
import { usePreventHistoryBack } from "@dashboard/hooks/usePreventHistoryBack";
|
||||
import DataEditor, {
|
||||
DataEditorProps,
|
||||
|
@ -94,6 +95,7 @@ export interface DatagridProps {
|
|||
freezeColumns?: DataEditorProps["freezeColumns"];
|
||||
verticalBorder?: DataEditorProps["verticalBorder"];
|
||||
columnSelect?: DataEditorProps["columnSelect"];
|
||||
rowAnchor?: (item: Item) => string;
|
||||
}
|
||||
|
||||
export const Datagrid: React.FC<DatagridProps> = ({
|
||||
|
@ -120,6 +122,7 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
|||
onColumnMoved,
|
||||
onColumnResize,
|
||||
loading,
|
||||
rowAnchor,
|
||||
hasRowHover = false,
|
||||
...datagridProps
|
||||
}): ReactElement => {
|
||||
|
@ -129,6 +132,9 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
|||
const editor = useRef<DataEditorRef>();
|
||||
const customRenderers = useCustomCellRenderers();
|
||||
|
||||
const hackARef = useRef<HTMLAnchorElement>(null);
|
||||
const navigate = useNavigator();
|
||||
|
||||
const { scrolledToRight, scroller } = useScrollRight();
|
||||
|
||||
const defualtColumnPickerProps = getDefultColumnPickerProps(
|
||||
|
@ -227,8 +233,25 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
|||
if (hasRowHover) {
|
||||
setHoverRow(args.kind !== "cell" ? undefined : args.location[1]);
|
||||
}
|
||||
|
||||
// the code below is responsible for adding native <a> element when hovering over rows in the datagrid
|
||||
// this makes it possible to open links in a new tab and copy them
|
||||
if (args.kind !== "cell" || !hackARef.current || !rowAnchor) {
|
||||
return;
|
||||
}
|
||||
const href = rowAnchor(args.location);
|
||||
|
||||
if (!href) {
|
||||
return;
|
||||
}
|
||||
|
||||
hackARef.current.style.left = `${window.scrollX + args.bounds.x}px`;
|
||||
hackARef.current.style.width = `${args.bounds.width}px`;
|
||||
hackARef.current.style.top = `${window.scrollY + args.bounds.y}px`;
|
||||
hackARef.current.style.height = `${args.bounds.height}px`;
|
||||
hackARef.current.href = href;
|
||||
},
|
||||
[hasRowHover],
|
||||
[hasRowHover, rowAnchor],
|
||||
);
|
||||
|
||||
const handleGridSelectionChange = (gridSelection: GridSelection) => {
|
||||
|
@ -487,6 +510,16 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
|||
bounds={tooltip?.bounds}
|
||||
title={tooltip?.title}
|
||||
/>
|
||||
<a
|
||||
ref={hackARef}
|
||||
style={{ position: "absolute" }}
|
||||
tabIndex={-1}
|
||||
aria-hidden={true}
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
navigate(e.currentTarget.pathname);
|
||||
}}
|
||||
/>
|
||||
</FullScreenContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -22,7 +22,8 @@ interface OrderListDatagridProps
|
|||
extends ListProps,
|
||||
SortPage<OrderListUrlSortField> {
|
||||
orders: RelayToFlat<OrderListQuery["orders"]>;
|
||||
onRowClick: (id: string) => void;
|
||||
onRowClick?: (id: string) => void;
|
||||
rowAnchor?: (id: string) => string;
|
||||
hasRowHover?: boolean;
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,7 @@ export const OrderListDatagrid: React.FC<OrderListDatagridProps> = ({
|
|||
sort,
|
||||
onRowClick,
|
||||
hasRowHover,
|
||||
rowAnchor,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const datagrid = useDatagridChangeState();
|
||||
|
@ -65,12 +67,27 @@ export const OrderListDatagrid: React.FC<OrderListDatagridProps> = ({
|
|||
|
||||
const handleRowClick = useCallback(
|
||||
([_, row]: Item) => {
|
||||
if (!onRowClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rowData = orders[row];
|
||||
onRowClick(rowData.id);
|
||||
},
|
||||
[onRowClick, orders],
|
||||
);
|
||||
|
||||
const handleRowAnchor = useCallback(
|
||||
([, row]: Item) => {
|
||||
if (!rowAnchor) {
|
||||
return;
|
||||
}
|
||||
const rowData = orders[row];
|
||||
return rowAnchor(rowData.id);
|
||||
},
|
||||
[rowAnchor, orders],
|
||||
);
|
||||
|
||||
const getCellContent = useGetCellContent({
|
||||
columns,
|
||||
orders,
|
||||
|
@ -113,6 +130,7 @@ export const OrderListDatagrid: React.FC<OrderListDatagridProps> = ({
|
|||
)}
|
||||
fullScreenTitle={intl.formatMessage(messages.orders)}
|
||||
onRowClick={handleRowClick}
|
||||
rowAnchor={handleRowAnchor}
|
||||
/>
|
||||
|
||||
<Box paddingX={9}>
|
||||
|
|
|
@ -12,7 +12,6 @@ import { useDevModeContext } from "@dashboard/components/DevModePanel/hooks";
|
|||
import { FilterPresetsSelect } from "@dashboard/components/FilterPresetsSelect";
|
||||
import { ListPageLayout } from "@dashboard/components/Layouts";
|
||||
import { OrderListQuery, RefreshLimitsQuery } from "@dashboard/graphql";
|
||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||
import { sectionNames } from "@dashboard/intl";
|
||||
import { orderMessages } from "@dashboard/orders/messages";
|
||||
import { DevModeQuery } from "@dashboard/orders/queries";
|
||||
|
@ -87,7 +86,6 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
|||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
const navigate = useNavigator();
|
||||
const filterStructure = createFilterStructure(intl, filterOpts);
|
||||
const limitsReached = isLimitReached(limits, "orders");
|
||||
const [isFilterPresetOpen, setFilterPresetOpen] = useState(false);
|
||||
|
@ -221,9 +219,7 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
|||
<OrderListDatagrid
|
||||
{...listProps}
|
||||
hasRowHover={!isFilterPresetOpen}
|
||||
onRowClick={id => {
|
||||
navigate(orderUrl(id));
|
||||
}}
|
||||
rowAnchor={orderUrl}
|
||||
/>
|
||||
</Card>
|
||||
</ListPageLayout>
|
||||
|
|
|
@ -49,7 +49,8 @@ interface ProductListDatagridProps
|
|||
activeAttributeSortId: string;
|
||||
gridAttributes: RelayToFlat<GridAttributesQuery["grid"]>;
|
||||
products: RelayToFlat<ProductListQuery["products"]>;
|
||||
onRowClick: (id: string) => void;
|
||||
onRowClick?: (id: string) => void;
|
||||
rowAnchor?: (id: string) => string;
|
||||
columnQuery: string;
|
||||
availableInGridAttributes: RelayToFlat<
|
||||
SearchAvailableInGridAttributesQuery["availableInGrid"]
|
||||
|
@ -80,6 +81,7 @@ export const ProductListDatagrid: React.FC<ProductListDatagridProps> = ({
|
|||
activeAttributeSortId,
|
||||
filterDependency,
|
||||
hasRowHover,
|
||||
rowAnchor,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const searchProductType = useSearchProductTypes();
|
||||
|
@ -185,12 +187,26 @@ export const ProductListDatagrid: React.FC<ProductListDatagridProps> = ({
|
|||
|
||||
const handleRowClick = useCallback(
|
||||
([_, row]: Item) => {
|
||||
if (!onRowClick) {
|
||||
return;
|
||||
}
|
||||
const rowData = products[row];
|
||||
onRowClick(rowData.id);
|
||||
},
|
||||
[onRowClick, products],
|
||||
);
|
||||
|
||||
const handleRowAnchor = useCallback(
|
||||
([, row]: Item) => {
|
||||
if (!rowAnchor) {
|
||||
return;
|
||||
}
|
||||
const rowData = products[row];
|
||||
return rowAnchor(rowData.id);
|
||||
},
|
||||
[rowAnchor, products],
|
||||
);
|
||||
|
||||
const handleGetColumnTooltipContent = useCallback(
|
||||
(colIndex: number): string => {
|
||||
const { columnName } = getColumnMetadata(columns[colIndex].id);
|
||||
|
@ -245,6 +261,7 @@ export const ProductListDatagrid: React.FC<ProductListDatagridProps> = ({
|
|||
selectionActions={() => null}
|
||||
fullScreenTitle={intl.formatMessage(messages.products)}
|
||||
onRowClick={handleRowClick}
|
||||
rowAnchor={handleRowAnchor}
|
||||
renderColumnPicker={defaultProps => (
|
||||
<ColumnPicker
|
||||
{...defaultProps}
|
||||
|
|
|
@ -287,9 +287,7 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
|
|||
settings={settings}
|
||||
selectedChannelId={selectedChannelId}
|
||||
onUpdateListSettings={onUpdateListSettings}
|
||||
onRowClick={id => {
|
||||
navigate(productUrl(id));
|
||||
}}
|
||||
rowAnchor={productUrl}
|
||||
/>
|
||||
) : (
|
||||
<ProductListTiles
|
||||
|
|
Loading…
Reference in a new issue