Add eslint rule padding-line-between-statements (#1593)

Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
This commit is contained in:
Panu Horsmalahti authored and GitHub committed 2020-12-02 09:55:52 +02:00
1 parent 7b77f18376
commit dcf253e7d5
401 files changed
+2018 -40

No files matched your search

@@ -31,8 +31,10 @@ describe("empty config", () => {
"lens-cluster-store.json": JSON.stringify({})
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -59,6 +61,7 @@ describe("empty config", () => {
it("adds new cluster to store", async () => {
const storedCluster = clusterStore.getById("foo");
expect(storedCluster.id).toBe("foo");
expect(storedCluster.preferences.terminalCWD).toBe("/tmp");
expect(storedCluster.preferences.icon).toBe("data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5");
@@ -67,6 +70,7 @@ describe("empty config", () => {
it("adds cluster to default workspace", () => {
const storedCluster = clusterStore.getById("foo");
expect(storedCluster.workspace).toBe("default");
});
@@ -114,6 +118,7 @@ describe("empty config", () => {
it("gets clusters by workspaces", () => {
const wsClusters = clusterStore.getByWorkspaceId("workstation");
const defaultClusters = clusterStore.getByWorkspaceId("default");
expect(defaultClusters.length).toBe(0);
expect(wsClusters.length).toBe(2);
expect(wsClusters[0].id).toBe("prod");
@@ -122,6 +127,7 @@ describe("empty config", () => {
it("check if cluster's kubeconfig file saved", () => {
const file = ClusterStore.embedCustomKubeConfig("boo", "kubeconfig");
expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig");
});
@@ -129,6 +135,7 @@ describe("empty config", () => {
clusterStore.swapIconOrders("workstation", 1, 1);
const clusters = clusterStore.getByWorkspaceId("workstation");
expect(clusters[0].id).toBe("prod");
expect(clusters[0].preferences.iconOrder).toBe(0);
expect(clusters[1].id).toBe("dev");
@@ -139,6 +146,7 @@ describe("empty config", () => {
clusterStore.swapIconOrders("workstation", 0, 1);
const clusters = clusterStore.getByWorkspaceId("workstation");
expect(clusters[0].id).toBe("dev");
expect(clusters[0].preferences.iconOrder).toBe(0);
expect(clusters[1].id).toBe("prod");
@@ -192,8 +200,10 @@ describe("config with existing clusters", () => {
})
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -203,6 +213,7 @@ describe("config with existing clusters", () => {
it("allows to retrieve a cluster", () => {
const storedCluster = clusterStore.getById("cluster1");
expect(storedCluster.id).toBe("cluster1");
expect(storedCluster.preferences.terminalCWD).toBe("/foo");
});
@@ -210,13 +221,16 @@ describe("config with existing clusters", () => {
it("allows to delete a cluster", () => {
clusterStore.removeById("cluster2");
const storedCluster = clusterStore.getById("cluster1");
expect(storedCluster).toBeTruthy();
const storedCluster2 = clusterStore.getById("cluster2");
expect(storedCluster2).toBeUndefined();
});
it("allows getting all of the clusters", async () => {
const storedClusters = clusterStore.clustersList;
expect(storedClusters.length).toBe(3);
expect(storedClusters[0].id).toBe("cluster1");
expect(storedClusters[0].preferences.terminalCWD).toBe("/foo");
@@ -227,6 +241,7 @@ describe("config with existing clusters", () => {
it("marks owned cluster disabled by default", () => {
const storedClusters = clusterStore.clustersList;
expect(storedClusters[0].enabled).toBe(true);
expect(storedClusters[2].enabled).toBe(false);
});
@@ -247,8 +262,10 @@ describe("pre 2.0 config with an existing cluster", () => {
})
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -258,6 +275,7 @@ describe("pre 2.0 config with an existing cluster", () => {
it("migrates to modern format with kubeconfig in a file", async () => {
const config = clusterStore.clustersList[0].kubeConfigPath;
expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content");
});
});
@@ -279,8 +297,10 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () =>
})
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -292,6 +312,7 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () =>
const file = clusterStore.clustersList[0].kubeConfigPath;
const config = fs.readFileSync(file, "utf8");
const kc = yaml.safeLoad(config);
expect(kc.users[0].user["auth-provider"].config["access-token"]).toBe("should be string");
expect(kc.users[0].user["auth-provider"].config["expiry"]).toBe("should be string");
});
@@ -319,8 +340,10 @@ describe("pre 2.6.0 config with a cluster icon", () => {
"icon_path": testDataIcon,
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -330,6 +353,7 @@ describe("pre 2.6.0 config with a cluster icon", () => {
it("moves the icon into preferences", async () => {
const storedClusterData = clusterStore.clustersList[0];
expect(storedClusterData.hasOwnProperty("icon")).toBe(false);
expect(storedClusterData.preferences.hasOwnProperty("icon")).toBe(true);
expect(storedClusterData.preferences.icon.startsWith("data:;base64,")).toBe(true);
@@ -356,8 +380,10 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => {
})
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -367,6 +393,7 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => {
it("adds cluster to default workspace", async () => {
const storedClusterData = clusterStore.clustersList[0];
expect(storedClusterData.workspace).toBe("default");
});
});
@@ -396,8 +423,10 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
"icon_path": testDataIcon,
}
};
mockFs(mockOpts);
clusterStore = ClusterStore.getInstance<ClusterStore>();
return clusterStore.load();
});
@@ -407,11 +436,13 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
it("migrates to modern format with kubeconfig in a file", async () => {
const config = clusterStore.clustersList[0].kubeConfigPath;
expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content");
});
it("migrates to modern format with icon not in file", async () => {
const { icon } = clusterStore.clustersList[0].preferences;
expect(icon.startsWith("data:;base64,")).toBe(true);
});
});
+1
View File
@@ -4,6 +4,7 @@ describe("event bus tests", () => {
describe("emit", () => {
it("emits an event", () => {
let event: AppEvent = null;
appEventBus.addListener((data) => {
event = data;
});
+1 -1
View File
@@ -5,7 +5,6 @@
import { SearchStore } from "../search-store";
let searchStore: SearchStore = null;
const logs = [
"1:M 30 Oct 2020 16:17:41.553 # Connection with replica 172.17.0.12:6379 lost",
"1:M 30 Oct 2020 16:17:41.623 * Replica 172.17.0.12:6379 asks for synchronization",
@@ -64,6 +63,7 @@ describe("search store tests", () => {
it("escapes string for using in regex", () => {
const regex = searchStore.escapeRegex("some.interesting-query\\#?()[]");
expect(regex).toBe("some\\.interesting\\-query\\\\\\#\\?\\(\\)\\[\\]");
});
+1
View File
@@ -59,6 +59,7 @@ describe("user store tests", () => {
it("correctly resets theme to default value", async () => {
const us = UserStore.getInstance<UserStore>();
us.isLoaded = true;
us.preferences.colorTheme = "some other theme";
+1 -1
View File
@@ -44,7 +44,6 @@ describe("workspace store tests", () => {
it("can update workspace description", () => {
const ws = WorkspaceStore.getInstance<WorkspaceStore>();
const workspace = ws.addWorkspace(new Workspace({
id: "foobar",
name: "foobar",
@@ -65,6 +64,7 @@ describe("workspace store tests", () => {
}));
const workspace = ws.getById("123");
expect(workspace.name).toBe("foobar");
expect(workspace.enabled).toBe(true);
});
+7
View File
@@ -55,6 +55,7 @@ export abstract class BaseStore<T = any> extends Singleton {
if (this.params.autoLoad) {
await this.load();
}
if (this.params.syncEnabled) {
await this.whenLoaded;
this.enableSync();
@@ -63,6 +64,7 @@ export abstract class BaseStore<T = any> extends Singleton {
async load() {
const { autoLoad, syncEnabled, ...confOptions } = this.params;
this.storeConfig = new Config({
...confOptions,
projectName: "lens",
@@ -90,19 +92,23 @@ export abstract class BaseStore<T = any> extends Singleton {
this.syncDisposers.push(
reaction(() => this.toJSON(), model => this.onModelChange(model), this.params.syncOptions),
);
if (ipcMain) {
const callback = (event: IpcMainEvent, model: T) => {
logger.silly(`[STORE]: SYNC ${this.name} from renderer`, { model });
this.onSync(model);
};
subscribeToBroadcast(this.syncMainChannel, callback);
this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncMainChannel, callback));
}
if (ipcRenderer) {
const callback = (event: IpcRendererEvent, model: T) => {
logger.silly(`[STORE]: SYNC ${this.name} from main`, { model });
this.onSyncFromMain(model);
};
subscribeToBroadcast(this.syncRendererChannel, callback);
this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncRendererChannel, callback));
}
@@ -127,6 +133,7 @@ export abstract class BaseStore<T = any> extends Singleton {
protected applyWithoutSync(callback: () => void) {
this.disableSync();
runInAction(callback);
if (this.params.syncEnabled) {
this.enableSync();
}
+7
View File
@@ -15,6 +15,7 @@ export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all";
if (ipcMain) {
handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
const cluster = clusterStore.getById(clusterId);
if (cluster) {
return cluster.activate(force);
}
@@ -22,20 +23,24 @@ if (ipcMain) {
handleRequest(clusterSetFrameIdHandler, (event, clusterId: ClusterId, frameId: number) => {
const cluster = clusterStore.getById(clusterId);
if (cluster) {
clusterFrameMap.set(cluster.id, frameId);
return cluster.pushState();
}
});
handleRequest(clusterRefreshHandler, (event, clusterId: ClusterId) => {
const cluster = clusterStore.getById(clusterId);
if (cluster) return cluster.refresh({ refreshMetadata: true });
});
handleRequest(clusterDisconnectHandler, (event, clusterId: ClusterId) => {
appEventBus.emit({name: "cluster", action: "stop"});
const cluster = clusterStore.getById(clusterId);
if (cluster) {
cluster.disconnect();
clusterFrameMap.delete(cluster.id);
@@ -45,8 +50,10 @@ if (ipcMain) {
handleRequest(clusterKubectlApplyAllHandler, (event, clusterId: ClusterId, resources: string[]) => {
appEventBus.emit({name: "cluster", action: "kubectl-apply-all"});
const cluster = clusterStore.getById(clusterId);
if (cluster) {
const applier = new ResourceApplier(cluster);
applier.kubectlApplyAll(resources);
} else {
throw `${clusterId} is not a valid cluster id`;
+21
View File
@@ -98,7 +98,9 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
static embedCustomKubeConfig(clusterId: ClusterId, kubeConfig: KubeConfig | string): string {
const filePath = ClusterStore.getCustomKubeConfigPath(clusterId);
const fileContents = typeof kubeConfig == "string" ? kubeConfig : dumpConfigYaml(kubeConfig);
saveToAppFiles(filePath, fileContents, { mode: 0o600 });
return filePath;
}
@@ -127,11 +129,14 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
id: string;
state: ClusterState;
};
if (ipcRenderer) {
logger.info("[CLUSTER-STORE] requesting initial state sync");
const clusterStates: clusterStateSync[] = await requestMain(ClusterStore.stateRequestChannel);
clusterStates.forEach((clusterState) => {
const cluster = this.getById(clusterState.id);
if (cluster) {
cluster.setState(clusterState.state);
}
@@ -139,12 +144,14 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
} else {
handleRequest(ClusterStore.stateRequestChannel, (): clusterStateSync[] => {
const states: clusterStateSync[] = [];
this.clustersList.forEach((cluster) => {
states.push({
state: cluster.getState(),
id: cluster.id
});
});
return states;
});
}
@@ -207,6 +214,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
@action
setActive(id: ClusterId) {
const clusterId = this.clusters.has(id) ? id : null;
this.activeCluster = clusterId;
workspaceStore.setLastActiveClusterId(clusterId);
}
@@ -214,11 +222,13 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
@action
swapIconOrders(workspace: WorkspaceId, from: number, to: number) {
const clusters = this.getByWorkspaceId(workspace);
if (from < 0 || to < 0 || from >= clusters.length || to >= clusters.length || isNaN(from) || isNaN(to)) {
throw new Error(`invalid from<->to arguments`);
}
move.mutate(clusters, from, to);
for (const i in clusters) {
// This resets the iconOrder to the current display order
clusters[i].preferences.iconOrder = +i;
@@ -236,12 +246,14 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
getByWorkspaceId(workspaceId: string): Cluster[] {
const clusters = Array.from(this.clusters.values())
.filter(cluster => cluster.workspace === workspaceId);
return _.sortBy(clusters, cluster => cluster.preferences.iconOrder);
}
@action
addClusters(...models: ClusterModel[]): Cluster[] {
const clusters: Cluster[] = [];
models.forEach(model => {
clusters.push(this.addCluster(model));
});
@@ -253,13 +265,16 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
addCluster(model: ClusterModel | Cluster): Cluster {
appEventBus.emit({ name: "cluster", action: "add" });
let cluster = model as Cluster;
if (!(model instanceof Cluster)) {
cluster = new Cluster(model);
}
if (!cluster.isManaged) {
cluster.enabled = true;
}
this.clusters.set(model.id, cluster);
return cluster;
}
@@ -271,11 +286,14 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
async removeById(clusterId: ClusterId) {
appEventBus.emit({ name: "cluster", action: "remove" });
const cluster = this.getById(clusterId);
if (cluster) {
this.clusters.delete(clusterId);
if (this.activeCluster === clusterId) {
this.setActive(null);
}
// remove only custom kubeconfigs (pasted as text)
if (cluster.kubeConfigPath == ClusterStore.getCustomKubeConfigPath(clusterId)) {
unlink(cluster.kubeConfigPath).catch(() => null);
@@ -299,10 +317,12 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
// update new clusters
for (const clusterModel of clusters) {
let cluster = currentClusters.get(clusterModel.id);
if (cluster) {
cluster.updateModel(clusterModel);
} else {
cluster = new Cluster(clusterModel);
if (!cluster.isManaged) {
cluster.enabled = true;
}
@@ -336,6 +356,7 @@ export const clusterStore = ClusterStore.getInstance<ClusterStore>();
export function getClusterIdFromHost(hostname: string): ClusterId {
const subDomains = hostname.split(":")[0].split(".");
return subDomains.slice(-2)[0]; // e.g host == "%clusterId.localhost:45345"
}
+1
View File
@@ -2,6 +2,7 @@ export class ExecValidationNotFoundError extends Error {
constructor(execPath: string, isAbsolute: boolean) {
super(`User Exec command "${execPath}" not found on host.`);
let message = `User Exec command "${execPath}" not found on host.`;
if (!isAbsolute) {
message += ` Please ensure binary is found in PATH or use absolute path to binary in Kubeconfig`;
}
+3
View File
@@ -13,6 +13,7 @@ export class EventEmitter<D extends [...any[]]> {
addListener(callback: Callback<D>, options: Options = {}) {
if (options.prepend) {
const listeners = [...this.listeners];
listeners.unshift([callback, options]);
this.listeners = new Map(listeners);
}
@@ -33,7 +34,9 @@ export class EventEmitter<D extends [...any[]]> {
[...this.listeners].every(([callback, options]) => {
if (options.once) this.removeListener(callback);
const result = callback(...data);
if (result === false) return; // break cycle
return true;
});
}
+5
View File
@@ -16,18 +16,22 @@ export async function requestMain(channel: string, ...args: any[]) {
async function getSubFrames(): Promise<number[]> {
const subFrames: number[] = [];
clusterFrameMap.forEach(frameId => {
subFrames.push(frameId);
});
return subFrames;
}
export function broadcastMessage(channel: string, ...args: any[]) {
const views = (webContents || remote?.webContents)?.getAllWebContents();
if (!views) return;
views.forEach(webContent => {
const type = webContent.getType();
logger.silly(`[IPC]: broadcasting "${channel}" to ${type}=${webContent.id}`, { args });
webContent.send(channel, ...args);
getSubFrames().then((frames) => {
@@ -36,6 +40,7 @@ export function broadcastMessage(channel: string, ...args: any[]) {
});
}).catch((e) => e);
});
if (ipcRenderer) {
ipcRenderer.send(channel, ...args);
} else {
+10 -1
View File
@@ -13,6 +13,7 @@ function resolveTilde(filePath: string) {
if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) {
return filePath.replace("~", os.homedir());
}
return filePath;
}
@@ -40,12 +41,15 @@ export function validateConfig(config: KubeConfig | string): KubeConfig {
config = loadConfig(config);
}
logger.debug(`validating kube config: ${JSON.stringify(config)}`);
if (!config.users || config.users.length == 0) {
throw new Error("No users provided in config");
}
if (!config.clusters || config.clusters.length == 0) {
throw new Error("No clusters provided in config");
}
if (!config.contexts || config.contexts.length == 0) {
throw new Error("No contexts provided in config");
}
@@ -58,11 +62,13 @@ export function validateConfig(config: KubeConfig | string): KubeConfig {
*/
export function splitConfig(kubeConfig: KubeConfig): KubeConfig[] {
const configs: KubeConfig[] = [];
if (!kubeConfig.contexts) {
return configs;
}
kubeConfig.contexts.forEach(ctx => {
const kc = new KubeConfig();
kc.clusters = [kubeConfig.getCluster(ctx.cluster)].filter(n => n);
kc.users = [kubeConfig.getUser(ctx.user)].filter(n => n);
kc.contexts = [kubeConfig.getContextObject(ctx.name)].filter(n => n);
@@ -70,6 +76,7 @@ export function splitConfig(kubeConfig: KubeConfig): KubeConfig[] {
configs.push(kc);
});
return configs;
}
@@ -153,11 +160,13 @@ export function validateKubeConfig (config: KubeConfig) {
logger.debug(`validateKubeConfig: validating kubeconfig - ${JSON.stringify(config)}`);
// Validate the User Object
const user = config.getCurrentUser();
const user = config.getCurrentUser();
if (user.exec) {
const execCommand = user.exec["command"];
// check if the command is absolute or not
const isAbsolute = path.isAbsolute(execCommand);
// validate the exec struct in the user object, start with the command field
logger.debug(`validateKubeConfig: validating user exec command - ${JSON.stringify(execCommand)}`);
+1
View File
@@ -6,6 +6,7 @@ import { PrometheusProviderRegistry } from "../main/prometheus/provider-registry
[PrometheusLens, PrometheusHelm, PrometheusOperator, PrometheusStacklight].forEach(providerClass => {
const provider = new providerClass();
PrometheusProviderRegistry.registerProvider(provider.id, provider);
});
+2
View File
@@ -42,10 +42,12 @@ export function isAllowedResource(resources: KubeResource | KubeResource[]) {
resources = [resources];
}
const { allowedResources = [] } = getHostedCluster() || {};
for (const resource of resources) {
if (!allowedResources.includes(resource)) {
return false;
}
}
return true;
}
+1
View File
@@ -7,6 +7,7 @@ export function registerFileProtocol(name: string, basePath: string) {
protocol.registerFileProtocol(name, (request, callback) => {
const filePath = request.url.replace(`${name}://`, "");
const absPath = path.resolve(basePath, filePath);
callback({ path: absPath });
});
}
+1
View File
@@ -7,6 +7,7 @@ import { userStore } from "./user-store";
function getDefaultRequestOpts(): Partial<request.Options> {
const { httpsProxy, allowUntrustedCAs } = userStore.preferences;
return {
proxy: httpsProxy || undefined,
rejectUnauthorized: !allowUntrustedCAs,
+10
View File
@@ -14,8 +14,10 @@ export class SearchStore {
@action
onSearch(text: string[], query = this.searchQuery) {
this.searchQuery = query;
if (!query) {
this.reset();
return;
}
this.occurrences = this.findOccurences(text, query);
@@ -36,11 +38,14 @@ export class SearchStore {
findOccurences(text: string[], query: string) {
if (!text) return [];
const occurences: number[] = [];
text.forEach((line, index) => {
const regex = new RegExp(this.escapeRegex(query), "gi");
const matches = [...line.matchAll(regex)];
matches.forEach(() => occurences.push(index));
});
return occurences;
}
@@ -51,9 +56,11 @@ export class SearchStore {
*/
getNextOverlay(loopOver = false) {
const next = this.activeOverlayIndex + 1;
if (next > this.occurrences.length - 1) {
return loopOver ? 0 : this.activeOverlayIndex;
}
return next;
}
@@ -64,9 +71,11 @@ export class SearchStore {
*/
getPrevOverlay(loopOver = false) {
const prev = this.activeOverlayIndex - 1;
if (prev < 0) {
return loopOver ? this.occurrences.length - 1 : this.activeOverlayIndex;
}
return prev;
}
@@ -104,6 +113,7 @@ export class SearchStore {
@autobind()
isActiveOverlay(line: number, occurence: number) {
const firstLineIndex = this.occurrences.findIndex(item => item === line);
return firstLineIndex + occurence === this.activeOverlayIndex;
}
+2
View File
@@ -6,9 +6,11 @@ import logger from "../main/logger";
if (isMac) {
for (const crt of macca.all()) {
const attributes = crt.issuer?.attributes?.map((a: any) => `${a.name}=${a.value}`);
logger.debug(`Using host CA: ${attributes.join(",")}`);
}
}
if (isWindows) {
winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats
}
+5
View File
@@ -102,6 +102,7 @@ export class UserStore extends BaseStore<UserStoreModel> {
protected refreshNewContexts = async () => {
try {
const kubeConfig = await readFile(this.kubeConfigPath, "utf8");
if (kubeConfig) {
this.newContexts.clear();
loadConfig(kubeConfig).getContexts()
@@ -118,6 +119,7 @@ export class UserStore extends BaseStore<UserStoreModel> {
@action
markNewContextsAsSeen() {
const { seenContexts, newContexts } = this;
this.seenContexts.replace([...seenContexts, ...newContexts]);
this.newContexts.clear();
}
@@ -133,9 +135,11 @@ export class UserStore extends BaseStore<UserStoreModel> {
@action
protected async fromStore(data: Partial<UserStoreModel> = {}) {
const { lastSeenAppVersion, seenContexts = [], preferences, kubeConfigPath } = data;
if (lastSeenAppVersion) {
this.lastSeenAppVersion = lastSeenAppVersion;
}
if (kubeConfigPath) {
this.kubeConfigPath = kubeConfigPath;
}
@@ -150,6 +154,7 @@ export class UserStore extends BaseStore<UserStoreModel> {
seenContexts: Array.from(this.seenContexts),
preferences: this.preferences,
};
return toJS(model, {
recurseEverything: true,
});
+2 -1
View File
@@ -12,7 +12,6 @@ export function autobind() {
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";
@@ -21,6 +20,7 @@ function bindClass<T extends Constructor>(constructor: T) {
Object.keys(descriptors).forEach(prop => {
if (skipMethod(prop)) return;
const boundDescriptor = bindMethod(proto, prop, descriptors[prop]);
Object.defineProperty(proto, prop, boundDescriptor);
});
}
@@ -38,6 +38,7 @@ function bindMethod(target: object, prop?: string, descriptor?: PropertyDescript
get() {
if (this === target) return func; // direct access from prototype
if (!boundFunc.has(this)) boundFunc.set(this, func.bind(this));
return boundFunc.get(this);
}
});
+2
View File
@@ -7,8 +7,10 @@ export interface IURLParams<P extends object = {}, Q extends object = {}> {
export function buildURL<P extends object = {}, Q extends object = {}>(path: string | any) {
const pathBuilder = compile(String(path));
return function ({ params, query }: IURLParams<P, Q> = {}) {
const queryParams = query ? new URLSearchParams(Object.entries(query)).toString() : "";
return pathBuilder(params) + (queryParams ? `?${queryParams}` : "");
};
}
+2
View File
@@ -8,7 +8,9 @@ export function toCamelCase(obj: Record<string, any>): any {
else if (isPlainObject(obj)) {
return Object.keys(obj).reduce((result, key) => {
const value = obj[key];
result[camelCase(key)] = typeof value === "object" ? toCamelCase(value) : value;
return result;
}, {} as any);
}
+1
View File
@@ -2,6 +2,7 @@
export function debouncePromise<T, F extends any[]>(func: (...args: F) => T | Promise<T>, timeout = 0): (...args: F) => Promise<T> {
let timer: NodeJS.Timeout;
return (...params: any[]) => new Promise(resolve => {
clearTimeout(timer);
timer = global.setTimeout(() => resolve(func.apply(this, params)), timeout);
+1
View File
@@ -26,6 +26,7 @@ export function downloadFile({ url, timeout, gzip = true }: DownloadFileOptions)
resolve(Buffer.concat(fileChunks));
});
});
return {
url,
promise,
+1
View File
@@ -2,5 +2,6 @@
export function getRandId({ prefix = "", suffix = "", sep = "_" } = {}) {
const randId = () => Math.random().toString(16).substr(2);
return [prefix, randId(), suffix].filter(s => s).join(sep);
}
+2
View File
@@ -6,7 +6,9 @@ import { WriteFileOptions } from "fs";
export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string {
const absPath = path.resolve((app || remote.app).getPath("userData"), filePath);
ensureDirSync(path.dirname(absPath));
writeFileSync(absPath, contents, options);
return absPath;
}
+1
View File
@@ -16,6 +16,7 @@ class Singleton {
if (!Singleton.instances.has(this)) {
Singleton.instances.set(this, Reflect.construct(this, args));
}
return Singleton.instances.get(this) as T;
}
+2
View File
@@ -12,8 +12,10 @@
*/
export function splitArray<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];
}
+3
View File
@@ -26,6 +26,7 @@ export function readFileFromTar<R = Buffer>({ tarPath, filePath, parseJson }: Re
entry.once("end", () => {
const data = Buffer.concat(fileChunks);
const result = parseJson ? JSON.parse(data.toString("utf8")) : data;
resolve(result);
});
},
@@ -39,12 +40,14 @@ export function readFileFromTar<R = Buffer>({ tarPath, filePath, parseJson }: Re
export async function listTarEntries(filePath: string): Promise<string[]> {
const entries: string[] = [];
await tar.list({
file: filePath,
onentry: (entry: FileStat) => {
entries.push(path.normalize(entry.path as any as string));
},
});
return entries;
}
+1
View File
@@ -30,6 +30,7 @@ defineGlobal("__static", {
if (isDevelopment) {
return path.resolve(contextDir, "static");
}
return path.resolve(process.resourcesPath, "static");
}
});
+14
View File
@@ -125,11 +125,14 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
id: string;
state: WorkspaceState;
};
if (ipcRenderer) {
logger.info("[WORKSPACE-STORE] requesting initial state sync");
const workspaceStates: workspaceStateSync[] = await requestMain(WorkspaceStore.stateRequestChannel);
workspaceStates.forEach((workspaceState) => {
const workspace = this.getById(workspaceState.id);
if (workspace) {
workspace.setState(workspaceState.state);
}
@@ -137,12 +140,14 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
} else {
handleRequest(WorkspaceStore.stateRequestChannel, (): workspaceStateSync[] => {
const states: workspaceStateSync[] = [];
this.workspacesList.forEach((workspace) => {
states.push({
state: workspace.getState(),
id: workspace.id
});
});
return states;
});
}
@@ -202,6 +207,7 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
@action
setActive(id = WorkspaceStore.defaultId) {
if (id === this.currentWorkspaceId) return;
if (!this.getById(id)) {
throw new Error(`workspace ${id} doesn't exist`);
}
@@ -211,15 +217,18 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
@action
addWorkspace(workspace: Workspace) {
const { id, name } = workspace;
if (!name.trim() || this.getByName(name.trim())) {
return;
}
this.workspaces.set(id, workspace);
if (!workspace.isManaged) {
workspace.enabled = true;
}
appEventBus.emit({name: "workspace", action: "add"});
return workspace;
}
@@ -237,10 +246,13 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
@action
removeWorkspaceById(id: WorkspaceId) {
const workspace = this.getById(id);
if (!workspace) return;
if (this.isDefault(id)) {
throw new Error("Cannot remove default workspace");
}
if (this.currentWorkspaceId === id) {
this.currentWorkspaceId = WorkspaceStore.defaultId; // reset to default
}
@@ -259,10 +271,12 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
if (currentWorkspace) {
this.currentWorkspaceId = currentWorkspace;
}
if (workspaces.length) {
this.workspaces.clear();
workspaces.forEach(ws => {
const workspace = new Workspace(ws);
if (!workspace.isManaged) {
workspace.enabled = true;
}