Skip to content

Commit 531f61e

Browse files
longshuicylmariniddey2
authored
132 reactive search routes when token expire logout (#164)
* replace dataset card * Explore page cleanup (#108) * Removed placeholder right column on Explore page. Switched to clickable card for datasets. * Show only 5 max lines for description of dataset card and add ellypsis. * Default sort dataset list by creation date descending. * Make sure Dataset CardActionArea fills the card so that CardAction is flushed at the bottom. * Fixed dataset grid so that items are same width even if we don't have enough for one row. * New previous/next buttons on dataset list. * Change default page size for dataset list to 20, a multiple of 4, the default screen size columns size. * Placeholder icons for download card download, favorite, share actions. * Black formatting. * Extra margin around dataset card icons to make it easier to click on icons. * Set outer grid item size for proper layout when there is few datasets. * remove wrong primary * add layout * add styling * customize the searchbox * styling the search dataset page * add links to the side bar * add files table * default to its original * add TODOs * Added endpoint to search both file and dataset. * embed datasearch to topbar * add embedded search to the correct place * wrap the search base on parent comp and dynamically switching between index for now * embedded search working now * multi search * combine two searches into one * identify based on index * work on result component * initial styles * add more index * include more fields on file * fix typo * no need to pass dataset name as a query parameter; get that info from backend * black linting * use react router link instead of the refreshing link * remove unused component * add error boundary * bump mui icon version up; use dataset icon * add logic to refresh * when expire redirect to login * add refresh mechanism * separate out search error boundary * change route back * put hard coded search endpoint to config * breadcrumb functional now Co-authored-by: Luigi Marini <[email protected]> Co-authored-by: Dipannita Dey <[email protected]>
1 parent 2b24239 commit 531f61e

File tree

5 files changed

+160
-121
lines changed

5 files changed

+160
-121
lines changed

frontend/src/app.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface Config{
99
KeycloakLogout: string;
1010
KeycloakRefresh: string;
1111
KeycloakRegister: string;
12+
searchEndpoint: string;
1213
}
1314

1415
const config:Config = <Config>{};
@@ -31,4 +32,7 @@ config["KeycloakLogout"] = config.KeycloakBaseURL + "/logout";
3132
config["KeycloakRefresh"] = config.KeycloakBaseURL + "/refresh_token";
3233
config["KeycloakRegister"] = config.KeycloakBaseURL + "/register";
3334

35+
// elasticsearch
36+
config["searchEndpoint"] = config.hostname + "/api/v2/elasticsearch";
37+
3438
export default config;

frontend/src/components/Layout.tsx

Lines changed: 104 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import {useEffect} from 'react';
23
import {styled, useTheme} from '@mui/material/styles';
34
import Box from '@mui/material/Box';
45
import Drawer from '@mui/material/Drawer';
@@ -22,10 +23,11 @@ import {useSelector} from "react-redux";
2223
import {RootState} from "../types/data";
2324
import {AddBox, Explore} from "@material-ui/icons";
2425
import {EmbeddedSearch} from "./search/EmbeddedSearch";
26+
import {SearchErrorBoundary} from "./search/SearchErrorBoundary";
2527
import {searchTheme} from "../theme";
2628
import {ReactiveBase} from "@appbaseio/reactivesearch";
2729
import Cookies from "universal-cookie";
28-
import {useEffect} from "react";
30+
import config from '../app.config';
2931

3032
const cookies = new Cookies();
3133

@@ -50,6 +52,7 @@ const Main = styled('main', {shouldForwardProp: (prop) => prop !== 'open'})<{
5052
}),
5153
}));
5254

