go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/frontend/static/common/js/console.js (about) 1 // Copyright 2019 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Functions for rendering the Milo console. 16 // Requires: jquery 17 // 18 19 $(function () { 20 'use strict'; 21 22 // Figure out the number of rows, which is equal to the number of commits. 23 const numRows = $('.console-commit-item').length; 24 25 /** 26 * Resizes commit cells when the window resizes. 27 * 28 * In the expanded view, the width is set by the browser window size. 29 * When the window sizes changes, it changes the height of all the cells 30 * because the cells contains elements that flow left to right. 31 * Because the commit description on the left size are disjoint from 32 * the cells, the height of the commit descriptions need to be updated. 33 */ 34 function resizeHeight() { 35 if ($('#console-page').hasClass('collapsed')) { 36 return; // Don't do anything in collapsed mode. 37 } 38 // Find the row height using the first console-cell-container of 39 // each console-leaf-category. 40 var rowHeight = 200; // Minimum height. 41 // Find the max height of each of the leaf category rows. 42 $('.console-leaf-category').each(function() { 43 const thisContainer = $('.console-build-column-stacked .console-cell-container-inner').first(); 44 const thisHeight = thisContainer.height(); 45 if (thisHeight > rowHeight) rowHeight = thisHeight; 46 }); 47 48 // Now set all cells to be the same height, as well as commit descriptions; 49 $('.console-cell-container').height(rowHeight); 50 $('.console-commit-item').each(function() { 51 $(this).height(rowHeight - 1); // 1px for the border. 52 const desc = $(this).find('.console-commit-description').first(); 53 const text = desc.find('p').first(); 54 const isClipped = desc.height() < text.height(); 55 // Add a class if the commit description is clipped, 56 // so that we can render a fadeout. 57 $(this).toggleClass('bottom-hidden', isClipped); 58 }); 59 60 // Also set the width of the horizontal cell separator. 61 var width = 0; 62 $('#console>.console-column').each(function() {width += $(this).width();}); 63 $('.console-commit-item-overlay').width(width); 64 } 65 66 /** 67 /* Given a leaf category as a jQuery element, return the matrix of cells. 68 * 69 * @param {.console-leaf-category node} category A jQuery node containing 70 * a leaf ctegory. 71 * 72 * @returns {object} A data object, containing 'rows' and 'spaces'. 73 * rows is a matrix of cells, which are <a> nodes coorisponding to a commit 74 * and builder. 75 * spaces is the number of spaces needed to pad the top of the column. 76 */ 77 function getLeafCategoryData(category) { 78 // The data source. Each column represents a single builder. 79 const builders = category.find('.console-builder-column'); 80 81 // Use the first column to find out the number of console spaces. 82 // This is used to pad empty space in the categories. 83 const spaces = builders.first().find('.console-space').length; 84 85 // Contains a matrix of cells. 86 // Used to contain the actual bubbles. 87 const rows = []; 88 for (let i = 0; i < numRows; i++) { 89 rows.push([]); 90 } 91 92 // Gather the bubbles, populate the matrix. 93 builders.each(function() { 94 $(this).find('.console-cell-container').each(function(i) { 95 rows[i].push($(this).find('a').first()); 96 }); 97 }); 98 99 return { 100 rows: rows, 101 spaces: spaces 102 }; 103 } 104 105 /** 106 * Builds a leaf column from a matrix of rows. 107 * 108 * @param {object} data An object containing rows and spaces. 109 * 110 * @return {node} A console-builder-column to be appened under the leaf category. 111 */ 112 function newLeafColumn(data) { 113 // Create a new column for the leaf category. 114 const newBuilderColumn = $(document.createElement('div')); 115 newBuilderColumn.addClass('console-builder-column'); 116 newBuilderColumn.addClass('stacked'); 117 for (let i = 0; i < data.spaces; i++) { 118 // Pad the header with spaces. 119 newBuilderColumn.append('<div class="console-space"></div>'); 120 } 121 const newColumn = $(document.createElement('div')); 122 newColumn.addClass('console-build-column-stacked') 123 newBuilderColumn.append(newColumn); 124 125 // Populate each row. 126 for (const row of data.rows) { 127 const newContainer = $(document.createElement('div')); 128 newContainer.addClass('console-cell-container'); 129 newColumn.append(newContainer); 130 // We need an inner container to calculate height. 131 const newInnerContainer = $(document.createElement('div')) 132 newInnerContainer.addClass('console-cell-container-inner'); 133 newContainer.append(newInnerContainer); 134 135 for (const item of row) { 136 newInnerContainer.append($(item).clone()); 137 } 138 } 139 return newBuilderColumn; 140 } 141 142 /** 143 * Overrides the default expand/collapse state of the console in the cookie. 144 * 145 * @param {bool} overrideDefault whether or not the user wants the default state. 146 * If default is expand, and the user requested expand, this should be false. 147 * If default is expand, and the user requested collapse, this should be true. 148 * If default is collapse, and the user requested expand, this should be true. 149 * If default is collapse, and the user requested collapse, this should be false. 150 */ 151 function setCookie(overrideDefault) { 152 if (overrideDefault) { 153 Cookies.set('non-default', 1, {path: ''}) 154 } else { 155 Cookies.remove('non-default', {path: ''}) 156 } 157 } 158 159 // Collapsed Mode -> Expanded Mode. 160 $('.control-expand').click(function(e) { 161 e.preventDefault(); 162 // Switch the top level class so that the expanded view nodes render. 163 // TODO(hinoka): Refactor CSS so that we only need the expanded class. 164 $('#console-page').removeClass('collapsed'); 165 $('#console-page').addClass('expanded'); 166 167 // Stack the console. 168 $('.console-leaf-category').each(function() { 169 const category = $(this); 170 const data = getLeafCategoryData(category); 171 const newColumn = newLeafColumn(data); 172 173 // Hide the original columns. 174 category.find('.console-builder-column').hide(); 175 // Stick the new column in the leaf. 176 category.append(newColumn); 177 }); 178 179 resizeHeight(); 180 $(window).resize(resizeHeight); 181 182 $('.console-builder-item').hide(); // Hide the builder boxes. 183 184 // Default expand, requested expand - False 185 // Default collapse, requested expand - True 186 setCookie(!defaultExpand); 187 }); 188 189 // Expanded Mode -> Collapsed Mode. 190 $('.control-collapse').click(function(e) { 191 e.preventDefault(); 192 $('#console-page').addClass('collapsed'); 193 $('#console-page').removeClass('expanded'); 194 195 $('.stacked').remove(); // Delete all of the expanded elements. 196 $('.console-builder-item').show(); // Show the builder boxes. 197 $('.console-builder-column').show(); // Show the collapsed console. 198 $('.console-cell-container').height('auto'); 199 $('.console-commit-item').height('auto'); 200 201 // Default expand, requested collapse - True 202 // Default expand, requested expand - False 203 setCookie(defaultExpand); 204 }); 205 206 // We click on expand if: 207 // Default is expand, and we don't see a cookie 208 // Default is collapse, and we do see a cookie 209 // Essentially we want to XOR the cookie bit with the default bit. 210 if (Cookies.get('non-default') ? !defaultExpand : defaultExpand) { 211 $('.control-expand').first().click(); 212 } 213 });