Management windows grouped together.

editsong
Sander Vocke 5 years ago
parent ee5b80fadb
commit 94dd7a0dd6
  1. 19
      client/src/components/MainWindow.tsx
  2. 14
      client/src/components/appbar/AppBar.tsx
  3. 6
      client/src/components/windows/album/AlbumWindow.tsx
  4. 6
      client/src/components/windows/artist/ArtistWindow.tsx
  5. 63
      client/src/components/windows/manage/ManageWindow.tsx
  6. 2
      client/src/components/windows/manage_tags/ManageTagsWindow.tsx
  7. 11
      client/src/lib/backend/request.tsx
  8. 2
      client/src/lib/integration/useIntegrations.tsx

@ -16,7 +16,7 @@ import SettingsWindow from './windows/settings/SettingsWindow';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { ProvideIntegrations } from '../lib/integration/useIntegrations'; import { ProvideIntegrations } from '../lib/integration/useIntegrations';
import ManageLinksWindow from './windows/manage_links/ManageLinksWindow'; import ManageLinksWindow from './windows/manage_links/ManageLinksWindow';
import ManageWindow from './windows/manage/ManageWindow'; import ManageWindow, { ManageWhat } from './windows/manage/ManageWindow';
const darkTheme = createMuiTheme({ const darkTheme = createMuiTheme({
palette: { palette: {
@ -88,17 +88,16 @@ export default function MainWindow(props: any) {
<AppBar selectedTab={null} /> <AppBar selectedTab={null} />
<SongWindow /> <SongWindow />
</PrivateRoute> </PrivateRoute>
<PrivateRoute path="/tags"> <PrivateRoute path="/manage/tags">
<AppBar selectedTab={AppBarTab.Tags} /> <AppBar selectedTab={AppBarTab.Manage} />
<ManageTagsWindow /> <ManageWindow selectedWindow={ManageWhat.Tags}/>
</PrivateRoute> </PrivateRoute>
<PrivateRoute path="/links"> <PrivateRoute path="/manage/links">
<AppBar selectedTab={AppBarTab.Links} /> <AppBar selectedTab={AppBarTab.Manage} />
<ManageLinksWindow /> <ManageWindow selectedWindow={ManageWhat.Links}/>
</PrivateRoute> </PrivateRoute>
<PrivateRoute path="/manage"> <PrivateRoute exact path="/manage">
<AppBar selectedTab={null} /> <Redirect to={"/manage/tags"} />
<ManageWindow />
</PrivateRoute> </PrivateRoute>
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>

@ -3,13 +3,13 @@ import { AppBar as MuiAppBar, Box, Tab as MuiTab, Tabs, IconButton, Typography,
import SearchIcon from '@material-ui/icons/Search'; import SearchIcon from '@material-ui/icons/Search';
import LocalOfferIcon from '@material-ui/icons/LocalOffer'; import LocalOfferIcon from '@material-ui/icons/LocalOffer';
import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import OpenInNewIcon from '@material-ui/icons/OpenInNew';
import BuildIcon from '@material-ui/icons/Build';
import { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { useAuth } from '../../lib/useAuth'; import { useAuth } from '../../lib/useAuth';
export enum AppBarTab { export enum AppBarTab {
Query = 0, Query = 0,
Tags, Manage,
Links,
} }
export const appBarTabProps: Record<any, any> = { export const appBarTabProps: Record<any, any> = {
@ -17,13 +17,9 @@ export const appBarTabProps: Record<any, any> = {
label: <Box display="flex"><SearchIcon /><Typography variant="button">Query</Typography></Box>, label: <Box display="flex"><SearchIcon /><Typography variant="button">Query</Typography></Box>,
path: "/query", path: "/query",
}, },
[AppBarTab.Tags]: { [AppBarTab.Manage]: {
label: <Box display="flex"><LocalOfferIcon /><Typography variant="button">Tags</Typography></Box>, label: <Box display="flex"><BuildIcon /><Typography variant="button">Manage</Typography></Box>,
path: "/tags", path: "/manage",
},
[AppBarTab.Links]: {
label: <Box display="flex"><OpenInNewIcon /><Typography variant="button">Links</Typography></Box>,
path: "/links",
}, },
} }

@ -91,7 +91,7 @@ export function AlbumWindowControlled(props: {
value: m value: m
}); });
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }) .catch((e: any) => { handleNotLoggedIn(auth, e) })
}, [albumId, dispatch]); }, [albumId, dispatch]);
// Effect to get the album's songs. // Effect to get the album's songs.
@ -108,7 +108,7 @@ export function AlbumWindowControlled(props: {
offset: 0, offset: 0,
limit: -1, limit: -1,
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }); .catch((e: any) => { handleNotLoggedIn(auth, e) });
dispatch({ dispatch({
type: AlbumWindowStateActions.SetSongs, type: AlbumWindowStateActions.SetSongs,
value: songs, value: songs,
@ -159,7 +159,7 @@ export function AlbumWindowControlled(props: {
type: AlbumWindowStateActions.Reload type: AlbumWindowStateActions.Reload
}) })
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }) .catch((e: any) => { handleNotLoggedIn(auth, e) })
}} /> }} />
{applying && <CircularProgress />} {applying && <CircularProgress />}
</Box> </Box>

@ -95,7 +95,7 @@ export function ArtistWindowControlled(props: {
value: m value: m
}); });
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }) .catch((e: any) => { handleNotLoggedIn(auth, e) })
}, [artistId, dispatch]); }, [artistId, dispatch]);
// Effect to get the artist's songs. // Effect to get the artist's songs.
@ -112,7 +112,7 @@ export function ArtistWindowControlled(props: {
offset: 0, offset: 0,
limit: -1, limit: -1,
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }); .catch((e: any) => { handleNotLoggedIn(auth, e) });
dispatch({ dispatch({
type: ArtistWindowStateActions.SetSongs, type: ArtistWindowStateActions.SetSongs,
value: songs, value: songs,
@ -163,7 +163,7 @@ export function ArtistWindowControlled(props: {
type: ArtistWindowStateActions.Reload type: ArtistWindowStateActions.Reload
}) })
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }) .catch((e: any) => { handleNotLoggedIn(auth, e) })
}} /> }} />
{applying && <CircularProgress />} {applying && <CircularProgress />}
</Box> </Box>

@ -1,4 +1,4 @@
import React, { useReducer } from 'react'; import React, { ReactFragment, useReducer, useState } from 'react';
import { WindowState } from "../Windows"; import { WindowState } from "../Windows";
import { Box, Paper, Typography, TextField, Button, Tabs, Tab, Divider, IconButton } from "@material-ui/core"; import { Box, Paper, Typography, TextField, Button, Tabs, Tab, Divider, IconButton } from "@material-ui/core";
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
@ -8,45 +8,52 @@ import { Link } from 'react-router-dom';
import LocalOfferIcon from '@material-ui/icons/LocalOffer'; import LocalOfferIcon from '@material-ui/icons/LocalOffer';
import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import OpenInNewIcon from '@material-ui/icons/OpenInNew';
import ManageLinksWindow from '../manage_links/ManageLinksWindow'; import ManageLinksWindow from '../manage_links/ManageLinksWindow';
import ManageTagsWindow from '../manage_tags/ManageTagsWindow';
export enum ManageWhat { export enum ManageWhat {
Tags = 0, Tags = 0,
Links, Links,
} }
export interface ManageWindowState extends WindowState { export default function ManageWindow(props: {
dummy: boolean selectedWindow: ManageWhat,
} }) {
export enum ManageWindowActions { let history = useHistory();
SetDummy = "SetDummy",
}
export function ManageWindowReducer(state: ManageWindowState, action: any) {
switch (action.type) {
case ManageWindowActions.SetDummy: {
return state;
}
default:
throw new Error("Unimplemented ManageWindow state update.")
}
}
export default function ManageWindow(props: {}) { let NavButton = (props: {
const [state, dispatch] = useReducer(ManageWindowReducer, { label: string,
dummy: true, icon: ReactFragment,
}); selected: boolean,
onClick?: () => void,
}) => {
return <Button
style={{ textTransform: "none" }}
onClick={props.onClick}
variant={props.selected ? "outlined" : "text"}
>
<Box display="flex" flexDirection="column" alignItems="center">
{props.icon}{props.label}
</Box>
</Button>
return <ManageWindowControlled state={state} dispatch={dispatch} />
} }
export function ManageWindowControlled(props: {
state: ManageWindowState,
dispatch: (action: any) => void,
}) {
return <Box display="flex" alignItems="top" height="100%" m={2}> return <Box display="flex" alignItems="top" height="100%" m={2}>
<Box display="flex" flexDirection="column" alignItems="center"> <Box display="flex" flexDirection="column" alignItems="center">
<Box mt={2}><IconButton size="small"><LocalOfferIcon/></IconButton>Tags</Box> <NavButton
<Box mt={2}><IconButton size="small"><OpenInNewIcon/></IconButton>Links</Box> label="Tags"
icon={<LocalOfferIcon />}
selected={props.selectedWindow === ManageWhat.Tags}
onClick={() => history.push('/manage/tags')}
/>
<NavButton
label="Links"
icon={<OpenInNewIcon />}
selected={props.selectedWindow === ManageWhat.Links}
onClick={() => history.push('/manage/links')}
/>
</Box> </Box>
<ManageLinksWindow /> {props.selectedWindow === ManageWhat.Tags && <ManageTagsWindow/>}
{props.selectedWindow === ManageWhat.Links && <ManageLinksWindow/>}
</Box > </Box >
} }

