Permalink
Browse files

Merge pull request #2 from kata-team/feature/cloud

Title and logo are now customizable based on Settings page
  • Loading branch information...
marcomontalbano committed Jan 19, 2019
2 parents 4f3380d + 617d041 commit 984872b0758e1e40273d9d5a1d1f29c8de1bf04f
@@ -18,6 +18,7 @@ This project is freely based on technology-radar by [ThoughtWorks](https://www.t
- Hosted privately by [Heroku](https://www.heroku.com/)
- Automatic deploy with `git push origin production`
- Google Spreadsheets as database
- Cloud version - no setup required


## Live demo
@@ -67,11 +68,11 @@ npm start

## Google Spreadsheets integration

Technology Radar provides a Google Spreadsheets integration, so you can use spreadsheets to storage your data.
Technology Radar provides a Google Spreadsheets integration, so you can use spreadsheets as database to storage your data.

Here you can find the example used for our [live demo](#live-demo). Feel free to duplicate the document and make your own.

[https://docs.google.com/spreadsheets/d/112MlfyXSlIQ8nae85Te_xWDBP136GRaYeHlDdKgYyPo](https://docs.google.com/spreadsheets/d/112MlfyXSlIQ8nae85Te_xWDBP136GRaYeHlDdKgYyPo)
https://docs.google.com/spreadsheets/d/112MlfyXSlIQ8nae85Te_xWDBP136GRaYeHlDdKgYyPo

#### Create your own

@@ -84,6 +85,15 @@ Here you can find the example used for our [live demo](#live-demo). Feel free to
1. Save the file e compile the project with `npm run build`.


## Cloud

Now that you have a "database", the easiest and fastest way to create your own Technology Radar is to use the cloud based version.

`https://kata-team.github.io/technology-radar/?id=`**_`SPREADSHEET_ID`_**

https://kata-team.github.io/technology-radar/?id=112MlfyXSlIQ8nae85Te_xWDBP136GRaYeHlDdKgYyPo


## GitHub Pages

The project is a set of html, css and javascript so it can be executed using [GitHub Pages](https://pages.github.com/).
@@ -195,8 +205,8 @@ If you want a **protected** Technology Radar, you can use Heroku. In this way yo

1. Navigate to the [GitHub app registration page](https://github.com/settings/applications/new).
1. Give your app a name, a description and a logo.
1. Tell GitHub the URL you want the app to eventually live at. Use the name you decided previously. If using a free Heroku account, this will be something like: [https://technology-radar.herokuapp.com]()
1. Specify the callback URL; should be like this: [https://technology-radar.herokuapp.com/auth/github/callback](); note that this is https, not http.
1. Tell GitHub the URL you want the app to eventually live at. Use the name you decided previously. If using a free Heroku account, this will be something like: https://technology-radar.herokuapp.com
1. Specify the callback URL; should be like this: https://technology-radar.herokuapp.com/auth/github/callback note that this is https, not http.


#### Step 3 - Setting up hosting with Heroku

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -1,6 +1,6 @@
{
"name": "technology-radar",
"version": "4.2.0",
"version": "5.0.0",
"description": "Technology Radar is a tool that helps organizations to monitor their own discoveries. Keep track of your technologies according to your previous successes and failures.",
"main": "index.js",
"homepage": ".",
@@ -52,15 +52,15 @@
"classnames": "^2.2.6",
"color": "~3.1.0",
"flux": "^3.1.3",
"js-cookie": "~2.2.0",
"lodash": "~4.17.11",
"prop-types": "^15.6.2",
"react": "~16.6.3",
"react-dom": "~16.6.3",
"react": "~16.7.0",
"react-dom": "~16.7.0",
"rest": "^2.0.0",
"uikit": "~3.0.0-rc.26"
"uikit": "~3.0.2"
},
"devDependencies": {
"dotenv": "~6.2.0",
"gh-pages": "^1.2.0",
"less": "~3.9.0",
"less-plugin-clean-css": "^1.5.1",
@@ -1,3 +1,5 @@
require('dotenv').config({ silent: true });

const ghpages = require('gh-pages');
const config = require('../package.json');
const domain = process.env.GH_TOKEN ? `${process.env.GH_TOKEN}@github.com` : 'github.com';
@@ -1,28 +1,31 @@
import _ from 'lodash';
import Cookie from 'js-cookie';

import ItemsLoader from './class/ItemsLoader';
import SearchActions from './actions/SearchActions';
import AppActions from './actions/AppActions';

import Item from './class/Item';
import Category from './class/Category';
import Comment from './class/Comment';
import Settings from './class/Settings';

class Api {
setup() {
this.spreadsheetId = Cookie.get('document_id') || process.env.REACT_APP_SPREADSHEET_ID;
setup(spreadsheetId) {
this.spreadsheetId = spreadsheetId || process.env.REACT_APP_SPREADSHEET_ID;
this.urls = {
// items: 'mock/items.json',
// categories: 'mock/categories.json',
// comments: 'mock/comments.json',
// settings: 'mock/settings.json',
items: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/1/public/values?alt=json-in-script&callback={1}`,
categories: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/2/public/values?alt=json-in-script&callback={1}`,
comments: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/3/public/values?alt=json-in-script&callback={1}`,
settings: `https://spreadsheets.google.com/feeds/list/${this.spreadsheetId}/4/public/values?alt=json-in-script&callback={1}`,
};
}

load() {
this.setup();
load(spreadsheetId) {
this.setup(spreadsheetId);

SearchActions.startSearching();

@@ -33,8 +36,11 @@ class Api {

Promise.all([
ItemsLoader.load(this.urls.categories, Category),
ItemsLoader.load(this.urls.comments, Comment)
]).then(([categories, comments]) => {
ItemsLoader.load(this.urls.comments, Comment),
ItemsLoader.load(this.urls.settings, Settings),
]).then(([categories, comments, settings]) => {

AppActions.updateSettings(settings[0]);

const filterByName = (list, name) => {
return _.filter(list, (o) => { return o.name === name });
@@ -0,0 +1,25 @@
import AppDispatcher from '../dispatcher/AppDispatcher';
import AppConstants from '../constants/AppConstants';
import Api from '../Api';

export default {
load(spreadsheetId) {
Api.load(spreadsheetId);
},
updateSettings(settings) {
AppDispatcher.dispatch({
type: AppConstants.UPDATE_SETTINGS,
value: settings
});
},
selectGrid() {
AppDispatcher.dispatch({
type: AppConstants.VIEW_GRID,
});
},
selectList() {
AppDispatcher.dispatch({
type: AppConstants.VIEW_LIST,
});
},
};
@@ -1,11 +1,7 @@
import AppDispatcher from '../dispatcher/AppDispatcher';
import SearchConstants from '../constants/SearchConstants';
import Api from '../Api';

export default {
load() {
Api.load();
},
startSearching() {
AppDispatcher.dispatch({
type: SearchConstants.START_SEARCHING,

This file was deleted.

Oops, something went wrong.
@@ -0,0 +1,7 @@
export default class Settings {
constructor({ name = '', version = '', logo = '' }) {
this.name = name;
this.version = version;
this.logo = logo;
}
}
@@ -1,41 +1,20 @@
import React, { Component } from 'react';
import Cookies from 'js-cookie';
import NavbarComponent from './NavbarComponent';
import NavbarContainer from './NavbarContainer';
import ResultContainer from './ResultContainer';
import SearchActions from '../actions/SearchActions';
import AppActions from '../actions/AppActions';

export default class AppComponent extends Component {

constructor(props) {
super(props);
this.state = {
document_id: Cookies.get('document_id')
}

this.onLogoutHandler = this.onLogoutHandler.bind(this);
}

componentDidMount() {
SearchActions.load();
}

onLogoutHandler() {
Cookies.remove('document_id');
SearchActions.load();

this.setState({
document_id: undefined
})
const url = (new URL(window.location.href));
AppActions.load(url.searchParams.get('id'));
}

render() {
return (
<div className="app">
<NavbarComponent />
<NavbarContainer />
<ResultContainer />
{this.state.document_id ? (
<div className="uk-container uk-margin-top uk-text-right"><button className="uk-button uk-button-link" onClick={this.onLogoutHandler}>logout</button></div>
) : ''}
</div>
);
}
@@ -78,7 +78,7 @@ export default class ItemComponent extends Component {
return (
<div className="uk-card uk-card-default uk-card-hover" onClick={this.onClickModal}>
<div className="uk-card-body">
<div className="uk-card-badge uk-label" style={this.labelStyle}>{this.props.item.status}</div>
{this.props.item.status ? (<div className="uk-card-badge uk-label" style={this.labelStyle}>{this.props.item.status}</div>) : ''}
<h3 className="uk-card-title">{this.props.item.name}</h3>
<p className="uk-card-description">{this.props.item.description}</p>
</div>
@@ -100,7 +100,7 @@ export default class ItemComponent extends Component {
<h3 className="uk-modal-title">{this.props.item.name}</h3>
</div>
<div className="uk-modal-body">
<div className="uk-modal-badge uk-label" style={this.labelStyle}>{this.props.item.status}</div>
{this.props.item.status ? (<div className="uk-modal-badge uk-label" style={this.labelStyle}>{this.props.item.status}</div>) : ''}
<p className="uk-modal-description">{this.props.item.description}</p>
<a target="_blank" rel="noopener noreferrer" {...this.props.item.url ? { href: this.props.item.url } : {}}><i className="fa fa-globe"></i>website</a>
</div>
@@ -8,9 +8,9 @@ export default class NavbarComponent extends Component {
return (
<nav className="uk-navbar-container uk-navbar-fixed uk-navbar-brand">
<div className="uk-container">
<a href="/">
<img alt="Technology Radar logo" src="images/logo.png" />
<h1>Technology Radar</h1>
<a href="./">
<img alt="Technology Radar logo" src={this.props.appStore.settings.logo} />
<h1>{this.props.appStore.settings.name}</h1>
</a>
<div className="uk-search uk-width-1-4@s uk-align-right">
<SearchComponent />
Oops, something went wrong.

0 comments on commit 984872b

Please sign in to comment.