Skip to content

Commit

Permalink
[TRON-16423] Integrate Observation logging into the graphs-renderer l…
Browse files Browse the repository at this point in the history
…ibrary

- include the ObservationLoggingService.js as part of the library
- plug in the observation logging in the cfd and scatterplot renderers
- refactor the EventBus to export a singleton instance
- add webpack css loaders and include the tooltip styles in  a css module: tooltipStyles.module.css and import in the renderers
- refactor the examples code to include the updated view with teh sidebars and the observation logging form and the js code example for leveraging teh obs logging with the graphs
  • Loading branch information
ClaudiaGivan committed Sep 14, 2023
1 parent a6ffc30 commit 9b72652
Show file tree
Hide file tree
Showing 21 changed files with 1,136 additions and 96 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ To see usage examples of the library and the data format for the graph refer to

## Examples
There are some examples demonstrating the usage of `graphs-renderer` library.
You can find the examples in the [examples](./examples) directory.
You can find the examples in the [examples](examples) directory.
113 changes: 104 additions & 9 deletions examples/example.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,114 @@
<head>
<meta charset="UTF-8">
<title>Graphs Example</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div>
<h2>CFD graph</h2>
<div id="cfd"></div>
<div id="cfd-brush"></div>
<h2>Scatterplot graph</h2>
<div id="scatterplot"></div>
<div id="scatterplot-brush"></div>
<h2>Histogram graph</h2>
<div id="histogram"></div>
<div id="layout">
<h1 class="py-4 text-center font-bold bg-black text-white"> Graphs library</h1>
<div class="absolute z-10 w-8 border-2 border-black bg-black transition-width duration-200 overflow-x-hidden"
id="left-sidebar">
<button class="w-full h-10 p-1" id="left-sidebar-button">
<img class="w-5 h-5 mx-auto" id="left-sidebar-arrow-img" src="./images/double-right-arrowhead.svg"/>
</button>
<div class="hidden text-white p-2" id="left-sidebar-content">
<h3 class="pl-1">Legend:</h3>
<div>
<p class="my-2">
Predictability turns out to be more important than maximizing utilization. To provide better
predictability to stakeholders
and customers, start by focusing on stabilizing the rate that work items flow through the system.
</p>
<p class="my-2">
<b>Lead Time</b> is the average time a work items spends in a system Operational definition:
From when a team commits to work
until PR merge
</p>
<p class="my-2">
<b>Work in Progress</b> (WIP) is the set of work started but not yet completed or abandoned
Operational definition: Use the
same start and end time criteria as used for Lead Time
</p>
<p class="my-2">
<b>Throughput</b> is the average rate the work items enter and exit the system Operational
definition: Calculated as Lead Time
divided by WIP
</p>
</div>
</div>
</div>
<div
class="absolute z-10 w-8 border-2 border-black bg-black transition-width duration-200 overflow-x-hidden right-0"
id="right-sidebar">
<button class="w-full h-10 p-1" id="right-sidebar-button">
<img class="w-5 h-5 mx-auto" id="right-sidebar-arrow-img" src="./images/double-left-arrowhead.svg"/>
</button>
<!--Observation log Form-->
<div class="fixed top-0 right-0 w-96 hidden text-white p-2 " id="right-sidebar-content">
<div class="">
<h2 class="text-center text-white">Form</h2>
<div class="bg-white px-2 py-3 rounded">
<div class="mb-4">
<label class="block text-black font-bold" for="date-input">Date</label>
<p class="text-black mb-2">The date on the chart that this observation is made at.</p>
<input
class="shadow appearance-none border rounded w-full py-2 px-4 text-black leading-tight focus:outline-none focus:shadow-outline"
id="date-input"
type="date"/>
</div>
<div class="mb-4">
<label class="block text-black font-bold" for="work-item-input">Work Item</label>
<p class="text-black mb-2">The work item (e.g. Jira issue or Zendesk ticket) that this
observation is about.</p>
<input
class="shadow appearance-none border rounded w-full py-2 px-4 text-black leading-tight focus:outline-none focus:shadow-outline"
id="work-item-input"
type="text"/>
</div>
<div class="mb-2">
<label class="block text-black font-bold" for="observation-input">Observation</label>
<p class="text-black mb-2">
Focus on the observation - what happened at this particular point in the chart? Don't
over-complicate your
observations.You can draw insights and learnings from your observations at a later point
</p>
<textarea
class="shadow appearance-none border rounded w-full py-2 px-4 text-black leading-tight focus:outline-none focus:shadow-outline"
id="observation-input"
placeholder="Enter observation"
rows="10"></textarea>
</div>
<input id="service-id-input" name="service-id" type="hidden"/>
<input id="chart-type-input" name="chart-type" type="hidden"/>
<input id="observation-id-input" name="observation-id" type="hidden"/>
<button
class="bg-black text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
id="form-button"
type="button">
Submit
</button>
</div>
</div>
</div>
</div>
<div class="h-full ml-8 -z-10" id="page-content">
<div class="mx-auto mt-6">
<h1 class="my-2 text-center font-bold">CFD</h1>
<div id="cfd-area-div"></div>
<div id="cfd-brush-div"></div>
<h1 class="my-2 text-center font-bold">Scatterplot</h1>
<div id="scatterplot-area-div"></div>
<div id="scatterplot-brush-div"></div>
<h1 class="my-2 text-center font-bold">Histogram</h1>
<div id="histogram-area-div"></div>
</div>
</div>
</div>
</div>
<script src="../dist/graphs-renderer.js" type="module"></script>
<script src="sidebars.js" type="module"></script>
<script src="exampleData.js" type="module"></script>
<script src="example.js" type="module"></script>
</body>
</html>
</html>
79 changes: 62 additions & 17 deletions examples/example.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
import CFDGraph from "../src/graphs/cfd/CFDGraph";
import CFDRenderer from "../src/graphs/cfd/CFDRenderer";
import ScatterplotGraph from "../src/graphs/scatterplot/ScatterplotGraph";
import ScatterplotRenderer from "../src/graphs/scatterplot/ScatterplotRenderer";
import HistogramRenderer from "../src/graphs/histogram/HistogramRenderer";
import {processServiceData} from "../src";
import {exampleData} from "./exampleData.js";
import {EventBus} from "../src";
import {
CFDGraph,
CFDRenderer,
ScatterplotGraph,
ScatterplotRenderer,
HistogramRenderer,
ObservationLoggingService,
processServiceData,
eventBus
} from "../dist/graphs-renderer.js";
import {initializeForm,toggleRightSidebar} from "./sidebars.js"

