// ==UserScript==
// @name ADS changeset comment search
-// @version 0.2
+// @version 0.3
// @description Places a searchbox somewhere to search commit messages
// @author Tobias Sachs
// @match https://ads/*
-// @grant none
+// @grant GM_addStyle
// @updateURL https://src.twobees.de/?p=tampermonkeyscripts.git;a=blob_plain;f=AzureDevOpsChangesetCommentSearch.js;hb=HEAD
// @downloadURL https://src.twobees.de/?p=tampermonkeyscripts.git;a=blob_plain;f=AzureDevOpsChangesetCommentSearch.js;hb=HEAD
// ==/UserScript==
+// 0.3: - fix abort search
+// - filter reuslts by committers name
+// - no need for an observer
+// - use GM_addStyle to improve readability
+// - "Escape" stops search and removes resultstab
+
/* jshint esversion:6 */
(function() {
'use strict';
- let timerId;
- let timerSuche;
- let pollUrl = 'https://ads/HeBa/Entwicklung/_apis/tfvc/changesets?$top=1000?maxCommentLength=500';
+
+ let searchDelayTimerId;
+ let pollUrl = 'https://ads/HeBa/Entwicklung/_apis/tfvc/changesets?maxCommentLength=500?$top=1000?searchCriteria.itemPath=$/Entwicklung/HEAD';
let skipParm = '&$skip=';
let changeSetUrl = `/HeBa/Entwicklung/_versionControl/changeset/`;
let totalReceived = 0;
let matchesFound = 0;
+ let searchTerm = "";
+
+ GM_addStyle(`#ts_cs_search {
+ display: block;
+ background: white;
+ position: absolute;
+ left: 450px;
+ top: 0px;
+ height: auto;
+ z-index: 9999;
+ }`);
+ GM_addStyle(`.ts_match {
+ background: orange;
+ }`);
+ GM_addStyle(`.ts_found {
+ padding: 2px;
+ }`);
+ GM_addStyle(`.ts_found a {
+ text-decoration: none;
+ }`);
+ GM_addStyle(`#ts_searchResults{
+ max-height: 500px;
+ background:#CCCCCC;
+ overflow: auto;
+ }`);
+
+ let searchDelayed = function(){
+ if (searchDelayTimerId) {
+ clearTimeout(searchDelayTimerId);
+ }
+
+ searchDelayTimerId = setTimeout(
+ () => {
+ searchDelayTimerId = undefined;
+ startSearching();
+ },
+ 200);
+ };
- let suchWasDelayed = function(){
- if (timerSuche) {
- clearTimeout(timerSuche);
+ let pressEscapeToAbort = function(e) {
+ if (e.key == "Escape"){
+ document.getElementById('ts_searchBox').value = "";
+ startSearching(); // will abort search and clean results
}
- timerSuche = setTimeout( () =>
- {
- timerSuche = undefined;
- suchWas();
- }, 200);
};
- let requestNext = function(skipCnt){
+ let requestNext = function(skipCnt, currentSearch){
let xhr = new XMLHttpRequest();
- xhr.onload = () => searchItems(xhr);
+ xhr.onload = () => searchItems(xhr, currentSearch);
xhr.onerror = function (e){
console.warning(`poll error: ${e.type}: ${e.loaded} bytes transferred\n` + JSON.stringify(e));
};
xhr.send();
};
- let searchItems = function(xhr){
-
- console.info("Die daten sind da...");
+ let searchItems = function(xhr, searchStr){
if (xhr.status !== 200){
console.info("poll failed: " + xhr.statusText);
return;
}
- let s = document.getElementById('suchBox').value;
- let resultDiv = document.getElementById('suchErg');
- let statsSpan = document.getElementById('suchStats');
- var d = JSON.parse(xhr.responseText);
- var regex = new RegExp("("+s+")", 'gi');
- totalReceived += d.value.length;
- for (let e in d.value){
- let cs = d.value[e];
-
- if (cs.comment && regex.test(cs.comment)){
- matchesFound++;
- let comment = cs.comment.replace(regex, `<span style="background: orange;">$1</span>`);
- let item =
- `<div style='margin: 2px;' >`
- + `<a href='` + changeSetUrl
- + cs.changesetId + `'>` + cs.changesetId + '</a>'
- + ": " + comment + " (" + cs.author.displayName + ")"
- + `</div>`;
- resultDiv.innerHTML += item;
- }
- }
- statsSpan.innerHTML = "matches: " + matchesFound +" searched comments: " + totalReceived;
- if (d.value.length > 0)
+ if (searchStr !== searchTerm)
{
- requestNext(totalReceived);
- }
- else
- {
- statsSpan.innerHTML += " -- All comments searched.";
+ console.info("Searchterm changed while searching to " + searchTerm);
+ return;
}
- };
- let suchWas = function (){
- let s = document.getElementById('suchBox');
- let results = document.getElementById('suchErg');
- totalReceived = 0;
- matchesFound = 0;
- results.innerHTML = "";
- document.getElementById('suchStats').innerHTML = "";
- if (s.value.length < 3){
- return;
+ let sp = searchStr.split(/(von:|from:)/i);
+ let searchName = undefined;
+ let search = searchStr;
+ if (sp.length == 3){
+ search = sp[0].trim();
+ searchName = sp[2].trim();
}
- requestNext(0);
- };
+ let resultDiv = document.getElementById('ts_searchResults');
+ let statsSpan = document.getElementById('ts_searchStats');
- let addSearch = () => {
- if (timerId) {
- clearTimeout(timerId);
+ var d = JSON.parse(xhr.responseText);
+ let regex = undefined;
+ let regexAuthor = undefined;
+ if (search){
+ regex = new RegExp("("+search+")", 'gi');
}
- observer.disconnect();
-
- timerId = setTimeout(function() {
- timerId = undefined;
- if (window.location.href.includes("_apis")){
- return;
+ if (searchName){
+ regexAuthor = new RegExp("("+searchName+")", 'i');
+ }
+ totalReceived += d.value.length;
+ for (let e in d.value){
+ let cs = d.value[e];
+ if (regex !== undefined && regexAuthor !== undefined)
+ {
+ if (!(cs.comment && regex.test(cs.comment) && regexAuthor.test(cs.author.displayName)))
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if ((
+ (cs.comment && regex !== undefined && regex.test(cs.comment))
+ || (regexAuthor !== undefined && regexAuthor.test(cs.author.displayName))
+ ) == false){
+ continue;
+ }
}
- if (window.location.href.includes("_sprints")){
- // macht sonst irgendwie das man im sprintboard nix anklicken kann ¯\_(ツ)_/¯
- return;
+ matchesFound++;
+ let comment;
+ let author;
+ if (regex){
+ comment = cs.comment.replace(regex, `<span class="ts_match">$1</span>`);
}
- let search = document.getElementById('supersearch');
- if (!search){
- let html = `<div id="supersearch" style="display: block;position: absolute; left: 450px; top: 0px; height: auto; z-index: 9999;" >
- <input id="suchBox" placeholder="search commit" />
- <span id="suchStats"> </span>
- <div id="suchErg" style="max-height: 500px; background:#CCCCCC; overflow: auto;" ></div>
- </div>`;
-
- document.body.insertAdjacentHTML('afterbegin', html);
- let s = document.getElementById('suchBox');
- s.addEventListener("keyup", suchWasDelayed);
+ else
+ {
+ comment = cs.comment;
+ }
+ if (regexAuthor){
+ author = cs.author.displayName.replace(regexAuthor, `<span class="ts_match">$1</span>`);
+ }
+ else{
+ author = cs.author.displayName;
}
- // keep watching for changes
- observer.observe(document, { subtree: true, childList: true, characterData: true });
- }, 500);
- };
- const observer = new MutationObserver(function() {
- addSearch();
- });
+ let item = `<div class='ts_found'>
+ <a href='${changeSetUrl}${cs.changesetId}'>
+ ${cs.changesetId}: ${comment} (${author})
+ </a>
+ </div>`;
+ resultDiv.innerHTML += item;
+ }
+ statsSpan.innerHTML = "matches: " + matchesFound +" searched comments: " + totalReceived;
+ if (d.value.length <= 0)
+ {
+ statsSpan.innerHTML += " -- search done.";
+ return;
+ }
+
+ requestNext(totalReceived, searchStr);
+};
+
+ let startSearching = function (){
+ searchTerm = document.getElementById('ts_searchBox').value;
+ let results = document.getElementById('ts_searchResults');
+ totalReceived = 0;
+ matchesFound = 0;
+ results.innerHTML = "";
+ document.getElementById('ts_searchStats').innerHTML = "";
+
+ if (searchTerm.length < 3){ return; }
+
+ console.debug("new search term: '" + searchTerm+"'");
+ requestNext(0, searchTerm);
+};
+
+let addSearch = () => {
+ if (window.location.href.includes("_apis")){ return; }
+
+ let search = document.getElementById('ts_cs_search');
+ if (search){ return; }
+
+ console.debug("adding searchbox");
+ let html = `<div id="ts_cs_search">
+ <input id="ts_searchBox" width="120" placeholder="searchstring [von:Name]" />
+ <span id="ts_searchStats"></span>
+ <div id="ts_searchResults"></div>
+ </div>`;
+
+ document.body.insertAdjacentHTML('afterbegin', html);
+ let s = document.getElementById('ts_searchBox');
+ s.addEventListener("keyup", searchDelayed);
+ document.body.addEventListener("keyup", pressEscapeToAbort);
- addSearch();
+ };
+addSearch();
})();