Skip to content

Commit

Permalink
Merge pull request #24 from 360Learning/master-urgency-work
Browse files Browse the repository at this point in the history
feat: monitor work in urgency
  • Loading branch information
MartinBB360 authored Feb 26, 2024
2 parents b37f08c + bceba3a commit 663a309
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 0 deletions.
3 changes: 3 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ <h1>List of tools</h1>
<li>
<a href="trelloCommentsDashboard.html">Trello comments dashboard</a>
</li>
<li>
<a href="trelloEngWorkInUrgencyDashboard.html">Trello engineering work in urgency dashboard</a>
</li>
</ul>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions scripts/trello/lists.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
async function fetchCardsInList(listId, { trelloApiKey, trelloOAuth1 } = {}) {
return new TrelloClient({ trelloApiKey, trelloOAuth1 }).get(`lists/${listId}/cards`);
}

async function fetchList(listId, { trelloApiKey, trelloOAuth1 } = {}) {
return new TrelloClient({ trelloApiKey, trelloOAuth1 }).get(`lists/${listId}`);
}
90 changes: 90 additions & 0 deletions scripts/trelloEngWorkInUrgencyDashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const TRELLO_BASE_URL = "https://trello.com";
const TRELLO_CREDENTIALS_HELPER_FILE = "https://docs.google.com/document/d/1HwaedNa861gkj93TaradW5n0MID8cbeamiU5SXCvX64/edit#heading=h.ijjo2dol5z6v"

const LIST_IDS = [
"65d8c6c2bdf8fb6ece5c3288"
]

new Vue({
el: '#app',
data: {
options: {
quarter: "",
squad: ""
},
error: null,
loading: false,
trelloCredentialsHelperFile: TRELLO_CREDENTIALS_HELPER_FILE,
credentials: {
trelloApiKey: "",
trelloOAuth1: ""
},
urgencyCardsBySquadName: {},
squadNames: null,
listIdBySquadName: {},
reportBuilt: false,
reportBuildForAllSquads: false
},
computed: {
areCredentialsValid() {
return !! this.credentials.trelloApiKey && !! this.credentials.trelloOAuth1;
},
isAccessButtonDisabled() {
return ! this.areCredentialsValid || this.loading;
},
isSubmitButtonDisabled() {
return ! this.areCredentialsValid || this.loading || ! this.options.squad || ! this.options.quarter;
}
},
methods: {
async buildReport() {
this.resetReport();
this.error = null;
this.loading = true;
const selectedSquadNames = this.getSelectedSquadNames();
try {
for (const selectedSquadName of selectedSquadNames) {
await this.buildReportForSquad(selectedSquadName);
}
this.reportBuilt = true;
this.reportBuildForAllSquads = (this.options.squad === "*");
} catch (error) {
this.error = error.message;
} finally {
this.loading = false;
}
},
async buildReportForSquad(squadName) {
const listId = this.listIdBySquadName[squadName];
const cards = await fetchCardsInList(listId, this.credentials);
const filteredCards = cards.filter(card => ! card.isTemplate && card.labels.map(label => label.name).includes(this.options.quarter));
this.urgencyCardsBySquadName[squadName] = filteredCards.map(({name, url}) => ({ name, url }));
},
async fetchSquadNames() {
this.error = null;
this.loading = true;
try {
this.squadNames = await Promise.all(LIST_IDS.map(this.getSquadNameFromListId));
}
catch (error) {
this.error = error.message;
} finally {
this.loading = false;
}
},
getSelectedSquadNames() {
return this.options.squad === "*" ? this.squadNames : [this.options.squad];
},
async getSquadNameFromListId(listId) {
const list = await fetchList(listId, this.credentials);
const squadName = list.name.match(/[^[]+(?=\])/g).pop();
this.listIdBySquadName[squadName] = listId;
return squadName;
},
resetReport() {
this.reportBuilt = false;
this.reportBuildForAllSquads = false;
this.urgencyCardsBySquadName = {};
}
}
});
141 changes: 141 additions & 0 deletions trelloEngWorkInUrgencyDashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>360Tools - Trello engineering work in urgency dashboard</title>
<link rel="stylesheet" type="text/css" href="./style/style.css">
<style>
.direction-column {
flex-direction: column;
}
</style>
</head>
<body>
<div id="app">
<div id="header">
<div class="container">
<a id="logo" href="index.html">360Tools</a>
</div>
</div>
<div class="container">
<h1>Trello engineering work in urgency dashboard</h1>

