Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev UI build steps chart #35141

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ InternalImportMapBuildItem createKnownInternalImportMap(NonApplicationRootPathBu
contextRoot + "echarts/echarts-horizontal-stacked-bar.js");
internalImportMapBuildItem.add("echarts-force-graph",
contextRoot + "echarts/echarts-force-graph.js");
internalImportMapBuildItem.add("echarts-bar-stack",
contextRoot + "echarts/echarts-bar-stack.js");

// Other assets
internalImportMapBuildItem.add("icon/", contextRoot + "icon/");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { EchartsAbstractCanvas } from './echarts-abstract-canvas.js';

/**
* This wraps the Bar Stack echart into a component
* see https://echarts.apache.org/examples/en/editor.html?c=bar-stack
*/
class EchartsBarStack extends EchartsAbstractCanvas {

static get properties() {
return {
xdata:{type: String},
xdataName: {type: String},
series: { type: String},
ydataName: {type: String}
};
}

constructor() {
super();

this.xdata = null;
this.xdataName = null;
this.series = null;
this.primaryTextColor = "--lumo-body-text-color";
}

getOption(){

let textColor = this.primaryTextColor;
if(textColor.startsWith('--')){
textColor = getComputedStyle(this.shadowRoot.host).getPropertyValue(textColor);
}
const barStackOption = new Object();

barStackOption.tooltip = new Object();
barStackOption.tooltip.trigger = "item";
barStackOption.tooltip.axisPointer= new Object();
barStackOption.tooltip.axisPointer.type = "shadow";
barStackOption.tooltip.formatter = function (params) {
let namesUL = "<ul>";
for (let i = 0; i < params.data.name.length; i++) {
namesUL = namesUL + "<li>" + params.data.name[i] + "</li>";
}
namesUL = namesUL + "</ul>";
return `
<b>${params.seriesName}</b></br>
${namesUL}`;
};
barStackOption.legend = new Object();
barStackOption.legend.textStyle = new Object();
barStackOption.legend.textStyle.color = textColor;

barStackOption.grid = new Object();
barStackOption.grid.top = "20%";
barStackOption.grid.left = "3%";
barStackOption.grid.right = "4%";
barStackOption.grid.bottom = "3%";
barStackOption.grid.containLabel = true;

let xAxis = new Object();
xAxis.type = "category";

xAxis.data = this.xdata.split(',');
xAxis.axisLine = new Object();
xAxis.axisLine.lineStyle = new Object();
xAxis.axisLine.lineStyle.color = textColor;
if(this.xdataName){
xAxis.name = this.xdataName;
xAxis.nameLocation = "center";
xAxis.nameGap = 30;
}
barStackOption.xAxis = [];
barStackOption.xAxis.push(xAxis);

let yAxis = new Object();
yAxis.type = "value";
yAxis.axisLine = new Object();
yAxis.axisLine.lineStyle = new Object();
yAxis.axisLine.lineStyle.color = textColor;
if(this.ydataName){
yAxis.name = this.ydataName;
yAxis.nameLocation = "center";
yAxis.nameGap = 30;
}

barStackOption.yAxis = [];
barStackOption.yAxis.push(yAxis);

barStackOption.series = [];
let seriesMap = new Map(Object.entries(JSON.parse(this.series)));


for (let [key, value] of seriesMap) {
let arr = [];

for (let i = 0; i < value.length; i++) {
let val = value[i];


let dataItem = new Object();
dataItem.name = val;
dataItem.label = new Object();
if(val.length > 0){
dataItem.value = 1;
}
arr.push(dataItem);
}

const serie = new Object();
serie.name = key;
serie.type = "bar";
serie.stack = "stack";
serie.emphasis = new Object();
serie.emphasis.focus = "series";

serie.data = arr;
barStackOption.series.push(serie);
}

return barStackOption;

}

}
customElements.define('echarts-bar-stack', EchartsBarStack);
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export class QwcBuildItems extends QwcHotReloadElement {
}`;

static properties = {
_buildStepsMetrics: { state: true },
_buildItems: { state: true },
_count: { state: false },
_filtered: {state: true, type: Array}
};

Expand All @@ -52,14 +53,15 @@ export class QwcBuildItems extends QwcHotReloadElement {
}

hotReload(){
this.jsonRpc.getBuildStepsMetrics().then(e => {
this._buildStepsMetrics = e.result;
this._filtered = this._buildStepsMetrics.items;
this.jsonRpc.getBuildItems().then(e => {
this._buildItems = e.result;
this._count = this._buildItems.length;
this._filtered = this._buildItems;
});
}

render() {
if (this._buildStepsMetrics && this._filtered) {
if (this._buildItems && this._filtered) {
return this._render();
}else {
return html`
Expand All @@ -81,18 +83,18 @@ export class QwcBuildItems extends QwcHotReloadElement {
_filter(e) {
const searchTerm = (e.detail.value || '').trim();
if (searchTerm === '') {
this._filtered = this._buildStepsMetrics.items;
this._filtered = this._buildItems;
return;
}

this._filtered = this._buildStepsMetrics.items.filter((item) => {
this._filtered = this._buildItems.filter((item) => {
return this._match(item.class, searchTerm);
});
}

_render() {
return html`<div class="build-items">
<div class="summary">Produced <strong>${this._buildStepsMetrics.itemsCount}</strong> build items.</div>
<div class="summary">Produced <strong>${this._count}</strong> build items.</div>
<vaadin-text-field
placeholder="Filter"
style="width: 100%;"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { LitElement, html, css} from 'lit';
import { JsonRpc } from 'jsonrpc';
import 'echarts-bar-stack';
import '@vaadin/button';
import '@vaadin/checkbox';
import '@vaadin/checkbox-group';
import '@vaadin/progress-bar';

/**
* This component shows the Build Step Execution Graph
*/
export class QwcBuildStepsExecutionGraph extends LitElement {

static styles = css`
.top-bar {
display: flex;
align-items: baseline;
gap: 20px;
padding-left: 20px;
padding-right: 20px;
}

.top-bar h4 {
color: var(--lumo-contrast-60pct);
}
`;

static properties = {
extensionName: {type: String}, // TODO: Add 'pane' concept in router to register internal extension pages.
_threadSlotRecords: {state: true},
_slots: {state: true}
};

constructor() {
super();
this._threadSlotRecords = null;
this._slots = null;
}

connectedCallback() {
super.connectedCallback();
this.jsonRpc = new JsonRpc(this.extensionName);
this._fetchBuildStepsExecutionData();
}

_fetchBuildStepsExecutionData(){
this.jsonRpc.getThreadSlotRecords().then(jsonRpcResponse => {
this._slots = jsonRpcResponse.result.slots;
this._threadSlotRecords = jsonRpcResponse.result.threadSlotRecords;
});
}

render() {

if(this._threadSlotRecords){
let xdata = this._slots.toString();
let xname = this._slots.length + " time slots (" + this._slots[0] +" ms)";
let yname = "Number of build threads used in a time slot";
return html`${this._renderTopBar()}
<echarts-bar-stack width="400px" height="400px"
xdata="${xdata}"
xdataName="${xname}"
ydataName="${yname}"
series="${JSON.stringify(this._threadSlotRecords)}">
</echarts-bar-stack>
`;
}else{
return html`
<div style="color: var(--lumo-secondary-text-color);width: 95%;" >
<div>Loading Build Steps Execution Graph...</div>
<vaadin-progress-bar indeterminate></vaadin-progress-bar>
</div>
`;
}


}

_renderTopBar(){
return html`
<div class="top-bar">
<vaadin-button @click="${this._backAction}">
<vaadin-icon icon="font-awesome-solid:caret-left" slot="prefix"></vaadin-icon>
Back
</vaadin-button>
<h4>Build Steps Concurrent Execution Chart</h4>
</div>`;
}

_backAction(){
const back = new CustomEvent("build-steps-graph-back", {
detail: {},
bubbles: true,
cancelable: true,
composed: false,
});
this.dispatchEvent(back);
}
}
customElements.define('qwc-build-steps-execution-graph', QwcBuildStepsExecutionGraph);
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import '@vaadin/text-field';
import '@vaadin/vertical-layout';
import '@vaadin/horizontal-layout';
import '@vaadin/progress-bar';
import '@vaadin/button';
import './qwc-build-step-graph.js';

import './qwc-build-steps-execution-graph.js';

/**
* This component shows the Build Steps
Expand Down Expand Up @@ -57,13 +58,15 @@ export class QwcBuildSteps extends QwcHotReloadElement {
static properties = {
_buildMetrics: { state: true },
_selectedBuildStep: {state: true},
_showBuildStepsExecutionGraph: {state: true},
_filtered: {state: true, type: Array}
};

constructor() {
super();
this._buildMetrics = null;
this._selectedBuildStep = null;
this._showBuildStepsExecutionGraph = false;
this.hotReload();
}

Expand Down Expand Up @@ -109,15 +112,23 @@ export class QwcBuildSteps extends QwcHotReloadElement {
_render() {
if(this._selectedBuildStep){
return this._renderBuildStepGraph();
}else{
}else if(this._showBuildStepsExecutionGraph){
return this._renderBuildStepsExecutionGraph();
}else{
return this._renderBuildStepList();
}
}

_renderBuildStepList(){

return html`<div class="build-steps">
<div class="summary">Executed <strong>${this._buildMetrics.records.length}</strong> build steps on <strong>${this._buildMetrics.numberOfThreads}</strong> threads in <strong>${this._buildMetrics.duration} ms</strong>.</div>
<div class="summary">
Executed <strong>${this._buildMetrics.records.length}</strong> build steps on <strong>${this._buildMetrics.numberOfThreads}</strong> threads in <strong>${this._buildMetrics.duration} ms</strong>.
<vaadin-button theme="tertiary" @click="${this._showBuildStepsChart}">
<vaadin-icon icon="font-awesome-solid:chart-simple" slot="prefix"></vaadin-icon>
Build Steps Concurrent Execution Chart
</vaadin-button>
</div>
<vaadin-text-field
placeholder="Filter"
style="width: 100%;"
Expand Down Expand Up @@ -157,14 +168,19 @@ export class QwcBuildSteps extends QwcHotReloadElement {
}

_renderBuildStepGraph(){

return html`<qwc-build-step-graph class="graph"
stepId="${this._selectedBuildStep.stepId}"
extensionName="${this.jsonRpc.getExtensionName()}"
@build-steps-graph-back=${this._showBuildStepsList}></qwc-build-step-graph>`;

}

_renderBuildStepsExecutionGraph(){
return html`<qwc-build-steps-execution-graph class="graph"
extensionName="${this.jsonRpc.getExtensionName()}"
@build-steps-graph-back=${this._showBuildStepsList}></qwc-build-steps-execution-graph>`;
}

_stepIdRenderer(record) {
return html`<code>${record.stepId}</code>`;
}
Expand All @@ -175,11 +191,17 @@ export class QwcBuildSteps extends QwcHotReloadElement {

_showGraph(buildStep){
this._selectedBuildStep = buildStep;
this._showBuildStepsExecutionGraph = false;
}

_showBuildStepsList(){
this._selectedBuildStep = null;
this._showBuildStepsExecutionGraph = false;
}

_showBuildStepsChart(){
this._selectedBuildStep = null;
this._showBuildStepsExecutionGraph = true;
}
}
customElements.define('qwc-build-steps', QwcBuildSteps);
Loading