Add settings panel
This commit is contained in:
parent
94cf41155b
commit
e0f6d8fa0b
|
@ -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,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: '',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue