Sync message popup
This commit is contained in:
parent
ae93c884ba
commit
56800b14a8
|
@ -10,6 +10,7 @@
|
||||||
"apollo-link-context": "^1.0.18",
|
"apollo-link-context": "^1.0.18",
|
||||||
"apollo-link-error": "^1.1.11",
|
"apollo-link-error": "^1.1.11",
|
||||||
"apollo-link-http": "^1.5.15",
|
"apollo-link-http": "^1.5.15",
|
||||||
|
"apollo-link-ws": "^1.0.18",
|
||||||
"babel-plugin-styled-components": "^1.10.6",
|
"babel-plugin-styled-components": "^1.10.6",
|
||||||
"cookie": "^0.4.0",
|
"cookie": "^0.4.0",
|
||||||
"graphql": "^14.2.1",
|
"graphql": "^14.2.1",
|
||||||
|
@ -24,7 +25,8 @@
|
||||||
"react-spring": "^8.0.27",
|
"react-spring": "^8.0.27",
|
||||||
"semantic-ui-css": "^2.4.1",
|
"semantic-ui-css": "^2.4.1",
|
||||||
"semantic-ui-react": "^0.87.2",
|
"semantic-ui-react": "^0.87.2",
|
||||||
"styled-components": "^4.3.2"
|
"styled-components": "^4.3.2",
|
||||||
|
"subscriptions-transport-ws": "^0.9.16"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "parcel start src/index.html",
|
"start": "parcel start src/index.html",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const GlobalStyle = createGlobalStyle`
|
||||||
`
|
`
|
||||||
|
|
||||||
import Routes from './Routes'
|
import Routes from './Routes'
|
||||||
|
import Messages from './Messages'
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
render() {
|
render() {
|
||||||
|
@ -16,6 +17,7 @@ class App extends Component {
|
||||||
<>
|
<>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<Routes />
|
<Routes />
|
||||||
|
<Messages />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ class Layout extends Component {
|
||||||
<Icon name="image outline" />
|
<Icon name="image outline" />
|
||||||
<SideButtonLabel>Photos</SideButtonLabel>
|
<SideButtonLabel>Photos</SideButtonLabel>
|
||||||
</SideButton>
|
</SideButton>
|
||||||
<SideButton to="/" exact>
|
<SideButton to="/albums" exact>
|
||||||
<Icon name="images outline" />
|
<Icon name="images outline" />
|
||||||
<SideButtonLabel>Albums</SideButtonLabel>
|
<SideButtonLabel>Albums</SideButtonLabel>
|
||||||
</SideButton>
|
</SideButton>
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { Message, Progress } from 'semantic-ui-react'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import { Subscription } from 'react-apollo'
|
||||||
|
|
||||||
|
const syncSubscription = gql`
|
||||||
|
subscription syncSubscription {
|
||||||
|
scannerStatusUpdate {
|
||||||
|
finished
|
||||||
|
error
|
||||||
|
errorMessage
|
||||||
|
progress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
width: 500px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const MessageProgress = ({ header, content, percent, ...props }) => {
|
||||||
|
const StyledProgress = styled(Progress)`
|
||||||
|
position: absolute !important;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Message floating {...props}>
|
||||||
|
<Message.Content>
|
||||||
|
<Message.Header>{header}</Message.Header>
|
||||||
|
{content}
|
||||||
|
<StyledProgress
|
||||||
|
percent={percent}
|
||||||
|
size="tiny"
|
||||||
|
attached="bottom"
|
||||||
|
indicating
|
||||||
|
/>
|
||||||
|
</Message.Content>
|
||||||
|
</Message>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Messages extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Subscription subscription={syncSubscription} shouldResubscribe>
|
||||||
|
{({ loading, error, data }) => {
|
||||||
|
if (error) return <div>error {error.message}</div>
|
||||||
|
if (loading) return null
|
||||||
|
|
||||||
|
console.log('Data update', data)
|
||||||
|
const update = data.scannerStatusUpdate
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MessageProgress
|
||||||
|
header={update.finished ? 'Synced' : 'Syncing'}
|
||||||
|
content={
|
||||||
|
update.finished ? 'Finished syncing' : 'Syncing in progress'
|
||||||
|
}
|
||||||
|
percent={update.progress}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</Subscription>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Messages
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react'
|
||||||
import Albums from './Albums'
|
import Albums from './Albums'
|
||||||
import Layout from '../../Layout'
|
import Layout from '../../Layout'
|
||||||
|
|
||||||
class HomePage extends Component {
|
class AlbumsPage extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
|
@ -13,4 +13,4 @@ class HomePage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HomePage
|
export default AlbumsPage
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { Route, Switch } from 'react-router-dom'
|
import { Route, Switch, Redirect } from 'react-router-dom'
|
||||||
|
|
||||||
import LoginPage from './Pages/LoginPage'
|
import LoginPage from './Pages/LoginPage'
|
||||||
import HomePage from './Pages/HomePage/HomePage'
|
import AlbumsPage from './Pages/AllAlbumsPage/AlbumsPage'
|
||||||
import AlbumPage from './Pages/AlbumPage/AlbumPage'
|
import AlbumPage from './Pages/AlbumPage/AlbumPage'
|
||||||
import AuthorizedRoute from './AuthorizedRoute'
|
import AuthorizedRoute from './AuthorizedRoute'
|
||||||
import PhotosPage from './Pages/PhotosPage/PhotosPage'
|
import PhotosPage from './Pages/PhotosPage/PhotosPage'
|
||||||
|
@ -12,9 +12,11 @@ class Routes extends Component {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/login" component={LoginPage} />
|
<Route path="/login" component={LoginPage} />
|
||||||
<AuthorizedRoute exact path="/" component={HomePage} />
|
<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" />} />
|
||||||
|
<Route render={() => <div>Page not found</div>} />
|
||||||
</Switch>
|
</Switch>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,41 @@
|
||||||
import { ApolloClient } from 'apollo-client'
|
import { ApolloClient } from 'apollo-client'
|
||||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||||
import { HttpLink } from 'apollo-link-http'
|
import { HttpLink } from 'apollo-link-http'
|
||||||
|
import { WebSocketLink } from 'apollo-link-ws'
|
||||||
import { onError } from 'apollo-link-error'
|
import { onError } from 'apollo-link-error'
|
||||||
import { setContext } from 'apollo-link-context'
|
import { setContext } from 'apollo-link-context'
|
||||||
import { ApolloLink } from 'apollo-link'
|
import { ApolloLink, split } from 'apollo-link'
|
||||||
|
import { getMainDefinition } from 'apollo-utilities'
|
||||||
|
|
||||||
const httpLink = new HttpLink({
|
const httpLink = new HttpLink({
|
||||||
uri: process.env.REACT_APP_GRAPHQL_URI,
|
uri: process.env.REACT_APP_GRAPHQL_URI,
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const wsLink = new WebSocketLink({
|
||||||
|
uri: `ws://localhost:4001/graphql`,
|
||||||
|
credentials: 'same-origin',
|
||||||
|
options: {
|
||||||
|
reconnect: true,
|
||||||
|
connectionParams: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const link = split(
|
||||||
|
// split based on operation type
|
||||||
|
({ query }) => {
|
||||||
|
const definition = getMainDefinition(query)
|
||||||
|
return (
|
||||||
|
definition.kind === 'OperationDefinition' &&
|
||||||
|
definition.operation === 'subscription'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
wsLink,
|
||||||
|
httpLink
|
||||||
|
)
|
||||||
|
|
||||||
const linkError = onError(({ graphQLErrors, networkError }) => {
|
const linkError = onError(({ graphQLErrors, networkError }) => {
|
||||||
if (graphQLErrors)
|
if (graphQLErrors)
|
||||||
graphQLErrors.map(({ message, locations, path }) =>
|
graphQLErrors.map(({ message, locations, path }) =>
|
||||||
|
@ -17,7 +43,8 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
|
||||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (networkError) console.log(`[Network error]: ${networkError}`)
|
if (networkError)
|
||||||
|
console.log(`[Network error]: ${JSON.stringify(networkError)}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
const authLink = setContext((_, { headers }) => {
|
const authLink = setContext((_, { headers }) => {
|
||||||
|
@ -33,7 +60,7 @@ const authLink = setContext((_, { headers }) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const client = new ApolloClient({
|
const client = new ApolloClient({
|
||||||
link: ApolloLink.from([linkError, authLink.concat(httpLink)]),
|
link: ApolloLink.from([linkError, authLink.concat(link)]),
|
||||||
cache: new InMemoryCache(),
|
cache: new InMemoryCache(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
33
ui/yarn.lock
33
ui/yarn.lock
|
@ -1133,6 +1133,14 @@ apollo-link-http@^1.5.15:
|
||||||
apollo-link-http-common "^0.2.14"
|
apollo-link-http-common "^0.2.14"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
apollo-link-ws@^1.0.18:
|
||||||
|
version "1.0.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/apollo-link-ws/-/apollo-link-ws-1.0.18.tgz#281b9b0826d5fc7e2aa14d2784c5193d8b761112"
|
||||||
|
integrity sha512-nrWh9m7k1FQw1AK1GB1VTJS0o01cpsP2RYmTAh2j+P4lL2/72WgsblhbuF+yA1/jsgVrzg6xa+TNw3UwgGp3+g==
|
||||||
|
dependencies:
|
||||||
|
apollo-link "^1.2.12"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
apollo-link@^1.0.0, apollo-link@^1.2.12:
|
apollo-link@^1.0.0, apollo-link@^1.2.12:
|
||||||
version "1.2.12"
|
version "1.2.12"
|
||||||
resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.12.tgz#014b514fba95f1945c38ad4c216f31bcfee68429"
|
resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.12.tgz#014b514fba95f1945c38ad4c216f31bcfee68429"
|
||||||
|
@ -1328,6 +1336,11 @@ babylon-walk@^1.0.2:
|
||||||
babel-types "^6.15.0"
|
babel-types "^6.15.0"
|
||||||
lodash.clone "^4.5.0"
|
lodash.clone "^4.5.0"
|
||||||
|
|
||||||
|
backo2@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
|
||||||
|
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
|
@ -2515,6 +2528,11 @@ etag@~1.8.1:
|
||||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
|
eventemitter3@^3.1.0:
|
||||||
|
version "3.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
|
||||||
|
integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
|
||||||
|
|
||||||
events@^3.0.0:
|
events@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
|
resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
|
||||||
|
@ -3531,7 +3549,7 @@ isstream@~0.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||||
|
|
||||||
iterall@^1.2.2:
|
iterall@^1.2.1, iterall@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
|
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
|
||||||
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
|
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
|
||||||
|
@ -6034,6 +6052,17 @@ stylis@^3.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
|
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
|
||||||
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
|
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
|
||||||
|
|
||||||
|
subscriptions-transport-ws@^0.9.16:
|
||||||
|
version "0.9.16"
|
||||||
|
resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.16.tgz#90a422f0771d9c32069294c08608af2d47f596ec"
|
||||||
|
integrity sha512-pQdoU7nC+EpStXnCfh/+ho0zE0Z+ma+i7xvj7bkXKb1dvYHSZxgRPaU6spRP+Bjzow67c/rRDoix5RT0uU9omw==
|
||||||
|
dependencies:
|
||||||
|
backo2 "^1.0.2"
|
||||||
|
eventemitter3 "^3.1.0"
|
||||||
|
iterall "^1.2.1"
|
||||||
|
symbol-observable "^1.0.4"
|
||||||
|
ws "^5.2.0"
|
||||||
|
|
||||||
supports-color@^2.0.0:
|
supports-color@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||||
|
@ -6080,7 +6109,7 @@ svgo@^1.0.0, svgo@^1.0.5:
|
||||||
unquote "~1.1.1"
|
unquote "~1.1.1"
|
||||||
util.promisify "~1.0.0"
|
util.promisify "~1.0.0"
|
||||||
|
|
||||||
symbol-observable@^1.0.2, symbol-observable@^1.1.0:
|
symbol-observable@^1.0.2, symbol-observable@^1.0.4, symbol-observable@^1.1.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||||
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
||||||
|
|
Loading…
Reference in New Issue