@vidispine/cra-template-vdt 0.15.0-pre.7 → 21.4.0-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +3 -3
- package/template/README.md +1 -1
- package/template/src/pages/Root/Root.js +14 -21
- package/template/src/pages/Root/components/Drawer.js +75 -0
- package/template/src/pages/Root/components/Header.js +34 -9
- package/template/src/pages/Root/components/Layout.js +40 -0
- package/template/src/pages/Root/index.js +1 -0
- package/template/src/pages/Root/path.js +5 -0
- package/template/src/pages/SearchCollection/SearchCollection.js +41 -0
- package/template/src/pages/SearchCollection/hooks/useSearchCollection.js +26 -0
- package/template/src/pages/SearchCollection/index.js +2 -0
- package/template/src/pages/SearchCollection/path.js +5 -0
- package/template/src/pages/{Search/Search.js → SearchItem/SearchItem.js} +5 -5
- package/template/src/pages/{Search → SearchItem}/hooks/useSearchItem.js +5 -6
- package/template/src/pages/SearchItem/index.js +2 -0
- package/template/src/pages/SearchItem/path.js +5 -0
- package/template/src/themes/LightTheme.js +7 -2
- package/template.json +8 -7
- package/template/src/pages/Search/index.js +0 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ See [Custom Templates](https://create-react-app.dev/docs/custom-templates/) for
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
npx create-react-app my-vdt-app --template @vidispine/vdt
|
|
10
|
+
npx create-react-app my-vdt-app --template @vidispine/vdt@latest
|
|
11
11
|
cd my-vdt-app
|
|
12
12
|
REACT_APP_VIDISPINE_URL=https://example.myvidispine.com npm start
|
|
13
13
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vidispine/cra-template-vdt",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "21.4.0-pre.1",
|
|
4
4
|
"homepage": "https://github.com/vidispine/vdt#readme",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"template.json"
|
|
19
19
|
],
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@vidispine/eslint-config": "^
|
|
22
|
-
"@vidispine/prettier-config": "^
|
|
21
|
+
"@vidispine/eslint-config": "^21.4.0-pre.1",
|
|
22
|
+
"@vidispine/prettier-config": "^21.4.0-pre.1"
|
|
23
23
|
},
|
|
24
24
|
"eslintConfig": {
|
|
25
25
|
"extends": [
|
package/template/README.md
CHANGED
|
@@ -5,7 +5,7 @@ See [Create React App](https://create-react-app.dev/docs/getting-started) for mo
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
npx create-react-app my-vdt-app --template @vidispine/vdt
|
|
8
|
+
npx create-react-app my-vdt-app --template @vidispine/vdt@latest
|
|
9
9
|
cd my-vdt-app
|
|
10
10
|
REACT_APP_VIDISPINE_URL=https://example.myvidispine.com npm start
|
|
11
11
|
```
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Route, Redirect, Switch } from 'react-router-dom';
|
|
3
|
-
import { withStyles } from '@material-ui/core';
|
|
4
3
|
import { AuthProvider } from '@vidispine/vdt-react';
|
|
5
4
|
|
|
6
5
|
import { LOGIN_EXPIRES_SECONDS, APP_BASENAME, VIDISPINE_URL } from '../../const';
|
|
7
|
-
import
|
|
6
|
+
import SearchItem, { path as SearchItemPath } from '../SearchItem';
|
|
7
|
+
import SearchCollection, { path as SearchCollectionPath } from '../SearchCollection';
|
|
8
8
|
import Login from '../Login';
|
|
9
9
|
import NotFound from '../NotFound';
|
|
10
|
-
import
|
|
10
|
+
import Layout from './components/Layout';
|
|
11
|
+
import RootPath from './path';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
container: {
|
|
14
|
-
height: '100vh',
|
|
15
|
-
overflow: 'auto',
|
|
16
|
-
paddingTop: theme.mixins.toolbar.minHeight,
|
|
17
|
-
marginRight: theme.spacing(1),
|
|
18
|
-
marginLeft: theme.spacing(1),
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
function Root({ classes }) {
|
|
13
|
+
function Root() {
|
|
23
14
|
const [loginError, setLoginError] = React.useState(!VIDISPINE_URL && 'VIDISPINE_URL is unset');
|
|
24
15
|
const handleLoginError = ({ message }) => {
|
|
25
16
|
setLoginError(message);
|
|
@@ -36,20 +27,22 @@ function Root({ classes }) {
|
|
|
36
27
|
LoginProps={{ error: loginError }}
|
|
37
28
|
serverUrl="/"
|
|
38
29
|
>
|
|
39
|
-
<
|
|
40
|
-
<div className={classes.container}>
|
|
30
|
+
<Layout>
|
|
41
31
|
<Switch>
|
|
42
|
-
<Route exact path=
|
|
43
|
-
<
|
|
32
|
+
<Route exact path={SearchItemPath()}>
|
|
33
|
+
<SearchItem />
|
|
34
|
+
</Route>
|
|
35
|
+
<Route exact path={SearchCollectionPath()}>
|
|
36
|
+
<SearchCollection />
|
|
44
37
|
</Route>
|
|
45
|
-
<Redirect exact from=
|
|
38
|
+
<Redirect exact from={RootPath()} push to={SearchItemPath()} />
|
|
46
39
|
<Route path="*">
|
|
47
40
|
<NotFound />
|
|
48
41
|
</Route>
|
|
49
42
|
</Switch>
|
|
50
|
-
</
|
|
43
|
+
</Layout>
|
|
51
44
|
</AuthProvider>
|
|
52
45
|
);
|
|
53
46
|
}
|
|
54
47
|
|
|
55
|
-
export default
|
|
48
|
+
export default Root;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { NavLink } from 'react-router-dom';
|
|
4
|
+
import {
|
|
5
|
+
withStyles,
|
|
6
|
+
List,
|
|
7
|
+
ListItem,
|
|
8
|
+
ListItemIcon,
|
|
9
|
+
ListItemText,
|
|
10
|
+
Drawer as MUIDrawer,
|
|
11
|
+
} from '@material-ui/core';
|
|
12
|
+
import WebAssetIcon from '@material-ui/icons/WebAsset';
|
|
13
|
+
import CollectionsIcon from '@material-ui/icons/Collections';
|
|
14
|
+
|
|
15
|
+
import { path as SearchItemPath } from '../../SearchItem';
|
|
16
|
+
import { path as SearchCollectionPath } from '../../SearchCollection';
|
|
17
|
+
|
|
18
|
+
const styles = (theme) => ({
|
|
19
|
+
drawerPaper: {
|
|
20
|
+
position: 'relative',
|
|
21
|
+
whiteSpace: 'nowrap',
|
|
22
|
+
width: theme.spacing(20),
|
|
23
|
+
transition: theme.transitions.create('width', {
|
|
24
|
+
easing: theme.transitions.easing.sharp,
|
|
25
|
+
duration: theme.transitions.duration.enteringScreen,
|
|
26
|
+
}),
|
|
27
|
+
},
|
|
28
|
+
drawerPaperClose: {
|
|
29
|
+
overflowX: 'hidden',
|
|
30
|
+
transition: theme.transitions.create('width', {
|
|
31
|
+
easing: theme.transitions.easing.sharp,
|
|
32
|
+
duration: theme.transitions.duration.leavingScreen,
|
|
33
|
+
}),
|
|
34
|
+
width: theme.spacing(7),
|
|
35
|
+
[theme.breakpoints.up('sm')]: {
|
|
36
|
+
width: theme.spacing(9),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
appBarSpacer: theme.mixins.toolbar,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function Drawer({ classes, open }) {
|
|
43
|
+
return (
|
|
44
|
+
<MUIDrawer
|
|
45
|
+
classes={{
|
|
46
|
+
paper: clsx(classes.drawerPaper, !open && classes.drawerPaperClose),
|
|
47
|
+
}}
|
|
48
|
+
variant="permanent"
|
|
49
|
+
open={open}
|
|
50
|
+
>
|
|
51
|
+
<div className={classes.appBarSpacer} />
|
|
52
|
+
<List>
|
|
53
|
+
<ListItem button component={NavLink} activeClassName="Mui-selected" to={SearchItemPath()}>
|
|
54
|
+
<ListItemIcon>
|
|
55
|
+
<WebAssetIcon />
|
|
56
|
+
</ListItemIcon>
|
|
57
|
+
<ListItemText primary="Items" />
|
|
58
|
+
</ListItem>
|
|
59
|
+
<ListItem
|
|
60
|
+
button
|
|
61
|
+
component={NavLink}
|
|
62
|
+
activeClassName="Mui-selected"
|
|
63
|
+
to={SearchCollectionPath()}
|
|
64
|
+
>
|
|
65
|
+
<ListItemIcon>
|
|
66
|
+
<CollectionsIcon />
|
|
67
|
+
</ListItemIcon>
|
|
68
|
+
<ListItemText primary="Collections" />
|
|
69
|
+
</ListItem>
|
|
70
|
+
</List>
|
|
71
|
+
</MUIDrawer>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default withStyles(styles)(Drawer);
|
|
@@ -1,27 +1,52 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { withStyles, IconButton, Typography, Toolbar, AppBar } from '@material-ui/core';
|
|
3
|
+
import MenuIcon from '@material-ui/icons/Menu';
|
|
4
4
|
import { useAuthContext } from '@vidispine/vdt-react';
|
|
5
|
+
import { UserAvatarButton } from '@vidispine/vdt-materialui';
|
|
5
6
|
|
|
6
7
|
import { APP_TITLE, HEADER_LOGO } from '../../../const';
|
|
7
8
|
|
|
8
9
|
const styles = (theme) => ({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
toolbar: {
|
|
11
|
+
paddingRight: 24, // keep right padding when drawer closed
|
|
12
|
+
},
|
|
13
|
+
appBar: {
|
|
14
|
+
zIndex: theme.zIndex.drawer + 1,
|
|
15
|
+
transition: theme.transitions.create(['width', 'margin'], {
|
|
16
|
+
easing: theme.transitions.easing.sharp,
|
|
17
|
+
duration: theme.transitions.duration.leavingScreen,
|
|
18
|
+
}),
|
|
19
|
+
},
|
|
20
|
+
menuButton: {
|
|
21
|
+
marginRight: 36,
|
|
12
22
|
},
|
|
13
23
|
title: {
|
|
14
24
|
flexGrow: 1,
|
|
15
25
|
},
|
|
26
|
+
logo: {
|
|
27
|
+
height: `calc(${theme.mixins.toolbar.minHeight}px - ${theme.spacing(4)}px)`,
|
|
28
|
+
marginRight: theme.spacing(4),
|
|
29
|
+
},
|
|
16
30
|
});
|
|
17
31
|
|
|
18
|
-
function Header({ classes }) {
|
|
32
|
+
function Header({ classes, toggleDrawer }) {
|
|
19
33
|
const { userName, onLogout } = useAuthContext();
|
|
34
|
+
|
|
20
35
|
return (
|
|
21
|
-
<AppBar elevation={0}>
|
|
22
|
-
<Toolbar
|
|
36
|
+
<AppBar position="absolute" className={classes.appBar} elevation={0}>
|
|
37
|
+
<Toolbar className={classes.toolbar}>
|
|
38
|
+
<IconButton
|
|
39
|
+
edge="start"
|
|
40
|
+
color="inherit"
|
|
41
|
+
onClick={toggleDrawer}
|
|
42
|
+
className={classes.menuButton}
|
|
43
|
+
>
|
|
44
|
+
<MenuIcon />
|
|
45
|
+
</IconButton>
|
|
23
46
|
<img className={classes.logo} src={HEADER_LOGO} alt={APP_TITLE} />
|
|
24
|
-
<
|
|
47
|
+
<Typography component="h1" variant="h6" color="inherit" noWrap className={classes.title}>
|
|
48
|
+
{APP_TITLE}
|
|
49
|
+
</Typography>
|
|
25
50
|
<UserAvatarButton userName={userName} onLogout={onLogout} />
|
|
26
51
|
</Toolbar>
|
|
27
52
|
</AppBar>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { withStyles, Container } from '@material-ui/core';
|
|
3
|
+
|
|
4
|
+
import Header from './Header';
|
|
5
|
+
import Drawer from './Drawer';
|
|
6
|
+
|
|
7
|
+
const styles = (theme) => ({
|
|
8
|
+
root: {
|
|
9
|
+
display: 'flex',
|
|
10
|
+
},
|
|
11
|
+
appBarSpacer: theme.mixins.toolbar,
|
|
12
|
+
content: {
|
|
13
|
+
flexGrow: 1,
|
|
14
|
+
height: '100vh',
|
|
15
|
+
overflow: 'auto',
|
|
16
|
+
},
|
|
17
|
+
container: {
|
|
18
|
+
paddingTop: theme.spacing(4),
|
|
19
|
+
paddingBottom: theme.spacing(4),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function Layout({ classes, children }) {
|
|
24
|
+
const [open, setOpen] = React.useState(true);
|
|
25
|
+
const toggleDrawer = () => setOpen((prevState) => !prevState);
|
|
26
|
+
return (
|
|
27
|
+
<div className={classes.root}>
|
|
28
|
+
<Header toggleDrawer={toggleDrawer} open={open} />
|
|
29
|
+
<Drawer open={open} />
|
|
30
|
+
<main className={classes.content}>
|
|
31
|
+
<div className={classes.appBarSpacer} />
|
|
32
|
+
<Container maxWidth="lg" className={classes.container}>
|
|
33
|
+
{children}
|
|
34
|
+
</Container>
|
|
35
|
+
</main>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default withStyles(styles)(Layout);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { withStyles, Card, CardHeader, CardContent } from '@material-ui/core';
|
|
3
|
+
import { SearchInput, CollectionList } from '@vidispine/vdt-materialui';
|
|
4
|
+
|
|
5
|
+
import useSearchCollection from './hooks/useSearchCollection';
|
|
6
|
+
|
|
7
|
+
const styles = (theme) => ({
|
|
8
|
+
root: {
|
|
9
|
+
paddingTop: theme.spacing(2),
|
|
10
|
+
paddingBottom: theme.spacing(2),
|
|
11
|
+
paddingLeft: theme.spacing(4),
|
|
12
|
+
paddingRight: theme.spacing(4),
|
|
13
|
+
},
|
|
14
|
+
ItemList: {},
|
|
15
|
+
SearchInput: {},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function SearchCollection({ classes }) {
|
|
19
|
+
const { onSearchCollection, collectionListType, isLoading } = useSearchCollection();
|
|
20
|
+
return (
|
|
21
|
+
<div className={classes.root}>
|
|
22
|
+
<Card variant="outlined">
|
|
23
|
+
<CardHeader title="Search For Collections" />
|
|
24
|
+
<CardContent>
|
|
25
|
+
<SearchInput
|
|
26
|
+
className={classes.SearchInput}
|
|
27
|
+
onSubmit={onSearchCollection}
|
|
28
|
+
submitting={isLoading}
|
|
29
|
+
/>
|
|
30
|
+
<CollectionList
|
|
31
|
+
className={classes.ItemList}
|
|
32
|
+
collectionListType={collectionListType}
|
|
33
|
+
CollectionListItemProps={{ primary: 'title', secondary: 'collectionId' }}
|
|
34
|
+
/>
|
|
35
|
+
</CardContent>
|
|
36
|
+
</Card>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default withStyles(styles)(SearchCollection);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { collection as CollectionApi } from '@vidispine/vdt-api';
|
|
2
|
+
import { useApi } from '@vidispine/vdt-react';
|
|
3
|
+
|
|
4
|
+
const useSearchCollection = () => {
|
|
5
|
+
const {
|
|
6
|
+
data: collectionListType,
|
|
7
|
+
request: searchCollection,
|
|
8
|
+
isLoading,
|
|
9
|
+
} = useApi(CollectionApi.searchCollection, { isLoading: false });
|
|
10
|
+
const onSearchCollection = (value) =>
|
|
11
|
+
searchCollection({
|
|
12
|
+
itemSearchDocument: { text: [{ value }] },
|
|
13
|
+
queryParams: {
|
|
14
|
+
number: 10,
|
|
15
|
+
content: 'metadata',
|
|
16
|
+
field: ['title', 'collectionId'],
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
onSearchCollection,
|
|
21
|
+
collectionListType,
|
|
22
|
+
isLoading,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default useSearchCollection;
|
|
@@ -15,8 +15,8 @@ const styles = (theme) => ({
|
|
|
15
15
|
SearchInput: {},
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
function
|
|
19
|
-
const {
|
|
18
|
+
function SearchItem({ classes }) {
|
|
19
|
+
const { onSearchItem, itemListType, isLoading } = useSearchItem();
|
|
20
20
|
return (
|
|
21
21
|
<div className={classes.root}>
|
|
22
22
|
<Card variant="outlined">
|
|
@@ -24,8 +24,8 @@ function Search({ classes }) {
|
|
|
24
24
|
<CardContent>
|
|
25
25
|
<SearchInput
|
|
26
26
|
className={classes.SearchInput}
|
|
27
|
-
onSubmit={
|
|
28
|
-
submitting={
|
|
27
|
+
onSubmit={onSearchItem}
|
|
28
|
+
submitting={isLoading}
|
|
29
29
|
/>
|
|
30
30
|
<ItemList
|
|
31
31
|
className={classes.ItemList}
|
|
@@ -38,4 +38,4 @@ function Search({ classes }) {
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export default withStyles(styles)(
|
|
41
|
+
export default withStyles(styles)(SearchItem);
|
|
@@ -2,10 +2,10 @@ import { item as ItemApi } from '@vidispine/vdt-api';
|
|
|
2
2
|
import { useApi } from '@vidispine/vdt-react';
|
|
3
3
|
|
|
4
4
|
const useSearchItem = () => {
|
|
5
|
-
const { data: itemListType, request: searchItem, isLoading
|
|
6
|
-
|
|
7
|
-
);
|
|
8
|
-
const
|
|
5
|
+
const { data: itemListType, request: searchItem, isLoading } = useApi(ItemApi.searchItem, {
|
|
6
|
+
isLoading: false,
|
|
7
|
+
});
|
|
8
|
+
const onSearchItem = (value) =>
|
|
9
9
|
searchItem({
|
|
10
10
|
itemSearchDocument: { text: [{ value }] },
|
|
11
11
|
queryParams: {
|
|
@@ -15,10 +15,9 @@ const useSearchItem = () => {
|
|
|
15
15
|
},
|
|
16
16
|
});
|
|
17
17
|
return {
|
|
18
|
-
|
|
18
|
+
onSearchItem,
|
|
19
19
|
itemListType,
|
|
20
20
|
isLoading,
|
|
21
|
-
hasLoaded,
|
|
22
21
|
};
|
|
23
22
|
};
|
|
24
23
|
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createTheme } from '@material-ui/core/styles';
|
|
2
2
|
import indigo from '@material-ui/core/colors/indigo';
|
|
3
3
|
|
|
4
4
|
import 'typeface-roboto';
|
|
5
5
|
import '@vidispine/vdt-materialui/dist/index.css';
|
|
6
6
|
|
|
7
|
-
const theme =
|
|
7
|
+
const theme = createTheme({
|
|
8
8
|
typography: {
|
|
9
9
|
useNextVariants: true,
|
|
10
10
|
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
|
11
11
|
},
|
|
12
|
+
mixins: {
|
|
13
|
+
toolbar: {
|
|
14
|
+
minHeight: 48,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
12
17
|
palette: {
|
|
13
18
|
type: 'light',
|
|
14
19
|
primary: {
|
package/template.json
CHANGED
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
"@material-ui/core": "^4.11.0",
|
|
5
5
|
"@material-ui/icons": "^4.9.1",
|
|
6
6
|
"@material-ui/lab": "^4.0.0-alpha.56",
|
|
7
|
-
"@vidispine/vdt-api": "^
|
|
8
|
-
"@vidispine/vdt-materialui": "^
|
|
9
|
-
"@vidispine/vdt-react": "^
|
|
7
|
+
"@vidispine/vdt-api": "^21.4.0-pre.1",
|
|
8
|
+
"@vidispine/vdt-materialui": "^21.4.0-pre.1",
|
|
9
|
+
"@vidispine/vdt-react": "^21.4.0-pre.1",
|
|
10
|
+
"clsx": "^1.1.1",
|
|
10
11
|
"react-cookie": "^4.0.3",
|
|
11
12
|
"react-router-dom": "^5.2.0",
|
|
12
13
|
"typeface-roboto": "^0.0.75"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
15
|
-
"@vidispine/eslint-config": "^
|
|
16
|
-
"@vidispine/eslint-config-base": "^
|
|
17
|
-
"@vidispine/eslint-config-react": "^
|
|
18
|
-
"@vidispine/prettier-config": "^
|
|
16
|
+
"@vidispine/eslint-config": "^21.4.0-pre.1",
|
|
17
|
+
"@vidispine/eslint-config-base": "^21.4.0-pre.1",
|
|
18
|
+
"@vidispine/eslint-config-react": "^21.4.0-pre.1",
|
|
19
|
+
"@vidispine/prettier-config": "^21.4.0-pre.1",
|
|
19
20
|
"eslint-config-airbnb": "^18.2.1",
|
|
20
21
|
"eslint-config-prettier": "^7.1.0",
|
|
21
22
|
"eslint-plugin-jsx-a11y": "^6.4.1",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from './Search';
|