diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 9372c439a9..db54f2bd12 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -127,7 +127,7 @@ export class Kubectl { } try { - const { stdout, stderr } = await promiseExec(`"${this.path}" version --client=true -o json`) + const { stdout } = await promiseExec(`"${this.path}" version --client=true -o json`) const output = JSON.parse(stdout) let version: string = output.clientVersion.gitVersion if (version[0] === 'v') { diff --git a/src/renderer/utils/formatDuration.ts b/src/renderer/utils/formatDuration.ts index 48107d3c0b..84f90731b5 100644 --- a/src/renderer/utils/formatDuration.ts +++ b/src/renderer/utils/formatDuration.ts @@ -1,24 +1,35 @@ -// Formatting date duration in shorten format, e.g. "2d", or "25m" - import moment from "moment"; +const suffixes = ["w", "d", "h", "m", "s"]; + +/** + * This function formats durations in a more human readable form. + * @param timeValue the duration in milliseconds to format + * @param compact when true, only the largest non-zero time frame will be returned + */ export function formatDuration(timeValue: number, compact: boolean) { - let result = ""; - const duration = moment.duration(timeValue); - const suffixes = ["d", "h", "m"]; + const duration = moment.duration(timeValue, "milliseconds"); const durationValues = [ - Math.round(duration.asDays()), + Math.floor(duration.asWeeks()), + Math.floor(duration.asDays()) % 7, duration.hours(), duration.minutes(), + duration.seconds(), ]; - durationValues.forEach((value, index) => { - if (value) result += value + suffixes[index] + " "; - }); + + const meaningfulValues = durationValues + .map((a, i): [number, string] => [a, suffixes[i]]) + .filter(([dur, _suf]) => dur > 0) + .filter(([_dur, suf], i) => i === 0 || suf !== "s") // remove seconds, unless it is the only one + .map(([dur, suf]) => dur + suf); + + if (meaningfulValues.length === 0) { + return "0s"; + } + if (compact) { - result = result.split(" ")[0]; + return meaningfulValues[0]; } - if (!result) { - return "<1m"; - } - return result; -} \ No newline at end of file + + return meaningfulValues.join(" "); +} diff --git a/src/renderer/utils/formatDuration_spec.ts b/src/renderer/utils/formatDuration_spec.ts new file mode 100644 index 0000000000..53e2148286 --- /dev/null +++ b/src/renderer/utils/formatDuration_spec.ts @@ -0,0 +1,56 @@ +import { formatDuration } from "./formatDuration"; + +const second = 1000; +const minute = 60 * second; +const hour = 60 * minute; +const day = 24 * hour; +const week = 7 * day; + +describe("human format durations", () => { + test("long formatted durations less than 24 hours long shouldn't have a 'd' component", () => { + const res = formatDuration(19 * 60 * 60 * 1000, false); + + expect(res).not.toContain("d"); + expect(res).toBe("19h"); + }); + + test("long formatted durations more than a week have correct day count", () => { + const res = formatDuration(2 * week + 2 * day, false); + + expect(res).toBe("2w 2d"); + }); + + test("durations > 1/2 week shouldn't show 1w has passed", () => { + const res = formatDuration(5 * 24 * 60 * 60 * 1000, false); + + expect(res).not.toContain("w"); + expect(res).toBe("5d"); + }); + + test("durations shouldn't include zero magnitude parts", () => { + const res = formatDuration(6 * day + 2 * minute, false); + + expect(res).not.toContain("h"); + expect(res).toBe("6d 2m"); + }); + + test("seconds are ignored unless they are significant (< 1m)", () => { + const insignificant = formatDuration(1 * hour + 2 * minute + 31 * second, false); + + expect(insignificant).not.toContain("s"); + expect(insignificant).toBe("1h 2m"); + + const significant = formatDuration(31 * second, false); + expect(significant).toBe("31s"); + }); + + test("zero duration should output something", () => { + expect(formatDuration(0, false)).toBe("0s"); + expect(formatDuration(0, true)).toBe("0s"); + }); + + test("small duration should output something", () => { + expect(formatDuration(1, false)).toBe("0s"); + expect(formatDuration(3, true)).toBe("0s"); + }); +});