Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WCMS-21498: Add fullscreen mode to dataset table tab #237

Merged
merged 10 commits into from
Aug 19, 2024
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