Skip to content

Commit

Permalink
feat(table) add scrollable table component WD-3408
Browse files Browse the repository at this point in the history
  • Loading branch information
edlerd committed May 26, 2023
1 parent 8469384 commit 416dc86
Show file tree
Hide file tree
Showing 13 changed files with 218 additions and 280 deletions.
9 changes: 5 additions & 4 deletions src/components/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Button, Icon, Input, Select } from "@canonical/react-components";
import React, { FC, useEffect, useState } from "react";
import React, { FC, HTMLAttributes, useEffect, useState } from "react";
import { paginationOptions } from "util/pagination";
import useEventListener from "@use-it/event-listener";

Expand All @@ -11,7 +11,7 @@ const figureSmallScreen = () => {
return descriptionElement.getBoundingClientRect().width < 230;
};

interface Props {
type Props = {
pageSize: number;
setPageSize: (val: number) => void;
currentPage: number;
Expand All @@ -20,7 +20,7 @@ interface Props {
totalCount: number;
totalPages: number;
keyword: string;
}
} & HTMLAttributes<HTMLDivElement>;

const Pagination: FC<Props> = ({
pageSize,
Expand All @@ -31,6 +31,7 @@ const Pagination: FC<Props> = ({
totalCount,
totalPages,
keyword,
...divProps
}) => {
const [isSmallScreen, setSmallScreen] = useState(figureSmallScreen());

Expand All @@ -41,7 +42,7 @@ const Pagination: FC<Props> = ({
useEffect(resize, []);

return (
<div className="pagination">
<div className="pagination" {...divProps}>
<div className="description" id="pagination-description">
{isSmallScreen
? `${visibleCount}\xa0out\xa0of\xa0${totalCount}`
Expand Down
46 changes: 46 additions & 0 deletions src/components/ScrollableTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { DependencyList, FC, ReactNode, useEffect, useRef } from "react";
import useEventListener from "@use-it/event-listener";

interface Props {
children: ReactNode;
dependencies: DependencyList;
belowId?: string;
}

const ScrollableTable: FC<Props> = ({ dependencies, children, belowId }) => {
const ref = useRef<HTMLDivElement>(null);

const getAbsoluteHeightBelow = () => {
const element = belowId ? document.getElementById(belowId) : undefined;
if (!element) {
return 0;
}
const style = window.getComputedStyle(element);
const margin = parseInt(style.marginTop) + parseInt(style.marginBottom);
return element.offsetHeight + margin;
};

const updateTBodyHeight = () => {
const table = ref.current?.children[0];
if (!table || table.children.length !== 2) {
return;
}
const tBody = table.children[1];
const above = tBody.getBoundingClientRect().top + 1;
const below = getAbsoluteHeightBelow();
const offset = Math.ceil(above + below);
const style = `height: calc(100vh - ${offset}px); min-height: calc(100vh - ${offset}px)`;
tBody.setAttribute("style", style);
};

useEventListener("resize", updateTBodyHeight);
useEffect(updateTBodyHeight, [...dependencies, ref]);

return (
<div ref={ref} className="scrollable-table">
{children}
</div>
);
};

export default ScrollableTable;
70 changes: 30 additions & 40 deletions src/pages/instances/InstanceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { useInstanceLoading } from "context/instanceLoading";
import InstanceLink from "pages/instances/InstanceLink";
import Pagination from "components/Pagination";
import { usePagination } from "util/pagination";
import { updateTBodyHeight } from "util/updateTBodyHeight";
import SelectableMainTable from "components/SelectableMainTable";
import InstanceBulkActions from "pages/instances/actions/InstanceBulkActions";
import { getIpAddresses } from "util/networks";
Expand All @@ -44,6 +43,7 @@ import {
TYPE,
} from "util/instanceTable";
import { getInstanceName } from "util/operations";
import ScrollableTable from "components/ScrollableTable";

const loadHidden = () => {
const saved = localStorage.getItem("instanceListHiddenColumns");
Expand Down Expand Up @@ -446,20 +446,6 @@ const InstanceList: FC = () => {
creationOperations,
]);

const updateTableHeight = () => updateTBodyHeight("instance-table-wrapper");
useEventListener("resize", updateTableHeight);
useEffect(updateTableHeight, [
instances,
creationOperations,
notify.notification,
filters.queries,
filters.statuses,
filters.types,
filters.profileQueries,
pagination.pageSize,
pagination.currentPage,
]);

const hasInstances =
isLoading || instances.length > 0 || creationOperations.length > 0;
const selectedInstances = instances.filter((instance) =>
Expand Down Expand Up @@ -535,32 +521,36 @@ const InstanceList: FC = () => {
"u-hide": panelParams.instance,
})}
/>
<SelectableMainTable
headers={getHeaders(userHidden.concat(sizeHidden))}
rows={pagination.pageData}
sortable
className="instance-table"
id="instance-table-wrapper"
emptyStateMsg={
isLoading ? (
<Loader text="Loading instances..." />
) : (
<>No instance found matching this search</>
)
}
itemName="instance"
parentName="project"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
totalCount={instances.length}
filteredNames={filteredInstances.map(
(instance) => instance.name
)}
onUpdateSort={pagination.updateSort}
/>
<ScrollableTable
belowId="pagination"
dependencies={[filteredInstances, notify.notification]}
>
<SelectableMainTable
headers={getHeaders(userHidden.concat(sizeHidden))}
rows={pagination.pageData}
sortable
emptyStateMsg={
isLoading ? (
<Loader text="Loading instances..." />
) : (
<>No instance found matching this search</>
)
}
itemName="instance"
parentName="project"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
totalCount={instances.length}
filteredNames={filteredInstances.map(
(instance) => instance.name
)}
onUpdateSort={pagination.updateSort}
/>
</ScrollableTable>
<Pagination
{...pagination}
id="pagination"
totalCount={instances.length + creationOperations.length}
visibleCount={
filteredInstances.length === instances.length
Expand All @@ -573,7 +563,7 @@ const InstanceList: FC = () => {
<SelectableMainTable
headers={getHeaders(userHidden)}
rows={getRows(userHidden)}
className="instance-table u-table-layout--auto"
className="scrollable-table"
itemName="instance"
parentName="project"
selectedNames={selectedNames}
Expand Down
50 changes: 23 additions & 27 deletions src/pages/instances/InstanceSnapshots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import SnapshotActions from "./actions/snapshots/SnapshotActions";
import useEventListener from "@use-it/event-listener";
import Pagination from "components/Pagination";
import { usePagination } from "util/pagination";
import { updateTBodyHeight } from "util/updateTBodyHeight";
import ItemName from "components/ItemName";
import SelectableMainTable from "components/SelectableMainTable";
import SnapshotBulkDelete from "pages/instances/actions/snapshots/SnapshotBulkDelete";
import ConfigureSnapshotsBtn from "pages/instances/actions/snapshots/ConfigureSnapshotsBtn";
import Loader from "components/Loader";
import { useProject } from "context/project";
import ScrollableTable from "components/ScrollableTable";

const collapsedViewMaxWidth = 1250;
export const figureCollapsedScreen = (): boolean =>
Expand Down Expand Up @@ -175,17 +175,9 @@ const InstanceSnapshots: FC<Props> = ({ instance }) => {
const pagination = usePagination(rows, "created_at", "descending");

const resize = () => {
updateTBodyHeight("snapshots-table-wrapper");
setSmallScreen(figureCollapsedScreen());
};
useEventListener("resize", resize);
useEffect(resize, [
instance.snapshots,
inTabNotification,
query,
pagination.pageSize,
pagination.currentPage,
]);

return isLoading ? (
<Loader />
Expand Down Expand Up @@ -258,26 +250,30 @@ const InstanceSnapshots: FC<Props> = ({ instance }) => {
/>
{hasSnapshots ? (
<>
<SelectableMainTable
headers={headers}
rows={pagination.pageData}
sortable
className="snapshots-table"
id="snapshots-table-wrapper"
emptyStateMsg="No snapshot found matching this search"
itemName="snapshot"
parentName="instance"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
totalCount={instance.snapshots?.length ?? 0}
filteredNames={filteredSnapshots.map((snapshot) => snapshot.name)}
onUpdateSort={pagination.updateSort}
defaultSort="created_at"
defaultSortDirection="descending"
/>
<ScrollableTable
dependencies={[filteredSnapshots, inTabNotification]}
belowId="pagination"
>
<SelectableMainTable
headers={headers}
rows={pagination.pageData}
sortable
emptyStateMsg="No snapshot found matching this search"
itemName="snapshot"
parentName="instance"
selectedNames={selectedNames}
setSelectedNames={setSelectedNames}
processingNames={processingNames}
totalCount={instance.snapshots?.length ?? 0}
filteredNames={filteredSnapshots.map((snapshot) => snapshot.name)}
onUpdateSort={pagination.updateSort}
defaultSort="created_at"
defaultSortDirection="descending"
/>
</ScrollableTable>
<Pagination
{...pagination}
id="pagination"
totalCount={instance.snapshots?.length ?? 0}
visibleCount={
filteredSnapshots.length === instance.snapshots?.length
Expand Down
21 changes: 10 additions & 11 deletions src/pages/instances/forms/ConfigurationTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, ReactNode, useEffect, useState } from "react";
import React, { FC, ReactNode, useState } from "react";
import { Icon, MainTable, Tooltip } from "@canonical/react-components";
import {
MainTableCell,
Expand All @@ -8,9 +8,9 @@ import {
import { figureCollapsedScreen } from "util/formFields";
import { SharedFormikTypes } from "pages/instances/forms/sharedFormTypes";
import useEventListener from "@use-it/event-listener";
import { updateTBodyHeight } from "util/updateTBodyHeight";
import { useNotify } from "context/notify";
import { TOOLTIP_OVER_MODAL_ZINDEX } from "util/zIndex";
import ScrollableTable from "components/ScrollableTable";

interface Props {
formik: SharedFormikTypes;
Expand All @@ -32,11 +32,9 @@ const ConfigurationTable: FC<Props> = ({
const isCollapsedView = isSmallScreen || isCollapsedOverride;

const resize = () => {
updateTBodyHeight("configuration-table");
setSmallScreen(figureCollapsedScreen());
};
useEventListener("resize", resize);
useEffect(resize, [notify.notification]);

const isReadOnly = formik.values.readOnly;

Expand Down Expand Up @@ -104,13 +102,14 @@ const ConfigurationTable: FC<Props> = ({
];

return (
<MainTable
className="u-table-layout--fixed configuration-table"
id="configuration-table"
emptyStateMsg={emptyStateMsg}
headers={filterHeaders(headers)}
rows={filterRows(collapseRows(rows))}
/>
<ScrollableTable dependencies={[notify.notification]}>
<MainTable
className="configuration-table"
emptyStateMsg={emptyStateMsg}
headers={filterHeaders(headers)}
rows={filterRows(collapseRows(rows))}
/>
</ScrollableTable>
);
};

Expand Down
Loading

0 comments on commit 416dc86

Please sign in to comment.