Skip to content

Commit

Permalink
Merge pull request #340 from smiclea/CORWEB-189
Browse files Browse the repository at this point in the history
Move UI configuration file to server side
  • Loading branch information
thenoizz authored Mar 12, 2019
2 parents da25c8a + 89fcdad commit 7fdc92f
Show file tree
Hide file tree
Showing 57 changed files with 341 additions and 271 deletions.
60 changes: 60 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// @flow

import type { Config } from './src/types/Config'

const conf: Config = {

// The list of pages which will not appear in the navigation menu
// Remove or comment to enable them
disabledPages: [
'planning',
'users',
'projects',
],

// Whether to show the user domain name input when logging in
showUserDomainInput: false,

// The default user domain name used for logging in
defaultUserDomain: 'default',

// Shows the 'Use Current User/Project/Domain for Authentification' switch
// when creating a new openstack endpoint
showOpenstackCurrentUserSwitch: false,

// Whether to use Barbican secrets when creating a new endpoint
useBarbicanSecrets: true,

// The timeout between polling requests
requestPollTimeout: 5000,

// The list of providers which offer storage listing
storageProviders: ['openstack', 'azure'],

// The list of providers which offer source options
sourceOptionsProviders: ['aws'],

// - Specifies the `limit` for each provider when listing all its VMs for pagination.
// - If the provider is not in this list, the 'default' value will be used.
// - If the `default` value is lower than the number of instances that fit into a page, the latter number will be used.
// - `Infinity` value means no `limit` will be used, i.e. all VMs will be listed.
instancesListBackgroundLoading: { default: 10, ovm: Infinity },

// A list of providers for which `destination-options` API call(s) will be made
// If the item is just a string with the provider name, only one API call will be made
// If the item has `envRequiredFields`, an additional API call will be made once the specified fields are filled
providersWithExtraOptions: [
'openstack',
'oracle_vm',
{
name: 'azure',
envRequiredFields: ['location', 'resource_group'],
},
{
name: 'oci',
envRequiredFields: ['compartment', 'availability_domain'],
},
],
}

export const config = conf
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"react-notification-system": "^0.2.15",
"react-router-dom": "^4.2.2",
"react-tooltip": "^3.4.0",
"require-without-cache": "^0.0.6",
"rimraf": "^2.6.2",
"styled-components": "2.2.0",
"styled-tools": "^0.2.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ 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 { navigationMenu } from '../../../../src/config'
import { navigationMenu } from '../../../../src/constants'

