blob: be8a9fe4295df254d3b06aace01b5a1dea6521c4 [file] [log] [blame]
/**
* Utility javascript functions used across the different CT FE pages.
*/
import { pad } from '../../infra-sk/modules/human';
import { fromObject } from '../../infra-sk/modules/query';
import { jsonOrThrow } from '../../infra-sk/modules/jsonOrThrow';
import { errorMessage } from '../../elements-sk/modules/errorMessage';
import { BenchmarksPlatformsResponse } from './json';
/**
* Converts the timestamp used in CTFE DB into a user friendly string.
*/
export function getFormattedTimestamp(timestamp: number): string {
if (!timestamp) {
return '<pending>';
}
return getTimestamp(timestamp).toLocaleString();
}
/**
* Converts the timestamp used in CTFE DB into a Javascript timestamp.
*/
export function getTimestamp(timestamp: number): Date {
const date = new Date();
if (!timestamp) {
return date;
}
// Timestamp is of the form YYYYMMDDhhmmss.
// Consume the pieces off the right to build the date.
const consumeDigits = (n: number) => {
const first_n_digits = timestamp % 10 ** n;
timestamp = (timestamp - first_n_digits) / 10 ** n;
return first_n_digits;
};
date.setUTCSeconds(consumeDigits(2));
date.setUTCMinutes(consumeDigits(2));
date.setUTCHours(consumeDigits(2));
date.setUTCDate(consumeDigits(2));
date.setUTCMonth(consumeDigits(2) - 1); // Month is 0 based in JS.
date.setUTCFullYear(consumeDigits(4));
return date;
}
/**
* Convert from Javascript Date to timestamp recognized by CTFE DB.
*/
export function getCtDbTimestamp(d: Date): string {
const timestamp =
String(d.getUTCFullYear()) +
pad(d.getUTCMonth() + 1, 2) +
pad(d.getUTCDate(), 2) +
pad(d.getUTCHours(), 2) +
pad(d.getUTCMinutes(), 2) +
pad(d.getUTCSeconds(), 2);
return timestamp;
}
/**
* Append gsPath with appropriate url to fetch from ct.skia.org.
*/
export function getGSLink(gsPath: string): string {
return `https://ct.skia.org/results/cluster-telemetry/${gsPath}`;
}
/**
* Returns true if gsPath is not set or if the patch's SHA1 digest in the specified
* google storage path is for an empty string.
*/
export function isEmptyPatch(gsPath: string): boolean {
// Compare against empty string and against the SHA1 digest of an empty string.
return (
gsPath === '' ||
gsPath === 'patches/da39a3ee5e6b4b0d3255bfef95601890afd80709.patch'
);
}
/**
* Express numeric days in a readable format (e.g. 'Weekly'; 'Every 3 days')
*/
export function formatRepeatAfterDays(num: number): string {
if (num === 0) {
return 'N/A';
}
if (num === 1) {
return 'Daily';
}
if (num === 7) {
return 'Weekly';
}
return `Every ${num} days`;
}
/**
* Fetches benchmarks with doc links, and platforms with descriptions.
*
* @param {func<Object>} func - Function called with fetched benchmarks and
* platforms object.
*/
export function fetchBenchmarksAndPlatforms(
func: (json: BenchmarksPlatformsResponse) => void
): void {
fetch('/_/benchmarks_platforms/', {
method: 'POST',
})
.then(jsonOrThrow)
.then(func)
.catch(errorMessage);
}
/**
*
* @param {Array<string>} descriptions - Array of CL descriptions, combined
* into a description string if at least one is noneempty.
*
* @returns string - Combined description.
*/
export function combineClDescriptions(descriptions: string[]): string {
const combinedDesc = descriptions
.filter(Boolean)
.reduce((str, desc) => (str += str === '' ? desc : ` and ${desc}`), '');
return combinedDesc ? `Testing ${combinedDesc}` : '';
}
export function missingLiveSitesWithCustomWebpages(
customWebpages: string,
benchmarkArgs: string
): boolean {
if (customWebpages && !benchmarkArgs.includes('--use-live-sites')) {
errorMessage(
'Please specify --use-live-sites in benchmark arguments ' +
'when using custom web pages.'
);
return true;
}
return false;
}
let activeTasks = 0;
/**
* Asynchronously queries the logged in user's active task count.
* This is best effort, so doesn't bother with returning a promise.
*
* @returns function() boolean : Whether or not the task count
* previously fetched is more than 3.
*/
export function moreThanThreeActiveTasksChecker(): () => boolean {
const queryParams = {
size: 1,
not_completed: true,
filter_by_logged_in_user: true,
};
const queryStr = `?${fromObject(queryParams)}`;
taskDescriptors.forEach((obj) => {
fetch(obj.get_url + queryStr, {
method: 'POST',
})
.then(jsonOrThrow)
.then((json) => {
activeTasks += json.pagination.total;
})
.catch(errorMessage);
});
return () => {
if (activeTasks > 3) {
errorMessage(
`You have ${activeTasks} currently running tasks. Please wait` +
' for them to complete before scheduling more CT tasks.'
);
return true;
}
return false;
};
}
/**
* Used to describe the type and get/delete URLs of various CT tasks.
*/
export interface TaskDescriptor {
type: string;
get_url: string;
delete_url: string;
}
/**
* List of task types and the associated urls to fetch and delete them.
*/
export const taskDescriptors: Array<TaskDescriptor> = [
{
type: 'ChromiumPerf',
get_url: '/_/get_chromium_perf_tasks',
delete_url: '/_/delete_chromium_perf_task',
},
{
type: 'ChromiumAnalysis',
get_url: '/_/get_chromium_analysis_tasks',
delete_url: '/_/delete_chromium_analysis_task',
},
{
type: 'MetricsAnalysis',
get_url: '/_/get_metrics_analysis_tasks',
delete_url: '/_/delete_metrics_analysis_task',
},
{
type: 'RecreatePageSets',
get_url: '/_/get_recreate_page_sets_tasks',
delete_url: '/_/delete_recreate_page_sets_task',
},
{
type: 'RecreateWebpageArchives',
get_url: '/_/get_recreate_webpage_archives_tasks',
delete_url: '/_/delete_recreate_webpage_archives_task',
},
];