Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #45

Merged
merged 21 commits into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4f87484
Add version number to the app bar, as well as logs and tooltip with g…
Jonesy Jan 30, 2019
e0ec980
Add an about dialog that can list all the versions of the API's and UI.
Jonesy Jan 30, 2019
6d367d8
Merge branch 'develop' into feature/version
Jonesy Jan 31, 2019
7520b4f
Load in API info from other microservices.
Jonesy Jan 31, 2019
c198335
Add some fixes to retaining last visited page after logging back in, …
Jonesy Feb 1, 2019
997895e
added a config option for always scanning files
BrandonSharratt Feb 1, 2019
b0a4c5e
enabled automated tests for submitting and editing
Feb 1, 2019
c450c7c
Merge branch 'develop' of https://github.com/bcgov/OCWA into develop
BrandonSharratt Feb 4, 2019
e434538
fixed json
BrandonSharratt Feb 4, 2019
6a446de
fixed json
BrandonSharratt Feb 4, 2019
b4a06fa
Force bash scripts have LF line endings
jujaga Feb 1, 2019
559b13e
Fix issue #38 - missing length attribute in loop
jujaga Feb 4, 2019
a1c8d8d
Update TF mongodb.tpl rules with updated logic
jujaga Feb 4, 2019
7e83ec7
Merge branch 'fix/ocwa-#38' into develop
jujaga Feb 4, 2019
34efd12
Merge branch 'develop' into feature/version
Jonesy Feb 4, 2019
799f7c3
Merge branch 'develop' into feature/version
Jonesy Feb 4, 2019
eef49dd
fixed validate always scan
BrandonSharratt Feb 4, 2019
ff33ea4
Merge branch 'develop' into feature/version
Jonesy Feb 4, 2019
bb0634e
Merge branch 'feature/testing' into develop
jujaga Feb 5, 2019
d39400a
Remove `git-revision-webpack-plugin` (doesn't work) and used GITHASH …
Jonesy Feb 5, 2019
88d42f3
Add `parseApiHost` to the version requests.
Jonesy Feb 6, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
*.c text
*.h text

# Declare files that will always have LF line endings on checkout.
*.sh text eol=lf

# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=lf
*.sln text eol=crlf

# Denote all files that are truly binary and should not be modified.
*.png binary
Expand Down
4 changes: 3 additions & 1 deletion frontend/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"globals": {
"__DEV__": true,
"FILES_API_HOST": true,
"SOCKET_HOST": true
"SOCKET_HOST": true,
"VERSION": true,
"COMMIT": true
},
"parser": "babel-eslint",
"rules": {
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "requests-app",
"version": "1.0.0",
"version": "0.8.0",
"main": "src/index.js",
"license": "MIT",
"scripts": {
Expand Down
6 changes: 4 additions & 2 deletions frontend/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');

require('./auth');
const { parseApiHost, parseWsHost } = require('./utils');
const { parseApiHost, parseWsHost, storeUrl } = require('./utils');
const proxy = require('./proxy');
const authRoute = require('./routes/auth');
const filesRoute = require('./routes/files');
const versionsRoute = require('./routes/versions');
const webpackConfig = require('../webpack.dev');

// Main constants and setup
Expand Down Expand Up @@ -78,12 +79,13 @@ app.get('/login', passport.authenticate('openidconnect'));
app.use('/api/v1/forums', proxy.forum);
app.use('/api/v1/requests', proxy.request);
app.use('/api/v1/files', filesRoute);
app.use('/versions', versionsRoute);

app.get('/hello', (req, res) => {
res.status(200).send('hi');
});

app.get(/^((?!.json|__webpack_hmr).)*$/, (req, res) => {
app.get('*', storeUrl, (req, res) => {
res.render('index', {
isDevelopment,
title: 'OCWA [Development Version]',
Expand Down
7 changes: 6 additions & 1 deletion frontend/server/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ router.get(
// Clean up the token on first successful sign in
const jwtSecret = config.get('jwtSecret');
const jwtClaims = get(req, 'user.claims');
const { redirectTo } = req.session;

if (redirectTo) {
delete req.session.redirectTo;
}

if (jwtClaims) {
// Passport/KeyCloak doesn't sign the token correctly, sign here
req.user.accessToken = jwt.sign(jwtClaims, jwtSecret);
}

res.redirect('/');
res.redirect(redirectTo || '/');
}
);

Expand Down
38 changes: 38 additions & 0 deletions frontend/server/routes/versions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const config = require('config');
const express = require('express');
const request = require('request');
const { parseApiHost } = require('../utils');

const router = express.Router();

const forumApiHost = config.get('forumApiHost');
const requestApiHost = config.get('requestApiHost');

function versionRequest(url) {
return new Promise((resolve, reject) => {
request.get(`${parseApiHost(url)}/version`, (err, resp, body) => {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
});
});
}

router.get('/', (req, res) => {
Promise.all([versionRequest(forumApiHost), versionRequest(requestApiHost)])
.then(json =>
res.json({
versions: json,
})
)
.catch(err => {
res.status(500);
res.json({
error: err.message,
});
});
});

module.exports = router;
18 changes: 18 additions & 0 deletions frontend/server/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const path = require('path');

const pathRewrite = path => path.replace(/\/api\/v1\/\w+/, '');

const parseApiHost = url => {
Expand All @@ -16,8 +18,24 @@ const parseWsHost = url => {
return url;
};

// Middleware to store a URL when unauthenticated so you can be returned to it
// after sign in is completed
const storeUrl = (req, res, done) => {
if (!req.user || !req.isAuthenticated || !req.isAuthenticated()) {
const { originalUrl } = req;
const testForExt = path.extname(originalUrl);

if (testForExt.length < 1) {
req.session.redirectTo = req.originalUrl;
}
}

done();
};

module.exports = {
pathRewrite,
parseApiHost,
parseWsHost,
storeUrl,
};
13 changes: 9 additions & 4 deletions frontend/src/components/app-bar/index.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import * as React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import Tooltip from '@atlaskit/tooltip';
import { commit, version } from '@src/services/config';

import * as styles from './styles.css';

function AppBar({ children, icon, title }) {
return (
<div className={styles.container}>
<Link id="app-bar-brand" to="/" className={styles.brand}>
{icon}
{title}
</Link>
<Tooltip content={`OCWA Version ${version} - ${commit}`}>
<Link id="app-bar-brand" to="/" className={styles.brand}>
{icon}
{title}
<small>{`v${version}`}</small>
</Link>
</Tooltip>
<div className={styles.actions}>{children}</div>
</div>
);
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/components/app-bar/menu.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Avatar from '@atlaskit/avatar';
import Dropdown, { DropdownItem } from '@atlaskit/dropdown-menu';
import aboutButton from '@src/modules/app/containers/about-button';

const AboutDropdownItem = props => (
<DropdownItem {...props}>About this App</DropdownItem>
);
const AboutButton = aboutButton(AboutDropdownItem);

function AppBarMenu({ children, user }) {
return (
<Dropdown
position="bottom right"
trigger={<Avatar borderColor="#0052CC" name={user.displayName} />}
>
<DropdownItem>{`Howdy, ${user.displayName}`}</DropdownItem>
{children}
<AboutButton />
<DropdownItem href="/auth/logout">Logout</DropdownItem>
</Dropdown>
);
}

AppBarMenu.propTypes = {
children: PropTypes.arrayOf(PropTypes.instanceOf(DropdownItem)),
user: PropTypes.shape({
displayName: PropTypes.string.isRequired,
}).isRequired,
};

AppBarMenu.defaultProps = {
children: null,
};

export default AppBarMenu;
6 changes: 6 additions & 0 deletions frontend/src/components/app-bar/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
margin-right: 15px;
}

.brand small {
margin: 11px 0 0 10px;
font-size: 11px;
color: rgba(255, 255, 255, 0.25);
}

.actions {
display: flex;
align-items: center;
Expand Down
30 changes: 14 additions & 16 deletions frontend/src/components/app/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@ import { Switch, Route } from 'react-router-dom';
import Requests from '@src/modules/requests/containers/requests-list';
import '@atlaskit/css-reset';

class App extends React.Component {
render() {
return (
<main>
<AppBar />
<Switch>
<Route exact path="/" component={Requests} />
<Route
exact
path="/requests/:requestId"
render={() => 'Request Page'}
/>
</Switch>
</main>
);
}
function App() {
return (
<main>
<AppBar />
<Switch>
<Route exact path="/" component={Requests} />
<Route
exact
path="/requests/:requestId"
render={() => 'Request Page'}
/>
</Switch>
</main>
);
}

export default App;
11 changes: 11 additions & 0 deletions frontend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import { commit, version } from '@src/services/config';

import App from 'modules/app/containers/app';
import createStore from './services/store';
Expand All @@ -10,7 +11,16 @@ import sagas from './sagas';

const containerEl = document.getElementById('main');

/* eslint-disable no-console */
console.log('-------------------------');
console.log('OCWA');
console.log(`Version: ${version}`);
console.log(`Commit: ${commit}`);
console.log('-------------------------');
/* eslint-enable no-console */

const store = createStore(reducers, sagas);
/* eslint-disable react/jsx-filename-extension */
const renderApp = () =>
render(
<Provider store={store}>
Expand All @@ -20,6 +30,7 @@ const renderApp = () =>
</Provider>,
containerEl
);
/* eslint-enable react/jsx-filename-extension */

renderApp();

Expand Down
23 changes: 23 additions & 0 deletions frontend/src/modules/app/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@ export const fetchToken = () => ({
type: 'app/get/token',
});

export const toggleAbout = () => ({
type: 'app/about/toggle',
});

export const versionsRequested = () => ({
type: 'app/versions/requested',
});

export const versionsSuccess = payload => ({
type: 'app/versions/success',
payload,
});

export const versionsFailed = payload => ({
type: 'app/versions/failed',
error: true,
payload,
});

export default {
fetchToken,
toggleAbout,
versionsFailed,
versionsRequested,
versionsSuccess,
};
64 changes: 64 additions & 0 deletions frontend/src/modules/app/components/app/about.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Modal, { ModalTransition } from '@atlaskit/modal-dialog';
import Spinner from '@atlaskit/spinner';
import WarningIcon from '@atlaskit/icon/glyph/warning';
import { commit, version } from '@src/services/config';
import { uid } from 'react-uid';

import * as styles from './styles.css';

const makeVersionString = (v, hash) => [v, hash].join(' - ');

function About({ data, fetchStatus, open, onToggle }) {
return (
<ModalTransition>
{open && (
<Modal
actions={[{ text: 'Done', onClick: onToggle }]}
heading="About this App"
>
{fetchStatus === 'loading' && (
<div className={styles.aboutLoading}>
<Spinner size="large" />
</div>
)}
{fetchStatus === 'failed' && (
<div className={styles.aboutErrorText}>
<WarningIcon primaryColor="red" size="large" />
<h5>Unable to load version data at this moment</h5>
</div>
)}
{fetchStatus === 'loaded' && (
<dl className={styles.aboutList}>
<dt>User Interface Version</dt>
<dd>{`${version} - ${commit}`}</dd>
{data.map(d => (
<React.Fragment key={uid(d)}>
<dt>{d.name}</dt>
<dd>{makeVersionString(d.v, d.hash)}</dd>
</React.Fragment>
))}
</dl>
)}
</Modal>
)}
</ModalTransition>
);
}

About.propTypes = {
data: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string.isRequired,
v: PropTypes.string.isRequired,
hash: PropTypes.string.isRequired,
version: PropTypes.string.isRequired,
})
).isRequired,
fetchStatus: PropTypes.oneOf(['idle', 'loading', 'loaded', 'failed']),
open: PropTypes.bool.isRequired,
onToggle: PropTypes.func.isRequired,
};

export default About;
Loading