Skip to content

Commit

Permalink
feat(demo-website): add simple page showing projects - EUBFR-46 (#26)
Browse files Browse the repository at this point in the history
* feat(form-upload): bootstrap package

* feat(form-upload): update yarn.lock

* feat(form-upload): linter rules

* feat(form-upload): save work

* rename to demo

* one level up

* public folder is required

* feat(form-upload): correct lifecycles

* simplify

* Placing cors back as the function assumes specific structure

* share latest, it is for demo purposes only

* step back

* preparing the signature before the request to get signed url

* feat(demo-server): add endpoint to retrieve signed upload url - EUBFR-43 (#23)

* feat(ingestion-manager): dynamically call producer's SNS topic - EUBFR-45 (#22)

* feat(demo-server): add endpoint to retrieve signed upload url - EUBFR-43

* Add doc

* integrate demo server

* removing the tricky quotes

* Save latest

* First successful upload

* Add meta index endpoint

* Add app deployment task

* split demo services

* Add "download" endpoint

* save

* Remove debug

* Bucket should enable cors for the put of the uploader

* remove unnecessary lines

* Integrate "existing files" dashboard

* Skip linting issues

* Update dependencies

* Pass the original filename as producer_key

* Add return

* Code refactoring

* Unify

* Quick fix demo server

* feat(demo-website): add simple page showing projects - EUBFR-46 (#25)

* feat(demo-website): add simple page showing projects - EUBFR-46

* Use <details> instead

* Export stack info on deploy and consume it

* mkdir -p before ln

* Automatically deploy demo website

* Update bucket name
  • Loading branch information
yhuard authored Oct 17, 2017
1 parent 7e6a45c commit 3547b6f
Show file tree
Hide file tree
Showing 41 changed files with 1,051 additions and 7 deletions.
11 changes: 11 additions & 0 deletions demo/budg/dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# testing
/coverage

# imported files
/src/meta

# production
/build
/client/dist
3 changes: 3 additions & 0 deletions demo/budg/dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Form Upload

Helper form to upload files for ingestion.
25 changes: 25 additions & 0 deletions demo/budg/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@eubfr/demo-budg-dashboard",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "16.0.0",
"react-dom": "16.0.0",
"react-s3-uploader": "4.5.0",
"react-scripts": "1.0.14"
},
"scripts": {
"start": "npm run prepare && react-scripts start",
"build": "npm run prepare && react-scripts build && mv build client/dist",
"deploy": "sls client deploy",
"prepare":
"mkdir -p ./src/meta && ln -f ../server/.serverless/stack-output.json ./src/meta/server.json",
"release": "npm run build && npm run deploy",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"serverless": "1.23.0",
"serverless-finch": "1.1.1"
}
}
Binary file added demo/budg/dashboard/public/favicon.ico
Binary file not shown.
40 changes: 40 additions & 0 deletions demo/budg/dashboard/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
-
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>EUBFR App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
-
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
-
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
15 changes: 15 additions & 0 deletions demo/budg/dashboard/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "EUBFR App",
"name": "EUBFR App",
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
20 changes: 20 additions & 0 deletions demo/budg/dashboard/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
service: demo-budg-dashboard

plugins:
- serverless-finch

custom:
client:
bucketName: eubfr-${self:provider.stage}-demo-budg-dashboard
eubfrEnvironment: ${opt:eubfr_env, file(../../../config.json):eubfr_env, env:EUBFR_ENV, 'dev'}
SIGNED_UPLOADS_API_ID: ${opt:SIGNED_UPLOADS_API_ID, file(../../../config.json):demo.SIGNED_UPLOADS_API_ID, env:SIGNED_UPLOADS_API_ID, ''}

provider:
name: aws
runtime: nodejs6.10
stage: ${opt:stage, file(../../../config.json):stage, 'dev'}
region: ${opt:region, file(../../../config.json):region, 'eu-central-1'}
deploymentBucket:
name: eubfr-${self:custom.eubfrEnvironment}-deploy
stackTags:
ENV: ${self:custom.eubfrEnvironment}
22 changes: 22 additions & 0 deletions demo/budg/dashboard/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.App {
margin-top: 2em;
margin-left: auto;
margin-right: auto;
width: 500px;
}

.app-status {
margin-bottom: 2em;
}

.progress {
color: orange;
}

.error {
color: red;
}

.success {
color: green;
}
17 changes: 17 additions & 0 deletions demo/budg/dashboard/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import FormUpload from '../src/components/FormUpload';
import FilesList from './components/FilesList';

import './App.css';

const App = () => (
<div className="App">
<h1>BUDG dashboard</h1>
<h2>Upload a new file</h2>
<FormUpload />
<h2>Existing files</h2>
<FilesList />
</div>
);

export default App;
8 changes: 8 additions & 0 deletions demo/budg/dashboard/src/App.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
117 changes: 117 additions & 0 deletions demo/budg/dashboard/src/components/FilesList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React, { Component } from 'react';
import config from '../meta/server.json'; // eslint-disable-line import/no-unresolved

import handleErrors from '../lib/handleErrors';

const demoServer = `${config.ServiceEndpoint}/demo`;

class FilesList extends Component {
constructor() {
super();

this.state = {
loading: true,
files: [],
links: {},
};

this.generateLink = this.generateLink.bind(this);
this.loadFiles = this.loadFiles.bind(this);
}

componentDidMount() {
this.loadFiles();
}

loadFiles() {
this.setState({
loading: true,
});

window
.fetch(`${demoServer}/meta`)
.then(handleErrors)
.then(response => response.json())
.then(data =>
this.setState({
loading: false,
files: data,
})
)
.catch(error => {
console.log(`An error happened: ${error.message}`);
});
}

generateLink(key) {
return () => {
window
.fetch(`${demoServer}/download?key=${encodeURIComponent(key)}`)
.then(handleErrors)
.then(response => response.json())
.then(data =>
this.setState(state => ({
links: Object.assign(state.links, {
[key]: data.signedUrl,
}),
}))
)
.catch(error => {
console.log(`An error happened: ${error.message}`);
});
};
}

render() {
const { loading, files, links } = this.state;

if (loading) {
return <p>Loading...</p>;
}

if (files.length === 0) {
return (
<div>
<button onClick={this.loadFiles}>Refresh</button>
<p>No file found</p>
</div>
);
}

return (
<div>
<button onClick={this.loadFiles}>Refresh</button>
<table>
<thead>
<tr>
<th>Original name</th>
<th>Computed key</th>
<th>Content length</th>
<th />
</tr>
</thead>
<tbody>
{files.map(file => (
<tr key={file.computed_key}>
<td>{file.original_key || 'unknown'}</td>
<td>{file.computed_key}</td>
<td>{Math.floor(file.content_length / 1024)} kB</td>
<td>
{links[file.computed_key] ? (
<a href={links[file.computed_key]}>Download</a>
) : (
<button onClick={this.generateLink(file.computed_key)}>
Get download link
</button>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}

export default FilesList;
83 changes: 83 additions & 0 deletions demo/budg/dashboard/src/components/FormUpload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { Component } from 'react';
import Uploader from 'react-s3-uploader';
import config from '../meta/server.json'; // eslint-disable-line import/no-unresolved

import handleErrors from '../lib/handleErrors';

const demoSignedUrl = `${config.ServiceEndpoint}/demo/signed_url`;

class FormUpload extends Component {
constructor(props) {
super(props);

this.state = {
message: ``,
progress: 'clean',
};

this.getSignedUrl = this.getSignedUrl.bind(this);
this.onUploadProgress = this.onUploadProgress.bind(this);
this.onUploadError = this.onUploadError.bind(this);
this.onUploadFinish = this.onUploadFinish.bind(this);
}

/* eslint class-methods-use-this: "off" */
getSignedUrl(file, callback) {
window
.fetch(`${demoSignedUrl}?key=${encodeURIComponent(file.name)}`)
.then(handleErrors)
.then(data => data.json())
.then(j => {
const url = j.signedUrl;
// Remove the additional double quote from start and end.
// It messes with the way createCORSRequest() works internally for ReactS3Uploader
return {
signedUrl: url.replace(/['"]+/g, ''),
};
})
.then(callback)
.catch(callback);
}

onUploadProgress(percent, status) {
this.setState({
message: `${status}: ${percent}`,
progress: 'progress',
});
}

onUploadError(status) {
this.setState({
message: status,
progress: 'error',
});
}

onUploadFinish() {
this.setState({
message: `Done!`,
progress: 'success',
});
}

render() {
return (
<div className="App">
<p>Disclaimer</p>
<div className={`${`app-status `}${this.state.progress}`}>
{this.state.message}
</div>
<Uploader
getSignedUrl={this.getSignedUrl}
onProgress={this.onUploadProgress}
onError={this.onUploadError}
onFinish={this.onUploadFinish}
signingUrlHeaders={{}}
contentDisposition="auto"
/>
</div>
);
}
}

export default FormUpload;
5 changes: 5 additions & 0 deletions demo/budg/dashboard/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
6 changes: 6 additions & 0 deletions demo/budg/dashboard/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
6 changes: 6 additions & 0 deletions demo/budg/dashboard/src/lib/handleErrors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default response => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
};
Loading

0 comments on commit 3547b6f

Please sign in to comment.