Skip to content

Commit

Permalink
Merge pull request #131 from ECN/persist-active-queues-across-reloads
Browse files Browse the repository at this point in the history
Persist active queues across reloads
  • Loading branch information
campb303 authored Dec 1, 2020
2 parents 45037b9 + 1c8dedc commit 781cfd4
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 33 deletions.
8 changes: 4 additions & 4 deletions src/components/AppView/AppView.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ export default function AppView({ setDarkMode }){
<Box className={classes.leftCol}>
<ItemTableAppBar title="webqueue2" setDarkMode={setDarkMode} />
<QueueSelector
queueSelectorOpen={queueSelectorOpen}
setQueueSelectorOpen={setQueueSelectorOpen}
selectedQueues={selectedQueues}
setSelectedQueues={setSelectedQueues}
open={queueSelectorOpen}
setOpen={setQueueSelectorOpen}
value={selectedQueues}
setValue={setSelectedQueues}
/>
<ItemTable data={items} rowCanBeSelected={sidebarOpen}/>
</Box>
Expand Down
2 changes: 1 addition & 1 deletion src/components/AuthProvider/AuthProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function AuthProvider({ children }) {
const [loggedIn, setLoggedIn] = useState( false );
const [token, setToken] = useState( null );

const [cookies] = useCookies();
const [cookies] = useCookies(["csrf_refresh_token"]);

async function tryRefresh(csrf_refresh_token){
if (csrf_refresh_token === undefined){
Expand Down
108 changes: 80 additions & 28 deletions src/components/QueueSelector/QueueSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,100 @@ import { Autocomplete } from "@material-ui/lab";
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '@material-ui/icons/CheckBox';
import CircularProgress from '@material-ui/core/CircularProgress';
import { useCookies } from "react-cookie";
import { useToken } from "../AuthProvider/";

export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, selectedQueues, setSelectedQueues }) {
const open = queueSelectorOpen;
const setOpen = setQueueSelectorOpen;
/**
* Get queue names and number of items.
* @param {String} access_token A valid API access token.
* @returns Array of objects containing queue names and item counts.
*/
const getQueueCounts = async (access_token) => {
if (access_token === null){
return undefined
}

let myHeaders = new Headers();
myHeaders.append("Authorization", `Bearer ${access_token}`);
let requestOptions = { headers: myHeaders };

const apiResponse = await fetch(`/api/get_queues`, requestOptions);
const queueCountJson = await apiResponse.json();

return queueCountJson;
};

export default function QueueSelector({ open, setOpen, value, setValue }) {
const [queueCounts, setQueueCounts] = useState([]);
const [isFirstRender, setIsFirstRender] = useState(true);
const access_token = useToken();
const loading = open && queueCounts.length === 0;

const [cookies, setCookie] = useCookies(["active-queues"]);
const activeQueues = cookies['active-queues'] !== undefined ? cookies['active-queues'].split(',') : [];

const theme = useTheme();

// Prepopulate Active Queues from Cookies
useEffect( _ => {
const getQueueCounts = async _ => {
if (access_token === null){
return undefined
}

let myHeaders = new Headers();
myHeaders.append("Authorization", `Bearer ${access_token}`);
let requestOptions = { headers: myHeaders };

const apiResponse = await fetch(`/api/get_queues`, requestOptions);
const queueCountJson = await apiResponse.json();
setQueueCounts(queueCountJson);
};
if (access_token === null){
return undefined;
}

if (loading) {
getQueueCounts();
if (isFirstRender) {
( async _ => {
// Get queue counts
let queueCountsJson = await getQueueCounts(access_token);

// Find queue count info for queue names in active queues
let activeQueuesInfo = activeQueues.map((queueName) => (
queueCountsJson.find( ({ name }) => queueName === name )
));

// Filter undefined values
activeQueuesInfo = activeQueuesInfo.filter( (entry) => entry !== undefined);

setValue(activeQueuesInfo);
setIsFirstRender(false);
})();
}
}, []);

// Get queue counts if QueueSelector is open
useEffect( _ => {
(async _ => {
if (loading) {
let queueCountsJson = await getQueueCounts(access_token);
setQueueCounts(queueCountsJson);
}
})()
}, [loading, access_token]);

// Delete queue counts if QueueSelector is closed
useEffect(() => {
if (!open) {
setQueueCounts([]);
}
}, [open]);

const theme = useTheme();

const handleChange = (event, newValue) => {
setSelectedQueues(newValue)
setValue(newValue)

// Set active-queues cookie to csv of selected queue names
const activeQueueOptions = {
path: "/",
expires: (_ => {
let expiration_date = new Date();
expiration_date.setDate(expiration_date.getDate() + 365);
return expiration_date;
})()
};
const activeQueues = newValue.map( (value) => value.name).join(',');
setCookie("active-queues", activeQueues, activeQueueOptions);
};

// Function to render checkboxes in dropdown
// See `renderOptions` prop at https://material-ui.com/api/autocomplete/#props
const optionRenderer = (option, { selected }) => (
<>
<Checkbox
Expand All @@ -60,13 +112,14 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen,
);

return(
// Box is used for margin because Autocomplete CSS overrides don't work as expected.
<Box margin={`${theme.spacing(1)}px`}>
<Autocomplete
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder={selectedQueues.length === 0 ? "Click or type to select queues." : ""}
placeholder={value.length === 0 ? "Click or type to select queues." : ""}
autoFocus
// The MUI Autocomplete component uses the InputProps.startAdornment to store chips fpr multi-selection.
// Using InputProps.startAdornment directly will override those chips. Code below is a workaround.
Expand All @@ -90,9 +143,8 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen,
}}
/>
)}

options={queueCounts}
value={selectedQueues}
value={value}
onChange={handleChange}
getOptionLabel={(option) => `${option.name} (${option.number_of_items})`}
renderOption={optionRenderer}
Expand All @@ -114,11 +166,11 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen,

QueueSelector.propTypes = {
/** State variable to manage open status. */
"queueSelectorOpen": PropTypes.bool.isRequired,
"open": PropTypes.bool.isRequired,
/** Function to update state variable that manages open status. */
"setQueueSelectorOpen": PropTypes.func.isRequired,
"setOpen": PropTypes.func.isRequired,
/** State variable to manage selected queues. */
"selectedQueues": PropTypes.array.isRequired,
"value": PropTypes.array.isRequired,
/** Function to update state variable that manages selected queues. */
"setSelectedQueues": PropTypes.func.isRequired,
"setValue": PropTypes.func.isRequired,
};

0 comments on commit 781cfd4

Please sign in to comment.