Skip to content

Commit 375dda0

Browse files
authored
WCMS-21498: Add fullscreen mode to dataset table tab (#237)
1 parent 72d722d commit 375dda0

File tree

17 files changed

+592
-364
lines changed

17 files changed

+592
-364
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import React from "react";
2+
import { render, screen } from "@testing-library/react";
3+
import DataTableControls from ".";
4+
import { ManageColumnsContext } from "../DatasetTableTab/DataTableStateWrapper";
5+
import { DataTableContext } from "../../templates/Dataset";
6+
import * as resource from "../../tests/fixtures/resource.json";
7+
import * as distribution from "../../tests/fixtures/distribution.json";
8+
9+
describe('DataTableControls', () => {
10+
resource.setSort = jest.fn();
11+
it('Renders correctly', () => {
12+
render(
13+
<DataTableContext.Provider value={{
14+
resource: resource,
15+
distribution: distribution.distribution[0],
16+
rootUrl: "test/api/",
17+
}}>
18+
<ManageColumnsContext.Provider value={{
19+
columnOrder: [],
20+
setColumnOrder: jest.fn(),
21+
setColumnVisibility: jest.fn()
22+
}}>
23+
<DataTableControls
24+
id={"test"}
25+
columns={[]}
26+
defaultColumnOrder={[]}
27+
isModal={false}
28+
closeFullScreenModal={jest.fn()}
29+
/>
30+
</ManageColumnsContext.Provider>
31+
</DataTableContext.Provider>
32+
)
33+
expect(screen.getByRole("button", {name: "Manage columns - Opens in a dialog"})).toBeInTheDocument();
34+
expect(screen.getByRole("button", {name: "Full Screen mode - Opens in a dialog"})).toBeInTheDocument();
35+
});
36+
it('Renders hidden columns', () => {
37+
const columns = [
38+
{
39+
"id": "teaching_hospital_ccn",
40+
"depth": 0,
41+
"columnDef": {
42+
"header": "Teaching_Hospital_CCN",
43+
"filterFn": "auto",
44+
"sortingFn": "auto",
45+
"sortUndefined": 1,
46+
"aggregationFn": "auto",
47+
"size": 150,
48+
"minSize": 20,
49+
"maxSize": 9007199254740991,
50+
"accessorKey": "teaching_hospital_ccn"
51+
},
52+
"columns": [],
53+
"getIsVisible": () => false // mock not visible
54+
},
55+
{
56+
"id": "change_type",
57+
"depth": 0,
58+
"columnDef": {
59+
"header": "Change_Type",
60+
"filterFn": "auto",
61+
"sortingFn": "auto",
62+
"sortUndefined": 1,
63+
"aggregationFn": "auto",
64+
"size": 150,
65+
"minSize": 20,
66+
"maxSize": 9007199254740991,
67+
"accessorKey": "change_type"
68+
},
69+
"columns": [],
70+
"getIsVisible": () => true
71+
},
72+
];
73+
render(
74+
<ManageColumnsContext.Provider value={{
75+
columnOrder: [],
76+
setColumnOrder: jest.fn(),
77+
setColumnVisibility: jest.fn()
78+
}}>
79+
<DataTableControls
80+
id={"test"}
81+
columns={columns}
82+
defaultColumnOrder={[]}
83+
isModal={true}
84+
closeFullScreenModal={jest.fn()}
85+
/>
86+
</ManageColumnsContext.Provider>
87+
);
88+
expect(screen.getByText("1 Columns Hidden")).toBeInTheDocument();
89+
})
90+
it('Does not render the full screen dialog if we are already in a dialog', () => {
91+
render(
92+
<ManageColumnsContext.Provider value={{
93+
columnOrder: [],
94+
setColumnOrder: jest.fn(),
95+
setColumnVisibility: jest.fn()
96+
}}>
97+
<DataTableControls
98+
id={"test"}
99+
columns={[]}
100+
defaultColumnOrder={[]}
101+
isModal={true}
102+
closeFullScreenModal={jest.fn()}
103+
/>
104+
</ManageColumnsContext.Provider>
105+
);
106+
expect(screen.queryByRole("button", {name: "Full Screen mode - Opens in a dialog"})).not.toBeInTheDocument();
107+
expect(screen.getByRole("button", {name: "Close Full Screen dialog"})).toBeInTheDocument();
108+
})
109+
})
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from "react";
2+
import { useState } from "react";
3+
import { Alert } from "@cmsgov/design-system";
4+
import ManageColumns from "../ManageColumns/ManageColumns";
5+
import FullScreenDataTable from "../FullScreenDataTable";
6+
7+
const DataTableControls = (
8+
{id, columns, defaultColumnOrder, isModal, closeFullScreenModal} : {
9+
id: string,
10+
columns: Array<any>,
11+
defaultColumnOrder: Array<string>,
12+
isModal: boolean,
13+
closeFullScreenModal: Function
14+
}
15+
) => {
16+
const [manageColumnsModalOpen, setManageColumnsModalOpen] = useState(false);
17+
const [fullScreenModalOpen, setFullScreenModalOpen] = useState(false);
18+
19+
const hiddenColumns = columns.filter(c => c.getIsVisible() === false ).length;
20+
21+
return (
22+
<>
23+
<div className='ds-u-border-top--1 ds-u-fill--gray-lightest ds-u-display--flex ds-u-justify-content--between'>
24+
<div>
25+
{hiddenColumns > 0 && (
26+
<Alert variation="warn">{hiddenColumns} Columns Hidden</Alert>
27+
)}
28+
</div>
29+
<div>
30+
<button
31+
aria-label='Manage columns - Opens in a dialog'
32+
className="ds-c-button ds-c-button--ghost ds-u-margin-y--1"
33+
onClick={() => {
34+
setManageColumnsModalOpen(true)
35+
}}
36+
><i className="far fa-cog ds-u-margin-right--1"></i>Manage Columns</button>
37+
<button
38+
aria-label={isModal ? 'Close Full Screen dialog' : 'Full Screen mode - Opens in a dialog'}
39+
className="ds-c-button ds-c-button--ghost ds-u-margin-y--1"
40+
onClick={() => {
41+
if (isModal) {
42+
closeFullScreenModal();
43+
} else {
44+
setFullScreenModalOpen(true)
45+
}
46+
}}
47+
><i className={`fa ${isModal ? 'fa-compress' : 'fa-expand'} ds-u-margin-right--1`}></i>{isModal ? "Exit Full Screen" : "Full Screen"}</button>
48+
</div>
49+
</div>
50+
<div>
51+
<ManageColumns
52+
id={id}
53+
columns={columns}
54+
defaultColumnOrder={defaultColumnOrder}
55+
modalOpen={manageColumnsModalOpen}
56+
setModalOpen={setManageColumnsModalOpen}
57+
/>
58+
{!isModal && (
59+
<FullScreenDataTable modalOpen={fullScreenModalOpen} setModalOpen={setFullScreenModalOpen} />
60+
)}
61+
</div>
62+
</>
63+
)
64+
};
65+
66+
export default DataTableControls;

src/components/DatasetDataDictionaryTab/DatasetDataDictionaryTab.test.jsx

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ jest.mock('axios');
1212
describe('<DataDictionary />', () => {
1313
beforeEach(async () => {
1414
await axios.get.mockImplementation((url) => {
15-
console.log(url);
1615
switch (url) {
1716
case 'http://dkan.com/api/1/metastore/schemas/data-dictionary/items/sitewide-data-dictionary':
1817
return Promise.resolve({data: siteWideDataDictionary});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from "react";
2+
import { createContext, useContext, useState } from "react";
3+
import DatasetTable from ".";
4+
import { DataTableContext } from "../../templates/Dataset";
5+
6+
export const ManageColumnsContext = createContext({})
7+
8+
const DataTableStateWrapper = () => {
9+
const { id, datasetTableControls } = useContext(DataTableContext);
10+
// a wrapper component to keep column state synced between full screen and regular modes
11+
const localStorageData = id ? JSON.parse(localStorage.getItem(id) as string) : null;
12+
13+
const defaultPage = 1;
14+
const [page, setPage] = useState(defaultPage);
15+
16+
const [columnOrder, setColumnOrder] = useState(() => {
17+
if (datasetTableControls && localStorageData)
18+
return localStorageData.tableColumnOrder;
19+
else
20+
return [];
21+
})
22+
const [columnVisibility, setColumnVisibility] = useState(() => {
23+
if (datasetTableControls && localStorageData)
24+
return localStorageData.tableColumnVisibility;
25+
else
26+
return {};
27+
})
28+
29+
return (
30+
<ManageColumnsContext.Provider value={{
31+
columnOrder: columnOrder,
32+
setColumnOrder: setColumnOrder,
33+
columnVisibility: columnVisibility,
34+
setColumnVisibility: setColumnVisibility,
35+
page: page,
36+
setPage: setPage
37+
}}>
38+
<DatasetTable />
39+
</ManageColumnsContext.Provider>
40+
)
41+
}
42+
43+
export default DataTableStateWrapper;
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,98 @@
11
import React from 'react';
2-
import { render, screen } from '@testing-library/react';
2+
import { render, screen, act } from '@testing-library/react';
33
import '@testing-library/jest-dom';
4-
import DatasetTable from './index';
4+
import DataTableStateWrapper from './DataTableStateWrapper';
55
import * as resource from "../../tests/fixtures/resource.json";
66
import * as distribution from "../../tests/fixtures/distribution.json";
7+
import { DataTableContext } from '../../templates/Dataset';
78

89
describe('<DatasetTableTab />', () => {
9-
test("Renders correctly", () => {
10+
window.scrollTo = jest.fn();
11+
beforeEach(() => {
1012
resource.setSort = jest.fn();
13+
})
14+
test("Renders correctly", () => {
1115
render(
12-
<DatasetTable
13-
resource={resource}
14-
distribution={distribution.distribution[0]}
15-
rootUrl={"test/api/"}
16-
/>)
16+
<DataTableContext.Provider value={{
17+
resource: resource,
18+
distribution: distribution.distribution[0],
19+
rootUrl: "test/api/"
20+
}} >
21+
<DataTableStateWrapper />
22+
</DataTableContext.Provider>
23+
)
1724

1825
expect(screen.getByText("Data filters: none")).toBeInTheDocument();
1926
expect(screen.getByRole("table")).toBeInTheDocument();
2027
expect(screen.getByRole("navigation")).toHaveClass("ds-c-pagination");
2128
});
2229
test("Renders data dictionary info banner if prop is provided", () => {
23-
resource.setSort = jest.fn();
2430
render(
25-
<DatasetTable
26-
resource={resource}
27-
distribution={distribution.distribution[0]}
28-
rootUrl={"test/api/"}
29-
dataDictionaryBanner={true}
30-
/>)
31+
<DataTableContext.Provider value={{
32+
resource: resource,
33+
distribution: distribution.distribution[0],
34+
rootUrl: "test/api/",
35+
dataDictionaryBanner: true
36+
}} >
37+
<DataTableStateWrapper />
38+
</DataTableContext.Provider>
39+
)
3140
expect(screen.getByText('Click on the "Data Dictionary" tab above for full column definitions')).toBeInTheDocument();
3241
});
3342
test("Does not render data dictionary info banner if prop is not provided", () => {
34-
resource.setSort = jest.fn();
3543
render(
36-
<DatasetTable
37-
resource={resource}
38-
distribution={distribution.distribution[0]}
39-
rootUrl={"test/api/"}
40-
/>)
44+
<DataTableContext.Provider value={{
45+
resource: resource,
46+
distribution: distribution.distribution[0],
47+
rootUrl: "test/api/"
48+
}} >
49+
<DataTableStateWrapper />
50+
</DataTableContext.Provider>
51+
)
4152
expect(screen.queryByText('Click on the "Data Dictionary" tab above for full column definitions')).not.toBeInTheDocument();
4253
});
54+
test("Renders controls if prop is provided", () => {
55+
render(
56+
<DataTableContext.Provider value={{
57+
resource: resource,
58+
distribution: distribution.distribution[0],
59+
rootUrl: "test/api/",
60+
datasetTableControls: true
61+
}} >
62+
<DataTableStateWrapper />
63+
</DataTableContext.Provider>
64+
)
65+
66+
expect(screen.queryAllByText("Manage Columns")).toHaveLength(2);
67+
expect(screen.queryByText("Full Screen")).toBeInTheDocument();
68+
})
69+
test("State is synchronized between regular and full screen mode", async () => {
70+
render(
71+
<DataTableContext.Provider value={{
72+
resource: resource,
73+
distribution: distribution.distribution[0],
74+
rootUrl: "test/api/",
75+
datasetTableControls: true
76+
}} >
77+
<DataTableStateWrapper />
78+
</DataTableContext.Provider>
79+
)
80+
// Is there a better way to do this test because every step seems to need an act
81+
await act(async () => {
82+
await screen.queryAllByText("Manage Columns")[0].click();
83+
});
84+
await act(async() => {
85+
await screen.getByRole('checkbox', {name: "Select all"}).click()
86+
})
87+
await act(async() => {
88+
await screen.getByRole('button', {name: 'Save'}).click();
89+
})
90+
await act(async() => {
91+
await screen.getByRole('button', {name: 'Full Screen mode - Opens in a dialog'}).click();
92+
})
93+
await act(async () => {
94+
await screen.queryAllByText("Manage Columns")[1].click();
95+
});
96+
expect(screen.getByRole('checkbox', {name: "Select all"})).not.toBeChecked();
97+
}, 10000)
4398
});

0 commit comments

Comments
 (0)