(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);
}
});
diff --git a/src/common/utils/buildUrl.ts b/src/common/utils/buildUrl.ts
index c26e054491..e3bad9b302 100644
--- a/src/common/utils/buildUrl.ts
+++ b/src/common/utils/buildUrl.ts
@@ -7,8 +7,10 @@ export interface IURLParams {
export function buildURL
(path: string | any) {
const pathBuilder = compile(String(path));
+
return function ({ params, query }: IURLParams
= {}) {
const queryParams = query ? new URLSearchParams(Object.entries(query)).toString() : "";
+
return pathBuilder(params) + (queryParams ? `?${queryParams}` : "");
};
}
diff --git a/src/common/utils/camelCase.ts b/src/common/utils/camelCase.ts
index 90c048cad5..306cb45190 100644
--- a/src/common/utils/camelCase.ts
+++ b/src/common/utils/camelCase.ts
@@ -8,7 +8,9 @@ export function toCamelCase(obj: Record): 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);
}
diff --git a/src/common/utils/debouncePromise.ts b/src/common/utils/debouncePromise.ts
index e03c0e76bd..b5ad88d000 100755
--- a/src/common/utils/debouncePromise.ts
+++ b/src/common/utils/debouncePromise.ts
@@ -2,6 +2,7 @@
export function debouncePromise(func: (...args: F) => T | Promise, timeout = 0): (...args: F) => Promise {
let timer: NodeJS.Timeout;
+
return (...params: any[]) => new Promise(resolve => {
clearTimeout(timer);
timer = global.setTimeout(() => resolve(func.apply(this, params)), timeout);
diff --git a/src/common/utils/downloadFile.ts b/src/common/utils/downloadFile.ts
index 4c65901d3d..dfa549da07 100644
--- a/src/common/utils/downloadFile.ts
+++ b/src/common/utils/downloadFile.ts
@@ -26,6 +26,7 @@ export function downloadFile({ url, timeout, gzip = true }: DownloadFileOptions)
resolve(Buffer.concat(fileChunks));
});
});
+
return {
url,
promise,
diff --git a/src/common/utils/getRandId.ts b/src/common/utils/getRandId.ts
index afe075085d..ef02e2f0eb 100644
--- a/src/common/utils/getRandId.ts
+++ b/src/common/utils/getRandId.ts
@@ -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);
}
diff --git a/src/common/utils/saveToAppFiles.ts b/src/common/utils/saveToAppFiles.ts
index 57c47f0d70..87d09290c0 100644
--- a/src/common/utils/saveToAppFiles.ts
+++ b/src/common/utils/saveToAppFiles.ts
@@ -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;
}
diff --git a/src/common/utils/singleton.ts b/src/common/utils/singleton.ts
index ed3f0cc962..61269d10b1 100644
--- a/src/common/utils/singleton.ts
+++ b/src/common/utils/singleton.ts
@@ -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;
}
diff --git a/src/common/utils/splitArray.ts b/src/common/utils/splitArray.ts
index f93392f736..7be367ebe6 100644
--- a/src/common/utils/splitArray.ts
+++ b/src/common/utils/splitArray.ts
@@ -12,8 +12,10 @@
*/
export function splitArray(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];
}
diff --git a/src/common/utils/tar.ts b/src/common/utils/tar.ts
index bec7b5b3f2..f9876e2b27 100644
--- a/src/common/utils/tar.ts
+++ b/src/common/utils/tar.ts
@@ -26,6 +26,7 @@ export function readFileFromTar({ 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({ tarPath, filePath, parseJson }: Re
export async function listTarEntries(filePath: string): Promise {
const entries: string[] = [];
+
await tar.list({
file: filePath,
onentry: (entry: FileStat) => {
entries.push(path.normalize(entry.path as any as string));
},
});
+
return entries;
}
diff --git a/src/common/vars.ts b/src/common/vars.ts
index ac9f1336ee..396a1077c5 100644
--- a/src/common/vars.ts
+++ b/src/common/vars.ts
@@ -30,6 +30,7 @@ defineGlobal("__static", {
if (isDevelopment) {
return path.resolve(contextDir, "static");
}
+
return path.resolve(process.resourcesPath, "static");
}
});
diff --git a/src/common/workspace-store.ts b/src/common/workspace-store.ts
index 4d5af6da98..e1fa113ca3 100644
--- a/src/common/workspace-store.ts
+++ b/src/common/workspace-store.ts
@@ -125,11 +125,14 @@ export class WorkspaceStore extends BaseStore {
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 {
} 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 {
@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 {
@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 {
@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 {
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;
}
diff --git a/src/extensions/cluster-feature.ts b/src/extensions/cluster-feature.ts
index bb60e9d9b4..625f2b5973 100644
--- a/src/extensions/cluster-feature.ts
+++ b/src/extensions/cluster-feature.ts
@@ -108,12 +108,15 @@ export abstract class ClusterFeature {
*/
protected renderTemplates(folderPath: string): string[] {
const resources: string[] = [];
+
logger.info(`[FEATURE]: render templates from ${folderPath}`);
fs.readdirSync(folderPath).forEach(filename => {
const file = path.join(folderPath, filename);
const raw = fs.readFileSync(file);
+
if (filename.endsWith(".hb")) {
const template = hb.compile(raw.toString());
+
resources.push(template(this.templateContext));
} else {
resources.push(raw.toString());
diff --git a/src/extensions/core-api/app.ts b/src/extensions/core-api/app.ts
index 2664711db4..2c3a7a4f59 100644
--- a/src/extensions/core-api/app.ts
+++ b/src/extensions/core-api/app.ts
@@ -3,6 +3,7 @@ import { extensionsStore } from "../extensions-store";
export const version = getAppVersion();
export { isSnap, isWindows, isMac, isLinux, appName, slackUrl, issuesTrackerUrl } from "../../common/vars";
+
export function getEnabledExtensions(): string[] {
return extensionsStore.enabledExtensions;
}
diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts
index 699e37042f..105b8e2041 100644
--- a/src/extensions/extension-discovery.ts
+++ b/src/extensions/extension-discovery.ts
@@ -25,6 +25,7 @@ export interface InstalledExtension {
}
const logModule = "[EXTENSION-DISCOVERY]";
+
export const manifestFilename = "package.json";
/**
@@ -133,7 +134,6 @@ export class ExtensionDiscovery {
if (path.basename(filePath) === manifestFilename) {
try {
const absPath = path.dirname(filePath);
-
// this.loadExtensionFromPath updates this.packagesJson
const extension = await this.loadExtensionFromPath(absPath);
@@ -251,6 +251,7 @@ export class ExtensionDiscovery {
manifestJson = __non_webpack_require__(manifestPath);
const installedManifestPath = path.join(this.nodeModulesPath, manifestJson.name, "package.json");
+
this.packagesJson.dependencies[manifestJson.name] = path.dirname(manifestPath);
const isEnabled = isBundled || extensionsStore.isEnabled(installedManifestPath);
@@ -272,6 +273,7 @@ export class ExtensionDiscovery {
async loadExtensions(): Promise