mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor k8s api to common (#3553)
* refactor kube api to common Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor more utils to common Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor more utils to common Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * switch to use node-fetch on both sides Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * cleanup Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * improve logger Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix lint errors Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix/improve tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix node-fetch require error on prod build Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * preload fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * read serverAddress from apiBase Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * cleanup Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
476aa74101
commit
58a446bd45
250 files changed
+1244
-644
No files matched your search
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
* 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 moment from "moment";
|
||||
import { formatDuration } from "../formatDuration";
|
||||
|
||||
const second = 1000;
|
||||
const minute = 60 * second;
|
||||
const hour = 60 * minute;
|
||||
const day = 24 * hour;
|
||||
const year = 365 * day;
|
||||
|
||||
describe("human format durations", () => {
|
||||
test("small duration should output something", () => {
|
||||
expect(formatDuration(1)).toBe("0s");
|
||||
expect(formatDuration(3)).toBe("0s");
|
||||
});
|
||||
|
||||
test("returns seconds for duration under 1 min", () => {
|
||||
const res = formatDuration(8 * second);
|
||||
|
||||
expect(res).toBe("8s");
|
||||
});
|
||||
|
||||
test("zero duration should output something", () => {
|
||||
expect(formatDuration(0)).toBe("0s");
|
||||
});
|
||||
|
||||
describe("when compact is true", () => {
|
||||
|
||||
test("duration under 3 hours return minutes", () => {
|
||||
const res = formatDuration(1 * hour + 35 * minute);
|
||||
|
||||
expect(res).toBe("95m");
|
||||
});
|
||||
|
||||
test("duration under 8 hours return hours and minutes", () => {
|
||||
const res = formatDuration(6 * hour + 15 * minute + 20 * second);
|
||||
|
||||
expect(res).toBe("6h15m");
|
||||
});
|
||||
|
||||
test("duration under 48 hours return hours", () => {
|
||||
const res = formatDuration(1 * day + 4 * hour + 15 * minute);
|
||||
|
||||
expect(res).toBe("28h");
|
||||
});
|
||||
|
||||
test("duration under 2 years return days", () => {
|
||||
const res = formatDuration(400 * day + 4 * hour + 15 * minute);
|
||||
|
||||
expect(res).toBe("400d");
|
||||
});
|
||||
|
||||
test("durations less than 8 years returns years and days", () => {
|
||||
const timeValue = Date.now() - new Date(moment().subtract(2, "years").subtract(5, "days").subtract(2, "hours").toDate()).getTime();
|
||||
|
||||
const res = formatDuration(timeValue);
|
||||
|
||||
expect(res).toBe("2y5d");
|
||||
});
|
||||
|
||||
test("durations more than 8 years returns years", () => {
|
||||
const timeValue = Date.now() - new Date(moment().subtract(9, "years").subtract(5, "days").toDate()).getTime();
|
||||
|
||||
const res = formatDuration(timeValue);
|
||||
|
||||
expect(res).toBe("9y");
|
||||
});
|
||||
|
||||
test("durations more than 8 years returns years", () => {
|
||||
const res = formatDuration(10 * year + 25 * day);
|
||||
|
||||
expect(res).toBe("10y");
|
||||
});
|
||||
test("durations shouldn't include zero magnitude parts", () => {
|
||||
const zeroSeconds = formatDuration(8 * minute);
|
||||
|
||||
expect(zeroSeconds).toBe("8m");
|
||||
|
||||
const zeroMinutes = formatDuration(8 * hour + 15 * minute);
|
||||
|
||||
expect(zeroMinutes).toBe("8h");
|
||||
|
||||
const zeroHours = formatDuration(6 * day + 2 * minute);
|
||||
|
||||
expect(zeroHours).toBe("6d");
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Helper to convert CPU K8S units to numbers
|
||||
|
||||
const thousand = 1000;
|
||||
const million = thousand * thousand;
|
||||
const shortBillion = thousand * million;
|
||||
|
||||
export function cpuUnitsToNumber(cpu: string) {
|
||||
const cpuNum = parseInt(cpu);
|
||||
|
||||
if (cpu.includes("m")) return cpuNum / thousand;
|
||||
if (cpu.includes("u")) return cpuNum / million;
|
||||
if (cpu.includes("n")) return cpuNum / shortBillion;
|
||||
|
||||
return parseFloat(cpu);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Helper to convert memory from units Ki, Mi, Gi, Ti, Pi to bytes and vise versa
|
||||
|
||||
const base = 1024;
|
||||
const suffixes = ["K", "M", "G", "T", "P", "E"]; // Equivalents: Ki, Mi, Gi, Ti, Pi, Ei
|
||||
|
||||
export function unitsToBytes(value: string) {
|
||||
if (!suffixes.some(suffix => value.includes(suffix))) {
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
const suffix = value.replace(/[0-9]|i|\./g, "");
|
||||
const index = suffixes.indexOf(suffix);
|
||||
|
||||
return parseInt(
|
||||
(parseFloat(value) * Math.pow(base, index + 1)).toFixed(1)
|
||||
);
|
||||
}
|
||||
|
||||
export function bytesToUnits(bytes: number, precision = 1) {
|
||||
const sizes = ["B", ...suffixes];
|
||||
const index = Math.floor(Math.log(bytes) / Math.log(base));
|
||||
|
||||
if (!bytes) {
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
return `${bytes}${sizes[index]}`;
|
||||
}
|
||||
|
||||
return `${(bytes / (1024 ** index)).toFixed(precision)}${sizes[index]}i`;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/**
|
||||
* 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 moment from "moment";
|
||||
|
||||
/**
|
||||
* This function formats durations in a more human readable form.
|
||||
* @param timeValue the duration in milliseconds to format
|
||||
*/
|
||||
export function formatDuration(timeValue: number, compact = true) {
|
||||
const duration = moment.duration(timeValue, "milliseconds");
|
||||
const seconds = Math.floor(duration.asSeconds());
|
||||
const separator = compact ? "": " ";
|
||||
|
||||
if (seconds < 0) {
|
||||
return "0s";
|
||||
} else if (seconds < 60*2 ) {
|
||||
return `${seconds}s`;
|
||||
}
|
||||
|
||||
const minutes = Math.floor(duration.asMinutes());
|
||||
|
||||
if (minutes < 10) {
|
||||
const seconds = duration.seconds();
|
||||
|
||||
return getMeaningfulValues([minutes, seconds], ["m", "s"], separator);
|
||||
} else if (minutes < 60 * 3) {
|
||||
if (!compact) {
|
||||
return getMeaningfulValues([minutes, duration.seconds()], ["m", "s"]);
|
||||
}
|
||||
|
||||
return `${minutes}m`;
|
||||
}
|
||||
|
||||
const hours = Math.floor(duration.asHours());
|
||||
|
||||
if(hours < 8) {
|
||||
const minutes = duration.minutes();
|
||||
|
||||
return getMeaningfulValues([hours, minutes], ["h", "m"], separator);
|
||||
} else if (hours < 48) {
|
||||
if (compact) {
|
||||
return `${hours}h`;
|
||||
} else {
|
||||
return getMeaningfulValues([hours, duration.minutes()], ["h", "m"]);
|
||||
}
|
||||
}
|
||||
|
||||
const days = Math.floor(duration.asDays());
|
||||
|
||||
if (days < 8) {
|
||||
const hours = duration.hours();
|
||||
|
||||
if (compact) {
|
||||
return getMeaningfulValues([days, hours], ["d", "h"], separator);
|
||||
} else {
|
||||
return getMeaningfulValues([days, hours, duration.minutes()], ["d", "h", "m"]);
|
||||
}
|
||||
}
|
||||
const years = Math.floor(duration.asYears());
|
||||
|
||||
if (years < 2) {
|
||||
if (compact) {
|
||||
return `${days}d`;
|
||||
} else {
|
||||
return getMeaningfulValues([days, duration.hours(), duration.minutes()], ["d", "h", "m"]);
|
||||
}
|
||||
} else if (years < 8) {
|
||||
const days = duration.days();
|
||||
|
||||
if (compact) {
|
||||
return getMeaningfulValues([years, days], ["y", "d"], separator);
|
||||
}
|
||||
}
|
||||
|
||||
if (compact) {
|
||||
return `${years}y`;
|
||||
}
|
||||
|
||||
return getMeaningfulValues([years, duration.days(), duration.hours(), duration.minutes()], ["y", "d", "h", "m"]);
|
||||
}
|
||||
|
||||
function getMeaningfulValues(values: number[], suffixes: string[], separator = " ") {
|
||||
return values
|
||||
.map((a, i): [number, string] => [a, suffixes[i]])
|
||||
.filter(([dur]) => dur > 0)
|
||||
.map(([dur, suf]) => dur + suf)
|
||||
.join(separator);
|
||||
}
|
||||
@@ -32,10 +32,9 @@ export * from "./storageHelper";
|
||||
export * from "./createStorage";
|
||||
export * from "./interval";
|
||||
export * from "./copyToClipboard";
|
||||
export * from "./formatDuration";
|
||||
export * from "./isReactNode";
|
||||
export * from "./convertMemory";
|
||||
export * from "./convertCpu";
|
||||
export * from "../../common/utils/convertMemory";
|
||||
export * from "../../common/utils/convertCpu";
|
||||
export * from "./metricUnitsToNumber";
|
||||
export * from "./display-booleans";
|
||||
export * from "./isMiddleClick";
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* 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 { Readable } from "readable-stream";
|
||||
import type { TypedArray } from "type-fest";
|
||||
|
||||
/**
|
||||
* ReadableWebToNodeStream
|
||||
*
|
||||
* Copied from https://github.com/Borewit/readable-web-to-node-stream
|
||||
*
|
||||
* Adds read error handler
|
||||
*
|
||||
* */
|
||||
export class ReadableWebToNodeStream<T extends TypedArray> extends Readable {
|
||||
|
||||
public bytesRead = 0;
|
||||
public released = false;
|
||||
|
||||
/**
|
||||
* Default web API stream reader
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader
|
||||
*/
|
||||
private reader: ReadableStreamReader<T>;
|
||||
private pendingRead: Promise<ReadableStreamDefaultReadResult<T>>;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param stream ReadableStream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
|
||||
*/
|
||||
constructor(stream: ReadableStream<T>) {
|
||||
super();
|
||||
this.reader = stream.getReader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of readable._read(size).
|
||||
* When readable._read() is called, if data is available from the resource,
|
||||
* the implementation should begin pushing that data into the read queue
|
||||
* https://nodejs.org/api/stream.html#stream_readable_read_size_1
|
||||
*/
|
||||
public async _read() {
|
||||
// Should start pushing data into the queue
|
||||
// Read data from the underlying Web-API-readable-stream
|
||||
if (this.released) {
|
||||
this.push(null); // Signal EOF
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.pendingRead = this.reader.read();
|
||||
const data = await this.pendingRead;
|
||||
|
||||
// clear the promise before pushing pushing new data to the queue and allow sequential calls to _read()
|
||||
delete this.pendingRead;
|
||||
|
||||
if (data.done || this.released) {
|
||||
this.push(null); // Signal EOF
|
||||
} else {
|
||||
this.bytesRead += data.value.length;
|
||||
this.push(data.value); // Push new data to the queue
|
||||
}
|
||||
} catch (error) {
|
||||
this.push(null); // Signal EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is no unresolved read call to Web-API ReadableStream immediately returns;
|
||||
* otherwise will wait until the read is resolved.
|
||||
*/
|
||||
public async waitForReadToComplete() {
|
||||
if (this.pendingRead) {
|
||||
await this.pendingRead;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close wrapper
|
||||
*/
|
||||
public async close(): Promise<void> {
|
||||
await this.syncAndRelease();
|
||||
}
|
||||
|
||||
private async syncAndRelease() {
|
||||
this.released = true;
|
||||
await this.waitForReadToComplete();
|
||||
await this.reader.releaseLock();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user