@ -426,7 +426,7 @@ export function ManageTagsWindowControlled(props: {
type: ManageTagsWindowActions.Reset type: ManageTagsWindowActions.Reset
}); });
}) })
.catch((e: NotLoggedInError) => { handleNotLoggedIn(auth, e) }) .catch((e: any) => { handleNotLoggedIn(auth, e) })
.catch((e: Error) => { .catch((e: Error) => {
props.dispatch({ props.dispatch({
type: ManageTagsWindowActions.SetAlert, type: ManageTagsWindowActions.SetAlert,

@ -9,6 +9,10 @@ export class NotLoggedInError extends Error {
} }
} }
export function isNotLoggedInError(e: any): e is NotLoggedInError {
return e.name === NotLoggedInError;
}
export default async function backendRequest(url: any, ...restArgs: any[]): Promise<Response> { export default async function backendRequest(url: any, ...restArgs: any[]): Promise<Response> {
let response = await fetch(url, ...restArgs); let response = await fetch(url, ...restArgs);
if (response.status === 401 && (await response.json()).reason === "NotLoggedIn") { if (response.status === 401 && (await response.json()).reason === "NotLoggedIn") {
@ -18,7 +22,12 @@ export default async function backendRequest(url: any, ...restArgs: any[]): Prom
return response; return response;
} }
export function handleNotLoggedIn(auth: Auth, e: NotLoggedInError) { export function handleNotLoggedIn(auth: Auth, e: any) {
if (isNotLoggedInError(e)) {
console.log("Not logged in!") console.log("Not logged in!")
auth.signout(); auth.signout();
return;
}
// Rethrow if unhandled
throw e;
} }

@ -139,7 +139,7 @@ function useProvideIntegrations(): Integrations {
}) })
}); });
}) })
.catch((e: NotLoggedInError) => handleNotLoggedIn(auth, e)); .catch((e: any) => handleNotLoggedIn(auth, e));
} }
let addIntegration = async (v: serverApi.CreateIntegrationRequest) => { let addIntegration = async (v: serverApi.CreateIntegrationRequest) => {

Loading…
Cancel
Save