<div class="element form">

Platform squads sometimes need to work in urgency a/o out of usual development process. 🏃 🚧
<br>This dashboard will help you to get some metrics about it.

<hr>

<br>To get started, get your <a target="_blank" :href="trelloCredentialsHelperFile">Trello API information</a> and make sure to have your API key and authentication token.

<hr>

<div class="form-wrapper direction-column">
<div class="form-field">
<label for="trelloApiKey" class="field-name">Trello API key:</label>
<input id="trelloApiKey" type="text" placeholder="1234abcd1234abcd1234abcd1234abcd" v-model="credentials.trelloApiKey">
</div>
<div class="form-field">
<label for="trelloOAuth1" class="field-name">Authentication token:</label>
<input id="trelloOAuth1" type="text" placeholder="1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd" v-model="credentials.trelloOAuth1">
</div>

<br>
<button
class="button wide"
:class="{ disabled: isAccessButtonDisabled }"
:disabled="isAccessButtonDisabled"
v-if="! squadNames"
@click="fetchSquadNames()"
>
<template v-if="loading">fetching squad names ...</template>
<template v-else>Access dashboard</template>
</button>
<br>

<div v-if="squadNames">

<h2>Settings</h2>

<div class="form-field">
<label for="quarter" class="field-name">Quarter</label>
<select name="quarters" v-model="options.quarter">
<option value="Q4 2023">Q4 2023</option>
<option value="Q1 2024">Q1 2024</option>
<option value="Q2 2024">Q2 2024</option>
<option value="Q3 2024">Q3 2024</option>
<option value="Q4 2024">Q4 2024</option>
<option value="Q1 2025">Q1 2025</option>
<option value="Q1 2025">Q2 2025</option>
<option value="Q1 2025">Q3 2025</option>
<option value="Q1 2025">Q4 2025</option>
</select>
</div>
<div class="form-field">
<label for="squad" class="field-name">Squad</label>
<select name="squads" v-model="options.squad">
<option value="*">All squads</option>
<option v-for="squadName in squadNames" :value="squadName">
{{ squadName }}
</option>
</select>
</div>

<br>
<button
class="button wide"
:class="{ disabled: isSubmitButtonDisabled }"
:disabled="isSubmitButtonDisabled"
@click="buildReport()"
>
<template v-if="loading">building report...</template>
<template v-else>Build report</template>
</button>
<br>
</div>
</div>

<template v-if="error">
An error occurred: <strong>{{ error }}</strong>
<br>
<template v-if="error.includes('401')">
The API Key or token you entered may be incorrect.
</template>
</template>

<template v-if="reportBuilt">
<h2>Report</h2>

<template v-if="reportBuildForAllSquads">
<h3>Total number of occurrences in {{ options.quarter }} : {{ Object.values(urgencyCardsBySquadName).flat().length }}</h3>
<hr>
</template>

<ul class="{ list-style-type: none }">
<li v-for="(urgencyCards, selectedSquadName) in urgencyCardsBySquadName" class="{ list-style-type: none }">
<details>
<summary>Squad {{ selectedSquadName }} in {{ options.quarter }} has {{ urgencyCards.length }} occurence{{ urgencyCards.length > 1 ? 's' : '' }}.</summary>
<br>
<ul>
<li v-for="urgencyCard in urgencyCards">
<a target="_blank" :href="urgencyCard.url">{{ urgencyCard.name }}</a>
</li>
</ul>
</details>
<br>
</li>
</ul>
</template>
</div>
<br>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="./scripts/trello/api.js"></script>
<script src="./scripts/trello/lists.js"></script>
<script src="./scripts/trelloEngWorkInUrgencyDashboard.js"></script>
</body>
</html>

0 comments on commit 663a309

Please sign in to comment.