Commit d0f83aa1 authored by Andreas Åkre Solberg's avatar Andreas Åkre Solberg

Initial commit

parents
{
"presets": ["es2015","react", "stage-2"]
}
node_modules
package-lock.json
[*.{js,jsx}]
indent_style = space
indent_size = 2
API_URL="https://appstore.dataporten-api.no/v1"
REDIRECT_URL="https://appstore-ui.appstore-dep.ioudaas.no/"
CLIENT_ID="6716f943-72a2-4c3c-8b25-64947c1d33c7"
\ No newline at end of file
**/public/**
**/node_modules/**
**/webpack.config*.js
{
"extends": "react-app",
"parser": "babel-eslint"
}
node_modules
npm-debug.log
dataporten-resources
public
.env
language: node_js
node_js:
- "node"
services:
- docker
cache:
directories:
- "node_modules"
before_install:
- npm install
- $TRAVIS_BUILD_DIR/install-fonts.sh
deploy:
- provider: script
script: $TRAVIS_BUILD_DIR/deploy.sh latest
skip_cleanup: true
on:
branch: master
\ No newline at end of file
FROM node:6.11.1-alpine
RUN apk add --update --no-cache curl
RUN mkdir -p /usr/src/frontend
WORKDIR /usr/src/frontend
COPY package.json /usr/src/frontend/
RUN npm install
COPY . /usr/src/frontend
COPY .env.example .env
RUN ./install-fonts.sh
RUN npm run build:prod
EXPOSE 3000
CMD ["node", "server.js", "--use_strict"]
# OAuth Play
```
./install-fonts.sh
npm i
npm start
```
#!/bin/bash
set -euo pipefail
TAG=$1
QUAY_REPO=quay.io/uninett/k8s-appstore-frontend
docker build -t $QUAY_REPO:$TAG .
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" quay.io
docker push $QUAY_REPO:$TAG
#!/bin/sh
npm install bootstrap --save
npm install uninett-bootstrap-theme --save
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxBold.woff http://mal.uninett.no/uninett-theme/fonts/colfaxBold.woff
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxLight.woff http://mal.uninett.no/uninett-theme/fonts/colfaxLight.woff
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxMedium.woff http://mal.uninett.no/uninett-theme/fonts/colfaxMedium.woff
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegular.woff http://mal.uninett.no/uninett-theme/fonts/colfaxRegular.woff
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxThin.woff http://mal.uninett.no/uninett-theme/fonts/colfaxThin.woff
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegularItalic.woff http://mal.uninett.no/uninett-theme/fonts/colfaxRegularItalic.woff
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxBold.svg http://mal.uninett.no/uninett-theme/fonts/colfaxBold.svg
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxLight.svg http://mal.uninett.no/uninett-theme/fonts/colfaxLight.svg
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxMedium.svg http://mal.uninett.no/uninett-theme/fonts/colfaxMedium.svg
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegular.svg http://mal.uninett.no/uninett-theme/fonts/colfaxRegular.svg
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxThin.svg http://mal.uninett.no/uninett-theme/fonts/colfaxThin.svg
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegularItalic.svg http://mal.uninett.no/uninett-theme/fonts/colfaxRegularItalic.svg
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxBold.ttf http://mal.uninett.no/uninett-theme/fonts/colfaxBold.ttf
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxLight.ttf http://mal.uninett.no/uninett-theme/fonts/colfaxLight.ttf
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxMedium.ttf http://mal.uninett.no/uninett-theme/fonts/colfaxMedium.ttf
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegular.ttf http://mal.uninett.no/uninett-theme/fonts/colfaxRegular.ttf
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxThin.ttf http://mal.uninett.no/uninett-theme/fonts/colfaxThin.ttf
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegularItalic.ttf http://mal.uninett.no/uninett-theme/fonts/colfaxRegularItalic.ttf
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxBold.eot http://mal.uninett.no/uninett-theme/fonts/colfaxBold.eot
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxLight.eot http://mal.uninett.no/uninett-theme/fonts/colfaxLight.eot
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxMedium.eot http://mal.uninett.no/uninett-theme/fonts/colfaxMedium.eot
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegular.eot http://mal.uninett.no/uninett-theme/fonts/colfaxRegular.eot
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxThin.eot http://mal.uninett.no/uninett-theme/fonts/colfaxThin.eot
curl -o node_modules/uninett-bootstrap-theme/fonts/colfaxRegularItalic.eot http://mal.uninett.no/uninett-theme/fonts/colfaxRegularItalic.eot
This diff is collapsed.
{
"name": "oauth-play",
"description": "OAuth Play",
"version": "0.1.0",
"main": "",
"scripts": {
"start": "webpack-dev-server --content-base public --config ./webpack.dev.config.js --host 0.0.0.0 ",
"build": "webpack --display-error-details -d",
"build:prod": "webpack -p --config ./webpack.prod.config.js"
},
"author": "Andreas Åkre Solberg <andreas.solberg@uninett.no>",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.7.2",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.23.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.30.1",
"style-loader": "^0.13.0",
"url-loader": "^0.5.9",
"webpack": "^3.5.0",
"webpack-dev-server": "^2.7.1"
},
"dependencies": {
"axios": "^0.16.2",
"babel-polyfill": "^6.23.0",
"bootstrap": "^3.3.7",
"dotenv": "^4.0.0",
"express": "^4.15.4",
"extract-text-webpack-plugin": "^3.0.0",
"history": "^4.6.3",
"lodash": "^4.17.4",
"moment": "^2.18.1",
"react": "^15.6.1",
"react-bootstrap": "^0.31.2",
"react-dom": "^15.6.1",
"react-fontawesome": "^1.6.1",
"react-redux": "^5.0.5",
"react-remarkable": "^1.1.1",
"redux": "^3.7.1",
"redux-actions": "^2.2.1",
"redux-first-router": "^1.7.4",
"redux-first-router-link": "^1.0.7",
"redux-promise": "^0.5.3",
"redux-thunk": "^2.2.0",
"uninett-bootstrap-theme": "^1.0.1"
}
}
"use strict"
var express = require('express');
var app = express();
var path = require('path');
app.use(function(req, res, next) {
console.log(req.method + ' ' + req.url + ' status: ' + res.statusCode);
res.setHeader('Strict-Transport-Security', 'max-age=15768000');
next();
});
var staticDir = path.resolve(__dirname, 'public');
console.log("serving files from %s", staticDir);
app.use("/public", express.static(staticDir, {
maxAge: '2 days'
}));
// Always send the same file, so that our router can handle the routing.
app.get('*', function (req, res) {
res.sendFile(path.join(staticDir, 'index.html'));
});
var port = process.env.VCAP_APP_PORT || 3000;
var server = app.listen(port, function() {
console.log('Running app at http://%s:%s', "127.0.0.1", port);
});
import { createAction, createActions, handleActions, combineActions } from 'redux-actions'
import promiseMiddleware from 'redux-promise';
export const setHostname = createAction('setHostname')
import React from 'react'
const uninettLogo = require('../../node_modules/uninett-bootstrap-theme/images/Uninett_pil_rod.svg')
const stylex = {
"paddingBottom:": "-6px"
}
const Footer = () => (
<div className="container">
<div className="row">
<div className="col-lg-12">
<div className="footer-uninett">
<div className="footer-content-uninett">
<div className="footer-logo" >
<img src={uninettLogo} alt="Uninett logo" type="image/svg+xml" style={stylex} />
</div>
<div className="footer-uninett-department">UNINETT AS 2017</div>
</div>
<div className="clearfix"></div>
</div>
</div>
</div>
</div>
)
export default Footer
import React from 'react'
import {Navbar, Nav, NavItem} from 'react-bootstrap';
import Link from 'redux-first-router-link';
import BreadCrumb from './BreadCrumb'
import LoginController from '../containers/LoginController';
const uninettLogo = require('../../node_modules/uninett-bootstrap-theme/images/UNINETT_logo.svg')
var FontAwesome = require('react-fontawesome')
const navStyle = {
marginTop: "17px"
}
const checkActive = (currentLocation, check) => {
if (currentLocation === check ) {
return "active"
}
return ""
}
const Header = ({locationType, locationPayload}) => (
<Navbar >
<Navbar.Header>
<Navbar.Brand>
<Link to="/"><img alt="UNINETT Logo" src={uninettLogo} /></Link>
</Navbar.Brand>
</Navbar.Header>
<ul style={navStyle} className="nav nav-pills">
<li>OAuth Play <FontAwesome name='play-circle-o' /></li>
</ul>
</Navbar>
)
export default Header
import React from 'react'
import {Navbar, Nav, NavItem, NavDropdown, MenuItem, Glyphicon, Jumbotron, Button} from 'react-bootstrap'
import {Row, Col, Collapse, FormControl, FormGroup, ControlLabel, HelpBlock} from 'react-bootstrap'
import FontAwesome from 'react-fontawesome'
const foo = () => {
console.log("AYA")
}
const defaultHost = "https://auth.dataporten.no/"
const Component = ({text="Loading..."}) => (
<div>
<FormGroup
className="gutter"
controlId="formBasicText"
>
<h4>OAuth Server hostname</h4>
<FormControl
type="text"
bsSize="large"
value={defaultHost}
placeholder="https://auth.yourplatform.org/"
/>
<HelpBlock>Fill out the hostname of your OAuth server. Will only work if your OAuth server support OAuth Discovery. If not, please enter configuration manually.</HelpBlock>
</FormGroup>
<div><Button onCLick={foo} bsStyle="primary"><Glyphicon glyph="book" /> Discovery OAuth Provider</Button></div>
</div>
)
export default Component
import React from 'react'
import FontAwesome from 'react-fontawesome'
const LoadingIndicator = ({text="Loading..."}) => (
<div><FontAwesome name='circle-o-notch' spin /> {text}</div>
)
export default LoadingIndicator
import React from 'react'
import {Navbar, Nav, NavItem, NavDropdown, MenuItem, Glyphicon, Jumbotron, Button} from 'react-bootstrap'
import {Row, Col, Collapse, FormControl, FormGroup, ControlLabel, HelpBlock} from 'react-bootstrap'
import Link from 'redux-first-router-link';
import HostnameInput from './HostnameInput'
const MainContent = () => (
<div>
<div className="container">
<Jumbotron className="uninett-color-lightBlue">
<h1>Play with OAuth 2.0</h1>
<p>Learn more about how OAuth 2.0 works, and explore OAuth protected APIs without entering any code.</p>
<HostnameInput />
<p>Navigate the library of prepared applications, deploy and start using it within few minutes. This application platform is fully automated.</p>
<p>
<Link to="/"><Button bsStyle="primary"><Glyphicon glyph="book" /> Library</Button></Link>&nbsp;
<Link to="/applications"><Button bsStyle="success"><Glyphicon glyph="modal-window" /> My installed applications</Button></Link>
</p>
</Jumbotron>
</div>
</div>
)
export default MainContent
import React from 'react'
import {Row} from 'react-bootstrap'
const getClassNames = (gutter, padded) => {
var classNames = ["whitebox", "uninett-color-white"]
padded = padded === undefined ? true : padded
if (gutter) {
classNames.push("gutter")
}
if (padded) {
classNames.push("uninett-padded")
}
return classNames.join(" ")
}
const WhiteBox = ({gutter = true, padded = true, children, style}) => (
<Row style={style} className={getClassNames(gutter, padded)}>
{children}
</Row>
)
export default WhiteBox
import React from 'react'
import Footer from '../components/Footer'
import MainContent from '../components/MainContent'
import Header from '../components/Header'
import { connect } from 'react-redux'
const mainContent = {
HOME: <MainContent />,
}
const App = ({locationType, locationPayload}) => (
<div>
<Header locationType={locationType} locationPayload={locationPayload} />
{ mainContent[locationType] }
<Footer />
</div>
)
const mapStateToProps = (state) => ({
locationType: state.location.type,
locationPayload: state.location.payload
})
const mapDispatchToProps = {
}
const Controller = connect(
mapStateToProps,
mapDispatchToProps
)(App)
export default Controller
import { connect } from 'react-redux'
import HostnameInput from '../components/HostnameInput'
import { setHostname } from '../actions/'
const mapStateToProps = (state, ownProps) => (state)
const mapDispatchToProps = {
setHostname
}
const Controller = connect(
mapStateToProps,
mapDispatchToProps
)(HostnameInput)
export default Controller
.breadcrumb {
opacity: 0.9;
font-family: 'colfaxRegular', Arial, sans-serif;
font-size: 90%;
background-color: inherit;
}
.no-margins {
margin: 0px ! important;
padding: 0px ! important;
}
.clearfix {
clear: both
}
.advancedOptions {
border-left: 7px solid #AFEEEE ;
margin-top: 5px; margin-bottom: 5px;
}
.packageListItem {
cursor: pointer;
}
.packageListItem:hover {
box-shadow: 0px 0px 25px #000000;
z-index: 2;
-webkit-transition: all 80ms ease-in;
-webkit-transform: scale(1.05);
-ms-transition: all 80ms ease-in;
-ms-transform: scale(1.05);
-moz-transition: all 80ms ease-in;
-moz-transform: scale(1.05);
transition: all 80ms ease-in;
transform: scale(1.05);
}
import 'babel-polyfill'
import React from 'react'
import ReactDOM from 'react-dom'
import { combineReducers, createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import thunkMiddleware from 'redux-thunk'
import { connectRoutes } from 'redux-first-router'
import createHistory from 'history/createBrowserHistory'
import reducers from './reducers/'
import App from './containers/App'
import logger from './middleware/logger'
import { routesMap, options } from './routesMap'
// import { appJso, getUserInfo } from './actions/auth'
import '../node_modules/bootstrap/dist/css/bootstrap.min.css'
import '../node_modules/uninett-bootstrap-theme/css/uninett.css'
import './css/style.css'
// import {packageInstallStart, packageInstallFailed} from './actions/packages'
const history = createHistory()
const routerSetup = connectRoutes(history, routesMap, options)
let store = createStore(
combineReducers({
...reducers,
location: routerSetup.reducer
}),
compose(
routerSetup.enhancer,
applyMiddleware(
routerSetup.middleware,
thunkMiddleware,
logger
)
)
)
// const state = store.getState()
// if (!state.auth.user.token) {
// const token = appJso.checkToken()
// if (token) {
// store.dispatch({
// type: "AUTH_FROM_CACHE",
// payload: {
// "user" : {
// "token": token
// }
// }
// })
// getUserInfo(store.dispatch, token)
// }
// }
// store.dispatch({"type":"PACKAGE_INSTALL_START","payload":"bfcb2921-7a97-4180-b37b-d4607e7126bf"})
// setTimeout(() => {
// store.dispatch(packageInstallFailed('bfcb2921-7a97-4180-b37b-d4607e7126bf', 'It just failed!'))
// }, 2000)
ReactDOM.render((
<Provider store={store}>
<App />
</Provider>
),
document.getElementById('app')
)
<body>
<script src="https://use.fontawesome.com/24707de690.js"></script>
<div id="app"></div>
</body>
export default store => next => action => {
// console.log('---> dispatching', action)
let result = next(action)
console.log("---> action:", action, "result of action:", store.getState())
// console.log("ACTION: " + JSON.stringify(action))
}
import auth from './auth'
import packages from './packages'
import applications from './applications'
import installation from './installation'
import namespaces from './namespaces'
export default {
auth,
applications,
packages,
installation,
namespaces
}
import { getAllPackages, getPackage } from './actions/packages'
import { prepareApplication, getAllApplications } from './actions/applications'
import { login, isAuthenticated, loginAndRedirect } from './actions/auth'
const routesMap = {
HOME: '/',
// LOGIN: { path: '/login', thunk: login() },
// PACKAGES: { path: '/', thunk: getAllPackages() },
// PACKAGE: { path: '/packages/:repo/:packageName/:version', thunk: getPackage() },
// APPLICATIONS: { path: '/applications', thunk: getAllApplications(), requiresAuth: true },
// APPLICATION: { path: '/applications/:id', thunk: prepareApplication(), requiresAuth: true },
// INSTALLATION: { path: '/installation', requiresAuth: true },
}
const options = {
onBeforeChange: (dispatch, getState, action) => {
if (!routesMap.hasOwnProperty(action.type)) {
throw new Error("Cannot find routesMap for action type ", action.type)
}
const requiresAuth = routesMap[action.type].requiresAuth
window.scrollTo(0, 0)
if (requiresAuth) {
if (!isAuthenticated(getState())) {
dispatch(loginAndRedirect(action))
}
}
}
}
export { routesMap, options }
import React from 'react'
import {Label} from 'react-bootstrap'
import { RELEASE_STATUS_CODES, RELEASE_STATUS_TEXT } from '../actions/applications.js'
import moment from 'moment'
import 'moment/locale/nb';
// import 'moment/locale/en';
moment.locale("no");
export function createStatusLabel(statusCode) {
let statusType = undefined
switch(statusCode) {
case (RELEASE_STATUS_CODES.FAILED):
statusType = "danger"
break
case (RELEASE_STATUS_CODES.DEPLOYED):
statusType = "success"
break
case (RELEASE_STATUS_CODES.DELETING):
statusType = "warning"
break
case (RELEASE_STATUS_CODES.DELETED):
statusType = "info"
break
default:
statusType = "default"
break
}
return <Label bsStyle={statusType}>{RELEASE_STATUS_TEXT[statusCode]}</Label>
}
export function secondsToDate(dt) {
var seconds = Math.floor(new Date() / 1000);
const x = moment.unix(dt.seconds)
if (seconds - dt.seconds < 3600*24*3) {
return x.fromNow()
}
return x.format('lll')
}
import union from 'lodash/union'
export function authenticatedFetch(url, token) {
let config = {"headers": {}}
config.headers.Authorization = 'Bearer ' + token.access_token
config.headers["original-token"] = token.access_token
config.method = "GET"
config.mode = "cors"
// console.log(config)
return fetch(url, config).then((response) => {
if (response.ok) {
return response.json()
} else {
throw Error(response.statusText)
}
})
}
export function authenticatedPost(url, token, data) {
let config = {"headers": {}}
config.headers.Authorization = 'Bearer ' + token.access_token
config.headers['Accept'] = 'application/json'
config.headers['Content-Type'] = 'application/json'
config.method = "POST"
config.mode = "cors"
config.body = JSON.stringify(data)
return fetch(url, config)
}
export function authenticatedCustom(method, url, token, data) {
let config = {"headers": {}}
config.headers.Authorization = 'Bearer ' + token.access_token
config.headers['Accept'] = 'application/json'
config.headers['Content-Type'] = 'application/json'
config.method = method
config.mode = "cors"
if (data) {
config.body = JSON.stringify(data)
}
return fetch(url, config)
}
function getType(value) {
if (value instanceof Array) {
return "array"
}
if (typeof value === 'object') {
return "object"
}
return typeof value
}
export function processValues(defaults, uservalues) {
let result = {}
let keys = []
if (defaults) {
keys = union(keys, Object.keys(defaults))
}
if (uservalues) {
keys = union(keys, Object.keys(uservalues))
}
keys.forEach((key) => {
let item = {
type: null
}
console.log("Processing key", key)
if (defaults && defaults.hasOwnProperty(key)) {
item.type = getType(defaults[key])