Parcourir la source

Add `About` modal accessible from user dropdown

The version is taken from the `./package.json` file.
Sergiu Miclea il y a 7 ans
Parent
commit
007a63d66b

+ 3 - 0
server/main.js

@@ -14,6 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import express from 'express'
 import fs from 'fs'
+import packageJson from '../package.json'
 
 // Create our app
 const app = express()
@@ -34,6 +35,8 @@ app.use(express.static('dist'))
 
 require('./proxy')(app)
 
+app.get('/version', (req, res) => { res.send({ version: packageJson.version }) })
+
 app.use((req, res) => {
   res.redirect(`${req.baseUrl}/#${req.url}`)
 })

+ 3 - 7
src/components/molecules/UserDropdown/UserDropdown.jsx

@@ -53,11 +53,7 @@ const List = styled.div`
   z-index: 10;
 `
 const ListItem = styled.div`
-  padding: 8px 0;
-
-  &:last-child {
-    padding: 0;
-  }
+  padding-top: 8px;
 `
 
 const Label = styled.div`
@@ -188,8 +184,8 @@ class UserDropdown extends React.Component<Props, State> {
     }
 
     let items = [{
-      label: 'Download Log',
-      value: 'downloadlog',
+      label: 'About Coriolis',
+      value: 'about',
     }, {
       label: 'Sign Out',
       value: 'signout',

+ 134 - 0
src/components/organisms/AboutModal/AboutModal.jsx

@@ -0,0 +1,134 @@
+/*
+Copyright (C) 2019  Cloudbase Solutions SRL
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// @flow
+
+import React from 'react'
+import { observer } from 'mobx-react'
+import styled from 'styled-components'
+
+import apiCaller from '../../../utils/ApiCaller'
+import logger from '../../../utils/ApiLogger'
+
+import Button from '../../atoms/Button'
+import Modal from '../../molecules/Modal/Modal'
+
+import Palette from '../../styleUtils/Palette'
+
+import logoImage from './images/coriolis-logo.svg'
+
+const Wrapper = styled.div`
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 60px 0 32px 0;
+  position: relative;
+`
+const Gradient = styled.div`
+  position: absolute;
+  height: 100%;
+  max-height: 230px;
+  top: 0;
+  width: 100%;
+  background: linear-gradient(#A7B0CA, #FFFFFF);
+`
+const Content = styled.div`
+  z-index: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+`
+const Logo = styled.div`
+  width: 362px;
+  height: 71px;
+  background: url('${logoImage}') center no-repeat;
+`
+const Text = styled.div`
+  margin: 48px 0;
+  color: ${Palette.grayscale[5]};
+  font-size: 12px;
+`
+const TextLine = styled.div`
+  display: flex;
+  justify-content: center;
+  margin-left: -6px;
+  margin-top: 8px;
+  &:first-child {
+    margin-top: 0;
+  }
+  span, a {
+    margin-left: 6px;
+  }
+`
+const Link = styled.a`
+  color: inherit;
+`
+const LinkMock = styled.span`
+  text-decoration: underline;
+  cursor: pointer;
+`
+
+type Props = {
+  onRequestClose: () => void,
+}
+
+type State = {
+  version: string,
+}
+
+@observer
+class AboutModal extends React.Component<Props, State> {
+  state = {
+    version: '-',
+  }
+
+  componentWillMount() {
+    apiCaller.get('/version').then(res => {
+      this.setState({ version: res.data.version })
+    })
+  }
+
+  render() {
+    return (
+      <Modal
+        title="About"
+        isOpen
+        onRequestClose={() => { this.props.onRequestClose() }}
+      >
+        <Wrapper>
+          <Gradient />
+          <Content>
+            <Logo />
+            <Text>
+              <TextLine>
+                <span>Version {this.state.version}</span>
+                <span>|</span>
+                <Link href="https://github.com/cloudbase/coriolis/issues" target="_blank">Report an Issue</Link>
+                <span>|</span>
+                <LinkMock onClick={() => { logger.download() }} >Download Log</LinkMock>
+              </TextLine>
+              <TextLine>
+                © {new Date().getFullYear()} Cloudbase Solutions. All Rights Reserved.
+              </TextLine>
+            </Text>
+            <Button secondary large onClick={() => { this.props.onRequestClose() }}>Close</Button>
+          </Content>
+        </Wrapper>
+      </Modal>
+    )
+  }
+}
+
+export default AboutModal

Fichier diff supprimé car celui-ci est trop grand
+ 21 - 0
src/components/organisms/AboutModal/images/coriolis-logo.svg


+ 6 - 0
src/components/organisms/AboutModal/package.json

@@ -0,0 +1,6 @@
+{
+  "name": "AboutModal",
+  "version": "0.0.0",
+  "private": true,
+  "main": "./AboutModal.jsx"
+}

+ 19 - 6
src/components/organisms/DetailsPageHeader/DetailsPageHeader.jsx

@@ -21,10 +21,11 @@ import { observer } from 'mobx-react'
 import SideMenu from '../../molecules/SideMenu'
 import NotificationDropdown from '../../molecules/NotificationDropdown'
 import UserDropdown from '../../molecules/UserDropdown'
+import AboutModal from '../../organisms/AboutModal'
+
 import type { User as UserType } from '../../../types/User'
 
 import notificationStore from '../../../stores/NotificationStore'
-import logger from '../../../utils/ApiLogger'
 
 import backgroundImage from './images/star-bg.jpg'
 import logoImage from './images/logo.svg'
@@ -54,6 +55,9 @@ const User = styled.div`
   display: flex;
   align-items: center;
 `
+type State = {
+  showAbout: boolean,
+}
 type Props = {
   user?: ?UserType,
   onUserItemClick: (userItem: { label: string, value: string }) => void,
@@ -61,7 +65,11 @@ type Props = {
 }
 
 @observer
-class DetailsPageHeader extends React.Component<Props, {}> {
+class DetailsPageHeader extends React.Component<Props, State> {
+  state = {
+    showAbout: false,
+  }
+
   pollTimeout: TimeoutID
   stopPolling: boolean
 
@@ -83,10 +91,12 @@ class DetailsPageHeader extends React.Component<Props, {}> {
   }
 
   handleUserItemClick(item: { label: string, value: string }) {
-    if (item.value === 'downloadlog') {
-      logger.download()
-    } else {
-      this.props.onUserItemClick(item)
+    switch (item.value) {
+      case 'about':
+        this.setState({ showAbout: true })
+        break
+      default:
+        this.props.onUserItemClick(item)
     }
   }
 
@@ -120,6 +130,9 @@ class DetailsPageHeader extends React.Component<Props, {}> {
             data-test-id="dpHeader-userDropdown"
           />
         </User>
+        {this.state.showAbout ? (
+          <AboutModal onRequestClose={() => { this.setState({ showAbout: false }) }} />
+        ) : null}
       </Wrapper>
     )
   }

+ 8 - 3
src/components/organisms/PageHeader/PageHeader.jsx

@@ -30,8 +30,8 @@ import ChooseProvider from '../../organisms/ChooseProvider'
 import Endpoint from '../../organisms/Endpoint'
 import UserModal from '../../organisms/UserModal'
 import ProjectModal from '../../organisms/ProjectModal'
+import AboutModal from '../../organisms/AboutModal'
 
-import logger from '../../../utils/ApiLogger'
 import projectStore from '../../../stores/ProjectStore'
 import userStore from '../../../stores/UserStore'
 import notificationStore from '../../../stores/NotificationStore'
@@ -72,6 +72,7 @@ type State = {
   showEndpointModal: boolean,
   showUserModal: boolean,
   showProjectModal: boolean,
+  showAbout: boolean,
   providerType: ?string,
 }
 @observer
@@ -82,6 +83,7 @@ class PageHeader extends React.Component<Props, State> {
     showUserModal: false,
     showProjectModal: false,
     providerType: null,
+    showAbout: false,
   }
 
   pollTimeout: TimeoutID
@@ -108,8 +110,8 @@ class PageHeader extends React.Component<Props, State> {
 
   handleUserItemClick(item: { value: string }) {
     switch (item.value) {
-      case 'downloadlog':
-        logger.download()
+      case 'about':
+        this.setState({ showAbout: true })
         return
       case 'signout':
         userStore.logout()
@@ -295,6 +297,9 @@ class PageHeader extends React.Component<Props, State> {
             onUpdateClick={project => { this.handleProjectModalUpdateClick(project) }}
           />
         ) : null}
+        {this.state.showAbout ? (
+          <AboutModal onRequestClose={() => { this.setState({ showAbout: false }) }} />
+        ) : null}
       </Wrapper>
     )
   }

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff