Sfoglia il codice sorgente

Merge pull request #482 from smiclea/admin-page-load-ux

Improve and fix admin pages loading UX
Nashwan Azhari 6 anni fa
parent
commit
d75e74cec9

+ 23 - 4
src/components/App.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { Switch, Route } from 'react-router-dom'
 import styled, { injectGlobal } from 'styled-components'
+import { observe } from 'mobx'
 
 import Fonts from './atoms/Fonts'
 import Notifications from './organisms/Notifications'
@@ -85,6 +86,7 @@ class App extends React.Component<{}, State> {
   }
 
   async componentWillMount() {
+    observe(userStore, 'loggedUser', () => { this.setState({}) })
     userStore.tokenLogin()
     await configLoader.load()
     this.setState({ isConfigReady: true })
@@ -96,12 +98,29 @@ class App extends React.Component<{}, State> {
     }
 
     let renderOptionalPage = (name: string, component: any, path?: string, exact?: boolean) => {
-      const isAdmin = userStore.loggedUser && typeof userStore.loggedUser.isAdmin === 'boolean'
-        ? userStore.loggedUser.isAdmin : true
-      let isDisabled = configLoader.config.disabledPages.find(p => p === name)
-      if (navigationMenu.find(m => m.value === name && !isDisabled && (!m.requiresAdmin || isAdmin))) {
+      if (configLoader.config.disabledPages.find(p => p === name)) {
+        return null
+      }
+      let requiresAdmin = Boolean(navigationMenu.find(n => n.value === name && n.requiresAdmin))
+      if (!requiresAdmin) {
         return <Route path={`${path || `/${name}`}`} component={component} exact={exact} />
       }
+      const renderNotFound = (title: string, subtitle: string) => (
+        <Route
+          path={`${path || `/${name}`}`}
+          exact={exact}
+          render={() => <NotFoundPage title={title} subtitle={subtitle} />}
+        />
+      )
+      if (!userStore.loggedUser || userStore.loggedUser.isAdmin == null) {
+        return renderNotFound('Checking permissions...', 'Please wait while checking user\'s permissions.')
+      }
+      if (userStore.loggedUser && userStore.loggedUser.isAdmin === false) {
+        return renderNotFound('User doesn\'t have permissions to view this page', 'Please login in with an administrator acount to view this page.')
+      }
+      if (userStore.loggedUser && userStore.loggedUser.isAdmin) {
+        return <Route path={`${path || `/${name}`}`} exact={exact} component={component} />
+      }
       return null
     }
 

+ 1 - 1
src/components/pages/DashboardPage/DashboardPage.jsx

@@ -103,7 +103,7 @@ class ProjectsPage extends React.Component<{ history: any }, State> {
   }
 
   async loadAdminData(showLoading: boolean) {
-    await Utils.waitFor(() => Boolean(userStore.loggedUser && userStore.loggedUser.isAdmin), 3000, 100)
+    await Utils.waitFor(() => Boolean(userStore.loggedUser && userStore.loggedUser.isAdmin), 30000, 100)
     if (userStore.loggedUser && userStore.loggedUser.isAdmin) {
       await userStore.getAllUsers({ skipLog: true, showLoading })
     }

+ 7 - 4
src/components/pages/NotFoundPage/NotFoundPage.jsx

@@ -39,13 +39,16 @@ const Message = styled.div`
   margin-top: 16px;
   color: ${Palette.grayscale[8]};
 `
-
-const NotFoundPage = () => {
+type Props = {
+  title?: string,
+  subtitle?: string,
+}
+const NotFoundPage = (props: Props) => {
   return (
     <EmptyTemplate>
       <Wrapper>
-        <Title>Page Not Found</Title>
-        <Message>Sorry, but the page you are trying to view does not exist.</Message>
+        <Title>{props.title || 'Page Not Found'}</Title>
+        <Message>{props.subtitle || 'Sorry, but the page you are trying to view does not exist.'}</Message>
       </Wrapper>
     </EmptyTemplate>
   )

+ 2 - 1
src/constants.js

@@ -30,7 +30,8 @@ export const servicesUrl = {
   licence: licenceUrl,
 }
 
-export const navigationMenu = [
+export type NavigationMenuType = { label: string, value: string, hidden?: boolean, requiresAdmin?: boolean }
+export const navigationMenu: NavigationMenuType[] = [
   { label: 'Dashboard', value: 'dashboard' },
   { label: 'Replicas', value: 'replicas' },
   { label: 'Migrations', value: 'migrations' },

+ 8 - 7
src/stores/UserStore.js

@@ -20,7 +20,6 @@ import type { Project } from '../types/Project'
 import UserSource from '../sources/UserSource'
 import projectStore from './ProjectStore'
 import notificationStore from '../stores/NotificationStore'
-import DomUtils from '../utils/DomUtils'
 
 /**
  * This is the authentication / authorization flow:
@@ -101,7 +100,7 @@ class UserStore {
     }
 
     let userData: User = await UserSource.getUserInfo(this.loggedUser.id)
-    runInAction(() => { this.loggedUser = { ...this.loggedUser, ...userData, isAdmin: false } })
+    runInAction(() => { this.loggedUser = { ...this.loggedUser, ...userData, isAdmin: null } })
   }
 
   @action async tokenLogin(): Promise<void> {
@@ -169,18 +168,20 @@ class UserStore {
     if (!this.loggedUser) {
       return
     }
-    this.loggedUser.isAdmin = false
+    this.loggedUser = { ...this.loggedUser, isAdmin: null }
     try {
       let isAdmin = await UserSource.isAdmin(this.loggedUser.id)
       runInAction(() => {
         if (this.loggedUser) {
-          this.loggedUser.isAdmin = isAdmin
+          this.loggedUser = { ...this.loggedUser, isAdmin }
         }
       })
     } catch (err) {
-      if (window.location.href.indexOf(`${DomUtils.urlHashPrefix}project`) > -1 || window.location.href.indexOf(`${DomUtils.urlHashPrefix}user`) > -1) {
-        window.location.href = `${DomUtils.urlHashPrefix}`
-      }
+      runInAction(() => {
+        if (this.loggedUser) {
+          this.loggedUser = { ...this.loggedUser, isAdmin: false }
+        }
+      })
     }
   }
 

+ 1 - 1
src/types/User.js

@@ -26,7 +26,7 @@ export type User = {
   enabled?: boolean,
   project_id?: string,
   domain_id?: string,
-  isAdmin?: boolean,
+  isAdmin?: ?boolean,
   password?: string,
   extra?: any,
 }