1
Fork 0

Add settings panel

This commit is contained in:
viktorstrate 2019-07-31 12:30:00 +02:00
parent 94cf41155b
commit e0f6d8fa0b
9 changed files with 134 additions and 10 deletions

View File

@ -5,7 +5,7 @@ const Mutation = {
if (ctx.scanner.isRunning) { if (ctx.scanner.isRunning) {
return { return {
finished: false, finished: false,
error: true, success: false,
errorMessage: 'Scanner already running', errorMessage: 'Scanner already running',
} }
} }
@ -14,8 +14,9 @@ const Mutation = {
return { return {
finished: false, finished: false,
error: false, success: true,
progress: 0, progress: 0,
errorMessage: null,
} }
}, },
} }

View File

@ -1,6 +1,7 @@
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import uuid from 'uuid' import uuid from 'uuid'
import fs from 'fs-extra' import fs from 'fs-extra'
import { neo4jgraphql } from 'neo4j-graphql-js'
const Mutation = { const Mutation = {
async authorizeUser(root, args, ctx, info) { async authorizeUser(root, args, ctx, info) {
@ -87,6 +88,20 @@ const Mutation = {
export const registerUser = Mutation.registerUser export const registerUser = Mutation.registerUser
const Query = {
myUser(root, args, ctx, info) {
let customArgs = {
filter: {},
...args,
}
customArgs.filter.id = ctx.user.id
return neo4jgraphql(root, customArgs, ctx, info)
},
}
export default { export default {
Mutation, Mutation,
Query,
} }

View File

@ -37,7 +37,7 @@ class PhotoScanner {
scannerStatusUpdate: { scannerStatusUpdate: {
progress: (this.finishedImages / this.imagesToProgress) * 100, progress: (this.finishedImages / this.imagesToProgress) * 100,
finished: false, finished: false,
error: false, success: true,
errorMessage: '', errorMessage: '',
}, },
}) })
@ -77,7 +77,7 @@ class PhotoScanner {
scannerStatusUpdate: { scannerStatusUpdate: {
progress: 0, progress: 0,
finished: false, finished: false,
error: false, success: true,
errorMessage: '', errorMessage: '',
}, },
}) })
@ -89,7 +89,7 @@ class PhotoScanner {
scannerStatusUpdate: { scannerStatusUpdate: {
progress: 0, progress: 0,
finished: false, finished: false,
error: true, success: false,
errorMessage: error.message, errorMessage: error.message,
}, },
}) })
@ -104,7 +104,7 @@ class PhotoScanner {
scannerStatusUpdate: { scannerStatusUpdate: {
progress: 100, progress: 100,
finished: true, finished: true,
error: false, success: true,
errorMessage: '', errorMessage: '',
}, },
}) })

View File

