convert the cluster settings view from Vue to React (#613)

- Add a basic file picker component
- Now stores the icons as base64 img src formatted data blobs
- Changed over cluster settings to mobx
- Removed old Vue files

Signed-off-by: Sebastian Malton <smalton@mirantis.com>

Co-authored-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
Sebastian MaltonandSebastian Malton authored and GitHub committed 2020-08-02 15:56:39 +03:00
1 parent bac6fbaaf1
commit d4ff99f3bf
41 files changed
+1375 -209

No files matched your search

+30
View File
@@ -17,4 +17,34 @@ export const clusterIpc = {
return clusterStore.getById(clusterId)?.disconnect();
},
}),
installFeature: createIpcChannel({
channel: "cluster:install-feature",
handle: async (clusterId: ClusterId, feature: string, config?: any) => {
tracker.event("cluster", "install", feature);
const cluster = clusterStore.getById(clusterId);
if (cluster) {
await cluster.installFeature(feature, config)
} else {
throw `${clusterId} is not a valid cluster id`;
}
}
}),
uninstallFeature: createIpcChannel({
channel: "cluster:uninstall-feature",
handle: (clusterId: ClusterId, feature: string) => {
tracker.event("cluster", "uninstall", feature);
return clusterStore.getById(clusterId)?.uninstallFeature(feature)
}
}),
upgradeFeature: createIpcChannel({
channel: "cluster:upgrade-feature",
handle: (clusterId: ClusterId, feature: string, config?: any) => {
tracker.event("cluster", "upgrade", feature);
return clusterStore.getById(clusterId)?.upgradeFeature(feature, config)
}
}),
}
+3 -26
View File
@@ -1,7 +1,7 @@
import type { WorkspaceId } from "./workspace-store";
import path from "path";
import filenamify from "filenamify";
import { app, ipcRenderer } from "electron";
import { app, ipcRenderer, remote } from "electron";
import { copyFile, ensureDir, unlink } from "fs-extra";
import { action, computed, observable, toJS } from "mobx";
import { appProto, noClustersHost } from "./vars";
@@ -53,7 +53,8 @@ export interface ClusterPreferences {
export class ClusterStore extends BaseStore<ClusterStoreModel> {
static get iconsDir() {
return path.join(app.getPath("userData"), "icons");
// TODO: remove remote cheat
return path.join((app || remote.app).getPath("userData"), "icons");
}
private constructor() {
@@ -130,30 +131,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
})
}
@action
protected async uploadIcon({ clusterId, ...upload }: ClusterIconUpload): Promise<string> {
const cluster = this.getById(clusterId);
if (cluster) {
tracker.event("cluster", "upload-icon");
const fileDest = path.join(ClusterStore.iconsDir, filenamify(cluster.contextName + "-" + upload.name))
await ensureDir(path.dirname(fileDest));
await copyFile(upload.path, fileDest)
cluster.preferences.icon = `${appProto}:///icons/${fileDest}`
return cluster.preferences.icon;
}
}
@action
protected resetIcon(clusterId: ClusterId) {
const cluster = this.getById(clusterId);
if (cluster) {
tracker.event("cluster", "reset-icon")
const iconPath = path.join(ClusterStore.iconsDir, path.basename(cluster.preferences.icon));
unlink(iconPath).catch(() => null); // remove file
delete cluster.preferences.icon;
}
}
@action
protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) {
const currentClusters = this.clusters.toJS();
+2
View File
@@ -45,6 +45,8 @@ export async function invokeIpc<R = any>(channel: IpcChannel, ...args: any[]): P
// todo: make isomorphic api
export function handleIpc(channel: IpcChannel, handler: IpcMessageHandler, options: IpcHandleOpts = {}) {
const { timeout = 0 } = options;
logger.info(`[IPC]: setup to handle "${channel}"`);
ipcMain.handle(channel, async (event, ...args) => {
logger.info(`[IPC]: handle "${channel}"`, { args });
return new Promise(async (resolve, reject) => {
+11 -3
View File
@@ -5,6 +5,7 @@ import path from "path"
import os from "os"
import yaml from "js-yaml"
import logger from "../main/logger";
import fse from "fs-extra"
function resolveTilde(filePath: string) {
if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) {
@@ -15,11 +16,13 @@ function resolveTilde(filePath: string) {
export function loadConfig(pathOrContent?: string): KubeConfig {
const kc = new KubeConfig();
if (path.isAbsolute(pathOrContent)) {
kc.loadFromFile(resolveTilde(pathOrContent));
if (fse.pathExistsSync(pathOrContent)) {
kc.loadFromFile(path.resolve(resolveTilde(pathOrContent)));
} else {
kc.loadFromString(pathOrContent);
}
return kc
}
@@ -154,7 +157,12 @@ export function saveConfigToAppFiles(clusterId: string, kubeConfig: KubeConfig |
export async function getKubeConfigLocal(): Promise<string> {
try {
const configFile = path.join(process.env.HOME, '.kube', 'config');
return readFile(configFile, "utf8");
const file = await readFile(configFile, "utf8");
const obj = yaml.safeLoad(file);
if (obj.contexts) {
obj.contexts = obj.context.filter((ctx: any) => ctx?.context?.cluster && ctx?.name)
}
return yaml.safeDump(obj);
} catch (err) {
logger.debug(`Cannot read local kube-config: ${err}`)
return "";
+5 -5
View File
@@ -71,11 +71,11 @@ export class UserStore extends BaseStore<UserStoreModel> {
if (kubeConfig) {
this.newContexts.clear();
const localContexts = loadConfig(kubeConfig).getContexts();
localContexts.forEach(({ name }) => {
if (!this.seenContexts.has(name)) {
this.newContexts.add(name);
}
})
console.log(localContexts)
localContexts
.filter(ctx => ctx.cluster)
.filter(ctx => !this.seenContexts.has(ctx.name))
.forEach(ctx => this.newContexts.add(ctx.name));
}
}