├── .gitignore ├── README.md ├── assets └── intro.gif ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json └── src ├── actions └── fetchDataAction.js ├── components ├── Analysis.js ├── App.js ├── Filter.js ├── Home.js ├── Results.js └── WordCloudRender.js ├── css ├── App.css ├── Home.css ├── Results.css ├── Search.css ├── WordCloudRender.css └── index.css ├── index.js ├── reducers ├── fetchProjNamesReducer.js ├── fetchProjVarReducer.js ├── index.js └── wordCloudReducer.js └── store.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Javascript Popular Variable Frontend 2 | Ever had trouble naming your variable or function names? Wonder how the greatest repository did their naming? Well I made this website so you can search and reference how the most popular Javascript repository's varaible and function names. 3 | The website is deployed [here](https://billcccheng.github.io/js-popular-variable-frontend/). 4 | 5 | ## Demo 6 | 7 |

8 | 9 |

10 | 11 | ## Installation 12 | First clone the repository. 13 | ``` 14 | git clone https://github.com/billcccheng/js-popular-variable-frontend.git 15 | ``` 16 | 17 | Then `npm install` to install all the required packages. After you have 18 | all the packages installed, you can `npm run start` to play around with you app on `port 8000`. 19 | 20 | ``` 21 | npm install 22 | npm run start 23 | ``` 24 | If you want to change your port to 8080, just go to `package.json` and change `"start":...` to 25 | 26 | ``` 27 | "start": "PORT=8000 react-scripts start" 28 | ``` 29 | 30 | ## The Backend Server 31 | * All the logic and searching of the app is loaded on a heroku server. All the source code of the heroku server can be 32 | found [here](https://github.com/billcccheng/js-popular-variable-server) 33 | * Remember to comment out this [line](https://github.com/billcccheng/js-popular-variable-frontend/blob/master/src/actions/fetchDataAction.js#L5) if you want to test the server on your localhost or comment out this [line](https://github.com/billcccheng/js-popular-variable-frontend/blob/master/src/actions/fetchDataAction.js#L4) if you want to use the heroku server. 34 | 35 | ## Change Logs 36 | * 02.03.2018 System is live and up. Alpha Version RUNNING!!!! 37 | 38 | ## Future Update 39 | * Analysis 40 | 41 | ## Contributing 42 | 1. Fork it! 43 | 2. Create your feature branch: `git checkout -b my-new-feature` 44 | 3. Commit your changes: `git commit -am 'Add some feature'` 45 | 4. Push to the branch: `git push origin my-new-feature` 46 | 5. Submit a pull request :smile: 47 | 6. All contributions are **welcomed** :blush:! 48 | 49 | ## Credits 50 | Thanks to 51 | * [bentatum](https://github.com/bentatum/better-react-spinkit) for the wonderful loading icons. 52 | * [Yoctol](https://github.com/Yoctol/react-d3-cloud) for the beautiful word cloud library. 53 | * [JedWatson](https://github.com/JedWatson/react-select) for react dropdown/select library. 54 | 55 | ## License 56 | [MIT license](http://opensource.org/licenses/MIT). 57 | 58 | © 2018 Bill Cheng 59 | -------------------------------------------------------------------------------- /assets/intro.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billcccheng/js-popular-variable-frontend/f803b50194fd480af1489aa7d0ca20e08183f4cb/assets/intro.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-popular-variable-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "./", 6 | "devDependencies": { 7 | "gh-pages": "^1.1.0", 8 | "react-scripts": "1.1.0", 9 | "redux-logger": "^3.0.6" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.17.1", 13 | "better-react-spinkit": "^2.0.4", 14 | "d3-cloud": "^1.2.4", 15 | "d3v3": "^1.0.3", 16 | "material-ui": "^1.0.0-beta.30", 17 | "react": "^16.2.0", 18 | "react-d3-cloud": "^0.5.0", 19 | "react-dom": "^16.2.0", 20 | "react-mdl": "^1.11.0", 21 | "react-redux": "^5.0.6", 22 | "react-router-dom": "^4.2.2", 23 | "react-select": "^1.2.1", 24 | "react-spinkit": "^3.0.0", 25 | "react-tagcloud": "^1.2.0", 26 | "redux": "^3.7.2", 27 | "redux-promise-middleware": "^5.0.0", 28 | "redux-thunk": "^2.2.0", 29 | "thunk": "0.0.1" 30 | }, 31 | "scripts": { 32 | "start": "PORT=8000 react-scripts start --host=0.0.0.0", 33 | "build": "react-scripts build", 34 | "deploy": "react-scripts build && gh-pages -d build", 35 | "test": "react-scripts test --env=jsdom", 36 | "eject": "react-scripts eject" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billcccheng/js-popular-variable-frontend/f803b50194fd480af1489aa7d0ca20e08183f4cb/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | JavaScript Naming 20 | 21 | 22 | Fork me on GitHub 23 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/actions/fetchDataAction.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | /*LOCAL TESTING USE*/ 4 | //const hostName = "http://localhost:5000/api"; 5 | const hostName = "https://js-popular-variable-server.herokuapp.com/api" 6 | 7 | export function fetchProjectNames() { 8 | return (dispatch) => { 9 | const url = `${hostName}/getProjectNames`; 10 | dispatch({type: "FETCH_PROJECT_NAMES", payload: axios.get(url)}); 11 | } 12 | } 13 | 14 | export function fetchWCProjectNames() { 15 | return (dispatch) => { 16 | const url = `${hostName}/fetchWordCloudProjectNames`; 17 | dispatch({type: "FETCH_WC_PROJECT_NAMES", payload: axios.get(url)}); 18 | } 19 | } 20 | 21 | export function fetchProjectVariables(selectedProjects, filters, unFetchedProjects=[]) { 22 | return (dispatch, getState) => { 23 | const thisState = getState().fetchProjVarReducer; 24 | const url = `${hostName}/getProjectVariables`; 25 | dispatch({type: "FETCH_PROJECT_VARIABLES_PENDING"}); 26 | 27 | if(unFetchedProjects.length === 0) { 28 | const filteredResults = filterResults(thisState.results, selectedProjects, filters); 29 | dispatch({ 30 | type: "FETCH_PROJECT_VARIABLES_FULFILLED", 31 | filtered: filteredResults, 32 | results: thisState.results 33 | }); 34 | } else { 35 | axios.post(url,{ 36 | selectedProjects: unFetchedProjects 37 | }).then((res) => { 38 | const newResults = {...thisState.results, ...res.data} 39 | const filteredResults = filterResults(newResults, selectedProjects, filters); 40 | dispatch({ 41 | type: "FETCH_PROJECT_VARIABLES_FULFILLED", 42 | filtered: filteredResults, 43 | results: newResults 44 | }); 45 | }).catch((err) => { 46 | dispatch({type: "FETCH_PROJECT_VARIABLES_REJECTED"}); 47 | }); 48 | } 49 | } 50 | } 51 | 52 | export function simpleFilter(selectedProjects, filters) { 53 | return (dispatch, getState) => { 54 | const thisState = getState().fetchProjVarReducer; 55 | const results = thisState.results; 56 | const filteredResults = filterResults(results, selectedProjects, filters); 57 | dispatch({ 58 | type: "FETCH_PROJECT_VARIABLES_FULFILLED", 59 | filtered: filteredResults, 60 | results: results 61 | }); 62 | } 63 | } 64 | 65 | export function fetchWCSingleProjectVariables(selectedProject) { 66 | return (dispatch, getState) => { 67 | dispatch({type: "FETCH_WC_PROJECT_VARIABLES_PENDING"}); 68 | const thisState = getState().wordCloudReducer; 69 | const savedProject = Object.keys(thisState.wcSavedData); 70 | if(savedProject.indexOf(selectedProject) !== -1){ 71 | dispatch({ 72 | type: "FETCH_WC_PROJECT_VARIABLES_FULFILLED", 73 | savedResults: thisState.wcSavedData, 74 | resToBeShowed: thisState.wcSavedData[selectedProject] 75 | }); 76 | } else { 77 | const url = `${hostName}/getSingleProjectVariables/${selectedProject}`; 78 | axios.get(url).then((res) => { 79 | dispatch({ 80 | type: "FETCH_WC_PROJECT_VARIABLES_FULFILLED", 81 | savedResults: {...thisState.wcSavedData, ...{[selectedProject]: res.data}}, 82 | resToBeShowed: res.data 83 | }); 84 | }).catch((err) => { 85 | dispatch({ 86 | type: "FETCH_WC_PROJECT_VARIABLES_REJECTED", 87 | }); 88 | }); 89 | } 90 | } 91 | } 92 | 93 | export function clearShowResultsTree() { 94 | return (dispatch, getState) => { 95 | dispatch({ 96 | type: "CLEAR_FETCH_WC_PROJECT_VARIABLES_SHOW_RESULTS", 97 | }); 98 | } 99 | } 100 | 101 | export function wcSimpleFilter(selectedProject, filter) { 102 | return (dispatch, getState) => { 103 | dispatch({type: "FETCH_WC_PROJECT_VARIABLES_PENDING"}); 104 | const savedResults = getState().wordCloudReducer.wcSavedData; 105 | const lowerCaseFilter = filter.toLowerCase(); 106 | const updatedResults = savedResults[selectedProject].filter((itm) => { 107 | return itm.value.toLowerCase().includes(lowerCaseFilter); 108 | }); 109 | 110 | dispatch({ 111 | type: "FETCH_WC_PROJECT_VARIABLES_FULFILLED", 112 | resToBeShowed: updatedResults.length !== 0 ? updatedResults : [{ value: "NO RESULTS", count: 1000, url:'https://en.wikipedia.org/wiki/Null_result' }], 113 | savedResults: savedResults 114 | }); 115 | } 116 | } 117 | 118 | function filterResults(results, selectedProjects, filterInput) { 119 | const userInput = filterInput.toLowerCase(); 120 | let filteredResults = {}; 121 | selectedProjects.forEach(projectName => { 122 | projectName = projectName.charAt(0).toLowerCase() + projectName.slice(1); 123 | filteredResults[projectName] = {}; 124 | if(projectName in results){ 125 | const variableNames = Object.keys(results[projectName]); 126 | variableNames.filter(variableName => { 127 | return variableName.toLowerCase().includes(userInput); 128 | }).map((variableName) => { 129 | filteredResults[projectName][variableName] = results[projectName][variableName]; 130 | return filteredResults; 131 | }); 132 | } 133 | }); 134 | return filteredResults; 135 | } 136 | -------------------------------------------------------------------------------- /src/components/Analysis.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Analysis extends Component { 4 | render(){ 5 | return(
Under Construction: Will have some analysis on this tab in the future.
); 6 | } 7 | } 8 | 9 | export default Analysis; 10 | -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | import Analysis from "./Analysis"; 2 | import Home from "./Home"; 3 | import Filter from "./Filter"; 4 | import WordCloudRender from "./WordCloudRender"; 5 | import "../css/App.css"; 6 | 7 | import React, { Component } from "react"; 8 | import { Tabs, Tab } from "react-mdl/lib/Tabs"; 9 | 10 | class App extends Component { 11 | constructor(){ 12 | super(); 13 | this.state = { 14 | active: 0 15 | } 16 | } 17 | 18 | onChange(id) { 19 | this.setState({ active: id }); 20 | } 21 | 22 | render() { 23 | const tabs = [ 24 | {"ActivateComponent": React.createFactory(Home)}, 25 | {"ActivateComponent": React.createFactory(Filter)}, 26 | {"ActivateComponent": React.createFactory(WordCloudRender)}, 27 | {"ActivateComponent": React.createFactory(Analysis)} 28 | ]; 29 | return ( 30 |
31 |

Find JavaScript Variables

32 |
Note: API server is hosted on HEROKU so it may take some time to boot up the server if the server is sleeping.
33 |
34 | 35 | Home 36 | Filter 37 | Word Cloud 38 | Analysis 39 | 40 |
41 | {tabs[this.state.active].ActivateComponent()} 42 |
43 | ); 44 | } 45 | } 46 | 47 | export default App; 48 | -------------------------------------------------------------------------------- /src/components/Filter.js: -------------------------------------------------------------------------------- 1 | import Results from './Results'; 2 | import { fetchProjectNames } from '../actions/fetchDataAction'; 3 | import '../css/Search.css'; 4 | 5 | import React, { Component } from 'react'; 6 | import { Button } from 'react-mdl'; 7 | import { connect } from 'react-redux'; 8 | import { DoubleBounce } from 'better-react-spinkit'; 9 | 10 | class Search extends Component { 11 | constructor() { 12 | super(); 13 | this.state = { 14 | selectedProjects: [], 15 | updateResults: false 16 | } 17 | this.selectedProjects = []; 18 | } 19 | 20 | componentWillMount() { 21 | if(!this.props.projectNames.length) 22 | this.props.fetchProjectNames(); 23 | } 24 | 25 | submitCheckbox = () => { 26 | if(this.selectedProjects.length > 0) { 27 | this.setState({ 28 | selectedProjects: this.selectedProjects, 29 | updateResults: true 30 | }); 31 | } 32 | } 33 | 34 | toggleChange = (event) => { 35 | const selectedProject = event.target.name; 36 | const indexOfProject = this.selectedProjects.indexOf(selectedProject); 37 | if(indexOfProject !== -1) { 38 | this.selectedProjects = this.selectedProjects.filter((itm, i) => i !== indexOfProject); 39 | } else { 40 | this.selectedProjects = this.selectedProjects.concat(selectedProject); 41 | } 42 | } 43 | 44 | render() { 45 | if(this.props.isProjectNamesLoading) { 46 | return(); 47 | } else if(this.props.projectNameError) { 48 | return(
An Error Occured...Please try again later.
); 49 | } else { 50 | const projectNames = this.props.projectNames; 51 | return( 52 |
53 | 60 | {this.state.selectedProjects.length > 0 ? : null} 61 |
62 | ); 63 | } 64 | } 65 | } 66 | 67 | const ProjectCheckboxes = ({names, that}) => { 68 | return( 69 | names.map(name => ( 70 |
  • 78 | ) 79 | ) 80 | ); 81 | } 82 | 83 | const mapStateToProps = (state) => { 84 | return { 85 | projectNames: state.fetchProjNamesReducer.projectNames, 86 | isProjectNamesLoading: state.fetchProjNamesReducer.projectNamesIsLoading, 87 | projectNameError: state.fetchProjNamesReducer.fetchProjectNameHasError 88 | } 89 | } 90 | 91 | const mapDispatchToProps = (dispatch) => { 92 | return { 93 | fetchProjectNames: () => dispatch(fetchProjectNames()), 94 | } 95 | } 96 | 97 | export default connect(mapStateToProps, mapDispatchToProps)(Search); 98 | -------------------------------------------------------------------------------- /src/components/Home.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import '../css/Home.css'; 3 | 4 | class Home extends Component { 5 | render(){ 6 | return( 7 |
    8 |
    Why I Started This Project
    9 |
    10 |

    11 | This project extracted the top ten most popular (most stars) JavaScript repo on GitHub and pulled out the function names and variable names. Instructions on how to use this app is on GitHub but believe me - the app is self-explanatory. 12 |

    13 |

    14 | It's great to use programs like JavaScript and Python which are dynamically typed but sometimes it's just painful when you don't use it the right way. I started this project to help developers who are having difficulties naming there varibles (yes...I've been there a lot of time). Good variable names helps code reviews and produces better software qualities. Below are two real life example that good naming would benefit every software developers in the long run. 15 |

    16 |

    17 | There was this day when I was code reviewing one of the tickets that was assigned to me. It was a huge ticket and lots of code refactoring. Along the way, I saw this function named checkNextBillingDate. At first I assumed this meant returning back a string or date object. However, diving deeper into the code I found out that variable was returning back a boolean value. WHAT?!?! How does checkNextBillingDate return a boolean? Even if it did, how would I know what it was checking. Well after digging into the function, I finally figured out it was trying to check to check if the date passed in was a future. A better naming would have maybe been isDateInFuture or something like that. 18 |

    19 |

    20 | The last reason and the most important reason: Since I am not a native English speaker and believe me...naming variable is painful for non native speaker since we don't have the vocabulary size as a native speaker. During my undergraduate years in Taiwan, I had a lot of friends who were naming their variables in all sorts of strange name. To make matters worse: they had invented or misspelled a variable name they thought was something. Reading those code was a nightmare, not saying code reviewing them. 21 |

    22 |

    23 | To sum it up, I wish the app can be useful for people to reference how popoular repos name their variables or functions. In the end, all good software developer learn from the best codes and I believe that the most popular repos are always a good place to start. 24 |

    25 | Bill Cheng 26 |
    ); 27 | } 28 | } 29 | 30 | export default Home; 31 | -------------------------------------------------------------------------------- /src/components/Results.js: -------------------------------------------------------------------------------- 1 | import { fetchProjectVariables, simpleFilter } from '../actions/fetchDataAction'; 2 | import '../css/Results.css'; 3 | 4 | import React, { Component } from 'react'; 5 | import { connect } from 'react-redux'; 6 | import { DoubleBounce } from 'better-react-spinkit'; 7 | 8 | class Results extends Component { 9 | constructor(){ 10 | super(); 11 | this.receivedProjects = []; 12 | this.filterInput = ""; 13 | } 14 | 15 | componentWillMount() { 16 | this.fetchVariableData(this.props.selectedProjects); 17 | } 18 | 19 | componentWillReceiveProps(nextProps) { 20 | if(JSON.stringify(this.props.selectedProjects) !== JSON.stringify(nextProps.selectedProjects)) { 21 | this.fetchVariableData(nextProps.selectedProjects); 22 | } 23 | } 24 | 25 | fetchVariableData(selectedProjects) { 26 | const _receivedProjects = this.receivedProjects; 27 | const unFetchedProjects = selectedProjects.filter(itm => !_receivedProjects.includes(itm)) 28 | this.receivedProjects = _receivedProjects.concat(unFetchedProjects); 29 | if(!unFetchedProjects.length) { 30 | this.props.fetchProjectVariables(selectedProjects, this.filterInput, unFetchedProjects); 31 | } 32 | if(unFetchedProjects.length > 0) { 33 | this.props.fetchProjectVariables(selectedProjects, this.filterInput, unFetchedProjects); 34 | } 35 | } 36 | 37 | onFilterChange = (event) => { 38 | if(event.key === 'Enter') { 39 | const newFilterInput = event.target.value.trim(); 40 | if(this.filterInput !== newFilterInput) { 41 | this.filterInput = newFilterInput 42 | } 43 | this.props.simpleFilter(this.props.selectedProjects, this.filterInput); 44 | } 45 | } 46 | 47 | render() { 48 | if(this.props.hasError) { 49 | return(
    An Error Occured...Please try again later.
    ); 50 | } 51 | 52 | if(this.props.isLoading) { 53 | return(); 54 | } else { 55 | const results = this.props.filteredResults; 56 | const projectNames = Object.keys(results); 57 | return( 58 |
    59 | 0 ? this.filterInput : "Filter"} 63 | onKeyDown={this.onFilterChange} 64 | /> 65 | 66 |
    67 | ); 68 | } 69 | } 70 | } 71 | 72 | const ProjectVariableList = ({projectNames, results}) => { 73 | return ( 74 | projectNames.map(projectName => 75 |
    76 | {projectName.toUpperCase()} 77 |
      78 | {Object.keys(results[projectName]).map(variableName => 79 |
    1. {variableName}
    2. ) 80 | } 81 |
    82 |
    83 | ) 84 | ); 85 | } 86 | 87 | const mapStateToProps = (state) => { 88 | return { 89 | results: state.fetchProjVarReducer.results, 90 | filteredResults: state.fetchProjVarReducer.filteredResults, 91 | isLoading: state.fetchProjVarReducer.isLoading, 92 | hasError: state.fetchProjVarReducer.hasError 93 | } 94 | } 95 | 96 | const mapDispatchToProps = (dispatch) => { 97 | return { 98 | fetchProjectVariables: (projects, filters, unFetchedProjects) => dispatch(fetchProjectVariables(projects, filters, unFetchedProjects)), 99 | simpleFilter: (selectedProjects, filters) => dispatch(simpleFilter(selectedProjects, filters)) 100 | } 101 | } 102 | 103 | export default connect(mapStateToProps, mapDispatchToProps)(Results); 104 | -------------------------------------------------------------------------------- /src/components/WordCloudRender.js: -------------------------------------------------------------------------------- 1 | import { fetchWCProjectNames, fetchWCSingleProjectVariables } from "../actions/fetchDataAction"; 2 | import { wcSimpleFilter, clearShowResultsTree } from "../actions/fetchDataAction"; 3 | import "../css/WordCloudRender.css"; 4 | 5 | import React, { Component } from "react"; 6 | import Select from "react-select"; 7 | import { TagCloud } from "react-tagcloud"; 8 | import { connect } from "react-redux"; 9 | import { DoubleBounce } from "better-react-spinkit"; 10 | import "react-select/dist/react-select.css"; 11 | 12 | class WordCloudRender extends Component { 13 | constructor() { 14 | super(); 15 | this.filterInput = ""; 16 | } 17 | 18 | componentWillMount() { 19 | if(!this.props.wcProjectNames.length) { 20 | this.props.fetchWCProjectNames(); 21 | } 22 | this.selectedProject = ""; 23 | } 24 | 25 | componentWillUnmount() { 26 | this.props.clearShowResultsTree(); 27 | } 28 | 29 | onSelectChange = (selectedProject) => { 30 | this.selectedProject = selectedProject.value; 31 | const recievedProjects = this.props.wcSavedProjects; 32 | if(recievedProjects.indexOf(selectedProject.value) !== -1) { 33 | this.props.wcSimpleFilter(this.selectedProject, this.filterInput); 34 | } else { 35 | this.props.fetchWCSingleProjectVariables(this.selectedProject); 36 | } 37 | } 38 | 39 | onFilterChange = (event) => { 40 | if(event.key === "Enter") { 41 | const newFilterInput = event.target.value.trim(); 42 | this.filterInput = newFilterInput; 43 | this.props.wcSimpleFilter(this.selectedProject, this.filterInput); 44 | } 45 | } 46 | 47 | render() { 48 | const color = {luminosity: 'dark', hue: 'blue'}; 49 | return( 50 |
    51 |
    52 |
      53 |
    1. Node has been excluded in word cloud due to it's large volume of variables.
    2. 54 |
    3. Click on the word to take you to the Github search.
    4. 55 |
    56 |
    57 | 76 | window.open(tag.url, '_blank')} /> 82 |
    : 83 | } 84 | 85 | ); 86 | } 87 | } 88 | 89 | const ShowLoading = ({project}) => { 90 | return (project !== "" && ); 91 | } 92 | 93 | const mapStateToProps = (state) => { 94 | return { 95 | wcProjectNames: state.wordCloudReducer.data, 96 | isSelectLoading: state.wordCloudReducer.isLoading, 97 | wcSavedProjects: Object.keys(state.wordCloudReducer.wcSavedData), 98 | wcShowResults: state.wordCloudReducer.wcShowData, 99 | wcIsLoading: state.wordCloudReducer.wcIsLoading 100 | } 101 | } 102 | 103 | const mapDispatchToProps = (dispatch) => { 104 | return { 105 | fetchWCProjectNames: () => dispatch(fetchWCProjectNames()), 106 | fetchWCSingleProjectVariables: (project) => dispatch(fetchWCSingleProjectVariables(project)), 107 | wcSimpleFilter: (selectedProject, filter) => dispatch(wcSimpleFilter(selectedProject, filter)), 108 | clearShowResultsTree: () => dispatch(clearShowResultsTree()) 109 | } 110 | } 111 | export default connect(mapStateToProps, mapDispatchToProps)(WordCloudRender); 112 | -------------------------------------------------------------------------------- /src/css/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | background:#efefef; 3 | height:100%; 4 | margin:25px; 5 | padding:45px; 6 | } 7 | 8 | .App-title { 9 | font-size:40px; 10 | background: white; 11 | padding: 20px; 12 | margin-bottom: 30px; 13 | border-style: solid; 14 | border-color: #313131; 15 | text-align: center; 16 | } 17 | 18 | .App-intro { 19 | font-size: large; 20 | } 21 | 22 | .App-note { 23 | color: #ED4337; 24 | margin-left:40px; 25 | } 26 | -------------------------------------------------------------------------------- /src/css/Home.css: -------------------------------------------------------------------------------- 1 | #home { 2 | margin: 30px; 3 | text-align: justify; 4 | } 5 | -------------------------------------------------------------------------------- /src/css/Results.css: -------------------------------------------------------------------------------- 1 | .Results { 2 | width: 30%; 3 | margin-left: 40px; 4 | } 5 | 6 | .filter-word { 7 | /*margin-bottom: 5px;*/ 8 | } 9 | 10 | #variable-results { 11 | margin-top: 20px; 12 | } 13 | -------------------------------------------------------------------------------- /src/css/Search.css: -------------------------------------------------------------------------------- 1 | .checkbox-grid li { 2 | display: block; 3 | float: left; 4 | width: 50%; 5 | /*border-style: dotted;*/ 6 | } 7 | 8 | .checkbox-grid { 9 | margin-bottom: 15px; 10 | } 11 | 12 | .loading-symbol { 13 | margin: 50px 0px 0px 25px; 14 | } 15 | 16 | #checkBox-submit { 17 | /*background-color: grey;*/ 18 | margin-top: 10px; 19 | } 20 | -------------------------------------------------------------------------------- /src/css/WordCloudRender.css: -------------------------------------------------------------------------------- 1 | .project-select { 2 | width: 50%; 3 | margin: 10px 5px 5px 0px; 4 | } 5 | 6 | #word-cloud-note { 7 | margin-top: 10px; 8 | } 9 | -------------------------------------------------------------------------------- /src/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: grey; 3 | margin: 0; 4 | padding: 0; 5 | font-family: Gill Sans MT; 6 | } 7 | 8 | footer { 9 | width: 100%; 10 | height: 25px; 11 | position: fixed; 12 | bottom: 0px; 13 | color: white; 14 | background-color: #313131; 15 | text-align: center 16 | } 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import App from './components/App'; 2 | import store from "./store"; 3 | import './css/index.css'; 4 | 5 | import React from 'react'; 6 | import ReactDOM from 'react-dom'; 7 | import { Provider } from "react-redux"; 8 | import 'react-mdl/extra/material.css'; 9 | import 'react-mdl/extra/material.js'; 10 | 11 | const app = document.getElementById('root'); 12 | ReactDOM.render( 13 | 14 | , app); 15 | -------------------------------------------------------------------------------- /src/reducers/fetchProjNamesReducer.js: -------------------------------------------------------------------------------- 1 | const initState = { 2 | projectNames: [], 3 | projectNamesIsLoading: false, 4 | fetchProjectNameHasError: false 5 | } 6 | 7 | export default function reducer(state=initState, action) { 8 | switch(action.type) { 9 | case "FETCH_PROJECT_NAMES_PENDING": { 10 | return {...state, projectNamesIsLoading: true}; 11 | } 12 | case "FETCH_PROJECT_NAMES_REJECTED": { 13 | return {...state, projectNamesIsLoading: false, fetchProjectNameHasError: true}; 14 | } 15 | case "FETCH_PROJECT_NAMES_FULFILLED": { 16 | return {...state, projectNamesIsLoading: false, projectNames: action.payload.data}; 17 | } 18 | default: { 19 | return state; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/reducers/fetchProjVarReducer.js: -------------------------------------------------------------------------------- 1 | const initState = { 2 | results: {}, 3 | filteredResults: {}, 4 | isLoading: false, 5 | hasError: false 6 | } 7 | 8 | export default function reducer(state=initState, action) { 9 | switch(action.type) { 10 | case "FETCH_PROJECT_VARIABLES_PENDING": { 11 | return {...state, isLoading: true}; 12 | } 13 | case "FETCH_PROJECT_VARIABLES_REJECTED": { 14 | return {...state, isLoading: false, hasError: true}; 15 | } 16 | case "FETCH_PROJECT_VARIABLES_FULFILLED": { 17 | return {...state, isLoading: false, filteredResults: action.filtered, results: action.results}; 18 | } 19 | default: { 20 | return state; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | import fetchProjNamesReducer from "./fetchProjNamesReducer"; 3 | import fetchProjVarReducer from "./fetchProjVarReducer"; 4 | import wordCloudReducer from "./wordCloudReducer"; 5 | 6 | export default combineReducers({ 7 | fetchProjNamesReducer, 8 | fetchProjVarReducer, 9 | wordCloudReducer 10 | }) 11 | 12 | -------------------------------------------------------------------------------- /src/reducers/wordCloudReducer.js: -------------------------------------------------------------------------------- 1 | const initState = { 2 | data: [], 3 | isLoading: false, 4 | hasError: false, 5 | wcShowData: [], 6 | wcIsLoading: false, 7 | wcHasError: false, 8 | wcSavedData: {} 9 | } 10 | 11 | export default function reducer(state=initState, action) { 12 | switch(action.type) { 13 | case "FETCH_WC_PROJECT_NAMES_PENDING": { 14 | return {...state, isLoading: true}; 15 | } 16 | case "FETCH_WC_PROJECT_NAMES_REJECTED": { 17 | return {...state, isLoading: false, hasError: true}; 18 | } 19 | case "FETCH_WC_PROJECT_NAMES_FULFILLED": { 20 | return {...state, isLoading: false, data: action.payload.data}; 21 | } 22 | case "FETCH_WC_PROJECT_VARIABLES_PENDING": { 23 | return {...state, wcIsLoading: true} 24 | } 25 | case "FETCH_WC_PROJECT_VARIABLES_REJECTED": { 26 | return {...state, wcIsLoading: false, wcHasError: true} 27 | } 28 | case "FETCH_WC_PROJECT_VARIABLES_FULFILLED": { 29 | return {...state, wcIsLoading: false, wcSavedData: action.savedResults, wcShowData: action.resToBeShowed} 30 | } 31 | case "CLEAR_FETCH_WC_PROJECT_VARIABLES_SHOW_RESULTS": { 32 | return {...state, wcShowData: [] } 33 | } 34 | default: { 35 | return state; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, createStore } from "redux"; 2 | import thunk from "redux-thunk"; 3 | import promiseMiddleware from "redux-promise-middleware"; 4 | import reducer from "./reducers"; 5 | 6 | const middleware = applyMiddleware(promiseMiddleware(), thunk); 7 | 8 | export default createStore(reducer, middleware); 9 | 10 | --------------------------------------------------------------------------------