[ct] Add admin-task-runs-sk element.
Change-Id: Ida99a39a29e1d86a451527fcdf43fe1ce4a58f7c
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/306636
Reviewed-by: Ravi Mistry <rmistry@google.com>
diff --git a/ct/modules/admin-task-runs-sk/admin-task-runs-sk-demo.html b/ct/modules/admin-task-runs-sk/admin-task-runs-sk-demo.html
new file mode 100644
index 0000000..eeb5d7f
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/admin-task-runs-sk-demo.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Admin Task Runs</title>
+ <meta charset="utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ </head>
+ <body>
+ <h2>Admin-task-runs-sk Demo</h2><theme-chooser-sk></theme-chooser-sk>
+ <div id=container></div>
+ </body>
+</html>
diff --git a/ct/modules/admin-task-runs-sk/admin-task-runs-sk-demo.js b/ct/modules/admin-task-runs-sk/admin-task-runs-sk-demo.js
new file mode 100644
index 0000000..9d445d4
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/admin-task-runs-sk-demo.js
@@ -0,0 +1,19 @@
+import './index';
+import '../../../infra-sk/modules/theme-chooser-sk';
+import { $$ } from 'common-sk/modules/dom';
+import { fetchMock } from 'fetch-mock';
+import {
+ tasksResult0, tasksResult1, tasksResult2,
+} from './test_data';
+
+let i = 0;
+fetchMock.post('begin:/_/get_recreate_page_sets_tasks',
+ () => [tasksResult0, tasksResult1, tasksResult2][i++ % 3]);
+fetchMock.post('begin:/_/delete_recreate_page_sets_task', 200);
+fetchMock.post('begin:/_/redo_recreate_page_sets_task', 200);
+const cpr = document.createElement('admin-task-runs-sk');
+cpr.taskType = 'RecreatePageSets';
+cpr.getUrl = '/_/get_recreate_page_sets_tasks';
+cpr.deleteUrl = '/_/delete_recreate_page_sets_task';
+cpr.redoUrl = '/_/redo_recreate_page_sets_task';
+$$('#container').appendChild(cpr);
diff --git a/ct/modules/admin-task-runs-sk/admin-task-runs-sk.js b/ct/modules/admin-task-runs-sk/admin-task-runs-sk.js
new file mode 100644
index 0000000..c1b87e2
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/admin-task-runs-sk.js
@@ -0,0 +1,314 @@
+/**
+ * @fileoverview The bulk of the Recreate PageSets Runs History and
+ * Recreate Webpage Archives Runs History pages.
+ */
+
+import 'elements-sk/icon/delete-icon-sk';
+import 'elements-sk/icon/redo-icon-sk';
+import 'elements-sk/toast-sk';
+import '../../../infra-sk/modules/confirm-dialog-sk';
+import '../pagination-sk';
+
+import { $$, DomReady } from 'common-sk/modules/dom';
+import { fromObject } from 'common-sk/modules/query';
+import { jsonOrThrow } from 'common-sk/modules/jsonOrThrow';
+import { define } from 'elements-sk/define';
+import { errorMessage } from 'elements-sk/errorMessage';
+import { html } from 'lit-html';
+
+import { ElementSk } from '../../../infra-sk/modules/ElementSk';
+import {
+ getFormattedTimestamp,
+ formatRepeatAfterDays,
+ shortHash,
+ chromiumCommitUrl,
+ skiaCommitUrl,
+} from '../ctfe_utils';
+
+const template = (el) => html`
+<div>
+ <h2>${el._contrainByUser ? 'My ' : ''}${el.taskType}</h2>
+ <pagination-sk @page-changed=${(e) => 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 class=primary-variant-container-themes-sk>
+ <th>Id</th>
+ <th>User</th>
+ <th>Timestamps</th>
+ <th>Task Config</th>
+ <th>Results</th>
+ <th>Task Repeats</th>
+ </tr>
+ ${el._tasks.map((task, index) => taskRowTemplate(el, task, index))}
+ </table>
+</div>
+
+<confirm-dialog-sk id=confirm_dialog></confirm-dialog-sk>
+<toast-sk id=confirm_toast class=primary-variant-container-themes-sk duration=5000></toast-sk>
+`;
+
+const taskRowTemplate = (el, task, index) => html`
+<tr>
+ <!-- Id col -->
+ <td class=nowrap>
+ <span>${task.Id}</span>
+ <delete-icon-sk title="Delete this task" alt=Delete ?hidden=${!task.canDelete}
+ @click=${() => el._confirmDeleteTask(index)}></delete-icon-sk>
+ <redo-icon-sk title="Redo this task" alt=Redo ?hidden=${!task.canRedo}
+ @click=${() => el._confirmRedoTask(index)}></redo-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.TsAdded)}</td>
+ </tr>
+ <tr>
+ <td>Started:</td>
+ <td class=nowrap>${getFormattedTimestamp(task.TsStarted)}</td>
+ </tr>
+ <tr>
+ <td>Completed:</td>
+ <td class=nowrap>${getFormattedTimestamp(task.TsCompleted)}</td>
+ </tr>
+ </table>
+ </td>
+ <!-- Task Config col -->
+ <td>
+ <table class=inner-table>
+ <tr>
+ <td>PageSet:</td>
+ <td>${task.PageSets}</td>
+ </tr>
+ ${el.taskType === 'RecreateWebpageArchives' ? html`
+ <tr>
+ <td>ChromiumBuild:</td>
+ <td class=nowrap>
+ <a href="${chromiumCommitUrl(task.ChromiumRev)}">
+ ${shortHash(task.ChromiumRev)}
+ </a>
+ -
+ <a href="${skiaCommitUrl(task.SkiaRev)}">
+ ${shortHash(task.SkiaRev)}
+ </a>
+ </td>
+ </tr>` : ''}
+ </table>
+ </td>
+ <!-- Results col -->
+ <td class=nowrap>
+ ${task.Failure ? html`<div class=error>Failed</div>` : ''}
+ ${!task.TaskDone ? html`<div class=green>Waiting</div>` : ''}
+ ${!task.Failure && task.TaskDone ? 'Done' : ''}
+ ${task.SwarmingLogs ? html`
+ <br/>
+ <a href="${task.SwarmingLogs}" target=_blank rel="noopener noreferrer">
+ Swarming Logs
+ </a>` : ''}
+ </td>
+ <!-- Task Repeats -->
+ <td>${formatRepeatAfterDays(task.RepeatAfterDays)}</td>
+</tr>`;
+
+define('admin-task-runs-sk', class extends ElementSk {
+ constructor() {
+ super(template);
+ this._upgradeProperty('taskType');
+ this._upgradeProperty('getUrl');
+ this._upgradeProperty('deleteUrl');
+ this._upgradeProperty('redoUrl');
+ this._tasks = [];
+ this._constrainByUser = false;
+ this._constrainByTest = true;
+ this._resetPagination();
+ this._running = false;
+ }
+
+ connectedCallback() {
+ 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;
+ });
+ });
+ }
+
+ /**
+ * @prop {string} taskType - Specifies the type of task. Mirrors the
+ * attribute. Possible values include "RecreatePageSets" and
+ * "RecreateWebpageArchives".
+ */
+ get taskType() {
+ return this.getAttribute('taskType');
+ }
+
+ set taskType(val) {
+ this.setAttribute('taskType', val);
+ }
+
+ /**
+ * @prop {string} getUrl - Specifies the URL to fetch tasks. Mirrors the
+ * attribute.
+ */
+ get getUrl() {
+ return this.getAttribute('getUrl');
+ }
+
+ set getUrl(val) {
+ this.setAttribute('getUrl', val);
+ }
+
+ /**
+ * @prop {string} deleteUrl - Specifies the URL to delete tasks. Mirrors the
+ * attribute.
+ */
+ get deleteUrl() {
+ return this.getAttribute('deleteUrl');
+ }
+
+ set deleteUrl(val) {
+ this.setAttribute('deleteUrl', val);
+ }
+
+ /**
+ * @prop {string} redoUrl - Specifies the URL to redo tasks. Mirrors the
+ * attribute.
+ */
+ get redoUrl() {
+ return this.getAttribute('redoUrl');
+ }
+
+ set redoUrl(val) {
+ this.setAttribute('redoUrl', val);
+ }
+
+ _pageChanged(e) {
+ this._pagination.offset = e.detail.offset;
+ this._reload();
+ }
+
+ _reload() {
+ this.dispatchEvent(new CustomEvent('begin-task', { bubbles: true }));
+ this._tasks = [];
+ const queryParams = {
+ offset: this._pagination.offset,
+ size: this._pagination.size,
+ };
+ if (this._constrainByUser) {
+ queryParams.filter_by_logged_in_user = true;
+ }
+ if (this._constrainByTest) {
+ queryParams.exclude_dummy_page_sets = true;
+ }
+ return fetch(`${this.getUrl}?${fromObject(queryParams)}`,
+ { method: 'POST' })
+ .then(jsonOrThrow)
+ .then((json) => {
+ this._tasks = json.data;
+ this._pagination = json.pagination;
+ $$('pagination-sk', this).pagination = this._pagination;
+ for (let i = 0; i < this._tasks.length; i++) {
+ this._tasks[i].canDelete = json.permissions[i].DeleteAllowed;
+ this._tasks[i].canRedo = 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) {
+ document.getElementById('confirm_dialog')
+ .open('Proceed with deleting task?')
+ .then(() => {
+ this._deleteTask(index);
+ })
+ .catch(() => {});
+ }
+
+ _confirmRedoTask(index) {
+ document.getElementById('confirm_dialog')
+ .open('Reschedule this task?')
+ .then(() => {
+ this._redoTask(index);
+ })
+ .catch(() => {});
+ }
+
+ _deleteTask(index) {
+ const params = {};
+ params.id = this._tasks[index].Id;
+ fetch(this.deleteUrl, { method: 'POST', body: JSON.stringify(params) })
+ .then((res) => {
+ if (res.ok) {
+ $$('#confirm_toast').innerText = `Deleted task ${params.id}`;
+ $$('#confirm_toast').show();
+ return;
+ }
+ // Non-OK status. Read the response and punt it to the catch.
+ res.text().then((text) => { throw `Failed to delete the task: ${text}`; });
+ })
+ .then(() => {
+ this._reload();
+ })
+ .catch(errorMessage);
+ }
+
+ _redoTask(index) {
+ const params = {};
+ params.id = this._tasks[index].Id;
+ fetch(this.redoUrl, { method: 'POST', body: JSON.stringify(params) })
+ .then((res) => {
+ if (res.ok) {
+ $$('#confirm_toast').innerText = `Resubmitted task ${params.id}`;
+ $$('#confirm_toast').show();
+ return;
+ }
+ // Non-OK status. Read the response and punt it to the catch.
+ res.text().then((text) => { throw `Failed to resubmit the task: ${text}`; });
+ })
+ .then(() => {
+ this._reload();
+ })
+ .catch(errorMessage);
+ }
+
+
+ _resetPagination() {
+ this._pagination = { offset: 0, size: 10 };
+ }
+
+ _constrainRunsByUser() {
+ this._constrainByUser = !this._constrainByUser;
+ this._resetPagination();
+ this._reload();
+ }
+
+ _constrainRunsByTest() {
+ this._constrainByTest = !this._constrainByTest;
+ this._resetPagination();
+ this._reload();
+ }
+});
diff --git a/ct/modules/admin-task-runs-sk/admin-task-runs-sk.scss b/ct/modules/admin-task-runs-sk/admin-task-runs-sk.scss
new file mode 100644
index 0000000..ac7eab3
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/admin-task-runs-sk.scss
@@ -0,0 +1,55 @@
+@import '../colors.css';
+
+admin-task-runs-sk {
+ div.dialog-background {
+ width: 100%;
+ height: 100%;
+ z-index: 10;
+ position: fixed;
+ overflow: auto;
+ left: 0;
+ top: 0;
+ }
+ div.hidden {
+ display: none;
+ }
+ div.dialog-content {
+ min-width: 200px;
+ max-width: calc(100% - 10px);
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ padding: 2em;
+ border-radius: 1em;
+ }
+ table.runssummary > tbody > tr > td, table.runssummary>tbody>tr>th {
+ padding: 10px;
+ border: solid black 1px;
+ }
+ table.runssummary {
+ border-spacing: 0px;
+ padding-top: 2em;
+ padding-left: 2em;
+ th {
+ text-align: center;
+ }
+ td.nowrap {
+ white-space: nowrap;
+ }
+ }
+
+ table.inner-table {
+ td {
+ border: none;
+ .nowrap {
+ white-space: nowrap;
+ }
+ }
+ }
+}
+
+/* Outside admin-task-runs-sk because darkmode exists outside it. */
+.darkmode .queue a {
+ color: var(--secondary);
+}
diff --git a/ct/modules/admin-task-runs-sk/admin-task-runs-sk_test.js b/ct/modules/admin-task-runs-sk/admin-task-runs-sk_test.js
new file mode 100644
index 0000000..1412305
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/admin-task-runs-sk_test.js
@@ -0,0 +1,96 @@
+import './index';
+
+import { $, $$ } from 'common-sk/modules/dom';
+import { fetchMock } from 'fetch-mock';
+
+import {
+ tasksResult0, tasksResult1,
+} from './test_data';
+import {
+ eventPromise,
+ setUpElementUnderTest,
+} from '../../../infra-sk/modules/test_util';
+
+describe('admin-task-runs-sk', () => {
+ const newInstance = setUpElementUnderTest('admin-task-runs-sk');
+ const taskType = 'RecreatePageSets';
+ const getUrl = '/_/get_recreate_page_sets_tasks';
+ const deleteUrl = '/_/delete_recreate_page_sets_task';
+ const redoUrl = '/_/redo_recreate_page_sets_task';
+
+ fetchMock.config.overwriteRoutes = false;
+
+ let captureSkpRuns;
+ beforeEach(async () => {
+ await expectReload(() => captureSkpRuns = newInstance(
+ (el) => {
+ el.taskType = taskType;
+ el.getUrl = getUrl;
+ el.deleteUrl = deleteUrl;
+ el.redoUrl = redoUrl;
+ }));
+ });
+
+ afterEach(() => {
+ // Check all mock fetches called at least once and reset.
+ expect(fetchMock.done()).to.be.true;
+ fetchMock.reset();
+ });
+
+ // Expect 'trigger' to cause a reload, and execute it.
+ // Optionally pass desired result from server.
+ const expectReload = async (trigger, result) => {
+ result = result || tasksResult0;
+ const event = eventPromise('end-task');
+ fetchMock.postOnce(`begin:${getUrl}`, result);
+ trigger();
+ await event;
+ };
+
+ const confirmDialog = () => $$('dialog', captureSkpRuns).querySelectorAll('button')[1].click();
+
+ it('shows table entries', async () => {
+ expect($('table.runssummary>tbody>tr', captureSkpRuns)).to.have.length(11);
+ expect(fetchMock.lastUrl()).to.contain('exclude_dummy_page_sets=true');
+ expect(fetchMock.lastUrl()).to.contain('offset=0');
+ expect(fetchMock.lastUrl()).to.contain('size=10');
+ expect(fetchMock.lastUrl()).to.not.contain('filter_by_logged_in_user=true');
+ });
+
+ it('filters by user', async () => {
+ expect(fetchMock.lastUrl()).to.not.contain('filter_by_logged_in_user=true');
+ await expectReload(() => $$('#userFilter', captureSkpRuns).click());
+ expect(fetchMock.lastUrl()).to.contain('filter_by_logged_in_user=true');
+ });
+
+ it('filters by tests', async () => {
+ expect(fetchMock.lastUrl()).to.contain('exclude_dummy_page_sets=true');
+ await expectReload(() => $$('#testFilter', captureSkpRuns).click());
+ expect(fetchMock.lastUrl()).to.not.contain('exclude_dummy_page_sets=true');
+ });
+
+ it('navigates with pages', async () => {
+ expect(fetchMock.lastUrl()).to.contain('offset=0');
+ const result = tasksResult1;
+ result.pagination.offset = 10;
+ // 'Next page' button.
+ await expectReload(
+ () => $('pagination-sk button.action', captureSkpRuns)[2].click(), result);
+ expect(fetchMock.lastUrl()).to.contain('offset=10');
+ expect($('table.runssummary>tbody>tr', captureSkpRuns)).to.have.length(5);
+ });
+
+ it('deletes tasks', async () => {
+ $$('delete-icon-sk', captureSkpRuns).click();
+ fetchMock.post(`begin:${deleteUrl}`, 200);
+ await expectReload(confirmDialog);
+ expect(fetchMock.lastOptions('begin:/_/delete').body).to.contain('"id":66');
+ });
+
+ it('reschedules tasks', async () => {
+ $$('redo-icon-sk', captureSkpRuns).click();
+ fetchMock.post(`begin:${redoUrl}`, 200);
+ await expectReload(confirmDialog);
+ expect(fetchMock.lastOptions('begin:/_/redo').body).to.contain('"id":66');
+ });
+});
diff --git a/ct/modules/admin-task-runs-sk/index.js b/ct/modules/admin-task-runs-sk/index.js
new file mode 100644
index 0000000..6c64cac
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/index.js
@@ -0,0 +1,2 @@
+import './admin-task-runs-sk';
+import './admin-task-runs-sk.scss';
diff --git a/ct/modules/admin-task-runs-sk/test_data.js b/ct/modules/admin-task-runs-sk/test_data.js
new file mode 100644
index 0000000..f7fccb3
--- /dev/null
+++ b/ct/modules/admin-task-runs-sk/test_data.js
@@ -0,0 +1,51 @@
+export const tasksResult0 = {
+ data: [{
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20200205214318, TsStarted: 20200205214350, TsCompleted: 20200205215150, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-66\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '4a3020b701cc6510', PageSets: 'VoltMobile10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20191207143838, TsStarted: 20191207143848, TsCompleted: 20191207152018, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-65\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f99e03e8da2e10', PageSets: '100k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20191207143831, TsStarted: 20191207143847, TsCompleted: 20191207151818, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-64\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f99e01566bcd10', PageSets: 'Mobile100k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20191207141137, TsStarted: 20191207141211, TsCompleted: 20191207142218, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-63\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f985a8aef6af10', PageSets: '10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG-', TsAdded: 20191207141131, TsStarted: 20191207141211, TsCompleted: 20191207142219, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-62\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f985a8ec8a8310', PageSets: 'Mobile10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20190314210904, TsStarted: 20190314210907, TsCompleted: 20190314214915, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20190314210907\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: 'Mobile100k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20190314202843, TsStarted: 20190314202907, TsCompleted: 20190314211008, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20190314202907\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: '100k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20190314195608, TsStarted: 20190314200007, TsCompleted: 20190314200832, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20190314200007\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: 'Mobile10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20190314195550, TsStarted: 20190314195956, TsCompleted: 20190314200823, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20190314195956\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: '10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20170831003407, TsStarted: 20170831003445, TsCompleted: 20170831003554, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20170831003445\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: 'SVG1k', IsTestPageSet: false,
+ }],
+ ids: [66, 65, 64, 63, 62, 57, 56, 55, 54, 52],
+ pagination: { offset: 0, size: 10, total: 40 },
+ permissions: [{ DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }],
+};
+
+export const tasksResult1 = {
+ data: [{
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20200205214318, TsStarted: 20200205214350, TsCompleted: 20200205215150, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-66\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '4a3020b701cc6510', PageSets: 'VoltMobile10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20191207143838, TsStarted: 20191207143848, TsCompleted: 20191207152018, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-65\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f99e03e8da2e10', PageSets: '100k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20191207143831, TsStarted: 20191207143847, TsCompleted: 20191207151818, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-64\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f99e01566bcd10', PageSets: 'Mobile100k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20191207141137, TsStarted: 20191207141211, TsCompleted: 20191207142218, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-RecreatePageSets-63\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '48f985a8aef6af10', PageSets: '10k', IsTestPageSet: false,
+ }],
+ ids: [5094, 5091, 5084, 5082],
+ pagination: { offset: 10, size: 10, total: 50 },
+ permissions: [{ DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }],
+};
+export const tasksResult2 = {
+ data: [{
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20190314195608, TsStarted: 20190314200007, TsCompleted: 20190314200832, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20190314200007\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: 'Mobile10k', IsTestPageSet: false,
+ }, {
+ DatastoreKey: 'ASHADSJDGHDSGHJSDGDFSHTDSHDGDFGEGFDGHEGADFGADFGDSFGSDGDSEG', TsAdded: 20190314195550, TsStarted: 20190314195956, TsCompleted: 20190314200823, Username: 'rmistry@google.com', Failure: false, RepeatAfterDays: 0, SwarmingLogs: 'https://chrome-swarming.appspot.com/tasklist?l=500\u0026c=name\u0026c=created_ts\u0026c=bot\u0026c=duration\u0026c=state\u0026f=runid:rmistry-20190314195956\u0026st=1262304000000', TaskDone: true, SwarmingTaskID: '', PageSets: '10k', IsTestPageSet: false,
+ }],
+ ids: [5065, 5063],
+ pagination: { offset: 20, size: 10, total: 50 },
+ permissions: [{ DeleteAllowed: true, RedoAllowed: true }, { DeleteAllowed: true, RedoAllowed: true }],
+};