Lens app source code (#119)

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen authored and GitHub committed 2020-03-15 09:52:02 +02:00
1 parent 936cbd53d4
commit 1d0815abd2
797 files changed
+73714 -215

No files matched your search

View File
Whitespace-only changes.
+14
View File
@@ -0,0 +1,14 @@
import { app, remote } from "electron"
/**
*
* @returns app version correctly regardless of dev/prod mode and main/renderer differences
*/
export function getAppVersion(): string {
// app is undefined when running in renderer
let version = (app || remote.app).getVersion()
if(process.env.NODE_ENV === 'development') {
version = require("../../package.json").version
}
return version;
}
+113
View File
@@ -0,0 +1,113 @@
import * as ElectronStore from "electron-store"
import { Cluster, ClusterBaseInfo } from "../main/cluster";
import { getAppVersion } from "./app-utils"
import * as version200Beta2 from "./migrations/cluster-store/2.0.0-beta.2"
import * as version241 from "./migrations/cluster-store/2.4.1"
import * as version260Beta2 from "./migrations/cluster-store/2.6.0-beta.2"
import * as version260Beta3 from "./migrations/cluster-store/2.6.0-beta.3"
import * as version270Beta0 from "./migrations/cluster-store/2.7.0-beta.0"
import * as version270Beta1 from "./migrations/cluster-store/2.7.0-beta.1"
export class ClusterStore {
private static instance: ClusterStore;
public store: ElectronStore;
private constructor() {
this.store = new ElectronStore({
name: "lens-cluster-store",
projectVersion: getAppVersion(),
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
migrations: {
"2.0.0-beta.2": version200Beta2.migration,
"2.4.1": version241.migration,
"2.6.0-beta.2": version260Beta2.migration,
"2.6.0-beta.3": version260Beta3.migration,
"2.7.0-beta.0": version270Beta0.migration,
"2.7.0-beta.1": version270Beta1.migration
}
})
}
public getAllClusterObjects(): Array<Cluster> {
return this.store.get("clusters", []).map((clusterInfo: ClusterBaseInfo) => {
return new Cluster(clusterInfo)
})
}
public getAllClusters(): Array<ClusterBaseInfo> {
return this.store.get("clusters", [])
}
public removeCluster(id: string): void {
this.store.delete(id);
const clusterBaseInfos = this.getAllClusters()
const index = clusterBaseInfos.findIndex((cbi) => cbi.id === id)
if (index !== -1) {
clusterBaseInfos.splice(index, 1)
this.store.set("clusters", clusterBaseInfos)
}
}
public removeClustersByWorkspace(workspace: string) {
this.getAllClusters().forEach((cluster) => {
if (cluster.workspace === workspace) {
this.removeCluster(cluster.id)
}
})
}
public getCluster(id: string): Cluster {
const cluster = this.getAllClusterObjects().find((cluster) => cluster.id === id)
if (cluster) { return cluster}
return null
}
public storeCluster(cluster: ClusterBaseInfo) {
const clusters = this.getAllClusters();
const index = clusters.findIndex((cl) => cl.id === cluster.id)
const storable = {
id: cluster.id,
kubeConfig: cluster.kubeConfig,
preferences: cluster.preferences,
workspace: cluster.workspace
}
if (index === -1) {
clusters.push(storable)
} else {
clusters[index] = storable
}
this.store.set("clusters", clusters)
}
public storeClusters(clusters: ClusterBaseInfo[]) {
clusters.forEach((cluster: ClusterBaseInfo) => {
this.removeCluster(cluster.id)
this.storeCluster(cluster)
})
}
public reloadCluster(cluster: ClusterBaseInfo): void {
const storedCluster = this.getCluster(cluster.id);
if (storedCluster) {
cluster.kubeConfig = storedCluster.kubeConfig
cluster.preferences = storedCluster.preferences
cluster.workspace = storedCluster.workspace
}
}
static getInstance(): ClusterStore {
if(!ClusterStore.instance) {
ClusterStore.instance = new ClusterStore();
}
return ClusterStore.instance;
}
static resetInstance() {
ClusterStore.instance = null
}
}
const clusterStore: ClusterStore = ClusterStore.getInstance();
export { clusterStore };
@@ -0,0 +1,13 @@
/* Early store format had the kubeconfig directly under context name, this moves
it under the kubeConfig key */
export function migration(store: any) {
console.log("CLUSTER STORE, MIGRATION: 2.0.0-beta.2");
for (const value of store) {
const contextName = value[0];
// Looping all the keys gives out the store internal stuff too...
if(contextName === "__internal__" || value[1].hasOwnProperty('kubeConfig')) continue;
store.set(contextName, { kubeConfig: value[1] });
}
}
@@ -0,0 +1,11 @@
// Cleans up a store that had the state related data stored
export function migration(store: any) {
console.log("CLUSTER STORE, MIGRATION: 2.4.1");
for (const value of store) {
const contextName = value[0];
if(contextName === "__internal__") continue;
const cluster = value[1];
store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {} });
}
}
@@ -0,0 +1,15 @@
// Move cluster icon from root to preferences
export function migration(store: any) {
console.log("CLUSTER STORE, MIGRATION: 2.6.0-beta.2");
for (const value of store) {
const clusterKey = value[0];
if(clusterKey === "__internal__") continue
const cluster = value[1];
if(!cluster.preferences) cluster.preferences = {};
if(cluster.icon) {
cluster.preferences.icon = cluster.icon;
delete(cluster["icon"]);
}
store.set(clusterKey, { contextName: clusterKey, kubeConfig: value[1].kubeConfig, preferences: value[1].preferences });
}
}
@@ -0,0 +1,35 @@
import * as yaml from "js-yaml"
// Convert access token and expiry from arrays into strings
export function migration(store: any) {
console.log("CLUSTER STORE, MIGRATION: 2.6.0-beta.3");
for (const value of store) {
const clusterKey = value[0];
if(clusterKey === "__internal__") continue
const cluster = value[1];
if(!cluster.kubeConfig) continue
const kubeConfig = yaml.safeLoad(cluster.kubeConfig)
if(!kubeConfig.hasOwnProperty('users')) continue
const userObj = kubeConfig.users[0]
if (userObj) {
const user = userObj.user
if (user["auth-provider"] && user["auth-provider"].config) {
const authConfig = user["auth-provider"].config
if (authConfig["access-token"]) {
authConfig["access-token"] = `${authConfig["access-token"]}`
}
if (authConfig.expiry) {
authConfig.expiry = `${authConfig.expiry}`
}
console.log(authConfig)
user["auth-provider"].config = authConfig
kubeConfig.users = [{
name: userObj.name,
user: user
}]
cluster.kubeConfig = yaml.safeDump(kubeConfig)
store.set(clusterKey, cluster)
}
}
}
}
@@ -0,0 +1,11 @@
// Add existing clusters to "default" workspace
export function migration(store: any) {
console.log("CLUSTER STORE, MIGRATION: 2.7.0-beta.0");
for (const value of store) {
const clusterKey = value[0];
if(clusterKey === "__internal__") continue
const cluster = value[1];
cluster.workspace = "default"
store.set(clusterKey, cluster)
}
}
@@ -0,0 +1,22 @@
// add id for clusters and store them to array
import { v4 as uuid } from "uuid"
export function migration(store: any) {
console.log("CLUSTER STORE, MIGRATION: 2.7.0-beta.1");
const clusters: any[] = []
for (const value of store) {
const clusterKey = value[0];
if(clusterKey === "__internal__") continue
if(clusterKey === "clusters") continue
const cluster = value[1];
cluster.id = uuid()
if (!cluster.preferences.clusterName) {
cluster.preferences.clusterName = clusterKey
}
clusters.push(cluster)
store.delete(clusterKey)
}
if (clusters.length > 0) {
store.set("clusters", clusters)
}
}
@@ -0,0 +1,4 @@
// Add / reset "lastSeenAppVersion"
export function migration(store: any) {
store.set("lastSeenAppVersion", "0.0.0");
}
+12
View File
@@ -0,0 +1,12 @@
import * as request from "request"
import { userStore } from "../common/user-store"
export function globalRequestOpts(requestOpts: request.Options ) {
const userPrefs = userStore.getPreferences()
if (userPrefs.httpsProxy) {
requestOpts.proxy = userPrefs.httpsProxy
}
requestOpts.rejectUnauthorized = !userPrefs.allowUntrustedCAs;
return requestOpts
}
+6
View File
@@ -0,0 +1,6 @@
import * as winca from "win-ca/api"
import "mac-ca"
if (process.platform === "win32") {
winca.inject("+") // see: https://github.com/ukoloff/win-ca#caveats
}
+42
View File
@@ -0,0 +1,42 @@
import { machineIdSync } from 'node-machine-id'
import { userStore } from "../common/user-store"
import * as ua from "universal-analytics"
const GA_ID = "UA-159377374-1"
export class Tracker {
protected visitor: ua.Visitor
protected machineId: string = null;
protected ip: string = null;
protected appVersion: string;
protected locale: string;
protected electronUA: string;
constructor(app: Electron.App) {
try {
this.visitor = ua(GA_ID, machineIdSync(), {strictCidFormat: false})
} catch (error) {
this.visitor = ua(GA_ID)
}
this.visitor.set("dl", "https://lensapptelemetry.lakendlabs.com")
}
public async event(eventCategory: string, eventAction: string) {
return new Promise(async (resolve, reject) => {
if (!this.telemetryAllowed()) {
resolve()
return
}
this.visitor.event({
ec: eventCategory,
ea: eventAction
}).send()
resolve()
})
}
protected telemetryAllowed() {
const userPrefs = userStore.getPreferences()
return !!userPrefs.allowTelemetry
}
}
+94
View File
@@ -0,0 +1,94 @@
import * as ElectronStore from "electron-store"
import * as appUtil from "./app-utils"
import * as version210Beta4 from "./migrations/user-store/2.1.0-beta.4"
export interface User {
id?: string;
bio?: string;
company?: string;
email?: string;
'first-name'?: string;
'is-customer'?: boolean;
'is-partner'?: boolean;
'last-name'?: string;
'lens-invitation-used'?: boolean;
location?: string;
//notifications?: array;
url?: string;
'user-avatar-src'?: string;
username: string;
verified?: boolean;
}
export interface UserPreferences {
httpsProxy?: string;
colorTheme?: string;
allowUntrustedCAs?: boolean;
allowTelemetry?: boolean;
}
export class UserStore {
private static instance: UserStore;
public store: ElectronStore;
private constructor() {
this.store = new ElectronStore({
projectVersion: appUtil.getAppVersion(),
migrations: {
"2.1.0-beta.4": version210Beta4.migration,
}
});
}
public lastSeenAppVersion() {
return this.store.get('lastSeenAppVersion', "0.0.0")
}
public setLastSeenAppVersion(version: string) {
this.store.set('lastSeenAppVersion', version)
}
public getSeenContexts(): Array<string> {
return this.store.get("seenContexts", [])
}
public storeSeenContext(newContexts: string[]) {
const seenContexts = this.getSeenContexts().concat(newContexts)
// store unique contexts by casting array to set first
const newContextSet = new Set(seenContexts)
const allContexts = [...newContextSet]
this.store.set("seenContexts", allContexts)
return allContexts
}
public setPreferences(preferences: UserPreferences) {
this.store.set('preferences', preferences)
}
public getPreferences(): UserPreferences {
const prefs = this.store.get("preferences", {})
if (!prefs.colorTheme) {
prefs.colorTheme = "dark"
}
if (prefs.allowTelemetry === undefined) {
prefs.allowTelemetry = true
}
return prefs
}
static getInstance(): UserStore {
if(!UserStore.instance) {
UserStore.instance = new UserStore();
}
return UserStore.instance;
}
static resetInstance() {
UserStore.instance = null
}
}
const userStore: UserStore = UserStore.getInstance();
export { userStore };
+74
View File
@@ -0,0 +1,74 @@
import * as ElectronStore from "electron-store"
import { clusterStore } from "./cluster-store"
export interface WorkspaceData {
id: string;
name: string;
description?: string;
}
export class Workspace implements WorkspaceData {
public id: string
public name: string
public description?: string
public constructor(data: WorkspaceData) {
Object.assign(this, data)
}
}
export class WorkspaceStore {
private static instance: WorkspaceStore;
public store: ElectronStore;
private constructor() {
this.store = new ElectronStore({
name: "lens-workspace-store"
})
}
public storeWorkspace(workspace: WorkspaceData) {
const workspaces = this.getAllWorkspaces()
const index = workspaces.findIndex((w) => w.id === workspace.id)
if (index !== -1) {
workspaces[index] = workspace
} else {
workspaces.push(workspace)
}
this.store.set("workspaces", workspaces)
}
public removeWorkspace(workspace: Workspace) {
const workspaces = this.getAllWorkspaces()
const index = workspaces.findIndex((w) => w.id === workspace.id)
if (index !== -1) {
clusterStore.removeClustersByWorkspace(workspace.id)
workspaces.splice(index, 1)
this.store.set("workspaces", workspaces)
}
}
public getAllWorkspaces(): Array<Workspace> {
const workspacesData: WorkspaceData[] = this.store.get("workspaces", [])
return workspacesData.map((wsd) => new Workspace(wsd))
}
static getInstance(): WorkspaceStore {
if (!WorkspaceStore.instance) {
WorkspaceStore.instance = new WorkspaceStore()
}
return WorkspaceStore.instance
}
}
const workspaceStore: WorkspaceStore = WorkspaceStore.getInstance()
if (workspaceStore.getAllWorkspaces().length === 0) {
workspaceStore.storeWorkspace({
id: "default",
name: "default"
})
}
export { workspaceStore }