Skip to content

Commit

Permalink
WCMS-21498: Add fullscreen mode to dataset table tab (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
brdunfield authored Aug 19, 2024
1 parent 72d722d commit 375dda0
Show file tree
Hide file tree
Showing 17 changed files with 592 additions and 364 deletions.
109 changes: 109 additions & 0 deletions src/components/DataTableControls/DataTableControls.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import DataTableControls from ".";
import { ManageColumnsContext } from "../DatasetTableTab/DataTableStateWrapper";
import { DataTableContext } from "../../templates/Dataset";
import * as resource from "../../tests/fixtures/resource.json";
import * as distribution from "../../tests/fixtures/distribution.json";

describe('DataTableControls', () => {
resource.setSort = jest.fn();
it('Renders correctly', () => {
render(
<DataTableContext.Provider value={{
resource: resource,
distribution: distribution.distribution[0],
rootUrl: "test/api/",
}}>
<ManageColumnsContext.Provider value={{
columnOrder: [],
setColumnOrder: jest.fn(),
setColumnVisibility: jest.fn()
}}>
<DataTableControls
id={"test"}
columns={[]}
defaultColumnOrder={[]}
isModal={false}
closeFullScreenModal={jest.fn()}
/>
</ManageColumnsContext.Provider>
</DataTableContext.Provider>
)
expect(screen.getByRole("button", {name: "Manage columns - Opens in a dialog"})).toBeInTheDocument();
expect(screen.getByRole("button", {name: "Full Screen mode - Opens in a dialog"})).toBeInTheDocument();
});
it('Renders hidden columns', () => {
const columns = [
{
"id": "teaching_hospital_ccn",
"depth": 0,
"columnDef": {
"header": "Teaching_Hospital_CCN",
"filterFn": "auto",
"sortingFn": "auto",
"sortUndefined": 1,
"aggregationFn": "auto",
"size": 150,
"minSize": 20,
"maxSize": 9007199254740991,
"accessorKey": "teaching_hospital_ccn"
},
"columns": [],
"getIsVisible": () => false // mock not visible
},
{
"id": "change_type",
"depth": 0,
"columnDef": {
"header": "Change_Type",
"filterFn": "auto",
"sortingFn": "auto",
"sortUndefined": 1,
"aggregationFn": "auto",
"size": 150,
"minSize": 20,
"maxSize": 9007199254740991,
"accessorKey": "change_type"
},
"columns": [],
"getIsVisible": () => true
},
];
render(
<ManageColumnsContext.Provider value={{
columnOrder: [],
setColumnOrder: jest.fn(),
setColumnVisibility: jest.fn()
}}>
<DataTableControls
id={"test"}
columns={columns}
defaultColumnOrder={[]}
isModal={true}
closeFullScreenModal={jest.fn()}
/>
</ManageColumnsContext.Provider>
);
expect(screen.getByText("1 Columns Hidden")).toBeInTheDocument();
})
it('Does not render the full screen dialog if we are already in a dialog', () => {
render(
<ManageColumnsContext.Provider value={{
columnOrder: [],
setColumnOrder: jest.fn(),
setColumnVisibility: jest.fn()
}}>
<DataTableControls
id={"test"}
columns={[]}
defaultColumnOrder={[]}
isModal={true}
closeFullScreenModal={jest.fn()}
/>
</ManageColumnsContext.Provider>
);
expect(screen.queryByRole("button", {name: "Full Screen mode - Opens in a dialog"})).not.toBeInTheDocument();
expect(screen.getByRole("button", {name: "Close Full Screen dialog"})).toBeInTheDocument();
})
})
66 changes: 66 additions & 0 deletions src/components/DataTableControls/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from "react";
import { useState } from "react";
import { Alert } from "@cmsgov/design-system";
import ManageColumns from "../ManageColumns/ManageColumns";
import FullScreenDataTable from "../FullScreenDataTable";

const DataTableControls = (
{id, columns, defaultColumnOrder, isModal, closeFullScreenModal} : {
id: string,
columns: Array<any>,
defaultColumnOrder: Array<string>,
isModal: boolean,
closeFullScreenModal: Function
}
) => {
const [manageColumnsModalOpen, setManageColumnsModalOpen] = useState(false);
const [fullScreenModalOpen, setFullScreenModalOpen] = useState(false);

const hiddenColumns = columns.filter(c => c.getIsVisible() === false ).length;

return (
<>
<div className='ds-u-border-top--1 ds-u-fill--gray-lightest ds-u-display--flex ds-u-justify-content--between'>
<div>
{hiddenColumns > 0 && (
<Alert variation="warn">{hiddenColumns} Columns Hidden</Alert>
)}
</div>
<div>
<button
aria-label='Manage columns - Opens in a dialog'
className="ds-c-button ds-c-button--ghost ds-u-margin-y--1"
onClick={() => {
setManageColumnsModalOpen(true)
}}
><i className="far fa-cog ds-u-margin-right--1"></i>Manage Columns</button>
<button
aria-label={isModal ? 'Close Full Screen dialog' : 'Full Screen mode - Opens in a dialog'}
className="ds-c-button ds-c-button--ghost ds-u-margin-y--1"
onClick={() => {
if (isModal) {
closeFullScreenModal();
} else {
setFullScreenModalOpen(true)
}
}}
><i className={`fa ${isModal ? 'fa-compress' : 'fa-expand'} ds-u-margin-right--1`}></i>{isModal ? "Exit Full Screen" : "Full Screen"}</button>
</div>
</div>
<div>
<ManageColumns
id={id}
columns={columns}
defaultColumnOrder={defaultColumnOrder}
modalOpen={manageColumnsModalOpen}
setModalOpen={setManageColumnsModalOpen}
/>
{!isModal && (
<FullScreenDataTable modalOpen={fullScreenModalOpen} setModalOpen={setFullScreenModalOpen} />
)}
</div>
</>
)
};

export default DataTableControls;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ jest.mock('axios');
describe('<DataDictionary />', () => {
beforeEach(async () => {
await axios.get.mockImplementation((url) => {
console.log(url);
switch (url) {
case 'http://dkan.com/api/1/metastore/schemas/data-dictionary/items/sitewide-data-dictionary':
return Promise.resolve({data: siteWideDataDictionary});
Expand Down
43 changes: 43 additions & 0 deletions src/components/DatasetTableTab/DataTableStateWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { createContext, useContext, useState } from "react";
import DatasetTable from ".";
import { DataTableContext } from "../../templates/Dataset";

export const ManageColumnsContext = createContext({})

const DataTableStateWrapper = () => {
const { id, datasetTableControls } = useContext(DataTableContext);
// a wrapper component to keep column state synced between full screen and regular modes
const localStorageData = id ? JSON.parse(localStorage.getItem(id) as string) : null;

const defaultPage = 1;
const [page, setPage] = useState(defaultPage);

const [columnOrder, setColumnOrder] = useState(() => {
if (datasetTableControls && localStorageData)
return localStorageData.tableColumnOrder;
else
return [];
})
const [columnVisibility, setColumnVisibility] = useState(() => {
if (datasetTableControls && localStorageData)
return localStorageData.tableColumnVisibility;
else
return {};
})

return (
<ManageColumnsContext.Provider value={{
columnOrder: columnOrder,
setColumnOrder: setColumnOrder,
columnVisibility: columnVisibility,
setColumnVisibility: setColumnVisibility,
page: page,
setPage: setPage
}}>
<DatasetTable />
</ManageColumnsContext.Provider>
)
}

export default DataTableStateWrapper;
97 changes: 76 additions & 21 deletions src/components/DatasetTableTab/DatasetTableTab.test.jsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,98 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { render, screen, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import DatasetTable from './index';
import DataTableStateWrapper from './DataTableStateWrapper';
import * as resource from "../../tests/fixtures/resource.json";
import * as distribution from "../../tests/fixtures/distribution.json";
import { DataTableContext } from '../../templates/Dataset';

describe('<DatasetTableTab />', () => {
test("Renders correctly", () => {
window.scrollTo = jest.fn();
beforeEach(() => {
resource.setSort = jest.fn();
})
test("Renders correctly", () => {
render(
<DatasetTable
resource={resource}
distribution={distribution.distribution[0]}
rootUrl={"test/api/"}
/>)
<DataTableContext.Provider value={{
resource: resource,
distribution: distribution.distribution[0],
rootUrl: "test/api/"
}} >
<DataTableStateWrapper />
</DataTableContext.Provider>
)

expect(screen.getByText("Data filters: none")).toBeInTheDocument();
expect(screen.getByRole("table")).toBeInTheDocument();
expect(screen.getByRole("navigation")).toHaveClass("ds-c-pagination");
});
test("Renders data dictionary info banner if prop is provided", () => {
resource.setSort = jest.fn();
render(
<DatasetTable
resource={resource}
distribution={distribution.distribution[0]}
rootUrl={"test/api/"}
dataDictionaryBanner={true}
/>)
<DataTableContext.Provider value={{
resource: resource,
distribution: distribution.distribution[0],
rootUrl: "test/api/",
dataDictionaryBanner: true
}} >
<DataTableStateWrapper />
</DataTableContext.Provider>
)
expect(screen.getByText('Click on the "Data Dictionary" tab above for full column definitions')).toBeInTheDocument();
});
test("Does not render data dictionary info banner if prop is not provided", () => {
resource.setSort = jest.fn();
render(
<DatasetTable
resource={resource}
distribution={distribution.distribution[0]}
rootUrl={"test/api/"}
/>)
<DataTableContext.Provider value={{
resource: resource,
distribution: distribution.distribution[0],
rootUrl: "test/api/"
}} >
<DataTableStateWrapper />
</DataTableContext.Provider>
)
expect(screen.queryByText('Click on the "Data Dictionary" tab above for full column definitions')).not.toBeInTheDocument();
});
test("Renders controls if prop is provided", () => {
render(
<DataTableContext.Provider value={{
resource: resource,
distribution: distribution.distribution[0],
rootUrl: "test/api/",
datasetTableControls: true
}} >
<DataTableStateWrapper />
</DataTableContext.Provider>
)

expect(screen.queryAllByText("Manage Columns")).toHaveLength(2);
expect(screen.queryByText("Full Screen")).toBeInTheDocument();
})
test("State is synchronized between regular and full screen mode", async () => {
render(
<DataTableContext.Provider value={{
resource: resource,
distribution: distribution.distribution[0],
rootUrl: "test/api/",
datasetTableControls: true
}} >
<DataTableStateWrapper />
</DataTableContext.Provider>
)
// Is there a better way to do this test because every step seems to need an act
await act(async () => {
await screen.queryAllByText("Manage Columns")[0].click();
});
await act(async() => {
await screen.getByRole('checkbox', {name: "Select all"}).click()
})
await act(async() => {
await screen.getByRole('button', {name: 'Save'}).click();
})
await act(async() => {
await screen.getByRole('button', {name: 'Full Screen mode - Opens in a dialog'}).click();
})
await act(async () => {
await screen.queryAllByText("Manage Columns")[1].click();
});
expect(screen.getByRole('checkbox', {name: "Select all"})).not.toBeChecked();
}, 10000)
});
Loading

0 comments on commit 375dda0

Please sign in to comment.