const isEnabled: () => boolean = () => {
let usersEnabled = navigationMenu.find(i => i.value === 'users' && i.disabled === false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ 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 { navigationMenu } from '../../../../src/config'

const isEnabled: () => boolean = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ 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 { navigationMenu } from '../../../../src/config'

const isEnabled: () => boolean = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ 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 { navigationMenu } from '../../../../src/config'

const isEnabled: () => boolean = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ 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 { navigationMenu } from '../../../../src/config'

const isEnabled: () => boolean = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ 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 { navigationMenu } from '../../../../src/config'

const isEnabled: () => boolean = () => {
Expand Down
13 changes: 12 additions & 1 deletion server/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ 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 express from 'express'
import fs from 'fs'
import path from 'path'
import requireWithoutCache from 'require-without-cache'

import packageJson from '../package.json'

Expand All @@ -41,22 +44,30 @@ app.use(express.static('dist'))

require('./proxy')(app)

// $FlowIgnore
app.get('/version', (req, res) => { res.send({ version: packageJson.version }) })

// $FlowIgnore
app.get('/config', (req, res) => {
res.send(requireWithoutCache('../config.js', require).config)
})

if (isDev) {
// $FlowIgnore
app.use((req, res) => {
res.redirect(`${req.baseUrl}/#${req.url}`)
})
} else {
// $FlowIgnore
app.get('*/env.js', (req, res) => {
res.sendFile(path.resolve(__dirname, '../dist', 'env.js'))
})
// $FlowIgnore
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../dist', 'index.html'))
})
}


app.listen(PORT, () => {
console.log(`Express server is up on port ${PORT}`)
})
26 changes: 21 additions & 5 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ import UserDetailsPage from './pages/UserDetailsPage'
import ProjectsPage from './pages/ProjectsPage'
import ProjectDetailsPage from './pages/ProjectDetailsPage'

import { navigationMenu } from '../config'
import { navigationMenu } from '../constants'
import Palette from './styleUtils/Palette'
import StyleProps from './styleUtils/StyleProps'
import configLoader from '../utils/Config'

injectGlobal`
${Fonts}
Expand All @@ -63,16 +64,31 @@ const Wrapper = styled.div`
}
`

class App extends React.Component<{}> {
type State = {
isConfigReady: boolean,
}

class App extends React.Component<{}, State> {
state = {
isConfigReady: false,
}

componentWillMount() {
userStore.tokenLogin()
configLoader.load().then(() => {
this.setState({ isConfigReady: true })
})
}

render() {
if (!this.state.isConfigReady) {
return null
}

let renderOptionalPage = (name: string, component: any, path?: string, exact?: boolean) => {
const isAdmin = userStore.loggedUser ? userStore.loggedUser.isAdmin : true
// $FlowIgnore
if (navigationMenu.find(m => m.value === name && !m.disabled && (!m.requiresAdmin || isAdmin))) {
let isDisabled = configLoader.config.disabledPages.find(p => p === name)
if (navigationMenu.find(m => m.value === name && !isDisabled && (!m.requiresAdmin || isAdmin))) {
return <Route path={`${path || `/${name}`}`} component={component} exact={exact} />
}
return null
Expand Down Expand Up @@ -101,7 +117,7 @@ class App extends React.Component<{}> {
<Route component={NotFoundPage} />
</Switch>
<Notifications />
</Wrapper>
</Wrapper >
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/molecules/LoginOptions/LoginOptions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import styled, { css } from 'styled-components'

import StyleProps from '../../styleUtils/StyleProps'
import Palette from '../../styleUtils/Palette'
import { loginButtons } from '../../../config'
import { loginButtons } from '../../../constants'
import googleLogo from './images/google-logo.svg'
import microsoftLogo from './images/microsoft-logo.svg'
import facebookLogo from './images/facebook-logo.svg'
Expand Down Expand Up @@ -95,7 +95,7 @@ const Logo = styled.div`
${props => buttonStyle(props.id, true)}
`
type Props = {
buttons?: {name: string, id: string}[]
buttons?: { name: string, id: string }[]
}
const LoginOptions = (props: Props) => {
const buttons = props.buttons || loginButtons
Expand Down
10 changes: 7 additions & 3 deletions src/components/molecules/NewItemDropdown/NewItemDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ import DropdownButton from '../../atoms/DropdownButton'
import Palette from '../../styleUtils/Palette'
import StyleProps from '../../styleUtils/StyleProps'
import userStore from '../../../stores/UserStore'
import configLoader from '../../../utils/Config'

import migrationImage from './images/migration.svg'
import replicaImage from './images/replica.svg'
import endpointImage from './images/endpoint.svg'
import userImage from './images/user.svg'
import projectImage from './images/project.svg'

import { navigationMenu } from '../../../config'
import { navigationMenu } from '../../../constants'

const Wrapper = styled.div`
position: relative;
Expand Down Expand Up @@ -176,6 +177,7 @@ class NewItemDropdown extends React.Component<Props, State> {
}

