| /** |
| * @fileoverview The bulk of the Chromium Analysis Runs History page. |
| */ |
| |
| import '../../../elements-sk/modules/icons/delete-icon-sk'; |
| import '../../../elements-sk/modules/icons/redo-icon-sk'; |
| import '../../../elements-sk/modules/icons/cancel-icon-sk'; |
| import '../../../elements-sk/modules/icons/check-circle-icon-sk'; |
| import '../../../elements-sk/modules/icons/help-icon-sk'; |
| import '../../../elements-sk/modules/icons/mode-edit-icon-sk'; |
| import '../../../elements-sk/modules/toast-sk'; |
| import '../pagination-sk'; |
| |
| import { html } from 'lit-html'; |
| import { $$, DomReady } from '../../../infra-sk/modules/dom'; |
| import { fromObject } from '../../../infra-sk/modules/query'; |
| import { jsonOrThrow } from '../../../infra-sk/modules/jsonOrThrow'; |
| import { define } from '../../../elements-sk/modules/define'; |
| import { errorMessage } from '../../../elements-sk/modules/errorMessage'; |
| |
| import { PaginationSk } from '../pagination-sk/pagination-sk'; |
| import { ElementSk } from '../../../infra-sk/modules/ElementSk'; |
| import { |
| getFormattedTimestamp, |
| getGSLink, |
| isEmptyPatch, |
| formatRepeatAfterDays, |
| } from '../ctfe_utils'; |
| import { |
| ResponsePagination, |
| ChromiumAnalysisDatastoreTask, |
| RedoTaskRequest, |
| DeleteTaskRequest, |
| GetTasksResponse, |
| } from '../json'; |
| |
| function hideDialog(e: Event) { |
| const classList = (e.target as HTMLElement).classList; |
| if (classList.contains('dialog-background')) { |
| classList.add('hidden'); |
| } |
| } |
| |
| export class ChromiumAnalysisRunsSk extends ElementSk { |
| private _tasks: ChromiumAnalysisDatastoreTask[] = []; |
| |
| private _constrainByUser = false; |
| |
| private _constrainByTest = true; |
| |
| private _running = false; |
| |
| private _pagination: ResponsePagination | null = null; |
| |
| constructor() { |
| super(ChromiumAnalysisRunsSk.template); |
| this._resetPagination(); |
| } |
| |
| private static template = (el: ChromiumAnalysisRunsSk) => html` |
| <div> |
| <h2>${el._constrainByUser ? 'My ' : ''}Chromium Analysis Runs</h2> |
| <pagination-sk |
| @page-changed=${(e: CustomEvent) => el._pageChanged(e)}></pagination-sk> |
| <br /> |
| <button id="userFilter" @click=${() => el._constrainRunsByUser()}> |
| ${el._constrainByUser ? "View Everyone's Runs" : 'View Only My Runs'} |
| </button> |
| <button id="testFilter" @click=${() => el._constrainRunsByTest()}> |
| ${el._constrainByTest ? 'Include Test Run' : 'Exclude Test Runs'} |
| </button> |
| |
| <br /> |
| <br /> |
| <table |
| class="surface-themes-sk secondary-links runssummary" |
| id="runssummary"> |
| <tr> |
| <th>Id</th> |
| <th>User</th> |
| <th>Timestamps</th> |
| <th>Task Config</th> |
| <th>Description</th> |
| <th>Results</th> |
| <th>Arguments</th> |
| <th>Patches</th> |
| <th>Task Repeats</th> |
| </tr> |
| ${el._tasks.map((task, index) => |
| ChromiumAnalysisRunsSk.taskRowTemplate(el, task, index) |
| )} |
| </table> |
| </div> |
| |
| ${el._tasks.map((task, index) => |
| ChromiumAnalysisRunsSk.taskDialogTemplate(task, index) |
| )} |
| <toast-sk id="confirm_toast" duration="5000"></toast-sk> |
| `; |
| |
| private static taskRowTemplate = ( |
| el: ChromiumAnalysisRunsSk, |
| task: ChromiumAnalysisDatastoreTask, |
| index: number |
| ) => html` <tr> |
| <!-- Id col --> |
| <td class="nowrap"> |
| ${task.raw_output |
| ? html`<a |
| href="${task.raw_output}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >${task.id}</a |
| >` |
| : html`<span>${task.id}</span>`} |
| <delete-icon-sk |
| title="Delete this task" |
| alt="Delete" |
| ?hidden=${!task.can_delete} |
| @click=${() => el._confirmDeleteTask(index)}></delete-icon-sk> |
| <redo-icon-sk |
| title="Redo this task" |
| alt="Redo" |
| ?hidden=${!task.can_redo} |
| @click=${() => el._confirmRedoTask(index)}></redo-icon-sk> |
| <mode-edit-icon-sk |
| title="Edit and redo this task" |
| alt="Edit" |
| @click=${() => el._confirmEditTask(index)}></mode-edit-icon-sk> |
| </td> |
| <!-- User col --> |
| <td>${task.username}</td> |
| <!-- Timestamps col --> |
| <td> |
| <table class="inner-table"> |
| <tr> |
| <td>Added:</td> |
| <td class="nowrap">${getFormattedTimestamp(task.ts_added)}</td> |
| </tr> |
| <tr> |
| <td>Started:</td> |
| <td class="nowrap">${getFormattedTimestamp(task.ts_started)}</td> |
| </tr> |
| <tr> |
| <td>Completed:</td> |
| <td class="nowrap">${getFormattedTimestamp(task.ts_completed)}</td> |
| </tr> |
| </table> |
| </td> |
| <!-- Task Config col --> |
| <td> |
| <table class="inner-table"> |
| <tr> |
| <td>Benchmark:</td> |
| <td>${task.benchmark}</td> |
| </tr> |
| <tr> |
| <td>Platform:</td> |
| <td>${task.platform}</td> |
| </tr> |
| <tr> |
| <td>RunOnGCE:</td> |
| <td>${task.run_on_gce}</td> |
| </tr> |
| <tr> |
| <td>PageSet:</td> |
| <td> |
| ${!isEmptyPatch(task.custom_webpages_gspath) |
| ? html`<a |
| href="${getGSLink(task.custom_webpages_gspath)}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >Custom Webpages</a |
| >` |
| : task.page_sets} |
| </td> |
| </tr> |
| <tr> |
| <td>ParallelRun:</td> |
| <td>${task.run_in_parallel}</td> |
| </tr> |
| ${task.value_column_name |
| ? html`<tr> |
| <td class="nowrap">Value Column:</td> |
| <td class="nowrap">${task.value_column_name}</td> |
| </tr>` |
| : ''} |
| ${task.task_priority |
| ? html`<tr> |
| <td>TaskPriority:</td> |
| <td>${task.task_priority}</td> |
| </tr>` |
| : ''} |
| ${task.cc_list |
| ? html`<tr> |
| <td>CC List:</td> |
| <td>${task.cc_list}</td> |
| </tr>` |
| : ''} |
| ${task.group_name |
| ? html`<tr> |
| <td>GroupName:</td> |
| <td> |
| <a href="https://ct-perf.skia.org/e/?request_type=1" |
| >${task.group_name}</a |
| > |
| </td> |
| </tr>` |
| : ''} |
| ${task.chromium_hash |
| ? html`<tr> |
| <td>ChromiumHash:</td> |
| <td> |
| <a |
| href="https://chromium.googlesource.com/chromium/src/+show/${task.chromium_hash}" |
| >${task.chromium_hash}</a |
| > |
| </td> |
| </tr>` |
| : ''} |
| ${task.apk_gspath |
| ? html`<tr> |
| <td>ApkGsPath:</td> |
| <td> |
| <a |
| href="javascript:;" |
| class="details" |
| @click=${() => el._showDialog('apkGsPath', index)}> |
| Display Path |
| </a> |
| </td> |
| </tr>` |
| : ''} |
| ${task.chrome_build_gs_path |
| ? html`<tr> |
| <td>ChromeBuildGsPath:</td> |
| <td> |
| <a |
| href="javascript:;" |
| class="details" |
| @click=${() => el._showDialog('chromeBuildGsPath', index)}> |
| Display Path |
| </a> |
| </td> |
| </tr>` |
| : ''} |
| ${task.telemetry_isolate_hash |
| ? html`<tr> |
| <td>TelemetryCASHash:</td> |
| <td> |
| <a |
| href="https://cas-viewer.appspot.com/projects/chrome-swarming/instances/default_instance/blobs/${task.telemetry_isolate_hash}/tree" |
| >${task.telemetry_isolate_hash}</a |
| > |
| </td> |
| </tr>` |
| : ''} |
| </table> |
| </td> |
| |
| <!-- Description col --> |
| <td>${task.description}</td> |
| |
| <!-- Results col --> |
| <td class="nowrap"> |
| ${task.failure ? html`<div class="error">Failed</div>` : ''} |
| ${!task.task_done ? html`<div class="green">Waiting</div>` : ''} |
| ${task.raw_output |
| ? html`<a |
| href="${task.raw_output}" |
| target="_blank" |
| rel="noopener noreferrer"> |
| Output |
| </a>` |
| : ''} |
| ${task.swarming_logs |
| ? html`<br /> |
| <a |
| href="${task.swarming_logs}" |
| target="_blank" |
| rel="noopener noreferrer"> |
| Swarming Logs |
| </a>` |
| : ''} |
| </td> |
| |
| <!-- Arguments --> |
| <td class="nowrap"> |
| ${task.gn_args |
| ? html`<a |
| href="javascript:;" |
| class="details" |
| @click=${() => el._showDialog('gnArgs', index)}> |
| GN Args |
| </a> |
| <br />` |
| : ''} |
| ${task.benchmark_args |
| ? html`<a |
| href="javascript:;" |
| class="details" |
| @click=${() => el._showDialog('benchmarkArgs', index)}> |
| Benchmark Args |
| </a> |
| <br />` |
| : ''} |
| ${task.browser_args |
| ? html`<a |
| href="javascript:;" |
| class="details" |
| @click=${() => el._showDialog('browserArgs', index)}> |
| Browser Args |
| </a> |
| <br />` |
| : ''} |
| ${task.match_stdout_txt |
| ? html`<a |
| href="javascript:;" |
| class="details" |
| @click=${() => el._showDialog('matchStdoutTxt', index)}> |
| Match Stdout Text |
| </a> |
| <br />` |
| : ''} |
| </td> |
| |
| <!-- Patches --> |
| <td> |
| ${!isEmptyPatch(task.chromium_patch_gspath) |
| ? html`<a |
| href="${getGSLink(task.chromium_patch_gspath)}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >Chromium</a |
| > |
| <br /> ` |
| : ''} |
| ${!isEmptyPatch(task.skia_patch_gspath) |
| ? html`<a |
| href="${getGSLink(task.skia_patch_gspath)}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >Skia</a |
| > |
| <br /> ` |
| : ''} |
| ${!isEmptyPatch(task.v8_patch_gspath) |
| ? html`<a |
| href="${getGSLink(task.v8_patch_gspath)}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >V8</a |
| > |
| <br /> ` |
| : ''} |
| ${!isEmptyPatch(task.catapult_patch_gspath) |
| ? html`<a |
| href="${getGSLink(task.catapult_patch_gspath)}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >Catapult</a |
| > |
| <br /> ` |
| : ''} |
| ${!isEmptyPatch(task.benchmark_patch_gspath) |
| ? html`<a |
| href="${getGSLink(task.benchmark_patch_gspath)}" |
| target="_blank" |
| rel="noopener noreferrer" |
| >Telemetry</a |
| > |
| <br /> ` |
| : ''} |
| </td> |
| |
| <!-- Task Repeats --> |
| <td>${formatRepeatAfterDays(task.repeat_after_days)}</td> |
| </tr>`; |
| |
| private static taskDialogTemplate = ( |
| task: ChromiumAnalysisDatastoreTask, |
| index: number |
| ) => html` |
| <div |
| id=${`gnArgs${index}`} |
| class="dialog-background hidden overlay-themes-sk" |
| @click=${hideDialog}> |
| <div class="dialog-content surface-themes-sk"> |
| <pre>${task.gn_args}</pre> |
| </div> |
| </div> |
| <div |
| id=${`benchmarkArgs${index}`} |
| class="dialog-background hidden overlay-themes-sk" |
| @click=${hideDialog}> |
| <div class="dialog-content surface-themes-sk"> |
| <pre>${task.benchmark_args}</pre> |
| </div> |
| </div> |
| <div |
| id=${`browserArgs${index}`} |
| class="dialog-background hidden overlay-themes-sk" |
| @click=${hideDialog}> |
| <div class="dialog-content surface-themes-sk"> |
| <pre>${task.browser_args}</pre> |
| </div> |
| </div> |
| <div |
| id=${`matchStdoutTxt${index}`} |
| class="dialog-background hidden overlay-themes-sk" |
| @click=${hideDialog}> |
| <div class="dialog-content surface-themes-sk"> |
| <pre>${task.match_stdout_txt}</pre> |
| </div> |
| </div> |
| <div |
| id=${`apkGsPath${index}`} |
| class="dialog-background hidden overlay-themes-sk" |
| @click=${hideDialog}> |
| <div class="dialog-content surface-themes-sk"> |
| <pre>${task.apk_gspath}</pre> |
| </div> |
| </div> |
| <div |
| id=${`chromeBuildGsPath${index}`} |
| class="dialog-background hidden overlay-themes-sk" |
| @click=${hideDialog}> |
| <div class="dialog-content surface-themes-sk"> |
| <pre>${task.chrome_build_gs_path}</pre> |
| </div> |
| </div> |
| `; |
| |
| connectedCallback(): void { |
| super.connectedCallback(); |
| if (this._running) { |
| return; |
| } |
| this._running = true; |
| // We wait for everything to load so scaffolding event handlers are |
| // attached. |
| DomReady.then(() => { |
| this._render(); |
| this._reload().then(() => { |
| this._running = false; |
| }); |
| }); |
| } |
| |
| _showDialog(type: string, index: number): void { |
| $$(`#${type}${index}`, this)!.classList.remove('hidden'); |
| } |
| |
| _pageChanged(e: CustomEvent): void { |
| this._pagination!.offset = e.detail.offset; |
| this._reload(); |
| } |
| |
| _reload(): Promise<void> { |
| this.dispatchEvent(new CustomEvent('begin-task', { bubbles: true })); |
| this._tasks = []; |
| const queryParams = { |
| offset: this._pagination!.offset, |
| size: this._pagination!.size, |
| filter_by_logged_in_user: false, |
| exclude_dummy_page_sets: false, |
| }; |
| if (this._constrainByUser) { |
| queryParams.filter_by_logged_in_user = true; |
| } |
| if (this._constrainByTest) { |
| queryParams.exclude_dummy_page_sets = true; |
| } |
| return fetch(`/_/get_chromium_analysis_tasks?${fromObject(queryParams)}`, { |
| method: 'POST', |
| }) |
| .then(jsonOrThrow) |
| .then((json: GetTasksResponse) => { |
| this._tasks = json.data; |
| this._pagination = json.pagination; |
| ($$('pagination-sk', this) as PaginationSk).pagination = |
| this._pagination!; |
| for (let i = 0; i < this._tasks.length; i++) { |
| this._tasks[i].can_delete = json.permissions![i].DeleteAllowed; |
| this._tasks[i].can_redo = json.permissions![i].RedoAllowed; |
| this._tasks[i].id = json.ids![i]; |
| } |
| }) |
| .catch(errorMessage) |
| .finally(() => { |
| this._render(); |
| this.dispatchEvent(new CustomEvent('end-task', { bubbles: true })); |
| }); |
| } |
| |
| _confirmDeleteTask(index: number): void { |
| const confirmed = window.confirm('Delete this task?'); |
| if (confirmed) { |
| this._deleteTask(index); |
| } |
| } |
| |
| _confirmRedoTask(index: number): void { |
| const confirmed = window.confirm('Reschedule this task?'); |
| if (confirmed) { |
| this._redoTask(index); |
| } |
| } |
| |
| _confirmEditTask(index: number): void { |
| const confirmed = window.confirm('Edit this task?'); |
| if (confirmed) { |
| this._editTask(index); |
| } |
| } |
| |
| _deleteTask(index: number): void { |
| const req: DeleteTaskRequest = { id: this._tasks[index].id }; |
| fetch('/_/delete_chromium_analysis_task', { |
| method: 'POST', |
| body: JSON.stringify(req), |
| }) |
| .then((res) => { |
| if (res.ok) { |
| window.alert(`Deleted task ${req.id}`); |
| return; |
| } |
| // Non-OK status. Read the response and punt it to the catch. |
| res.text().then((text) => { |
| throw new Error(`Failed to delete the task: ${text}`); |
| }); |
| }) |
| .then(() => { |
| this._reload(); |
| }) |
| .catch(errorMessage); |
| } |
| |
| _redoTask(index: number): void { |
| const req: RedoTaskRequest = { id: this._tasks[index].id }; |
| fetch('/_/redo_chromium_analysis_task', { |
| method: 'POST', |
| body: JSON.stringify(req), |
| }) |
| .then((res) => { |
| if (res.ok) { |
| window.alert(`Resubmitted task ${req.id}`); |
| return; |
| } |
| // Non-OK status. Read the response and punt it to the catch. |
| res.text().then((text) => { |
| throw new Error(`Failed to resubmit the task: ${text}`); |
| }); |
| }) |
| .then(() => { |
| this._reload(); |
| }) |
| .catch(errorMessage); |
| } |
| |
| _editTask(index: number): void { |
| window.location.href = `/chromium_analysis/?template_id=${this._tasks[index].id}`; |
| } |
| |
| _resetPagination(): void { |
| this._pagination = { offset: 0, size: 10, total: 0 }; |
| } |
| |
| _constrainRunsByUser(): void { |
| this._constrainByUser = !this._constrainByUser; |
| this._resetPagination(); |
| this._reload(); |
| } |
| |
| _constrainRunsByTest(): void { |
| this._constrainByTest = !this._constrainByTest; |
| this._resetPagination(); |
| this._reload(); |
| } |
| } |
| |
| define('chromium-analysis-runs-sk', ChromiumAnalysisRunsSk); |