let removedTicketTypes = ["task"];
let removedRepos = ["wizard-lambda"];
let serviceData = exampleData
let serviceId = "0a95c-9151-448e"
let data = processServiceData(serviceData, removedRepos, removedTicketTypes);
if (!data || data.length === 0) {
console.log("There is no data for this service!");
} else {
renderGraphs(data);
renderGraphs(data, serviceId);
}

function renderGraphs(data) {
//Create an event bus for event driven communication between graphs
const eventBus = new EventBus();
async function renderGraphs(data, serviceId) {
//The Load and reset config input buttons css selectors
const loadConfigInputSelector = "#load-config-input";
const resetConfigInputSelector = "#reset-config-input";
//The controls div css selector that contains the reporting range days input and the x axis labeling units dropdown
const cfdUIControlsElementSelector = "#controls-div";
const controlsElementSelector = "#controls-div";

//The cfd area chart and brush window elements css selectors
const cfdGraphElementSelector = "#cfd-area-div";
Expand All @@ -41,7 +44,7 @@ function renderGraphs(data) {
if (cfdGraphDataSet.length > 0) {
cfdRenderer.drawGraph(cfdGraphElementSelector);
document.querySelector(cfdBrushElementSelector) && cfdRenderer.useBrush(cfdBrushElementSelector);
document.querySelector(cfdUIControlsElementSelector) && cfdRenderer.useControls("#reporting-range-input", "#range-increments-select");
document.querySelector(controlsElementSelector) && cfdRenderer.useControls("#reporting-range-input", "#range-increments-select");
document.querySelector(loadConfigInputSelector) && cfdRenderer.useConfigLoading(loadConfigInputSelector, resetConfigInputSelector);
} else {
cfdRenderer.clearGraph(cfdGraphElementSelector, cfdBrushElementSelector);
Expand All @@ -56,9 +59,8 @@ function renderGraphs(data) {
const scatterplotGraph = new ScatterplotGraph(data);
//Compute the dataset for the scatterplot and histogram graphs
const leadTimeDataSet = scatterplotGraph.computeDataSet(data);
const ticketUrlBase = "https://atlassian.net/browse/"
//Create a ScatterplotRenderer
const scatterplotRenderer = new ScatterplotRenderer(leadTimeDataSet, ticketUrlBase);
const scatterplotRenderer = new ScatterplotRenderer(leadTimeDataSet);
//Pass the created event bus to teh cfd graph
scatterplotRenderer.useEventBus(eventBus);
//Create a HistogramRenderer
Expand All @@ -68,7 +70,7 @@ function renderGraphs(data) {
scatterplotRenderer.drawGraph(scatterplotGraphElementSelector);
document.querySelector(histogramGraphElementSelector) && histogramRenderer.drawGraph(histogramGraphElementSelector);
document.querySelector(scatterplotBrushElementSelector) && scatterplotRenderer.useBrush(scatterplotBrushElementSelector);
document.querySelector(scatterplotUIControlsElementSelector) &&
document.querySelector(controlsElementSelector) &&
scatterplotRenderer.useControls("#reporting-range-input", "#range-increments-select");
document.querySelector(loadConfigInputSelector) &&
scatterplotRenderer.useConfigLoading(loadConfigInputSelector, resetConfigInputSelector);
Expand All @@ -77,4 +79,47 @@ function renderGraphs(data) {
histogramRenderer.clearGraph(histogramGraphElementSelector);
}
}
}
await useObservationLogging(scatterplotRenderer, cfdRenderer, serviceId);
}

async function useObservationLogging(scatterplotRenderer, cfdRenderer, serviceId) {
const observationLoggingServiceURL = "#";
const workTicketsURL = "#";
const observationLoggingService = new ObservationLoggingService(observationLoggingServiceURL, serviceId);
await observationLoggingService.loadObservations();
scatterplotRenderer.useObservationLogging(observationLoggingService.observationsByService, workTicketsURL);
cfdRenderer.useObservationLogging(observationLoggingService.observationsByService);

eventBus.addEventListener("scatterplot-click", (event) => {
initializeForm({...event, chartType: "SCATTERPLOT", serviceId});
toggleRightSidebar(true);
});

eventBus.addEventListener("cfd-click", (event) => {
initializeForm({...event, chartType: "CFD", serviceId});
toggleRightSidebar(true);
});

eventBus.addEventListener("submit-observation-form", async (observation) => {
let observationResponse;
const observationId = observation.data.observation_id;
delete observation.data.observation_id;
if (observationId) {
observationResponse = await observationLoggingService.updateObservation(observation, observationId);
} else {
observationResponse = await observationLoggingService.addObservation(observation);
}
if (observationResponse) {
console.log(observationResponse);
toggleRightSidebar(false);
if (observation.data.chart_type === "SCATTERPLOT") {
scatterplotRenderer.hideTooltip();
scatterplotRenderer.markObservations(observationLoggingService.observationsByService);
}
if (observation.data.chart_type === "CFD") {
cfdRenderer.hideTooltip();
cfdRenderer.markObservations(observationLoggingService.observationsByService);
}
}
});
}
7 changes: 7 additions & 0 deletions examples/images/double-left-arrowhead.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions examples/images/double-right-arrowhead.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9b72652

Please sign in to comment.