App.tsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. import { hot } from 'react-hot-loader/root'
  15. import React from 'react'
  16. import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
  17. import styled, { createGlobalStyle } from 'styled-components'
  18. import { observe } from 'mobx'
  19. import Fonts from './atoms/Fonts'
  20. import Notifications from './organisms/Notifications'
  21. import LoginPage from './pages/LoginPage'
  22. import ReplicasPage from './pages/ReplicasPage'
  23. import MessagePage from './pages/MessagePage'
  24. import ReplicaDetailsPage from './pages/ReplicaDetailsPage'
  25. import MigrationsPage from './pages/MigrationsPage'
  26. import MigrationDetailsPage from './pages/MigrationDetailsPage'
  27. import EndpointsPage from './pages/EndpointsPage'
  28. import EndpointDetailsPage from './pages/EndpointDetailsPage'
  29. import WizardPage from './pages/WizardPage'
  30. import userStore from '../stores/UserStore'
  31. import AssessmentsPage from './pages/AssessmentsPage'
  32. import AssessmentDetailsPage from './pages/AssessmentDetailsPage'
  33. import UsersPage from './pages/UsersPage'
  34. import UserDetailsPage from './pages/UserDetailsPage'
  35. import ProjectsPage from './pages/ProjectsPage'
  36. import ProjectDetailsPage from './pages/ProjectDetailsPage'
  37. import DashboardPage from './pages/DashboardPage'
  38. import LogsPage from './pages/LogsPage'
  39. import LogStreamPage from './pages/LogStreamPage'
  40. import Tooltip from './atoms/Tooltip/Tooltip'
  41. import { navigationMenu } from '../constants'
  42. import Palette from './styleUtils/Palette'
  43. import StyleProps from './styleUtils/StyleProps'
  44. import configLoader from '../utils/Config'
  45. import MinionPoolsPage from './pages/MinionPoolsPage/MinionPoolsPage'
  46. import MinionPoolDetailsPage from './pages/MinionPoolDetailsPage/MinionPoolDetailsPage'
  47. const GlobalStyle = createGlobalStyle`
  48. ${Fonts}
  49. html, body, main {
  50. height: 100%;
  51. display: flex;
  52. flex-direction: column;
  53. min-height: 0;
  54. }
  55. body {
  56. margin: 0;
  57. color: ${Palette.black};
  58. font-family: Rubik;
  59. font-size: 14px;
  60. font-weight: ${StyleProps.fontWeights.regular};
  61. -webkit-font-smoothing: antialiased;
  62. -moz-osx-font-smoothing: grayscale;
  63. }
  64. `
  65. const Wrapper = styled.div<any>`
  66. height: 100%;
  67. min-height: 0;
  68. display: flex;
  69. flex-direction: column;
  70. > div:first-child {
  71. height: 100%;
  72. }
  73. `
  74. type State = {
  75. isConfigReady: boolean,
  76. }
  77. class App extends React.Component<{}, State> {
  78. state = {
  79. isConfigReady: false,
  80. }
  81. awaitingRefresh: boolean = false
  82. async componentDidMount() {
  83. observe(userStore, 'loggedUser', () => {
  84. this.setState({})
  85. })
  86. await configLoader.load()
  87. userStore.tokenLogin()
  88. this.setState({ isConfigReady: true })
  89. }
  90. render() {
  91. if (!this.state.isConfigReady) {
  92. return null
  93. }
  94. const renderMessagePage = (options: {
  95. path: string,
  96. exact?: boolean,
  97. title: string,
  98. subtitle: string,
  99. showAuthAnimation?: boolean,
  100. showDenied?: boolean,
  101. }) => (
  102. <Route
  103. path={options.path}
  104. exact={options.exact}
  105. render={() => (
  106. <MessagePage
  107. title={options.title}
  108. subtitle={options.subtitle}
  109. showAuthAnimation={options.showAuthAnimation}
  110. showDenied={options.showDenied}
  111. />
  112. )}
  113. />
  114. )
  115. const renderRoute = (path: string, component: any, exact?: boolean) => {
  116. if (!userStore.loggedUser) {
  117. return renderMessagePage({
  118. path,
  119. exact,
  120. title: 'Authenticating...',
  121. subtitle: 'Please wait while authenticating user.',
  122. showAuthAnimation: true,
  123. })
  124. }
  125. return <Route path={path} component={component} exact={exact} />
  126. }
  127. const renderOptionalRoute = (name: string, component: any, path?: string, exact?: boolean) => {
  128. if (configLoader.config.disabledPages.find(p => p === name)) {
  129. return null
  130. }
  131. const actualPath = `${path || `/${name}`}`
  132. const requiresAdmin = Boolean(navigationMenu.find(n => n.value === name && n.requiresAdmin))
  133. if (!requiresAdmin) {
  134. return renderRoute(actualPath, component, exact)
  135. }
  136. if (!userStore.loggedUser || userStore.loggedUser.isAdmin == null) {
  137. return renderMessagePage({
  138. path: actualPath,
  139. exact,
  140. title: 'Checking permissions...',
  141. subtitle: 'Please wait while checking user\'s permissions.',
  142. showAuthAnimation: true,
  143. })
  144. }
  145. if (userStore.loggedUser && userStore.loggedUser.isAdmin === false) {
  146. return renderMessagePage({
  147. path: actualPath,
  148. exact,
  149. title: 'User doesn\'t have permissions to view this page',
  150. subtitle: 'Please login in with an administrator acount to view this page.',
  151. showDenied: true,
  152. })
  153. }
  154. if (userStore.loggedUser && userStore.loggedUser.isAdmin) {
  155. return <Route path={actualPath} exact={exact} component={component} />
  156. }
  157. return null
  158. }
  159. return (
  160. <Wrapper>
  161. <GlobalStyle />
  162. <Router>
  163. <Switch>
  164. {renderRoute('/', DashboardPage, true)}
  165. <Route path="/login" component={LoginPage} />
  166. {renderRoute('/dashboard', DashboardPage)}
  167. {renderRoute('/replicas', ReplicasPage, true)}
  168. {renderRoute('/replicas/:id', ReplicaDetailsPage, true)}
  169. {renderRoute('/replicas/:id/:page', ReplicaDetailsPage)}
  170. {renderRoute('/migrations', MigrationsPage, true)}
  171. {renderRoute('/migrations/:id', MigrationDetailsPage, true)}
  172. {renderRoute('/migrations/:id/:page', MigrationDetailsPage)}
  173. {renderRoute('/endpoints', EndpointsPage, true)}
  174. {renderRoute('/endpoints/:id', EndpointDetailsPage)}
  175. {renderRoute('/minion-pools', MinionPoolsPage, true)}
  176. {renderRoute('/minion-pools/:id', MinionPoolDetailsPage, true)}
  177. {renderRoute('/minion-pools/:id/:page', MinionPoolDetailsPage)}
  178. {renderRoute('/wizard/:type', WizardPage)}
  179. {renderOptionalRoute('planning', AssessmentsPage)}
  180. {renderOptionalRoute('planning', AssessmentDetailsPage, '/assessment/:info')}
  181. {renderOptionalRoute('users', UsersPage, undefined, true)}
  182. {renderOptionalRoute('users', UserDetailsPage, '/users/:id')}
  183. {renderOptionalRoute('projects', ProjectsPage, undefined, true)}
  184. {renderOptionalRoute('projects', ProjectDetailsPage, '/projects/:id')}
  185. {renderOptionalRoute('logging', LogsPage)}
  186. {renderRoute('/streamlog', LogStreamPage)}
  187. <Route component={MessagePage} />
  188. </Switch>
  189. </Router>
  190. <Notifications />
  191. <Tooltip />
  192. </Wrapper>
  193. )
  194. }
  195. }
  196. export default hot(App)