|
1 | 1 | // ==UserScript==
|
2 | 2 |
|
3 | 3 | // @name More Awesome Azure DevOps (userscript)
|
4 |
| -// @version 3.5.1 |
| 4 | +// @version 3.5.2 |
5 | 5 | // @author Alejandro Barreto (NI)
|
6 | 6 | // @description Makes general improvements to the Azure DevOps experience, particularly around pull requests. Also contains workflow improvements for NI engineers.
|
7 | 7 | // @license MIT
|
|
283 | 283 | cursor: not-allowed;
|
284 | 284 | color: #b1b1b1;
|
285 | 285 | }
|
| 286 | + .agent-name-span { |
| 287 | + width: calc(100% - 60px); |
| 288 | + } |
| 289 | + .capabilities-holder { |
| 290 | + font-size: 20px; |
| 291 | + text-align: left; |
| 292 | + width: 40px; |
| 293 | + margin-right: 20px; |
| 294 | + overflow: hidden; |
| 295 | + text-overflow: ellipsis; |
| 296 | + } |
| 297 | +
|
286 | 298 | `);
|
287 | 299 |
|
288 | 300 | session.onEveryNew(document, '.pipelines-pool-agents.page-content.page-content-top', agentsTable => {
|
|
389 | 401 | regexFilter = new RegExp(regexFilterString, 'i');
|
390 | 402 | } catch (e) {
|
391 | 403 | showAllAgents(e);
|
392 |
| - filterAgents.running = false; |
393 | 404 | return;
|
394 | 405 | }
|
395 | 406 | document.getElementById('agentFilterCounter').innerText = 'Filtering...';
|
|
404 | 415 | error(e);
|
405 | 416 | }
|
406 | 417 |
|
407 |
| - let totalCount = 0; |
408 |
| - let matchedCount = 0; |
409 | 418 | const agentRows = document.querySelectorAll('a.bolt-list-row.single-click-activation');
|
| 419 | + const totalCount = agentRows.length; |
410 | 420 |
|
411 | 421 | const poolName = Array.from(document.querySelectorAll('div.bolt-breadcrumb-item-text-container')).pop().innerText;
|
412 | 422 | const currentPoolId = await fetchJsonAndCache(
|
|
419 | 429 |
|
420 | 430 | const poolAgentsInfo = await fetchJsonAndCache(
|
421 | 431 | `azdoPool${poolName}IdAgents`,
|
422 |
| - 5, |
| 432 | + 6, |
423 | 433 | `${azdoApiBaseUrl}/_apis/distributedtask/pools/${currentPoolId}/agents?includeCapabilities=True&propertyFilters=*`,
|
424 | 434 | 2,
|
425 | 435 | poolAgentsInfoWithCapabilities => {
|
|
428 | 438 | filteredAgentInfo[agentInfo.name] = {
|
429 | 439 | id: agentInfo.id,
|
430 | 440 | userCapabilities: agentInfo.userCapabilities,
|
| 441 | + participatesInRelease: agentInfo.systemCapabilities.PARTICIPATES_IN_RELEASE, |
431 | 442 | properties: agentInfo.properties,
|
432 | 443 | };
|
433 | 444 | });
|
|
436 | 447 | );
|
437 | 448 |
|
438 | 449 | try {
|
439 |
| - agentRows.forEach(agentRow => { |
440 |
| - totalCount += 1; |
441 |
| - agentRow.classList.remove('hiddenAgentRow'); |
442 |
| - agentRow.classList.remove('visibleAgentRow'); |
| 450 | + $('.hiddenAgentRow').show(); |
| 451 | + $(agentRows).find('.disable-reason').remove(); |
| 452 | + $(agentRows).find('.capabilities-holder').remove(); |
443 | 453 |
|
444 |
| - if (atNI) { |
445 |
| - addAgentDisableReason(agentRow, currentPoolId, poolAgentsInfo); |
446 |
| - addAgentArbitrationInformation(agentRow, currentPoolId, poolAgentsInfo); |
447 |
| - } |
| 454 | + const matchedAgents = {}; |
| 455 | + agentRows.forEach(agentRow => { |
| 456 | + const agentCells = agentRow.querySelectorAll('div'); |
| 457 | + const agentName = agentCells[1].innerText; |
| 458 | + const disableReason = (poolAgentsInfo[agentName].userCapabilities || {}).DISABLE_REASON || null; |
448 | 459 |
|
449 |
| - const rowValue = agentRow.textContent.replace(/[\r\n]/g, '').trim(); |
| 460 | + const rowValue = agentRow.textContent.replace(/[\r\n]/g, '').trim() + disableReason; |
450 | 461 | if (!regexFilter.test(rowValue)) {
|
451 | 462 | agentRow.classList.add('hiddenAgentRow');
|
452 | 463 | } else {
|
453 |
| - matchedCount += 1; |
454 |
| - agentRow.classList.add('visibleAgentRow'); |
| 464 | + agentCells[1].querySelectorAll('span')[0].classList.add('agent-name-span'); |
| 465 | + agentRow.classList.remove('hiddenAgentRow'); |
| 466 | + if (atNI) { |
| 467 | + matchedAgents[agentName] = agentCells; |
| 468 | + } |
455 | 469 | }
|
456 | 470 | });
|
457 |
| - $('.visibleAgentRow').show(); |
458 | 471 | $('.hiddenAgentRow').hide();
|
459 |
| - document.getElementById('agentFilterCounter').innerText = `(${matchedCount}/${totalCount})`; |
| 472 | + |
| 473 | + for (const [agentName, agentCells] of Object.entries(matchedAgents)) { |
| 474 | + addAgentExtraInformation(agentCells, agentName, currentPoolId, poolAgentsInfo); |
| 475 | + } |
| 476 | + document.getElementById('agentFilterCounter').innerText = `(${Object.keys(matchedAgents).length}/${totalCount})`; |
460 | 477 | } catch (e) {
|
461 | 478 | showAllAgents(e);
|
| 479 | + return; |
462 | 480 | }
|
| 481 | + exitFilterAgents(); |
| 482 | + } |
463 | 483 |
|
| 484 | + function exitFilterAgents() { |
| 485 | + document.getElementById('agentFilterInput').readOnly = false; |
464 | 486 | filterAgents.running = false;
|
465 | 487 | filterAgents.enter = false;
|
466 |
| - document.getElementById('agentFilterInput').readOnly = false; |
467 |
| - } |
468 |
| - |
469 |
| - function addAgentArbitrationInformation(agentRow, currentPoolId, poolAgentsInfo) { |
470 |
| - $(agentRow).find('.arbiter').remove(); |
471 |
| - |
472 |
| - if (document.body.classList.contains('agent-arbitration-status-off')) return; |
473 |
| - |
474 |
| - const agentCells = agentRow.querySelectorAll('div'); |
475 |
| - const agentName = agentCells[1].innerText; |
476 |
| - const agentInfo = poolAgentsInfo[agentName]; |
477 |
| - |
478 |
| - if (agentInfo.properties && Object.prototype.hasOwnProperty.call(agentInfo.properties, 'under_arbitration')) { |
479 |
| - const underArbitration = agentInfo.properties.under_arbitration.$value.toLowerCase() === 'true'; |
480 |
| - const iconType = underArbitration ? 'CirclePause' : 'Airplane'; |
481 |
| - |
482 |
| - const arbitrationIcon = document.createElement('span'); |
483 |
| - arbitrationIcon.className = `arbiter fabric-icon ms-Icon--${iconType}`; |
484 |
| - arbitrationIcon.title = underArbitration ? 'Arbitration Started: ' : 'Last Arbitration: '; |
485 |
| - arbitrationIcon.title += new Date(agentInfo.properties.arbitration_start.$value * 1000); |
486 |
| - arbitrationIcon.style = 'padding-right: 5px'; |
487 |
| - |
488 |
| - agentCells[2].prepend(arbitrationIcon); |
489 |
| - } |
490 | 488 | }
|
491 | 489 |
|
492 |
| - function addAgentDisableReason(agentRow, currentPoolId, poolAgentsInfo) { |
493 |
| - const agentCells = agentRow.querySelectorAll('div'); |
494 |
| - const agentName = agentCells[1].innerText; |
| 490 | + function addAgentExtraInformation(agentCells, agentName, currentPoolId, poolAgentsInfo) { |
495 | 491 | const agentInfo = poolAgentsInfo[agentName];
|
496 | 492 |
|
497 |
| - $(agentRow).find('.disable-reason').remove(); |
498 | 493 | if (agentInfo.userCapabilities) {
|
499 | 494 | const disableReason = agentInfo.userCapabilities.DISABLE_REASON || null;
|
500 | 495 | if (disableReason) {
|
|
521 | 516 | $(agentCells[5]).prepend(disableReasonMessage);
|
522 | 517 | }
|
523 | 518 | }
|
| 519 | + |
| 520 | + const capabilitiesHolder = document.createElement('div'); |
| 521 | + capabilitiesHolder.className = 'capabilities-holder'; |
| 522 | + |
| 523 | + const participatesInRelease = agentInfo.participatesInRelease || null; |
| 524 | + if (participatesInRelease === '1') { |
| 525 | + const participatesInReleaseElement = document.createElement('span'); |
| 526 | + participatesInReleaseElement.className = 'capability-icon release-machine fabric-icon ms-Icon--Rocket'; |
| 527 | + participatesInReleaseElement.title = 'PARTICIPATES_IN_RELEASE'; |
| 528 | + capabilitiesHolder.append(participatesInReleaseElement); |
| 529 | + } |
| 530 | + |
| 531 | + if (!document.body.classList.contains('agent-arbitration-status-off')) { |
| 532 | + if (agentInfo.properties && Object.prototype.hasOwnProperty.call(agentInfo.properties, 'under_arbitration')) { |
| 533 | + const underArbitration = agentInfo.properties.under_arbitration.$value.toLowerCase() === 'true'; |
| 534 | + const iconType = underArbitration ? 'CirclePause' : 'Airplane'; |
| 535 | + |
| 536 | + const arbitrationIcon = document.createElement('span'); |
| 537 | + arbitrationIcon.className = `capability-icon arbiter fabric-icon ms-Icon--${iconType}`; |
| 538 | + arbitrationIcon.title = underArbitration ? 'Arbitration Started: ' : 'Last Arbitration: '; |
| 539 | + arbitrationIcon.title += new Date(agentInfo.properties.arbitration_start.$value * 1000); |
| 540 | + |
| 541 | + capabilitiesHolder.append(arbitrationIcon); |
| 542 | + } |
| 543 | + } |
| 544 | + |
| 545 | + agentCells[1].append(capabilitiesHolder); |
524 | 546 | }
|
525 | 547 |
|
526 | 548 | function showAllAgents(searchError) {
|
527 | 549 | if (searchError) {
|
528 | 550 | document.getElementById('agentFilterCounter').innerText = searchError;
|
529 | 551 | }
|
530 |
| - document.querySelectorAll('a.bolt-list-row.single-click-activation').forEach(agentRow => { |
531 |
| - $(agentRow).show(); |
532 |
| - }); |
533 |
| - document.getElementById('agentFilterRefresh').disabled = false; |
| 552 | + $('.hiddenAgentRow').show(); |
| 553 | + $('.hiddenAgentRow').removeClass('hiddenAgentRow'); |
| 554 | + exitFilterAgents(); |
534 | 555 | }
|
535 | 556 |
|
536 | 557 | async function watchForReviewerList(session) {
|
|
0 commit comments