mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
cleanup Lens repo with tighter linting
Signed-off-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
1 parent
e468105143
commit
b1ff34879a
470 files changed
+8447
-7443
No files matched your search
@@ -9,14 +9,14 @@ describe("k8s CPU units conversion", () => {
|
||||
"100m", // 0.1
|
||||
"930000n", // 0.00093
|
||||
"3028u", // 0.003028
|
||||
]
|
||||
const cpuCores = units.map(unit => cpuUnitsToNumber(unit))
|
||||
];
|
||||
const cpuCores = units.map(unit => cpuUnitsToNumber(unit));
|
||||
const expected = [
|
||||
0.5,
|
||||
0.1,
|
||||
0.00093,
|
||||
0.003028
|
||||
]
|
||||
expect(cpuCores).toEqual(expected)
|
||||
];
|
||||
expect(cpuCores).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -11,8 +11,8 @@ describe("Kubernetes units conversion", () => {
|
||||
4596968000, // 4.2Gi
|
||||
4596968000000, // 4.1Ti
|
||||
1.2384898975269E+15 // 1.1Pi
|
||||
]
|
||||
const units = bytes.map(byte => bytesToUnits(byte))
|
||||
];
|
||||
const units = bytes.map(byte => bytesToUnits(byte));
|
||||
const expected = [
|
||||
"128B",
|
||||
"2.0Ki",
|
||||
@@ -20,22 +20,22 @@ describe("Kubernetes units conversion", () => {
|
||||
"4.3Gi",
|
||||
"4.2Ti",
|
||||
"1.1Pi"
|
||||
]
|
||||
expect(units).toEqual(expected)
|
||||
];
|
||||
expect(units).toEqual(expected);
|
||||
});
|
||||
|
||||
test("Convert bytes to units with decimal precision", () => {
|
||||
const bytes = [
|
||||
2107152, // 2.010Mi
|
||||
4596968000, // 4.281Gi
|
||||
]
|
||||
const units = bytes.map(byte => bytesToUnits(byte, 3))
|
||||
];
|
||||
const units = bytes.map(byte => bytesToUnits(byte, 3));
|
||||
const expected = [
|
||||
"2.010Mi",
|
||||
"4.281Gi"
|
||||
]
|
||||
expect(units).toEqual(expected)
|
||||
})
|
||||
];
|
||||
expect(units).toEqual(expected);
|
||||
});
|
||||
|
||||
test("Convert 0 to bytes", () => {
|
||||
expect(bytesToUnits(0)).toEqual("N/A");
|
||||
@@ -49,7 +49,7 @@ describe("Kubernetes units conversion", () => {
|
||||
"7.99Gi", // 8579197173
|
||||
"2Ti", // 2199023255552
|
||||
"1Pi", // 1125899906842624
|
||||
]
|
||||
];
|
||||
const expected = [
|
||||
128,
|
||||
22528,
|
||||
@@ -57,9 +57,9 @@ describe("Kubernetes units conversion", () => {
|
||||
8579197173,
|
||||
2199023255552,
|
||||
1125899906842624
|
||||
]
|
||||
const bytes = units.map(unitsToBytes)
|
||||
expect(bytes).toEqual(expected)
|
||||
];
|
||||
const bytes = units.map(unitsToBytes);
|
||||
expect(bytes).toEqual(expected);
|
||||
});
|
||||
|
||||
test("Convert shorten units to bytes", () => {
|
||||
@@ -70,7 +70,7 @@ describe("Kubernetes units conversion", () => {
|
||||
"7.99G", // 8579197173
|
||||
"2T", // 2199023255552
|
||||
"1P", // 1125899906842624
|
||||
]
|
||||
];
|
||||
const expected = [
|
||||
128,
|
||||
22528,
|
||||
@@ -78,9 +78,9 @@ describe("Kubernetes units conversion", () => {
|
||||
8579197173,
|
||||
2199023255552,
|
||||
1125899906842624
|
||||
]
|
||||
const bytes = units.map(unitsToBytes)
|
||||
expect(bytes).toEqual(expected)
|
||||
];
|
||||
const bytes = units.map(unitsToBytes);
|
||||
expect(bytes).toEqual(expected);
|
||||
});
|
||||
|
||||
test("Convert strange unit to bytes", () => {
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
* @returns the left and right sub-arrays which when conjoined with `element`
|
||||
* is the same as `array`, and `true`
|
||||
*/
|
||||
export function split<T>(array: Array<T>, element: T): [Array<T>, Array<T>, boolean] {
|
||||
export function split<T>(array: T[], element: T): [T[], T[], boolean] {
|
||||
const index = array.indexOf(element);
|
||||
if (index < 0) {
|
||||
return [array, [], false];
|
||||
}
|
||||
|
||||
return [array.slice(0, index), array.slice(index+1, array.length), true]
|
||||
return [array.slice(0, index), array.slice(index+1, array.length), true];
|
||||
}
|
||||
@@ -2,32 +2,9 @@
|
||||
// Can be applied to class or single method as @autobind()
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
export function autobind() {
|
||||
return function (target: Constructor | object, prop?: string, descriptor?: PropertyDescriptor) {
|
||||
if (target instanceof Function) return bindClass(target);
|
||||
else return bindMethod(target, prop, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
function bindClass<T extends Constructor>(constructor: T) {
|
||||
const proto = constructor.prototype;
|
||||
const descriptors = Object.getOwnPropertyDescriptors(proto);
|
||||
|
||||
const skipMethod = (methodName: string) => {
|
||||
return methodName === "constructor"
|
||||
|| typeof descriptors[methodName].value !== "function";
|
||||
};
|
||||
|
||||
Object.keys(descriptors).forEach(prop => {
|
||||
if (skipMethod(prop)) return;
|
||||
const boundDescriptor = bindMethod(proto, prop, descriptors[prop]);
|
||||
Object.defineProperty(proto, prop, boundDescriptor);
|
||||
})
|
||||
}
|
||||
|
||||
function bindMethod(target: object, prop?: string, descriptor?: PropertyDescriptor) {
|
||||
function bindMethod(target: object, prop?: string, descriptor?: PropertyDescriptor): any {
|
||||
if (!descriptor || typeof descriptor.value !== "function") {
|
||||
throw new Error(`@autobind() must be used on class or method only`)
|
||||
throw new Error(`@autobind() must be used on class or method only`);
|
||||
}
|
||||
const { value: func, enumerable, configurable } = descriptor;
|
||||
const boundFunc = new WeakMap<object, Function>();
|
||||
@@ -36,9 +13,41 @@ function bindMethod(target: object, prop?: string, descriptor?: PropertyDescript
|
||||
enumerable,
|
||||
configurable,
|
||||
get() {
|
||||
if (this === target) return func; // direct access from prototype
|
||||
if (!boundFunc.has(this)) boundFunc.set(this, func.bind(this));
|
||||
if (this === target) {
|
||||
return func;
|
||||
} // direct access from prototype
|
||||
if (!boundFunc.has(this)) {
|
||||
boundFunc.set(this, func.bind(this));
|
||||
}
|
||||
return boundFunc.get(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bindClass<T extends Constructor>(constructor: T): void {
|
||||
const proto = constructor.prototype;
|
||||
const descriptors = Object.getOwnPropertyDescriptors(proto);
|
||||
|
||||
const skipMethod = (methodName: string): boolean => {
|
||||
return methodName === "constructor"
|
||||
|| typeof descriptors[methodName].value !== "function";
|
||||
};
|
||||
|
||||
Object.keys(descriptors).forEach(prop => {
|
||||
if (skipMethod(prop)) {
|
||||
return;
|
||||
}
|
||||
const boundDescriptor = bindMethod(proto, prop, descriptors[prop]);
|
||||
Object.defineProperty(proto, prop, boundDescriptor);
|
||||
});
|
||||
}
|
||||
|
||||
export function autobind(): (target: Constructor | object, prop?: string, descriptor?: PropertyDescriptor) => void | any {
|
||||
return function (target: Constructor | object, prop?: string, descriptor?: PropertyDescriptor): void | any {
|
||||
if (target instanceof Function) {
|
||||
return bindClass(target);
|
||||
} else {
|
||||
return bindMethod(target, prop, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import * as Base64 from "crypto-js/enc-base64";
|
||||
import * as Utf8 from "crypto-js/enc-utf8";
|
||||
|
||||
export const base64 = {
|
||||
decode(data: string) {
|
||||
decode(data: string): string {
|
||||
return Base64.parse(data).toString(Utf8);
|
||||
},
|
||||
encode(data: string) {
|
||||
encode(data: string): string {
|
||||
return Utf8.parse(data).toString(Base64);
|
||||
}
|
||||
};
|
||||
@@ -4,15 +4,13 @@ import { camelCase, isPlainObject } from "lodash";
|
||||
export function toCamelCase(data: any): any {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(toCamelCase);
|
||||
}
|
||||
else if (isPlainObject(data)) {
|
||||
} else if (isPlainObject(data)) {
|
||||
return Object.keys(data).reduce<any>((result, key) => {
|
||||
const value = data[key];
|
||||
result[camelCase(key)] = typeof value === "object" ? toCamelCase(value) : value;
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ interface WrappingFunction {
|
||||
<T>(result: T): T;
|
||||
}
|
||||
|
||||
export function cancelableFetch(reqInfo: RequestInfo, reqInit: RequestInit = {}) {
|
||||
export function cancelableFetch(reqInfo: RequestInfo, reqInit: RequestInit = {}): CancelablePromise<Response> {
|
||||
const abortController = new AbortController();
|
||||
const signal = abortController.signal;
|
||||
const cancel = abortController.abort.bind(abortController);
|
||||
@@ -20,14 +20,14 @@ export function cancelableFetch(reqInfo: RequestInfo, reqInit: RequestInit = {})
|
||||
const wrapResult: WrappingFunction = function (result: any) {
|
||||
if (result instanceof Promise) {
|
||||
const promise: CancelablePromise<any> = result as any;
|
||||
promise.then = function (onfulfilled, onrejected) {
|
||||
promise.then = function (onfulfilled, onrejected): any {
|
||||
const data = Object.getPrototypeOf(this).then.call(this, onfulfilled, onrejected);
|
||||
return wrapResult(data);
|
||||
}
|
||||
};
|
||||
promise.cancel = cancel;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
const req = fetch(reqInfo, { ...reqInit, signal });
|
||||
return wrapResult(req);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
// Helper to convert CPU K8S units to numbers
|
||||
|
||||
export function cpuUnitsToNumber(cpu: string) {
|
||||
const cpuNum = parseInt(cpu)
|
||||
const billion = 1000000 * 1000
|
||||
if (cpu.includes("m")) return cpuNum / 1000
|
||||
if (cpu.includes("u")) return cpuNum / 1000000
|
||||
if (cpu.includes("n")) return cpuNum / billion
|
||||
return parseFloat(cpu)
|
||||
export function cpuUnitsToNumber(cpu: string): number {
|
||||
const cpuNum = parseInt(cpu);
|
||||
const billion = 1000000 * 1000;
|
||||
if (cpu.includes("m")) {
|
||||
return cpuNum / 1000;
|
||||
}
|
||||
if (cpu.includes("u")) {
|
||||
return cpuNum / 1000000;
|
||||
}
|
||||
if (cpu.includes("n")) {
|
||||
return cpuNum / billion;
|
||||
}
|
||||
return parseFloat(cpu);
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
// 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
|
||||
const base = 1024;
|
||||
const suffixes = ['K', 'M', 'G', 'T', 'P', 'E']; // Equivalents: Ki, Mi, Gi, Ti, Pi, Ei
|
||||
|
||||
export function unitsToBytes(value: string) {
|
||||
export function unitsToBytes(value: string): number {
|
||||
if (!suffixes.some(suffix => value.includes(suffix))) {
|
||||
return parseFloat(value)
|
||||
return parseFloat(value);
|
||||
}
|
||||
const index = suffixes.findIndex(suffix =>
|
||||
suffix == value.replace(/[0-9]|i|\./g, '')
|
||||
)
|
||||
);
|
||||
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))
|
||||
export function bytesToUnits(bytes: number, precision = 1): string {
|
||||
const sizes = ["B", ...suffixes];
|
||||
const index = Math.floor(Math.log(bytes) / Math.log(base));
|
||||
if (!bytes) {
|
||||
return "N/A"
|
||||
return "N/A";
|
||||
}
|
||||
if (index === 0) {
|
||||
return `${bytes}${sizes[index]}`
|
||||
return `${bytes}${sizes[index]}`;
|
||||
}
|
||||
return `${(bytes / (1024 ** index)).toFixed(precision)}${sizes[index]}i`
|
||||
return `${(bytes / (1024 ** index)).toFixed(precision)}${sizes[index]}i`;
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
// Helper for selecting element's text content and copy in clipboard
|
||||
|
||||
function isSelectable(elem: HTMLElement): elem is HTMLInputElement {
|
||||
return !!(elem as HTMLInputElement).select;
|
||||
}
|
||||
|
||||
export function copyToClipboard(elem: HTMLElement, resetSelection = true): boolean {
|
||||
let clearSelection: () => void;
|
||||
if (isSelectable(elem)) {
|
||||
elem.select();
|
||||
clearSelection = () => elem.setSelectionRange(0, 0)
|
||||
}
|
||||
else {
|
||||
clearSelection = (): void => elem.setSelectionRange(0, 0);
|
||||
} else {
|
||||
const selection = window.getSelection();
|
||||
selection.selectAllChildren(elem);
|
||||
clearSelection = () => selection.removeAllRanges();
|
||||
clearSelection = (): void => selection.removeAllRanges();
|
||||
}
|
||||
const copyResult = document.execCommand("copy");
|
||||
if (resetSelection) clearSelection();
|
||||
if (resetSelection) {
|
||||
clearSelection();
|
||||
}
|
||||
return copyResult;
|
||||
}
|
||||
|
||||
function isSelectable(elem: HTMLElement): elem is HTMLInputElement {
|
||||
return !!(elem as HTMLInputElement).select;
|
||||
}
|
||||
@@ -1,23 +1,19 @@
|
||||
// Helper to work with browser's local/session storage api
|
||||
|
||||
export interface IStorageHelperOptions {
|
||||
export interface StorageHelperOptions {
|
||||
addKeyPrefix?: boolean;
|
||||
useSession?: boolean; // use `sessionStorage` instead of `localStorage`
|
||||
}
|
||||
|
||||
export function createStorage<T>(key: string, defaultValue?: T, options?: IStorageHelperOptions) {
|
||||
return new StorageHelper(key, defaultValue, options);
|
||||
}
|
||||
|
||||
export class StorageHelper<T> {
|
||||
static keyPrefix = "lens_";
|
||||
|
||||
static defaultOptions: IStorageHelperOptions = {
|
||||
static defaultOptions: StorageHelperOptions = {
|
||||
addKeyPrefix: true,
|
||||
useSession: false,
|
||||
}
|
||||
|
||||
constructor(protected key: string, protected defaultValue?: T, protected options?: IStorageHelperOptions) {
|
||||
constructor(protected key: string, protected defaultValue?: T, protected options?: StorageHelperOptions) {
|
||||
this.options = Object.assign({}, StorageHelper.defaultOptions, options);
|
||||
|
||||
if (this.options.addKeyPrefix) {
|
||||
@@ -25,8 +21,10 @@ export class StorageHelper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
protected get storage() {
|
||||
if (this.options.useSession) return window.sessionStorage;
|
||||
protected get storage(): Storage {
|
||||
if (this.options.useSession) {
|
||||
return window.sessionStorage;
|
||||
}
|
||||
return window.localStorage;
|
||||
}
|
||||
|
||||
@@ -36,32 +34,32 @@ export class StorageHelper<T> {
|
||||
try {
|
||||
return JSON.parse(strValue);
|
||||
} catch (e) {
|
||||
console.error(`Parsing json failed for pair: ${this.key}=${strValue}`)
|
||||
console.error(`Parsing json failed for pair: ${this.key}=${strValue}`);
|
||||
}
|
||||
}
|
||||
return this.defaultValue;
|
||||
}
|
||||
|
||||
set(value: T) {
|
||||
set(value: T): StorageHelper<T> {
|
||||
this.storage.setItem(this.key, JSON.stringify(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
merge(value: Partial<T>) {
|
||||
merge(value: Partial<T>): StorageHelper<T> {
|
||||
const currentValue = this.get();
|
||||
return this.set(Object.assign(currentValue, value));
|
||||
}
|
||||
|
||||
clear() {
|
||||
clear(): StorageHelper<T> {
|
||||
this.storage.removeItem(this.key);
|
||||
return this;
|
||||
}
|
||||
|
||||
getDefaultValue() {
|
||||
getDefaultValue(): T {
|
||||
return this.defaultValue;
|
||||
}
|
||||
|
||||
restoreDefaultValue() {
|
||||
restoreDefaultValue(): StorageHelper<T> {
|
||||
return this.set(this.defaultValue);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
// Helper for combining css classes inside components
|
||||
|
||||
export type IClassName = string | string[] | IClassNameMap;
|
||||
export type IClassNameMap = {
|
||||
export type ClassName = string | string[] | ClassNameMap;
|
||||
export interface ClassNameMap {
|
||||
[className: string]: boolean | any;
|
||||
};
|
||||
}
|
||||
|
||||
export function cssNames(...args: IClassName[]): string {
|
||||
const map: IClassNameMap = {};
|
||||
export function cssNames(...args: ClassName[]): string {
|
||||
const map: ClassNameMap = {};
|
||||
args.forEach(className => {
|
||||
if (typeof className === "string" || Array.isArray(className)) {
|
||||
[].concat(className).forEach(name => map[name] = true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Object.assign(map, className);
|
||||
}
|
||||
});
|
||||
return Object.entries(map)
|
||||
.filter(([className, isActive]) => !!isActive)
|
||||
.filter(([_className, isActive]) => !!isActive)
|
||||
.map(([className]) => className.trim())
|
||||
.join(' ');
|
||||
}
|
||||
@@ -1,17 +1,29 @@
|
||||
// Helper for getting/setting css-variables
|
||||
|
||||
export function cssVar(elem: HTMLElement) {
|
||||
export interface CSSVar {
|
||||
toString(): string;
|
||||
valueOf(): number;
|
||||
}
|
||||
|
||||
export interface CSSVarWrapper {
|
||||
get(name: string): CSSVar;
|
||||
set(name: string, value: number | string): void;
|
||||
}
|
||||
|
||||
export function cssVar(elem: HTMLElement): CSSVarWrapper {
|
||||
return {
|
||||
get(name: string) {
|
||||
get(name: string): CSSVar {
|
||||
const value = window.getComputedStyle(elem).getPropertyValue(name).trim();
|
||||
return {
|
||||
toString: () => value,
|
||||
valueOf: () => parseFloat(value)
|
||||
toString: (): string => value,
|
||||
valueOf: (): number => parseFloat(value)
|
||||
};
|
||||
},
|
||||
set(name: string, value: number | string) {
|
||||
if (typeof value === "number") value = value + "px";
|
||||
set(name: string, value: number | string): void {
|
||||
if (typeof value === "number") {
|
||||
value = value + "px";
|
||||
}
|
||||
elem.style.setProperty(name, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// Debouncing promise evaluation
|
||||
|
||||
export const debouncePromise = function (promisedFunc: Function, timeout = 0) {
|
||||
export const debouncePromise = function (promisedFunc: Function, timeout = 0): (...params: any[]) => Promise<any> {
|
||||
let timer: number;
|
||||
return (...params: any[]) => new Promise((resolve, reject) => {
|
||||
return (...params: any[]): Promise<any> => new Promise((resolve, _reject) => {
|
||||
clearTimeout(timer);
|
||||
timer = window.setTimeout(() => resolve(promisedFunc.apply(this, params)), timeout);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function downloadFile(filename: string, contents: any, type: string) {
|
||||
export function downloadFile(filename: string, contents: any, type: string): void {
|
||||
const data = new Blob([contents], { type: type });
|
||||
const url = URL.createObjectURL(data);
|
||||
const link = document.createElement("a");
|
||||
@@ -8,5 +8,5 @@ export function downloadFile(filename: string, contents: any, type: string) {
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url)
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
@@ -10,31 +10,34 @@ type Callback<D extends [...any[]]> = (...data: D) => void | boolean;
|
||||
export class EventEmitter<D extends [...any[]]> {
|
||||
protected listeners = new Map<Callback<D>, Options>();
|
||||
|
||||
addListener(callback: Callback<D>, options: Options = {}) {
|
||||
addListener(callback: Callback<D>, options: Options = {}): void {
|
||||
if (options.prepend) {
|
||||
const listeners = [...this.listeners];
|
||||
listeners.unshift([callback, options]);
|
||||
this.listeners = new Map(listeners);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.listeners.set(callback, options);
|
||||
}
|
||||
}
|
||||
|
||||
removeListener(callback: Callback<D>) {
|
||||
removeListener(callback: Callback<D>): void {
|
||||
this.listeners.delete(callback);
|
||||
}
|
||||
|
||||
removeAllListeners() {
|
||||
removeAllListeners(): void {
|
||||
this.listeners.clear();
|
||||
}
|
||||
|
||||
emit(...data: D) {
|
||||
emit(...data: D): void {
|
||||
[...this.listeners].every(([callback, options]) => {
|
||||
if (options.once) this.removeListener(callback);
|
||||
if (options.once) {
|
||||
this.removeListener(callback);
|
||||
}
|
||||
const result = callback(...data);
|
||||
if (result === false) return; // break cycle
|
||||
if (result === false) {
|
||||
return;
|
||||
} // break cycle
|
||||
return true;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
export function formatDuration(timeValue: number, compact: boolean) {
|
||||
export function formatDuration(timeValue: number, compact: boolean): string {
|
||||
let result = "";
|
||||
const duration = moment.duration(timeValue);
|
||||
const suffixes = ["d", "h", "m"];
|
||||
@@ -12,7 +12,9 @@ export function formatDuration(timeValue: number, compact: boolean) {
|
||||
duration.minutes(),
|
||||
];
|
||||
durationValues.forEach((value, index) => {
|
||||
if (value) result += value + suffixes[index] + " ";
|
||||
if (value) {
|
||||
result += value + suffixes[index] + " ";
|
||||
}
|
||||
});
|
||||
if (compact) {
|
||||
result = result.split(" ")[0];
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
// Common usage utils & helpers
|
||||
|
||||
export const noop = () => {};
|
||||
export const noop = (): void => {};
|
||||
export const isElectron = !!navigator.userAgent.match(/Electron/);
|
||||
|
||||
export * from './autobind'
|
||||
export * from './cssVar'
|
||||
export * from './cssNames'
|
||||
export * from './eventEmitter'
|
||||
export * from './downloadFile'
|
||||
export * from './prevDefault'
|
||||
export * from './createStorage'
|
||||
export * from './interval'
|
||||
export * from './debouncePromise'
|
||||
export * from './copyToClipboard'
|
||||
export * from './formatDuration'
|
||||
export * from './camelCase'
|
||||
export * from './base64'
|
||||
export * from './isReactNode'
|
||||
export * from './convertMemory'
|
||||
export * from './convertCpu'
|
||||
export * from './autobind';
|
||||
export * from './cssVar';
|
||||
export * from './cssNames';
|
||||
export * from './eventEmitter';
|
||||
export * from './downloadFile';
|
||||
export * from './prevDefault';
|
||||
export * from './createStorage';
|
||||
export * from './interval';
|
||||
export * from './debouncePromise';
|
||||
export * from './copyToClipboard';
|
||||
export * from './formatDuration';
|
||||
export * from './camelCase';
|
||||
export * from './base64';
|
||||
export * from './isReactNode';
|
||||
export * from './convertMemory';
|
||||
export * from './convertCpu';
|
||||
@@ -2,31 +2,48 @@
|
||||
|
||||
type IntervalCallback = (count: number) => void;
|
||||
|
||||
export function interval(timeSec = 1, callback: IntervalCallback, autoRun = false) {
|
||||
let count = 0;
|
||||
let timer = -1;
|
||||
let isRunning = false;
|
||||
const intervalManager = {
|
||||
start: function (runImmediately = false) {
|
||||
if (isRunning) return;
|
||||
const tick = () => callback(++count);
|
||||
isRunning = true;
|
||||
timer = window.setInterval(tick, 1000 * timeSec);
|
||||
if (runImmediately) tick();
|
||||
},
|
||||
stop: function () {
|
||||
count = 0;
|
||||
isRunning = false;
|
||||
clearInterval(timer);
|
||||
},
|
||||
restart: function (runImmediately = false) {
|
||||
this.stop();
|
||||
this.start(runImmediately);
|
||||
},
|
||||
get isRunning() {
|
||||
return isRunning;
|
||||
export class IntervalManager {
|
||||
private count: number;
|
||||
private timer: number;
|
||||
private isCurRunning: boolean;
|
||||
private timeSec: number;
|
||||
private callback: IntervalCallback;
|
||||
|
||||
constructor(timeSec = 1, callback: IntervalCallback, autoRun = false) {
|
||||
this.timeSec = timeSec;
|
||||
this.callback = callback;
|
||||
|
||||
if (autoRun) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
if (autoRun) intervalManager.start();
|
||||
return intervalManager;
|
||||
}
|
||||
|
||||
start(runImmediately?: boolean): void {
|
||||
if (this.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tick = (): void => this.callback(++this.count);
|
||||
this.isCurRunning = true;
|
||||
this.timer = window.setInterval(tick, 1000 * this.timeSec);
|
||||
|
||||
if (runImmediately) {
|
||||
tick();
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
this.count = 0;
|
||||
this.isCurRunning = false;
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
|
||||
restart(runImmediately = false): void {
|
||||
this.stop();
|
||||
this.start(runImmediately);
|
||||
}
|
||||
|
||||
get isRunning(): boolean {
|
||||
return this.isCurRunning;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
// Type guard for checking valid react node to use in render
|
||||
import React, { ReactNode } from "react"
|
||||
import React, { ReactNode } from "react";
|
||||
|
||||
export function isReactNode(node: ReactNode): node is ReactNode {
|
||||
return React.isValidElement(node)
|
||||
|| Array.isArray(node) && node.every(isReactNode)
|
||||
|| node == null
|
||||
|| typeof node !== "object"
|
||||
|| typeof node !== "object";
|
||||
}
|
||||
@@ -12,14 +12,14 @@ import * as React from "react";
|
||||
// <Icon onClick={prevDefault(() => console.log('stay on the page and open dialog'))}/>
|
||||
// </a>
|
||||
|
||||
export function prevDefault<E extends React.SyntheticEvent | Event>(callback: (evt: E) => any) {
|
||||
return function (evt: E) {
|
||||
export function prevDefault<E extends React.SyntheticEvent | Event>(callback: (evt: E) => any): (evt: E) => any {
|
||||
return function (evt: E): any {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
return callback(evt);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function stopPropagation(evt: Event | React.SyntheticEvent) {
|
||||
export function stopPropagation(evt: Event | React.SyntheticEvent): void {
|
||||
evt.stopPropagation();
|
||||
}
|
||||
Reference in new issue
Block a user