aboutsummaryrefslogtreecommitdiff
path: root/app/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/components')
-rw-r--r--app/components/about/about.html41
-rw-r--r--app/components/about/about.ts7
-rw-r--r--app/components/app/app.html3
-rw-r--r--app/components/app/app.ts4
-rw-r--r--app/components/plan-new/plan-new.html2
-rw-r--r--app/components/plan-node/plan-node.html13
-rw-r--r--app/components/plan-node/plan-node.ts2
-rw-r--r--app/components/plan-view/plan-view.html1
8 files changed, 63 insertions, 10 deletions
diff --git a/app/components/about/about.html b/app/components/about/about.html
new file mode 100644
index 0000000..08c913b
--- /dev/null
+++ b/app/components/about/about.html
@@ -0,0 +1,41 @@
+<div class="page page-content">
+ <h2>Postgres EXPLAIN Visualizer (Pev)</h2>
+ <p>
+ Pev is designed to make <a href="http://www.postgresql.org/docs/current/static/sql-explain.html">
+ Postgres query plans</a> easier to grok. It displays a plan as a tree, with each node representing a step that takes in a row set
+ and produces another. Pev can show you a number of useful things:</p>
+ <ul>
+ <li>overall plan stats</li>
+ <li>individual node stats (duration, row size, cost)</li>
+ <li>explanation of what each node does</li>
+ <li>outlier nodes</li>
+ <li>graph of a specific metric (like cost) for all nodes</li>
+ <li>for some nodes, highlighted part of the query which corresponds to the node</li>
+ </ul>
+
+ <p>You can tweak display options using the menu on the right.</p>
+
+ <h3>Usage tips</h3>
+ <p>Pev currently accepts only JSON formatted plans. In fact, the get the most out of it,
+ I recommend generating a query plan using the following line:
+ <code>EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)</code>. I also recommend submitting a (decently formatted)
+ SQL query that generated the plan. Doing so will make Pev more useful.
+ </p>
+
+ <p>Pev will remember the plans you analyzed. They are stored locally and are not submitted to me. This is good
+ because no one but you will see your queries. It's also bad because you can't share them with others.</p>
+
+ <h3>Acknowledgements</h3>
+ <p>Pev was inspired and heavily influenced by the excellent <a href="http://explain.depesz.com/">explain.depesz.com</a>. Both the
+ tool and the corresponding help files are a great resource to learn about Postgres and its planner.
+ </p>
+
+ <h3>Help me improve Pev</h3>
+ <p>If you want to help, there are multiple ways to contribute:</p>
+ <ul>
+ <li>give me your plans - I need more test cases for the layout</li>
+ <li>add descriptions for missing node types (especially ones from newer versions of Postgres)</li>
+ <li>contribute to the code on <a href="https://github.com/AlexTatiyants/pev">github</a></li>
+ </ul>
+
+</div>
diff --git a/app/components/about/about.ts b/app/components/about/about.ts
new file mode 100644
index 0000000..64777fc
--- /dev/null
+++ b/app/components/about/about.ts
@@ -0,0 +1,7 @@
+import {Component} from 'angular2/core';
+
+@Component({
+ selector: 'about',
+ templateUrl: './components/about/about.html'
+})
+export class About {}
diff --git a/app/components/app/app.html b/app/components/app/app.html
index b87937f..8d5072b 100644
--- a/app/components/app/app.html
+++ b/app/components/app/app.html
@@ -1,6 +1,7 @@
<nav>
<div class="nav-container">
- <a class="btn btn-primary btn-lg pull-right" [routerLink]="['/PlanNew']">new plan</a>
+ <a class="about"[routerLink]="['About']">about</a>
+ <a class="btn btn-primary btn-lg pull-right" [routerLink]="['PlanNew']">new plan</a>
<a [routerLink]="['PlanList']">plans</a>
</div>
</nav>
diff --git a/app/components/app/app.ts b/app/components/app/app.ts
index f9c83e0..1b78861 100644
--- a/app/components/app/app.ts
+++ b/app/components/app/app.ts
@@ -4,6 +4,7 @@ import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {PlanView} from '../plan-view/plan-view';
import {PlanList} from '../plan-list/plan-list';
import {PlanNew} from '../plan-new/plan-new';
+import {About} from '../about/about';
@Component({
selector: 'app',
@@ -16,7 +17,8 @@ import {PlanNew} from '../plan-new/plan-new';
{ path: '/', redirectTo: ['/PlanList'] },
{ path: '/plans', component: PlanList, name: 'PlanList' },
{ path: '/plans/new', component: PlanNew, name: 'PlanNew' },
- { path: '/plans/:id', component: PlanView, name: 'PlanView' }
+ { path: '/plans/:id', component: PlanView, name: 'PlanView' },
+ { path: '/about', component: About, name: 'About'}
])
export class App { }
diff --git a/app/components/plan-new/plan-new.html b/app/components/plan-new/plan-new.html
index ba65d99..ee2565e 100644
--- a/app/components/plan-new/plan-new.html
+++ b/app/components/plan-new/plan-new.html
@@ -2,7 +2,7 @@
<span class="text-muted">For best results, use EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)</span>
<div>
<input placeholder="name (optional)" class="input-box input-box-main" type="text" [(ngModel)]="newPlanName">
- <button class="btn btn-primary btn-lg pull-right" (click)="submitPlan()">submit</button>
+ <button class="btn btn-default btn-lg pad-top pull-right" (click)="submitPlan()">submit</button>
</div>
<textarea placeholder="paste execution plan" class="input-box input-box-lg" [(ngModel)]="newPlanContent"></textarea>
diff --git a/app/components/plan-node/plan-node.html b/app/components/plan-node/plan-node.html
index 08a7a96..fdc2c89 100644
--- a/app/components/plan-node/plan-node.html
+++ b/app/components/plan-node/plan-node.html
@@ -1,5 +1,5 @@
<div class="plan-node" [class.expanded]="showDetails">
- <header (click)="showDetails = !showDetails">
+ <header (click)="showDetails = !showDetails" tooltip="view node details">
<h4>{{node[_planService.NODE_TYPE_PROP] | uppercase}}
</h4>
<span class="node-duration">{{duration}}<span class="text-muted">{{durationUnit}} | </span>
@@ -7,11 +7,12 @@
</span>
</header>
- <div class="relation-name" *ngIf="node[_planService.RELATION_NAME_PROP]">
- <button *ngIf="plan.formattedQuery" class="btn btn-sm btn-default btn-slim pull-right" (click)="showQuery = !showQuery">
- <i class="fa fa-database"></i>
- </button>
+ <button *ngIf="plan.formattedQuery" tooltip="view corresponding query"
+ class="btn btn-sm btn-default btn-slim pull-right" (click)="showQuery = !showQuery">
+ <i class="fa fa-database"></i>
+ </button>
+ <div class="relation-name" *ngIf="node[_planService.RELATION_NAME_PROP]">
<span class="text-muted">on </span>
<span *ngIf="node[_planService.SCHEMA_PROP]">{{node[_planService.SCHEMA_PROP]}}.</span>{{node[_planService.RELATION_NAME_PROP]}}
<span *ngIf="node[_planService.ALIAS_PROP]"> ({{node[_planService.ALIAS_PROP]}})</span>
@@ -31,7 +32,7 @@
</div>
<div *ngIf="currentHighlightType !== highlightTypes.NONE">
- <div class="node-bar-container" [style.width]="(MAX_WIDTH+3)+'px'">
+ <div class="node-bar-container" [style.width]="(MAX_WIDTH)+'px'">
<span class="node-bar" [style.width]="width+'px'" [style.backgroundColor]="backgroundColor"></span>
</div>
<span class="node-bar-label">
diff --git a/app/components/plan-node/plan-node.ts b/app/components/plan-node/plan-node.ts
index fc865b8..2f3164e 100644
--- a/app/components/plan-node/plan-node.ts
+++ b/app/components/plan-node/plan-node.ts
@@ -66,7 +66,6 @@ export class PlanNode {
}
ngDoCheck() {
- // console.log("check", this.currentHighlightType, this.viewOptions.highlightType);
if (this.currentHighlightType !== this.viewOptions.highlightType) {
this.currentHighlightType = this.viewOptions.highlightType;
this.calculateBar();
@@ -78,6 +77,7 @@ export class PlanNode {
keyItems.push(this.node[this._planService.SCHEMA_PROP] + '.' + this.node[this._planService.RELATION_NAME_PROP]);
keyItems.push(' ' + this.node[this._planService.RELATION_NAME_PROP] + ' ');
keyItems.push(' ' + this.node[this._planService.ALIAS_PROP] + ' ');
+ keyItems.push(this.node[this._planService.GROUP_KEY_PROP]);
return this._syntaxHighlightService.highlightKeyItems(this.plan.formattedQuery, keyItems);
}
diff --git a/app/components/plan-view/plan-view.html b/app/components/plan-view/plan-view.html
index c63c4d1..268bdac 100644
--- a/app/components/plan-view/plan-view.html
+++ b/app/components/plan-view/plan-view.html
@@ -55,6 +55,7 @@
<span class="stat-value">{{plan.planStats.maxCost | number:'.0-2'}}</span>
<span class="stat-label">costliest node</span>
</div>
+ <div class="btn-close" (click)="viewOptions.showPlanStats = false"><i class="fa fa-close"></i></div>
</div>
<div class="plan">