const isAdmin = userStore.loggedUser ? userStore.loggedUser.isAdmin : false
const disabledPages = configLoader.config ? configLoader.config.disabledPages : []
let items: ItemType[] = [{
title: 'Migration',
href: '/wizard/migration',
Expand All @@ -196,13 +198,15 @@ class NewItemDropdown extends React.Component<Props, State> {
value: 'user',
description: 'Create a new Coriolis user',
icon: { user: true },
disabled: Boolean(navigationMenu.find(i => i.value === 'users' && (i.disabled || (i.requiresAdmin && !isAdmin)))),
disabled: Boolean(navigationMenu.find(i => i.value === 'users'
&& (disabledPages.find(p => p === 'users') || (i.requiresAdmin && !isAdmin)))),
}, {
title: 'Project',
value: 'project',
description: 'Create a new Coriolis project',
icon: { project: true },
disabled: Boolean(navigationMenu.find(i => i.value === 'projects' && (i.disabled || (i.requiresAdmin && !isAdmin)))),
disabled: Boolean(navigationMenu.find(i => i.value === 'projects'
&& (disabledPages.find(p => p === 'users') || (i.requiresAdmin && !isAdmin)))),
}]

let list = (
Expand Down
2 changes: 1 addition & 1 deletion src/components/molecules/ScheduleItem/ScheduleItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import DatetimePicker from '../../molecules/DatetimePicker'
import Button from '../../atoms/Button'
import type { Schedule } from '../../../types/Schedule'

import { executionOptions } from '../../../config'
import { executionOptions } from '../../../constants'
import Palette from '../../styleUtils/Palette'
import StyleProps from '../../styleUtils/StyleProps'
import DateUtils from '../../../utils/DateUtils'
Expand Down
6 changes: 4 additions & 2 deletions src/components/molecules/UserDropdown/UserDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import autobind from 'autobind-decorator'

import Palette from '../../styleUtils/Palette'
import StyleProps from '../../styleUtils/StyleProps'
import { navigationMenu } from '../../../config'
import { navigationMenu } from '../../../constants'
import type { User } from '../../../types/User'

import userImage from './images/user.svg'
import userWhiteImage from './images/user-white.svg'
import configLoader from '../../../utils/Config'

const Wrapper = styled.div`
position: relative;
Expand Down Expand Up @@ -161,7 +162,8 @@ class UserDropdown extends React.Component<Props, State> {

let href: ?string
let isAdmin = this.props.user.isAdmin
if (isAdmin && navigationMenu.find(m => m.value === 'users' && !m.disabled && (!m.requiresAdmin || isAdmin))) {
if (isAdmin && navigationMenu.find(m => m.value === 'users'
&& !configLoader.config.disabledPages.find(p => p === 'users') && (!m.requiresAdmin || isAdmin))) {
href = `/user/${this.props.user.id}`
}

Expand Down
13 changes: 3 additions & 10 deletions src/components/molecules/WizardBreadcrumbs/WizardBreadcrumbs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import styled from 'styled-components'

import Arrow from '../../atoms/Arrow'

import { wizardConfig } from '../../../config'
import Palette from '../../styleUtils/Palette'
import type { WizardPage } from '../../../types/WizardData'

const Wrapper = styled.div`
display: flex;
Expand All @@ -43,21 +43,14 @@ const Name = styled.div`

type Props = {
selected: { id: string },
wizardType: 'migration' | 'replica',
destinationProvider: ?string,
sourceProvider: ?string,
pages: WizardPage[],
}
@observer
class WizardBreadcrumbs extends React.Component<Props> {
render() {
let pages = wizardConfig.pages
.filter(p => !p.excludeFrom || p.excludeFrom !== this.props.wizardType)
.filter(p => !p.targetFilter || (this.props.destinationProvider && p.targetFilter(this.props.destinationProvider)))
.filter(p => !p.sourceFilter || (this.props.sourceProvider && p.sourceFilter(this.props.sourceProvider)))

return (
<Wrapper>
{pages.map(page => {
{this.props.pages.map(page => {
return (
<Breadcrumb key={page.id}>
<Name selected={this.props.selected.id === page.id} data-test-id={`wBreadCrumbs-name-${page.id}`}>{page.breadcrumb}</Name>
Expand Down
27 changes: 4 additions & 23 deletions src/components/molecules/WizardBreadcrumbs/test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,16 @@ import React from 'react'
import { shallow } from 'enzyme'
import WizardBreadcrumbs from '.'
import TW from '../../../utils/TestWrapper'
import { wizardConfig } from '../../../config'
import { wizardPages } from '../../../constants'

const wrap = props => new TW(
shallow(<WizardBreadcrumbs destinationProvider="oci" sourceProvider="vmware_vsphere" {...props} />),
shallow(<WizardBreadcrumbs pages={wizardPages} destinationProvider="oci" sourceProvider="vmware_vsphere" {...props} />),
'wBreadCrumbs'
)

describe('WizardBreadcrumbs Component', () => {
it('renders correct number of crumbs for replica', () => {
let wrapper = wrap({ selected: wizardConfig.pages[2], wizardType: 'replica' })
let pages = wizardConfig.pages.filter(p => !p.excludeFrom || p.excludeFrom !== 'replica')
expect(wrapper.find('name-', true).length).toBe(pages.length - 2)
})

it('renders correct number of crumbs for migration', () => {
let wrapper = wrap({ selected: wizardConfig.pages[2], wizardType: 'migration' })
let pages = wizardConfig.pages.filter(p => !p.excludeFrom || p.excludeFrom !== 'migration')
expect(wrapper.find('name-', true).length).toBe(pages.length - 2)
})

it('has correct page selected', () => {
let pages = wizardConfig.pages.filter(p => !p.excludeFrom || p.excludeFrom !== 'migration')
let wrapper = wrap({ selected: pages[1], wizardType: 'migration' })
expect(wrapper.findText(`name-${pages[1].id}`)).toBe(pages[1].breadcrumb)
})

it('renders correct number of crumbs for Openstack', () => {
let wrapper = wrap({ selected: wizardConfig.pages[2], wizardType: 'migration', destinationProvider: 'openstack' })
let pages = wizardConfig.pages.filter(p => !p.excludeFrom || p.excludeFrom !== 'migration')
expect(wrapper.find('name-', true).length).toBe(pages.length - 1)
let wrapper = wrap({ selected: wizardPages[3] })
expect(wrapper.findText(`name-${wizardPages[3].id}`)).toBe(wizardPages[3].breadcrumb)
})
})
Loading

0 comments on commit 7fdc92f

Please sign in to comment.