@ -111,6 +111,8 @@ type Mutation {
type Query { type Query {
siteInfo: SiteInfo siteInfo: SiteInfo
myUser: User @isAuthenticated
myAlbums: [Album] @isAuthenticated myAlbums: [Album] @isAuthenticated
album(id: ID): Album @isAuthenticated album(id: ID): Album @isAuthenticated

View File

@ -1,7 +1,17 @@
import React from 'react' import React from 'react'
import { Route, Redirect } from 'react-router-dom' import { Route, Redirect } from 'react-router-dom'
import gql from 'graphql-tag'
import { Query } from 'react-apollo'
const AuthorizedRoute = ({ component: Component, ...props }) => { const adminQuery = gql`
query adminQuery {
myUser {
admin
}
}
`
const AuthorizedRoute = ({ component: Component, admin, ...props }) => {
const token = localStorage.getItem('token') const token = localStorage.getItem('token')
let unauthorizedRedirect = null let unauthorizedRedirect = null
@ -9,12 +19,30 @@ const AuthorizedRoute = ({ component: Component, ...props }) => {
unauthorizedRedirect = <Redirect to="/login" /> unauthorizedRedirect = <Redirect to="/login" />
} }
let adminRedirect = null
if (token && admin) {
adminRedirect = (
<Query query={adminQuery}>
{({ loading, error, data }) => {
if (error) alert(error)
if (data && data.myUser && !data.myUser.admin) {
return <Redirect to="/" />
}
return null
}}
</Query>
)
}
return ( return (
<Route <Route
{...props} {...props}
render={routeProps => ( render={routeProps => (
<> <>
{unauthorizedRedirect} {unauthorizedRedirect}
{adminRedirect}
<Component {...routeProps} /> <Component {...routeProps} />
</> </>
)} )}

View File

@ -2,6 +2,16 @@ import React, { Component } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { NavLink } from 'react-router-dom' import { NavLink } from 'react-router-dom'
import { Icon } from 'semantic-ui-react' import { Icon } from 'semantic-ui-react'
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
const adminQuery = gql`
query adminQuery {
myUser {
admin
}
}
`
const Container = styled.div` const Container = styled.div`
height: 100%; height: 100%;
@ -86,6 +96,20 @@ class Layout extends Component {
<Icon name="images outline" /> <Icon name="images outline" />
<SideButtonLabel>Albums</SideButtonLabel> <SideButtonLabel>Albums</SideButtonLabel>
</SideButton> </SideButton>
<Query query={adminQuery}>
{({ loading, error, data }) => {
if (data && data.myUser && data.myUser.admin) {
return (
<SideButton to="/settings" exact>
<Icon name="settings" />
<SideButtonLabel>Settings</SideButtonLabel>
</SideButton>
)
}
return null
}}
</Query>
</LeftSidebar> </LeftSidebar>
<Content>{this.props.children}</Content> <Content>{this.props.children}</Content>
<Header> <Header>

View File

@ -7,7 +7,7 @@ import PhotoSidebar from '../../components/sidebar/PhotoSidebar'
const photoQuery = gql` const photoQuery = gql`
query allPhotosPage { query allPhotosPage {
myAlbums(orderBy: title_asc) { myAlbums(orderBy: title_asc, filter: { photos_not: null }) {
title title
id id
photos(orderBy: title_desc, first: 12) { photos(orderBy: title_desc, first: 12) {

View File

@ -0,0 +1,42 @@
import React from 'react'
import Layout from '../../Layout'
import { Button, Icon } from 'semantic-ui-react'
import { Mutation } from 'react-apollo'
import gql from 'graphql-tag'
const scanMutation = gql`
mutation scanAllMutation {
scanAll {
success
errorMessage
}
}
`
const SettingsPage = () => (
<Layout>
<h1>Settings</h1>
<Mutation mutation={scanMutation}>
{(scan, { data }) => (
<>
<h2>Scanner</h2>
<Button
icon
labelPosition="left"
onClick={() => {
scan()
}}
disabled={data && data.scanAll && data.scanAll.success}
>
<Icon name="sync" />
Scan All
</Button>
<p>Scan for new images for all users</p>
</>
)}
</Mutation>
</Layout>
)
export default SettingsPage

View File

@ -2,6 +2,7 @@ import React from 'react'
import { Route, Switch, Redirect } from 'react-router-dom' import { Route, Switch, Redirect } from 'react-router-dom'
import { Loader } from 'semantic-ui-react' import { Loader } from 'semantic-ui-react'
import Layout from './Layout'
const AlbumsPage = React.lazy(() => import('./Pages/AllAlbumsPage/AlbumsPage')) const AlbumsPage = React.lazy(() => import('./Pages/AllAlbumsPage/AlbumsPage'))
const AlbumPage = React.lazy(() => import('./Pages/AlbumPage/AlbumPage')) const AlbumPage = React.lazy(() => import('./Pages/AlbumPage/AlbumPage'))
@ -13,17 +14,28 @@ const InitialSetupPage = React.lazy(() =>
import('./Pages/LoginPage/InitialSetupPage') import('./Pages/LoginPage/InitialSetupPage')
) )
const SettingsPage = React.lazy(() =>
import('./Pages/SettingsPage/SettingsPage')
)
class Routes extends React.Component { class Routes extends React.Component {
render() { render() {
return ( return (
<React.Suspense fallback={<Loader active>Loading page</Loader>}> <React.Suspense
fallback={
<Layout>
<Loader active>Loading page</Loader>
</Layout>
}
>
<Switch> <Switch>
<Route path="/login" component={LoginPage} /> <Route path="/login" component={LoginPage} />
<Route path="/initialSetup" component={InitialSetupPage} /> <Route path="/initialSetup" component={InitialSetupPage} />
<AuthorizedRoute exact path="/albums" component={AlbumsPage} /> <AuthorizedRoute exact path="/albums" component={AlbumsPage} />
<AuthorizedRoute path="/album/:id" component={AlbumPage} /> <AuthorizedRoute path="/album/:id" component={AlbumPage} />
<AuthorizedRoute path="/photos" component={PhotosPage} /> <AuthorizedRoute path="/photos" component={PhotosPage} />
<Route path="/" exact render={() => <Redirect to="photos" />} /> <AuthorizedRoute admin path="/settings" component={SettingsPage} />
<Route path="/" exact render={() => <Redirect to="/photos" />} />
<Route render={() => <div>Page not found</div>} /> <Route render={() => <div>Page not found</div>} />
</Switch> </Switch>
</React.Suspense> </React.Suspense>