55+
5356
const SearchDiv = styled("div")(({ theme }) => ({
5457
position: "relative",
5558
marginLeft: theme.spacing(3),
@@ -94,6 +97,7 @@ const link = {
9497
m: 2,
9598
};
9699

100+
const headers = {"Authorization": cookies.get("Authorization")};
97101

98102
export default function PersistentDrawerLeft(props) {
99103
const {children} = props;
@@ -123,113 +127,110 @@ export default function PersistentDrawerLeft(props) {
123127
const loggedOut = useSelector((state: RootState) => state.error.loggedOut);
124128

125129

130+
// @ts-ignore
126131
return (
127132
// Wrap reactive search base on the most outside component
128133
<ReactiveBase
129-
// TODO put it in the Config file or other ways to dynamically pass in
130-
url="http://localhost:8000/api/v2/elasticsearch"
131-
app="file,dataset"
132-
headers={{"Authorization": cookies.get("Authorization")}}
133-
// transformResponse={(elasticsearchResponse) => {
134-
// console.log(elasticsearchResponse)
135-
// // if (elasticsearchResponse.detail.error === "invalid_token"){
136-
// // console.log("token expired!");
137-
// // }
138-
// }}
139-
theme={searchTheme}
134+
url={config.searchEndpoint}
135+
app="file,dataset"
136+
headers={headers}
137+
theme={searchTheme}
140138
>
141-
<Box sx={{display: 'flex'}}>
142-
<CssBaseline/>
143-
<AppBar position="fixed" open={open}>
144-
<Toolbar>
145-
<IconButton
146-
color="inherit"
147-
aria-label="open drawer"
148-
onClick={handleDrawerOpen}
149-
edge="start"
150-
sx={{mr: 2, ...(open && {display: 'none'})}}
151-
>
152-
<MenuIcon/>
153-
</IconButton>
154-
<Link href="/">
155-
<Box component="img" src="../../public/clowder-logo-sm.svg" alt="clowder-logo-sm" sx={{verticalAlign:"middle"}}/>
156-
</Link>
157-
158-
{/*for searching*/}
159-
<SearchDiv hidden={embeddedSearchHidden}>
160-
<EmbeddedSearch />
161-
</SearchDiv>
162-
<Box sx={{ flexGrow: 1 }} />
163-
<Box sx={{marginLeft: "auto"}}>
164-
{
165-
loggedOut ?
166-
<>
167-
<Link href="/auth/register" sx={link}>Register</Link>
168-
<Link href="/auth/login" sx={link}>Login</Link>
169-
</>
170-
:
171-
<Link href="/auth/logout" sx={link}>Logout</Link>
172-
}
173-
</Box>
174-
</Toolbar>
175-
</AppBar>
176-
<Drawer
177-
sx={{
178-
width: drawerWidth,
179-
flexShrink: 0,
180-
'& .MuiDrawer-paper': {
139+
<SearchErrorBoundary>
140+
<Box sx={{display: 'flex'}}>
141+
<CssBaseline/>
142+
<AppBar position="fixed" open={open}>
143+
<Toolbar>
144+
<IconButton
145+
color="inherit"
146+
aria-label="open drawer"
147+
onClick={handleDrawerOpen}
148+
edge="start"
149+
sx={{mr: 2, ...(open && {display: 'none'})}}
150+
>
151+
<MenuIcon/>
152+
</IconButton>
153+
<Link href="/">
154+
<Box component="img" src="../../public/clowder-logo-sm.svg" alt="clowder-logo-sm"
155+
sx={{verticalAlign: "middle"}}/>
156+
</Link>
157+
158+
{/*for searching*/}
159+
<SearchDiv hidden={embeddedSearchHidden}>
160+
<EmbeddedSearch/>
161+
</SearchDiv>
162+
<Box sx={{flexGrow: 1}}/>
163+
<Box sx={{marginLeft: "auto"}}>
164+
{
165+
loggedOut ?
166+
<>
167+
<Link href="/auth/register" sx={link}>Register</Link>
168+
<Link href="/auth/login" sx={link}>Login</Link>
169+
</>
170+
:
171+
<Link href="/auth/logout" sx={link}>Logout</Link>
172+
}
173+
</Box>
174+
</Toolbar>
175+
</AppBar>
176+
<Drawer
177+
sx={{
181178
width: drawerWidth,
182-
boxSizing: 'border-box',
183-
},
184-
}}
185-
variant="persistent"
186-
anchor="left"
187-
open={open}
188-
>
189-
<DrawerHeader>
190-
<IconButton onClick={handleDrawerClose}>
191-
{theme.direction === 'ltr' ? <ChevronLeftIcon/> : <ChevronRightIcon/>}
192-
</IconButton>
193-
</DrawerHeader>
194-
<Divider/>
195-
<List>
196-
<ListItem key={"explore"} disablePadding>
197-
<ListItemButton component={RouterLink} to="/">
198-
<ListItemIcon>
199-
<Explore/>
200-
</ListItemIcon>
201-
<ListItemText primary={"Explore"}/>
202-
</ListItemButton>
203-
</ListItem>
204-
</List>
205-
<Divider/>
206-
<List>
207-
<ListItem key={"search"} disablePadding>
208-
<ListItemButton component={RouterLink} to="/search">
209-
<ListItemIcon>
210-
<SearchDatasetIcon/>
211-
</ListItemIcon>
212-
<ListItemText primary={"Search"}/>
213-
</ListItemButton>
214-
</ListItem>
215-
</List>
216-
<Divider/>
217-
<List>
218-
<ListItem key={"newdataset"} disablePadding>
219-
<ListItemButton component={RouterLink} to="/create-dataset">
220-
<ListItemIcon>
221-
<AddBox/>
222-
</ListItemIcon>
223-
<ListItemText primary={"New Dataset"}/>
224-
</ListItemButton>
225-
</ListItem>
226-
</List>
227-
</Drawer>
228-
<Main open={open}>
229-
<DrawerHeader/>
230-
{children}
231-
</Main>
232-
</Box>
179+
flexShrink: 0,
180+
'& .MuiDrawer-paper': {
181+
width: drawerWidth,
182+
boxSizing: 'border-box',
183+
},
184+
}}
185+
variant="persistent"
186+
anchor="left"
187+
open={open}
188+
>
189+
<DrawerHeader>
190+
<IconButton onClick={handleDrawerClose}>
191+
{theme.direction === 'ltr' ? <ChevronLeftIcon/> : <ChevronRightIcon/>}
192+
</IconButton>
193+
</DrawerHeader>
194+
<Divider/>
195+
<List>
196+
<ListItem key={"explore"} disablePadding>
197+
<ListItemButton component={RouterLink} to="/">
198+
<ListItemIcon>
199+
<Explore/>
200+
</ListItemIcon>
201+
<ListItemText primary={"Explore"}/>
202+
</ListItemButton>
203+
</ListItem>
204+
</List>
205+
<Divider/>
206+
<List>
207+
<ListItem key={"search"} disablePadding>
208+
<ListItemButton component={RouterLink} to="/search">
209+
<ListItemIcon>
210+
<SearchDatasetIcon/>
211+
</ListItemIcon>
212+
<ListItemText primary={"Search"}/>
213+
</ListItemButton>
214+
</ListItem>
215+
</List>
216+
<Divider/>
217+
<List>
218+
<ListItem key={"newdataset"} disablePadding>
219+
<ListItemButton component={RouterLink} to="/create-dataset">
220+
<ListItemIcon>
221+
<AddBox/>
222+
</ListItemIcon>
223+
<ListItemText primary={"New Dataset"}/>
224+
</ListItemButton>
225+
</ListItem>
226+
</List>
227+
</Drawer>
228+
<Main open={open}>
229+
<DrawerHeader/>
230+
{children}
231+
</Main>
232+
</Box>
233+
</SearchErrorBoundary>
233234
</ReactiveBase>
234235
);
235236
}

frontend/src/components/navigation/BreadCrumb.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from "react";
2-
import Typography from "@mui/material/Typography";
32
import Breadcrumbs from "@mui/material/Breadcrumbs";
43
import {Button} from "@mui/material";
54
import {useNavigate} from "react-router-dom";

frontend/src/components/search/Search.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
import React from "react";
2-
import {DataSearch, ReactiveList, MultiDropdownList, SingleDropdownRange} from "@appbaseio/reactivesearch";
3-
import {parseDate} from "../../utils/common";
4-
5-
import DatasetCard from "../datasets/DatasetCard";
2+
import {DataSearch, MultiDropdownList, ReactiveList, SingleDropdownRange} from "@appbaseio/reactivesearch";
63
import {Grid} from "@mui/material";
74
import Layout from "../Layout";
8-
import {FilesTableFileEntry} from "../files/FilesTableFileEntry";
9-
import { SearchResult } from "./SearchResult";
5+
import {SearchResult} from "./SearchResult";
106

117

128
export function Search() {
@@ -25,9 +21,11 @@ export function Search() {
2521
queryFormat="or"
2622
fuzziness={0}
2723
debounce={100}
28-
react={{ and: ["creatorfilter",
24+
react={{
25+
and: ["creatorfilter",
2926
"downloadfilter",
30-
"modifyfilter"]}}
27+
"modifyfilter"]
28+
}}
3129
// apply react to the filter
3230
URLParams={true}
3331
showFilter={true}
@@ -37,8 +35,8 @@ export function Search() {
3735
{field: "name", weight: 3},
3836
{field: "description", weight: 2},
3937
{field: "author.keyword", weight: 1},
40-
{field: "creator.keyword", weight:1}
41-
]}
38+
{field: "creator.keyword", weight: 1}
39+
]}
4240
// placeholder="Search for Dataset"
4341
innerClass={{
4442
title: "search-title",
@@ -64,9 +62,9 @@ export function Search() {
6462
<SingleDropdownRange
6563
componentId="downloadfilter"
6664
dataField="download"
67-
data={[{ start: 0, label: "0 time and up" },
68-
{ start: 10, label: "10 times and up" },
69-
{ start: 100, label: "100 times and up" },
65+
data={[{start: 0, label: "0 time and up"},
66+
{start: 10, label: "10 times and up"},
67+
{start: 100, label: "100 times and up"},
7068
]}
7169
placeholder="Download Times: All"
7270
innerClass={{
@@ -78,9 +76,10 @@ export function Search() {
7876
<SingleDropdownRange
7977
componentId="modifyfilter"
8078
dataField="modified"
81-
data={[{ start: 0, label: "0 time and up" },
82-
{ start: 10, label: "10 times and up" },
83-
{ start: 100, label: "100 times and up" },
79+
data={[{start: 0, label: "0 time and up"},
80+
{start: 10, label: "10 times and up"},
81+
{start: 100, label: "100 times and up"},
82+
8483
]}
8584
placeholder="Modify Times: All"
8685
innerClass={{
@@ -89,7 +88,6 @@ export function Search() {
8988
/>
9089
</Grid>
9190
</Grid>
92-
9391
{/*result*/}
9492
<ReactiveList componentId="results" dataField="_score" size={20} pagination={true}
9593
react={{
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from "react";
2+
import {ErrorBoundary} from "@appbaseio/reactivesearch";
3+
import {V2} from "../../openapi";
4+
import {Navigate} from "react-router-dom";
5+
6+
7+
import Cookies from "universal-cookie";
8+
9+
const cookies = new Cookies();
10+
11+
export function SearchErrorBoundary(props) {
12+
13+
const {children} = props;
14+
15+
return (
16+
<ErrorBoundary
17+
renderError={error => (
18+
<>
19+
{
20+
(() => {
21+
if (error["status"] === 401 || error["status"] === 403) {
22+
V2.OpenAPI.TOKEN = undefined;
23+
cookies.remove("Authorization", {path: "/"});
24+
return <Navigate to="/auth/login"/>;
25+
} else {
26+
// TODO add prettier message or report function
27+
return <h1>An error has happened.</h1>
28+
}
29+
})()
30+
}
31+
</>
32+
)}
33+
>
34+
{children}
35+
</ErrorBoundary>
36+
)
37+
}

0 commit comments

Comments
 (0)