Skip to content

Commit

Permalink
Front-end stuff as a first class citizen.
Browse files Browse the repository at this point in the history
- Introducing test framework, assertion library.
- Adding first batch of test.
- Improving front-end directory structure.
- Adding linting tool.

Related to #28.
  • Loading branch information
afronski committed Dec 23, 2016
1 parent 8ff5c9d commit b21d44a
Show file tree
Hide file tree
Showing 30 changed files with 5,347 additions and 5,212 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ otp_release:
- 18.3
- 17.5
- R16B03-1
install:
./rebar3 deps
script:
make test
after_success:
- ./rebar3 cover
- if [ $TRAVIS_OTP_RELEASE = "18.3" ]; then erl -noshell -pa _build/test/lib/*/ebin -eval 'ecoveralls:travis_ci("_build/test/cover/ct.coverdata"), init:stop()'; fi
- if [ $TRAVIS_OTP_RELEASE = "18.3" ]; then ./rebar3 coveralls send; fi
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2015, Michal Niec <michal.niec@gmail.com>.
Copyright (c) 2015, Michal Niec <michal.niec@appliscale.io>.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
14 changes: 10 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,24 @@ compile:
dev: compile webpack
./rebar3 as dev shell

npm:
cd priv; npm install

bower: npm
cd priv; $(BIN_DIR)/bower install

webpack: bower
check_front_end: bower
cd priv; $(BIN_DIR)/eslint *.json app/*.jsx app/*.js test/*.js

test_front_end: check_front_end
cd priv; $(BIN_DIR)/mocha test/.setup.js test/*.test.js

webpack: test_front_end
cd priv; $(BIN_DIR)/webpack

webpack_autoreload: bower
cd priv; $(BIN_DIR)/webpack -w -d

npm:
cd priv; npm install

test: compile
./rebar3 do eunit -c, ct -c, cover

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ The WebUI uses

All sources are in _priv_ directory. The _app_ folder contains the sources and
the _build_ folder is a placeholder for final JS generated by webpack and then
served by cowboy server (xprof's dependency).
served by cowboy server (*XProf's* dependency).

### Starting `xprof` in development mode

Expand Down
3 changes: 3 additions & 0 deletions priv/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": [ "airbnb" ]
}
2 changes: 2 additions & 0 deletions priv/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/*.js
build/*.js.map
3 changes: 2 additions & 1 deletion priv/app/call_tracer.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import 'underscore';
import React from 'react';

import FlotGraph from "./graph_flot.jsx"

export default class CallsTracer extends React.Component {
Expand Down
24 changes: 11 additions & 13 deletions priv/app/function_browser.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import 'underscore';
import React from 'react';

import Utils from './utils.js';

class ACModal extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -31,8 +33,8 @@ class ACModal extends React.Component {
this.setState(this.state);
}

handleFunClick(fun, e) {
var query = ACModal.formatFun(fun);
handleFunClick(MFA, e) {
var query = Utils.formatMFA(MFA);
this.props.addGraph(query);
}

Expand All @@ -56,17 +58,13 @@ class ACModal extends React.Component {
return fun;
}

static formatFun(fun) {
return `${fun[0]}:${fun[1]}/${fun[2]}`
}

render() {
var funs = this.state.funs;
var mfas = this.state.funs;
var rows = [];
var highlightClass = "";
var width, height;

for (let i = 0; i < funs.length && i < 100; i++) {
for (let i = 0; i < mfas.length && i < 100; i++) {

if(i == this.state.position)
highlightClass = "row-highlight";
Expand All @@ -76,7 +74,7 @@ class ACModal extends React.Component {
rows.push(
<tr className={highlightClass} key={funs[i]}
onClick={this.handleFunClick.bind(this, funs[i])}>
<td>{ACModal.formatFun(funs[i])}</td>
<td>{Utils.formatMFA(mfas[i])}</td>
</tr>);
}

Expand Down Expand Up @@ -165,11 +163,11 @@ export default class FunctionBrowser extends React.Component {
}

completeSearch() {
var highlightedFun = this.refs.acm.highlightedFun();
var highlightedMFA = this.refs.acm.highlightedFun();
var funStr;

if(highlightedFun) {
funStr = ACModal.formatFun(highlightedFun);
if(highlightedMFA) {
funStr = Utils.formatMA(highlightedMFA);
$(this.getSearchBox()).val(funStr);
this.refs.acm.displayFuns([]);
}
Expand Down
13 changes: 8 additions & 5 deletions priv/app/graph.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React from 'react';
import 'underscore';
import FlotGraph from "./graph_flot.jsx"
import CallsTracer from "./call_tracer.jsx"
import React from 'react';

import FlotGraph from "./graph_flot.jsx";
import CallsTracer from "./call_tracer.jsx";

import Utils from "./utils.js";

const UPDATE_INTERVAL = 1000;
const MAX_DPS = 5 * 60; //10 minutes
Expand Down Expand Up @@ -29,7 +32,7 @@ export default class Graph extends React.Component {
}

render() {
var fun = this.props.fun;
var MFA = this.props.fun;
var panelType = "panel panel-default ";
var errorMsg = "";

Expand All @@ -45,7 +48,7 @@ export default class Graph extends React.Component {
className="close" data-dismiss="modal"
aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
<h3 className="panel-title">{fun[0]}:{fun[1]}/{fun[2]}{errorMsg}</h3>
<h3 className="panel-title">{Utils.formatMFA(MFA)}{errorMsg}</h3>
</div>
<div className="panel-body">

Expand Down
2 changes: 1 addition & 1 deletion priv/app/graph_flot.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import 'jquery';
import React from 'react';

import 'Flot';
import "Flot/jquery.flot.fillbetween.js";
Expand Down
1 change: 1 addition & 0 deletions priv/app/graph_panel.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';

import Graph from './graph.jsx'

export default class GraphPanel extends React.Component {
Expand Down
8 changes: 5 additions & 3 deletions priv/app/main.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import 'jquery';
import 'bootswatch/flatly/bootstrap.css';
import React from 'react';

import 'Flot';
import 'bootswatch/flatly/bootstrap.css';

import Graph from './graph.jsx'
import TracingSwitch from './tracing_switch.jsx'
import GraphPanel from './graph_panel.jsx'
Expand All @@ -26,7 +28,7 @@ class App extends React.Component {
<nav className="navbar navbar-default navbar-fixed-top">
<div className="navbar-header">
<a className="navbar-brand" href="#">
<img src="build/img/xprof_logo.png" height="45px"/>
<img src="img/xprof_logo.png" height="45px"/>
</a>
</div>

Expand Down
6 changes: 3 additions & 3 deletions priv/app/tracing_switch.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import 'underscore';
import React from 'react';

export default class TracingSwitch extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -38,9 +38,9 @@ export default class TracingSwitch extends React.Component {
}

render() {
var symbol = "glyphicon glyphicon-" + (this.state.tracing ? "pause" : "record");
var symbol = "glyphicon glyphicon-" + (this.state.tracing ? "pause" : "record");
var btnColor = "btn btn-" + (this.state.tracing ? "danger" : "success");
var text = this.state.tracing ? "Pause tracing" : "Trace all";
var text = this.state.tracing ? "Pause tracing" : "Trace all";

return (
<form className="navbar-form navbar-left" role="search">
Expand Down
45 changes: 45 additions & 0 deletions priv/app/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export default class Utils {
static can_be_unescaped_atom(atom) {
if (atom[0].search(/[a-z]/) === -1) {
return false;
}

if (atom.search(/[^a-zA-Z@0-9_]/) !== -1) {
return false;
}

return true;
}

static formatMFA(MFA) {
if (MFA.length !== 3) {
throw new Error(`Unexpected argument passed to the formatter (MFA length: ${MFA.length}).`)
}

if (typeof(MFA[0]) !== "string") {
throw new Error("Module name is not a string.");
}

if (MFA[0].length === 0) {
throw new Error("Module name is an empty string.");
}

if (typeof(MFA[1]) !== "string") {
throw new Error("Function name is not a string.");
}

if (MFA[1].length === 0) {
throw new Error("Function name is an empty string.");
}

if (!Utils.can_be_unescaped_atom(MFA[0])) {
MFA[0] = `'${MFA[0]}'`;
}

if (!Utils.can_be_unescaped_atom(MFA[1])) {
MFA[1] = `'${MFA[1]}'`;
}

return `${MFA[0]}:${MFA[1]}/${MFA[2]}`
}
}
2 changes: 1 addition & 1 deletion priv/bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"authors": [
"Michal Niec <michal.niec@appliscale.io>"
],
"description": "Visual BEAM profiler",
"description": "XProf - BEAM profiler",
"keywords": [
"xprof"
],
Expand Down
Loading

0 comments on commit b21d44a

Please sign in to comment.