Skip to content

Commit

Permalink
Update datatable dispatch to localforage and add loading spinner
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWags committed Mar 28, 2024
1 parent 70f2592 commit aafba8e
Show file tree
Hide file tree
Showing 7 changed files with 963 additions and 1,288 deletions.
1 change: 1 addition & 0 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@types/react-dom": "^17.0.11",
"@visdesignlab/upset2-core": "^0.1.0",
"@visdesignlab/upset2-react": "^0.1.0",
"localforage": "^1.10.0",
"multinet": "0.23.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
6 changes: 6 additions & 0 deletions packages/app/src/atoms/loadingAtom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { atom } from "recoil";

export const loadingAtom = atom({
key: 'loading-atom',
default: false,
});
30 changes: 19 additions & 11 deletions packages/app/src/components/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import React from 'react';
import { elementSidebarAtom } from '../atoms/elementSidebarAtom';
import { api } from '../atoms/authAtoms';
import { altTextSidebarAtom } from '../atoms/altTextSidebarAtom';
import { loadingAtom } from '../atoms/loadingAtom';
import { Backdrop, CircularProgress } from '@mui/material';

type Props = {
yOffset: number;
Expand All @@ -25,6 +27,7 @@ export const Body = ({ yOffset, data, config }: Props) => {
const [ isProvVisOpen, setIsProvVisOpen ] = useRecoilState(provenanceVisAtom);
const [ isElementSidebarOpen, setIsElementSidebarOpen ] = useRecoilState(elementSidebarAtom);
const [ isAltTextSidebarOpen, setIsAltTextSidebarOpen ] = useRecoilState(altTextSidebarAtom);
const loading = useRecoilValue(loadingAtom);

const provVis = {
open: isProvVisOpen,
Expand Down Expand Up @@ -70,17 +73,22 @@ export const Body = ({ yOffset, data, config }: Props) => {
<div style={{maxWidth: "100vw"}}>
{ data.setColumns.length === 0 ?
<ErrorModal />:
<Upset
data={data}
loadAttributes={3}
yOffset={yOffset === -1 ? 0 : yOffset}
extProvenance={provObject}
config={config}
provVis={provVis}
elementSidebar={elementSidebar}
altTextSidebar={altTextSidebar}
generateAltText={generateAltText}
/>
<div>
<Backdrop open={loading} style={{zIndex: 1000}}>
<CircularProgress color="inherit" />
</Backdrop>
<Upset
data={data}
loadAttributes={3}
yOffset={yOffset === -1 ? 0 : yOffset}
extProvenance={provObject}
config={config}
provVis={provVis}
elementSidebar={elementSidebar}
altTextSidebar={altTextSidebar}
generateAltText={generateAltText}
/>
</div>
}
</div>
);
Expand Down
39 changes: 28 additions & 11 deletions packages/app/src/components/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Box, Button } from "@mui/material"
import { Backdrop, Box, Button, CircularProgress } from "@mui/material"
import { AccessibleDataEntry, CoreUpsetData } from "@visdesignlab/upset2-core";
import { useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { DataGrid, GridColDef } from '@mui/x-data-grid';
import { getAccessibleData } from "@visdesignlab/upset2-react";
import DownloadIcon from '@mui/icons-material/Download';
import localforage from "localforage";

const getRowData = (row: AccessibleDataEntry) => {
return {id: row.id, elementName: `${(row.type === "Aggregate") ? "Aggregate: " : ""}${row.elementName.replaceAll("~&~", " & ")}`, size: row.size}
Expand Down Expand Up @@ -87,16 +88,29 @@ const DownloadButton = ({onClick}: DownloadButtonProps) => {
}

export const DataTable = () => {
const storedData = localStorage.getItem("data");
const storedRows = localStorage.getItem("rows");
const storedVisibleSets = localStorage.getItem("visibleSets");
const storedHiddenSets = localStorage.getItem("hiddenSets");

const data = storedData ? JSON.parse(storedData) as CoreUpsetData : null;
const rows = storedRows ? JSON.parse(storedRows) as ReturnType<typeof getAccessibleData> : null;
const visibleSets = storedVisibleSets ? JSON.parse(storedVisibleSets) as string[] : null;
const hiddenSets = storedHiddenSets ? JSON.parse(storedHiddenSets) as string[] : null;
const [data , setData] = useState<CoreUpsetData | null>(null);
const [rows, setRows] = useState<ReturnType<typeof getAccessibleData> | null>(null);
const [visibleSets, setVisibleSets] = useState<string[] | null>(null);
const [hiddenSets, setHiddenSets] = useState<string[] | null>(null);
const [loading, setLoading] = useState(false);

useEffect(() => {
setLoading(true);
Promise.all([
localforage.getItem("data"),
localforage.getItem("rows"),
localforage.getItem("visibleSets"),
localforage.getItem("hiddenSets")
]).then(([storedData, storedRows, storedVisibleSets, storedHiddenSets]) => {
console.log("Fetched items!");
setData(storedData as CoreUpsetData);
setRows(storedRows as ReturnType<typeof getAccessibleData>);
setVisibleSets(storedVisibleSets as string[]);
setHiddenSets(storedHiddenSets as string[]);
});
setLoading(false);
}, []);

// fetch subset data and create row objects with subset name and size
const tableRows: ReturnType<typeof getRowData>[] = useMemo(() => {
if (rows === null) {
Expand Down Expand Up @@ -183,6 +197,9 @@ export const DataTable = () => {
return (
<>
<Box sx={{display: "flex", justifyContent: "space-between"}}>
<Backdrop open={loading} style={{zIndex: 1000}}>
<CircularProgress color="inherit" />
</Backdrop>
<Box sx={{width: "50%", margin: "20px"}}>
<div style={headerCSS}>
<h2>UpSet Data Table</h2>
Expand Down
21 changes: 15 additions & 6 deletions packages/app/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import MoreVertIcon from '@mui/icons-material/MoreVert';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { AccountCircle, ErrorOutline } from '@mui/icons-material';
import { AppBar, Avatar, Box, Button, ButtonGroup, IconButton, Menu, MenuItem, Toolbar, Tooltip, Typography } from '@mui/material';
import { useRecoilValue, useRecoilState } from 'recoil';
import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil';
import React, { useContext, useEffect, useState } from 'react';
import localforage from 'localforage';
import { getMultinetDataUrl, oAuth } from '../../atoms/authAtoms';
import { getQueryParam, queryParamAtom, saveQueryParam } from '../../atoms/queryParamAtom';
import { provenanceVisAtom } from '../../atoms/provenanceVisAtom';
Expand All @@ -21,13 +22,15 @@ import { Link } from 'react-router-dom';
import { getUserInfo } from '../../getUserInfo';
import { restoreQueryParam } from '../../atoms/queryParamAtom';
import { altTextSidebarAtom } from '../../atoms/altTextSidebarAtom';
import { loadingAtom } from '../../atoms/loadingAtom';

const Header = ({ data }: { data: any }) => {
const { workspace } = useRecoilValue(queryParamAtom);
const [ isProvVisOpen, setIsProvVisOpen ] = useRecoilState(provenanceVisAtom);
const [ isElementSidebarOpen, setIsElementSidebarOpen ] = useRecoilState(elementSidebarAtom);
const [ isAltTextSidebarOpen, setIsAltTextSidebarOpen ] = useRecoilState(altTextSidebarAtom);
const importError = useRecoilValue(importErrorAtom);
const setLoading = useSetRecoilState(loadingAtom);

const { provenance } = useContext(ProvenanceContext);

Expand Down Expand Up @@ -101,12 +104,18 @@ const Header = ({ data }: { data: any }) => {
* This function saves the 'data', 'rows', 'visibleSets', 'hiddenSets', and query parameters to the local storage.
* TODO: resolve cache size limit issues for large datasets (10mb)
*/
const dispatchState = () => {
localStorage.setItem('data', JSON.stringify(data));
localStorage.setItem('rows', JSON.stringify(getAccessibleData(getRows(data, provenance.getState()), true)));
localStorage.setItem('visibleSets', JSON.stringify(visibleSets));
localStorage.setItem('hiddenSets', JSON.stringify(hiddenSets.map((set: Column) => set.name)));
const dispatchState = async () => {
setLoading(true);
await Promise.all([
localforage.clear(),
localforage.setItem('data', data),
localforage.setItem('rows', getAccessibleData(getRows(data, provenance.getState()), true)),
localforage.setItem('visibleSets', visibleSets),
localforage.setItem('hiddenSets', hiddenSets.map((set: Column) => set.name))
]);

saveQueryParam();
setLoading(false);
};

const [ userInfo, setUserInfo ] = useState<UserSpec | null>(null);
Expand Down
9 changes: 9 additions & 0 deletions packages/app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@ import App from './App';
import DefaultTheme from './components/theme';
import { api, client_id, oAuth } from './atoms/authAtoms';
import { readSharedLoginCookie, writeSharedLoginCookie, invalidateSharedLoginCookie } from 'multinet';
import localforage from 'localforage';

// import reportWebVitals from './reportWebVitals';

localforage.config({
name: 'UpSet2-Data',
storeName: 'upset2-data',
description: 'Local storage for Upset2 datatable',
size: 30 * 1024 * 1024, // Size of the database in bytes (30 MB) (used only in WEBSQL fallback driver)
driver: [localforage.INDEXEDDB, localforage.WEBSQL, localforage.LOCALSTORAGE], // fallback drivers
});

const loginTokenKey = `oauth-token-${client_id}`;
const sharedLoginCookie = readSharedLoginCookie();
if (sharedLoginCookie !== null) {
Expand Down
Loading

0 comments on commit aafba8e

Please sign in to comment.