diff --git a/src/common/hotbar-types.ts b/src/common/hotbar-types.ts index f8fc5a225b..ee65071e0e 100644 --- a/src/common/hotbar-types.ts +++ b/src/common/hotbar-types.ts @@ -20,7 +20,7 @@ */ import * as uuid from "uuid"; -import type { Tuple } from "./utils"; +import { tuple, Tuple } from "./utils"; export interface HotbarItem { entity: { @@ -46,7 +46,7 @@ export const defaultHotbarCells = 12; // Number is chosen to easy hit any item w export function getEmptyHotbar(name: string, id: string = uuid.v4()): Hotbar { return { id, - items: Array(defaultHotbarCells).fill(null) as Tuple, + items: tuple.filled(defaultHotbarCells, null), name, }; } diff --git a/src/common/utils/__tests__/tuple.test.ts b/src/common/utils/__tests__/tuple.test.ts new file mode 100644 index 0000000000..5de0b64a87 --- /dev/null +++ b/src/common/utils/__tests__/tuple.test.ts @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { tuple } from "../../utils"; + +describe("tuple tests", () => { + describe("zip()", () => { + it("should yield 0 times and return 1 tuple of empty arrays when given empty array", () => { + expect(tuple.zip([]).next()).toEqual({ + done: true, + value: [[]], + }); + }); + + it("should yield 1 times and return 2 tuple of empty arrays when given one element array tuples", () => { + const i = tuple.zip([1], [2]); + + expect(i.next()).toEqual({ + done: false, + value: [1, 2] + }); + expect(i.next()).toEqual({ + done: true, + value: [[], []], + }); + }); + + it("should yield 1 times and return 2 tuple of partial arrays when given one element array tuples", () => { + const i = tuple.zip([1], [2, 3]); + + expect(i.next()).toEqual({ + done: false, + value: [1, 2] + }); + expect(i.next()).toEqual({ + done: true, + value: [[], [3]], + }); + }); + }); +}); diff --git a/src/common/utils/array.ts b/src/common/utils/array.ts index b0561e3eaf..54e122b9ba 100644 --- a/src/common/utils/array.ts +++ b/src/common/utils/array.ts @@ -19,26 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export type Tuple = N extends N ? number extends N ? T[] : _TupleOf : never; -type _TupleOf = R["length"] extends N ? R : _TupleOf; - /** - * - * @param sources The source arrays - * @yields A tuple of the next element from each of the sources - * @returns The tuple of all the sources as soon as at least one of the sources is exausted + * A inference typed version of `Array(length).fill(value)` + * @param length The number of entries + * @param value The value of each of the indices */ -export function* zipStrict(...sources: Tuple): Iterator, Tuple> { - const maxSafeLength = sources.reduce((prev, cur) => Math.min(prev, cur.length), Number.POSITIVE_INFINITY); - - if (!isFinite(maxSafeLength)) { - // There are no sources, thus just return - return [] as Tuple; - } - - for (let i = 0; i < maxSafeLength; i += 1) { - yield sources.map(source => source[i]) as Tuple; - } - - return sources.map(source => source.slice(maxSafeLength)) as Tuple; +export function filled(length: number, value: T): T[] { + return Array(length).fill(value); } diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index fdf91d39c1..b39dcd0fae 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -61,5 +61,10 @@ export * from "./convertCpu"; import * as iter from "./iter"; import * as array from "./array"; +import * as tuple from "./tuple"; -export { iter, array }; +export { + iter, + array, + tuple, +}; diff --git a/src/common/utils/tuple.ts b/src/common/utils/tuple.ts new file mode 100644 index 0000000000..5a252cf89c --- /dev/null +++ b/src/common/utils/tuple.ts @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { array } from "../utils"; + +/** + * A strict N-tuple of type T + */ +export type Tuple = N extends N ? number extends N ? T[] : _TupleOf : never; +type _TupleOf = R["length"] extends N ? R : _TupleOf; + +/** + * Iterates over `sources` yielding full tuples until one of the tuple arrays + * is empty. Then it returns a tuple with the rest of each of tuples + * @param sources The source arrays + * @yields A tuple of the next element from each of the sources + * @returns The tuple of all the sources as soon as at least one of the sources is exausted + */ +export function* zip(...sources: Tuple): Iterator, Tuple> { + const maxSafeLength = Math.min(...sources.map(source => source.length)); + + for (let i = 0; i < maxSafeLength; i += 1) { + yield sources.map(source => source[i]) as Tuple; + } + + return sources.map(source => source.slice(maxSafeLength)) as Tuple; +} + +/** + * Returns a `length` tuple filled with copies of `value` + * @param length The size of the tuple + * @param value The value for each of the tuple entries + */ +export function filled(length: L, value: T): Tuple { + return array.filled(length, value) as Tuple; +} diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index 2b8aa0f921..eef0c19800 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import _ from "lodash"; import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; import type { Cluster } from "../cluster"; @@ -33,8 +32,7 @@ export type IMetricsQuery = string | string[] | { }; // This is used for backoff retry tracking. -const MAX_ATTEMPTS = 5; -const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true]; +const ATTEMPTS = [false, false, false, false, true]; // prometheus metrics loader async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record): Promise { diff --git a/src/renderer/components/+user-management/+service-accounts/secret.tsx b/src/renderer/components/+user-management/+service-accounts/secret.tsx index 3acd53f0dc..f0a182cb60 100644 --- a/src/renderer/components/+user-management/+service-accounts/secret.tsx +++ b/src/renderer/components/+user-management/+service-accounts/secret.tsx @@ -49,7 +49,7 @@ export class ServiceAccountsSecret extends React.Component { <> {!showToken && ( <> - {Array(16).fill("•").join("")} + {"•".repeat(16)} { render() { const { isLoading } = this.props; const isInitLoading = isLoading && !this.logs.length; - const rowHeights = new Array(this.logs.length).fill(this.lineHeight); + const rowHeights = array.filled(this.logs.length, this.lineHeight); if (isInitLoading) { return ( diff --git a/src/renderer/components/table/sorting.ts b/src/renderer/components/table/sorting.ts index ca9ea959fc..9f907b0ae5 100644 --- a/src/renderer/components/table/sorting.ts +++ b/src/renderer/components/table/sorting.ts @@ -20,7 +20,7 @@ */ import type { TableSortCallback } from "./table"; -import { array, Ordering, rectifyOrdering, sortCompare } from "../../utils"; +import { Ordering, rectifyOrdering, sortCompare, tuple } from "../../utils"; export function getSorted(rawItems: T[], sortingCallback: TableSortCallback | undefined, orderByRaw: string): T[] { if (typeof sortingCallback !== "function") { @@ -40,7 +40,7 @@ export function getSorted(rawItems: T[], sortingCallback: TableSortCallback