resources/perf.webkit.org/public/v3/pages/analysis-category-page.js (255 lines of code) (raw):

class AnalysisCategoryPage extends PageWithHeading { constructor() { super('Analysis'); this._categoryToolbar = this.content().querySelector('analysis-category-toolbar').component(); this._categoryToolbar.setCategoryPage(this); this._renderedList = false; this._renderedFilter = false; this._fetched = false; this._errorMessage = null; } title() { var category = this._categoryToolbar.currentCategory(); return (category ? category.charAt(0).toUpperCase() + category.slice(1) + ' ' : '') + 'Analysis Tasks'; } routeName() { return 'analysis'; } open(state) { var self = this; AnalysisTask.fetchAll().then(function () { self._fetched = true; self.enqueueToRender(); }, function (error) { self._errorMessage = 'Failed to fetch the list of analysis tasks: ' + error; self.enqueueToRender(); }); super.open(state); } serializeState() { return this.stateForCategory(this._categoryToolbar.currentCategory()); } stateForCategory(category) { var state = {category: category}; var filter = this._categoryToolbar.filter(); if (filter) state.filter = filter; return state; } updateFromSerializedState(state, isOpen) { if (state.category instanceof Set) state.category = Array.from(state.category.values())[0]; if (state.filter instanceof Set) state.filter = Array.from(state.filter.values())[0]; if (this._categoryToolbar.setCategoryIfValid(state.category)) this._renderedList = false; if (state.filter) this._categoryToolbar.setFilter(state.filter); if (!isOpen) this.enqueueToRender(); } filterDidChange(shouldUpdateState) { this.enqueueToRender(); if (shouldUpdateState) this.scheduleUrlStateUpdate(); } render() { Instrumentation.startMeasuringTime('AnalysisCategoryPage', 'render'); super.render(); this._categoryToolbar.enqueueToRender(); if (this._errorMessage) { console.assert(!this._fetched); var element = ComponentBase.createElement; this.renderReplace(this.content().querySelector('tbody.analysis-tasks'), element('tr', element('td', {colspan: 6}, this._errorMessage))); this._renderedList = true; return; } if (!this._fetched) return; if (!this._renderedList) { this._reconstructTaskList(); this._renderedList = true; } var filter = this._categoryToolbar.filter(); if (filter || this._renderedFilter) { Instrumentation.startMeasuringTime('AnalysisCategoryPage', 'filterByKeywords'); var keywordList = filter ? filter.toLowerCase().split(/\s+/) : []; var tableRows = this.content().querySelectorAll('tbody.analysis-tasks tr'); for (var i = 0; i < tableRows.length; i++) { var row = tableRows[i]; var textContent = row.textContent.toLowerCase(); var display = null; for (var keyword of keywordList) { if (textContent.indexOf(keyword) < 0) { display = 'none'; break; } } row.style.display = display; } this._renderedFilter = !!filter; Instrumentation.endMeasuringTime('AnalysisCategoryPage', 'filterByKeywords'); } Instrumentation.endMeasuringTime('AnalysisCategoryPage', 'render'); } _reconstructTaskList() { Instrumentation.startMeasuringTime('AnalysisCategoryPage', 'reconstructTaskList'); console.assert(this.router()); const currentCategory = this._categoryToolbar.currentCategory(); const tasks = AnalysisTask.all().filter((task) => task.category() == currentCategory).sort((a, b) => { if (a.hasPendingRequests() == b.hasPendingRequests()) return b.createdAt() - a.createdAt(); else if (a.hasPendingRequests()) // a < b return -1; else if (b.hasPendingRequests()) // a > b return 1; return 0; }); const element = ComponentBase.createElement; const link = ComponentBase.createLink; const router = this.router(); this.renderReplace(this.content().querySelector('tbody.analysis-tasks'), tasks.map((task) => { const status = AnalysisCategoryPage._computeStatus(task); return element('tr', [ element('td', {class: 'status'}, element('span', {class: status.class}, status.label)), element('td', link(task.label(), router.url(`analysis/task/${task.id()}`))), element('td', {class: 'bugs'}, element('ul', task.bugs().map((bug) => { const url = bug.url(); const title = bug.title(); return element('li', url ? link(bug.label(), title, url, true) : title); }))), element('td', {class: 'author'}, task.author()), element('td', {class: 'platform'}, task.platform() ? task.platform().label() : null), element('td', task.metric() ? task.metric().fullName() : null), ]); })); Instrumentation.endMeasuringTime('AnalysisCategoryPage', 'reconstructTaskList'); } static _computeStatus(task) { if (task.hasPendingRequests()) return {label: task.requestLabel(), class: 'bisecting'}; var type = task.changeType(); switch (type) { case 'regression': return {label: 'Regression', class: type}; case 'progression': return {label: 'Progression', class: type}; case 'unchanged': return {label: 'No change', class: type}; case 'inconclusive': return {label: 'Inconclusive', class: type}; } if (task.hasResults()) return {label: 'New results', class: 'bisecting'}; return {label: 'Unconfirmed', class: 'unconfirmed'}; } static htmlTemplate() { return ` <div class="toolbar-container"><analysis-category-toolbar></analysis-category-toolbar></div> <div class="analysis-task-category"> <table> <thead> <tr> <td class="status">Status</td> <td>Name</td> <td>Bugs</td> <td>Author</td> <td>Platform</td> <td>Test Metric</td> </tr> </thead> <tbody class="analysis-tasks"></tbody> </table> </div>`; } static cssTemplate() { return ` .toolbar-container { text-align: center; } .analysis-task-category { width: calc(100% - 2rem); margin: 1rem; } .analysis-task-category table { width: 100%; border: 0; border-collapse: collapse; } .analysis-task-category td, .analysis-task-category th { border: none; border-collapse: collapse; text-align: left; font-size: 0.9rem; font-weight: normal; } .analysis-task-category thead td { color: #f96; font-weight: inherit; font-size: 1.1rem; padding: 0.2rem 0.4rem; } .analysis-task-category tbody td { border-top: solid 1px #eee; border-bottom: solid 1px #eee; padding: 0.2rem 0.2rem; } .analysis-task-category .bugs ul, .analysis-task-category .bugs li { padding: 0; margin: 0; list-style: none; } .analysis-task-category .status, .analysis-task-category .author, .analysis-task-category .platform { text-align: center; } .analysis-task-category .status span { display: inline; white-space: nowrap; border-radius: 0.3rem; padding: 0.2rem 0.3rem; font-size: 0.8rem; } .analysis-task-category .status .regression { background: #c33; color: #fff; } .analysis-task-category .status .progression { background: #36f; color: #fff; } .analysis-task-category .status .unchanged { background: #ccc; color: white; } .analysis-task-category .status .inconclusive { background: #666; color: white; } .analysis-task-category .status .bisecting { background: #ff9; } .analysis-task-category .status .unconfirmed { background: #f96; } `; } }