mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
1 parent
a4bcfc1e52
commit
24f754697b
13 files changed
+381
-60
No files matched your search
@@ -5,9 +5,14 @@ import migrations from "../migrations/user-store"
|
||||
import { getAppVersion } from "./utils/app-version";
|
||||
import { tracker } from "./tracker";
|
||||
|
||||
// todo: merge with common/user-store.ts
|
||||
// todo: merge with config.store.ts + theme.store.ts
|
||||
// fixme: detect new contexts from .kube/config since last open
|
||||
|
||||
export enum ThemeType {
|
||||
LIGHT = "light",
|
||||
DARK = "dark",
|
||||
}
|
||||
|
||||
export interface UserStoreModel {
|
||||
lastSeenAppVersion: string;
|
||||
seenContexts: string[];
|
||||
@@ -16,7 +21,7 @@ export interface UserStoreModel {
|
||||
|
||||
export interface UserPreferences {
|
||||
httpsProxy?: string;
|
||||
colorTheme?: string | "dark";
|
||||
colorTheme?: string | "dark" | "light";
|
||||
allowUntrustedCAs?: boolean;
|
||||
allowTelemetry?: boolean;
|
||||
downloadMirror?: string | "default";
|
||||
@@ -41,8 +46,10 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
||||
|
||||
@observable preferences: UserPreferences = {
|
||||
allowTelemetry: true,
|
||||
allowUntrustedCAs: false,
|
||||
colorTheme: "dark",
|
||||
downloadMirror: "default",
|
||||
httpsProxy: "",
|
||||
};
|
||||
|
||||
get isNewVersion() {
|
||||
|
||||
@@ -17,12 +17,13 @@ export type HelmRepo = {
|
||||
}
|
||||
|
||||
export class HelmRepoManager extends Singleton {
|
||||
public static cache = {}
|
||||
static cache = {}
|
||||
|
||||
protected helmEnv: HelmEnv
|
||||
protected initialized: boolean
|
||||
|
||||
public async init() {
|
||||
const helm = await helmCli.binaryPath()
|
||||
await helmCli.ensureBinary();
|
||||
if (!this.initialized) {
|
||||
this.helmEnv = await this.parseHelmEnv()
|
||||
await this.update()
|
||||
@@ -95,38 +96,6 @@ export class HelmRepoManager extends Singleton {
|
||||
return stdout
|
||||
}
|
||||
|
||||
protected async addRepositories(repositories: HelmRepo[]) {
|
||||
const currentRepositories = await this.repositories()
|
||||
repositories.forEach(async (repo: HelmRepo) => {
|
||||
try {
|
||||
const repoExists = currentRepositories.find((currentRepo: HelmRepo) => {
|
||||
return currentRepo.url == repo.url
|
||||
})
|
||||
if (!repoExists) {
|
||||
await this.addRepo(repo)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(JSON.stringify(error))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected async pruneRepositories(repositoriesToKeep: HelmRepo[]) {
|
||||
const repositories = await this.repositories()
|
||||
repositories.filter((repo: HelmRepo) => {
|
||||
return repositoriesToKeep.find((repoToKeep: HelmRepo) => {
|
||||
return repo.name == repoToKeep.name
|
||||
}) === undefined
|
||||
}).forEach(async (repo: HelmRepo) => {
|
||||
try {
|
||||
const output = await this.removeRepo(repo)
|
||||
logger.debug(output)
|
||||
} catch (error) {
|
||||
logger.error(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public async addRepo(repository: HelmRepo) {
|
||||
const helm = await helmCli.binaryPath()
|
||||
logger.debug(`${helm} repo add ${repository.name} ${repository.url}`)
|
||||
@@ -136,16 +105,6 @@ export class HelmRepoManager extends Singleton {
|
||||
})
|
||||
return stdout
|
||||
}
|
||||
|
||||
public async removeRepo(repository: HelmRepo): Promise<string> {
|
||||
const helm = await helmCli.binaryPath()
|
||||
logger.debug(`${helm} repo remove ${repository.name} ${repository.url}`)
|
||||
|
||||
const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${repository.name}`).catch((error) => {
|
||||
throw(error.stderr)
|
||||
})
|
||||
return stdout
|
||||
}
|
||||
}
|
||||
|
||||
export const repoManager = HelmRepoManager.getInstance<HelmRepoManager>()
|
||||
@@ -94,7 +94,7 @@ class ConfigRoute extends LensApi {
|
||||
const data: IConfigRoutePayload = {
|
||||
clusterName: cluster.contextName,
|
||||
lensVersion: app.getVersion(),
|
||||
lensTheme: `kontena-${userStore.preferences.colorTheme}`,
|
||||
lensTheme: userStore.preferences.colorTheme,
|
||||
kubeVersion: cluster.version,
|
||||
chartsEnabled: true,
|
||||
isClusterAdmin: cluster.isAdmin,
|
||||
|
||||
@@ -206,7 +206,10 @@ export default {
|
||||
loadHubRepositories: async function() {
|
||||
const res = await this.request({ uri: "https://hub.helm.sh/assets/js/repos.json"}).catch((error) => { this.hubRepositories = [] })
|
||||
this.hubRepositories = res.body.data.sort(this.repoCompare).map((repo) => {
|
||||
return { text: repo.name, value: repo.name+"|"+repo.url}
|
||||
return {
|
||||
text: repo.name,
|
||||
value: repo.name+"|"+repo.url
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
.Preferences {
|
||||
--flex-gap: #{$padding};
|
||||
|
||||
h2 {
|
||||
&:not(:first-child) {
|
||||
margin-top: $padding * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,106 @@
|
||||
import "./preferences.scss"
|
||||
import React from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { WizardLayout } from "../layout/wizard-layout";
|
||||
import { Icon } from "../icon";
|
||||
import { Select, SelectOption } from "../select";
|
||||
import { ThemeType, userStore } from "../../../common/user-store";
|
||||
import { Input } from "../input";
|
||||
import { Checkbox } from "../checkbox";
|
||||
|
||||
type ThemeSelectOption = SelectOption & { type: ThemeType }
|
||||
|
||||
@observer
|
||||
export class Preferences extends React.Component {
|
||||
render() {
|
||||
themeOptions: ThemeSelectOption[] = [
|
||||
{ value: "kontena-dark", label: <Trans>Dark</Trans>, type: ThemeType.DARK },
|
||||
{ value: "kontena-light", label: <Trans>Light</Trans>, type: ThemeType.LIGHT },
|
||||
]
|
||||
|
||||
downloadMirrorOptions: SelectOption[] = [
|
||||
{ value: "default", label: "Default (Google)" },
|
||||
{ value: "china", label: "China (Azure)" },
|
||||
]
|
||||
|
||||
onThemeChange = ({ value }: ThemeSelectOption) => {
|
||||
// themeStore.setTheme(value); // fixme: apply theme on the fly for current view
|
||||
userStore.preferences.colorTheme = value;
|
||||
}
|
||||
|
||||
renderInfo() {
|
||||
return (
|
||||
<div className="Preferences">
|
||||
Preferences
|
||||
</div>
|
||||
<Fragment>
|
||||
<h2>
|
||||
<Trans>Preferences</Trans>
|
||||
</h2>
|
||||
<div className="info-block flex gaps align-center">
|
||||
<Icon small material="info"/>
|
||||
<small>
|
||||
<Trans>Lens Global Settings</Trans> (<Trans>applicable to all clusters</Trans>)
|
||||
</small>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { preferences } = userStore;
|
||||
return (
|
||||
<WizardLayout className="Preferences" infoPanel={this.renderInfo()}>
|
||||
<h2><Trans>Color Theme</Trans></h2>
|
||||
<Select
|
||||
options={this.themeOptions}
|
||||
value={preferences.colorTheme}
|
||||
onChange={this.onThemeChange}
|
||||
/>
|
||||
|
||||
<h2><Trans>Download Mirror</Trans></h2>
|
||||
<Select
|
||||
placeholder={_i18n._(t`Download mirror for kubectl`)}
|
||||
options={this.downloadMirrorOptions}
|
||||
value={preferences.downloadMirror}
|
||||
onChange={({ value }: SelectOption) => preferences.downloadMirror = value}
|
||||
/>
|
||||
|
||||
<h2><Trans>Helm</Trans></h2>
|
||||
<div className="helm">
|
||||
// todo: added helm repos
|
||||
</div>
|
||||
|
||||
<h2><Trans>HTTP Proxy</Trans></h2>
|
||||
<Input
|
||||
placeholder={_i18n._(t`Type HTTP proxy url (example: http://proxy.acme.org:8080)`)}
|
||||
value={preferences.httpsProxy}
|
||||
onChange={v => preferences.httpsProxy = v}
|
||||
/>
|
||||
<small className="hint">
|
||||
<Trans>Proxy is used only for non-cluster communication.</Trans>
|
||||
</small>
|
||||
|
||||
<h2><Trans>Certificate Trust</Trans></h2>
|
||||
<Checkbox
|
||||
label={<Trans>Allow untrusted Certificate Authorities</Trans>}
|
||||
value={preferences.allowUntrustedCAs}
|
||||
onChange={v => preferences.allowUntrustedCAs = v}
|
||||
/>
|
||||
<small className="hint">
|
||||
<Trans>This will make Lens to trust ANY certificate authority without any validations.</Trans>{" "}
|
||||
<Trans>Needed with some corporate proxies that do certificate re-writing.</Trans>{" "}
|
||||
<Trans>Does not affect cluster communications!</Trans>
|
||||
</small>
|
||||
|
||||
<h2><Trans>Telemetry & Usage Tracking</Trans></h2>
|
||||
<Checkbox
|
||||
label={<Trans>Allow telemetry & usage tracking</Trans>}
|
||||
value={preferences.allowTelemetry}
|
||||
onChange={v => preferences.allowTelemetry = v}
|
||||
/>
|
||||
<small className="hint">
|
||||
<Trans>Telemetry & usage data is collected to continuously improve the Lens experience.</Trans>
|
||||
</small>
|
||||
</WizardLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import { clusterIpc } from "../../common/cluster-ipc";
|
||||
import { clusterStore } from "../../common/cluster-store";
|
||||
import { ClusterStatus } from "./cluster-manager/cluster-status";
|
||||
import { clusterStatusRoute, clusterStatusURL } from "./cluster-manager/cluster-status.route";
|
||||
import { Preferences, preferencesRoute } from "./+preferences";
|
||||
import { navigation } from "../navigation";
|
||||
import { CubeSpinner } from "./spinner";
|
||||
|
||||
@@ -85,6 +86,7 @@ export class App extends React.Component {
|
||||
<ErrorBoundary>
|
||||
<Switch>
|
||||
<Route component={LandingPage} {...landingRoute}/>
|
||||
<Route component={Preferences} {...preferencesRoute}/>
|
||||
<Route component={Workspaces} {...workspacesRoute}/>
|
||||
<Route component={AddCluster} {...addClusterRoute}/>
|
||||
<Route component={Cluster} {...clusterRoute}/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.WizardLayout {
|
||||
--flex-gap: #{$padding * 2};
|
||||
$spacing: $padding * 2;
|
||||
|
||||
position: relative;
|
||||
padding: $padding * 3;
|
||||
@@ -8,8 +8,9 @@
|
||||
grid-template-columns: 1fr 40%;
|
||||
|
||||
> .content-col {
|
||||
padding: var(--flex-gap);
|
||||
margin-right: var(--flex-gap);
|
||||
--flex-gap: #{$spacing};
|
||||
padding: $spacing;
|
||||
margin-right: $spacing;
|
||||
background-color: var(--clusters-menu-bgc);
|
||||
border-radius: $radius;
|
||||
|
||||
@@ -22,7 +23,8 @@
|
||||
|
||||
> .info-col {
|
||||
@include hidden-scrollbar;
|
||||
padding: var(--flex-gap);
|
||||
--flex-gap: #{$spacing};
|
||||
padding: $spacing;
|
||||
border-left: 1px solid #353a3e;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { createPortal } from "react-dom"
|
||||
import { autobind, cssNames } from "../../utils";
|
||||
import { Animate } from "../animate";
|
||||
|
||||
// todo: refactor -- better positioning + remove "flying effect"
|
||||
// fixme: refactor -- better positioning + remove "flying effect"
|
||||
// todo: always render outside of parent element ("overflow: auto" should not affect tooltip)
|
||||
|
||||
export interface TooltipProps {
|
||||
|
||||
@@ -13,7 +13,6 @@ import { _i18n } from "./i18n";
|
||||
import { ClusterManager } from "./components/cluster-manager";
|
||||
import { ErrorBoundary } from "./components/error-boundary";
|
||||
import { WhatsNew, whatsNewRoute } from "./components/+whats-new";
|
||||
import { Preferences, preferencesRoute } from "./components/+preferences";
|
||||
|
||||
@observer
|
||||
class LensApp extends React.Component {
|
||||
@@ -37,7 +36,6 @@ class LensApp extends React.Component {
|
||||
<Switch>
|
||||
{userStore.isNewVersion && <Route component={WhatsNew}/>}
|
||||
<Route component={WhatsNew} {...whatsNewRoute}/>
|
||||
<Route component={Preferences} {...preferencesRoute}/>
|
||||
<Route component={ClusterManager}/>
|
||||
</Switch>
|
||||
</ErrorBoundary>
|
||||
|
||||
Reference in new issue
Block a user