mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
commit
a9d2a9ea0d
@ -2,7 +2,7 @@
|
|||||||
"name": "kontena-lens",
|
"name": "kontena-lens",
|
||||||
"productName": "Lens",
|
"productName": "Lens",
|
||||||
"description": "Lens - The Kubernetes IDE",
|
"description": "Lens - The Kubernetes IDE",
|
||||||
"version": "4.0.6",
|
"version": "4.0.7",
|
||||||
"main": "static/build/main.js",
|
"main": "static/build/main.js",
|
||||||
"copyright": "© 2020, Mirantis, Inc.",
|
"copyright": "© 2020, Mirantis, Inc.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@ -36,6 +36,13 @@ describe("workspace store tests", () => {
|
|||||||
expect(ws.getById(WorkspaceStore.defaultId)).not.toBe(null);
|
expect(ws.getById(WorkspaceStore.defaultId)).not.toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("default workspace should be enabled", () => {
|
||||||
|
const ws = WorkspaceStore.getInstance<WorkspaceStore>();
|
||||||
|
|
||||||
|
expect(ws.workspaces.size).toBe(1);
|
||||||
|
expect(ws.getById(WorkspaceStore.defaultId).enabled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("cannot remove the default workspace", () => {
|
it("cannot remove the default workspace", () => {
|
||||||
const ws = WorkspaceStore.getInstance<WorkspaceStore>();
|
const ws = WorkspaceStore.getInstance<WorkspaceStore>();
|
||||||
|
|
||||||
|
|||||||
@ -58,14 +58,7 @@ export class Workspace implements WorkspaceModel, WorkspaceState {
|
|||||||
* @observable
|
* @observable
|
||||||
*/
|
*/
|
||||||
@observable ownerRef?: string;
|
@observable ownerRef?: string;
|
||||||
/**
|
|
||||||
* Is workspace enabled
|
|
||||||
*
|
|
||||||
* Workspaces that don't have ownerRef will be enabled by default. Workspaces with ownerRef need to explicitly enable a workspace.
|
|
||||||
*
|
|
||||||
* @observable
|
|
||||||
*/
|
|
||||||
@observable enabled: boolean;
|
|
||||||
/**
|
/**
|
||||||
* Last active cluster id
|
* Last active cluster id
|
||||||
*
|
*
|
||||||
@ -73,6 +66,9 @@ export class Workspace implements WorkspaceModel, WorkspaceState {
|
|||||||
*/
|
*/
|
||||||
@observable lastActiveClusterId?: ClusterId;
|
@observable lastActiveClusterId?: ClusterId;
|
||||||
|
|
||||||
|
|
||||||
|
@observable private _enabled: boolean;
|
||||||
|
|
||||||
constructor(data: WorkspaceModel) {
|
constructor(data: WorkspaceModel) {
|
||||||
Object.assign(this, data);
|
Object.assign(this, data);
|
||||||
|
|
||||||
@ -83,6 +79,21 @@ export class Workspace implements WorkspaceModel, WorkspaceState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is workspace enabled
|
||||||
|
*
|
||||||
|
* Workspaces that don't have ownerRef will be enabled by default. Workspaces with ownerRef need to explicitly enable a workspace.
|
||||||
|
*
|
||||||
|
* @observable
|
||||||
|
*/
|
||||||
|
get enabled(): boolean {
|
||||||
|
return !this.isManaged || this._enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
set enabled(enabled: boolean) {
|
||||||
|
this._enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is workspace managed by an extension
|
* Is workspace managed by an extension
|
||||||
*/
|
*/
|
||||||
@ -134,10 +145,18 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
|
|||||||
static readonly defaultId: WorkspaceId = "default";
|
static readonly defaultId: WorkspaceId = "default";
|
||||||
private static stateRequestChannel = "workspace:states";
|
private static stateRequestChannel = "workspace:states";
|
||||||
|
|
||||||
|
@observable currentWorkspaceId = WorkspaceStore.defaultId;
|
||||||
|
@observable workspaces = observable.map<WorkspaceId, Workspace>();
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
super({
|
super({
|
||||||
configName: "lens-workspace-store",
|
configName: "lens-workspace-store",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.workspaces.set(WorkspaceStore.defaultId, new Workspace({
|
||||||
|
id: WorkspaceStore.defaultId,
|
||||||
|
name: "default"
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
@ -186,15 +205,6 @@ export class WorkspaceStore extends BaseStore<WorkspaceStoreModel> {
|
|||||||
ipcRenderer.removeAllListeners("workspace:state");
|
ipcRenderer.removeAllListeners("workspace:state");
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable currentWorkspaceId = WorkspaceStore.defaultId;
|
|
||||||
|
|
||||||
@observable workspaces = observable.map<WorkspaceId, Workspace>({
|
|
||||||
[WorkspaceStore.defaultId]: new Workspace({
|
|
||||||
id: WorkspaceStore.defaultId,
|
|
||||||
name: "default"
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
@computed get currentWorkspace(): Workspace {
|
@computed get currentWorkspace(): Workspace {
|
||||||
return this.getById(this.currentWorkspaceId);
|
return this.getById(this.currentWorkspaceId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export class ClusterManager extends Singleton {
|
|||||||
// auto-init clusters
|
// auto-init clusters
|
||||||
autorun(() => {
|
autorun(() => {
|
||||||
clusterStore.enabledClustersList.forEach(cluster => {
|
clusterStore.enabledClustersList.forEach(cluster => {
|
||||||
if (!cluster.initialized) {
|
if (!cluster.initialized && !cluster.initializing) {
|
||||||
logger.info(`[CLUSTER-MANAGER]: init cluster`, cluster.getMeta());
|
logger.info(`[CLUSTER-MANAGER]: init cluster`, cluster.getMeta());
|
||||||
cluster.init(port);
|
cluster.init(port);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,6 +84,14 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
whenInitialized = when(() => this.initialized);
|
whenInitialized = when(() => this.initialized);
|
||||||
whenReady = when(() => this.ready);
|
whenReady = when(() => this.ready);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is cluster object initializinng on-going
|
||||||
|
*
|
||||||
|
* @observable
|
||||||
|
*/
|
||||||
|
@observable initializing = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is cluster object initialized
|
* Is cluster object initialized
|
||||||
*
|
*
|
||||||
@ -273,6 +281,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@action async init(port: number) {
|
@action async init(port: number) {
|
||||||
try {
|
try {
|
||||||
|
this.initializing = true;
|
||||||
this.contextHandler = new ContextHandler(this);
|
this.contextHandler = new ContextHandler(this);
|
||||||
this.kubeconfigManager = await KubeconfigManager.create(this, this.contextHandler, port);
|
this.kubeconfigManager = await KubeconfigManager.create(this, this.contextHandler, port);
|
||||||
this.kubeProxyUrl = `http://localhost:${port}${apiKubePrefix}`;
|
this.kubeProxyUrl = `http://localhost:${port}${apiKubePrefix}`;
|
||||||
@ -287,6 +296,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
error: err,
|
error: err,
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
this.initializing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,8 +75,8 @@ export class PrometheusLens implements PrometheusProvider {
|
|||||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"),
|
bytesSentSuccess: bytesSent(opts.ingress, "^2\\\\d*"),
|
||||||
bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"),
|
bytesSentFailure: bytesSent(opts.ingress, "^5\\\\d*"),
|
||||||
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
||||||
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
||||||
};
|
};
|
||||||
|
|||||||
@ -85,8 +85,8 @@ export class PrometheusOperator implements PrometheusProvider {
|
|||||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"),
|
bytesSentSuccess: bytesSent(opts.ingress, "^2\\\\d*"),
|
||||||
bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"),
|
bytesSentFailure: bytesSent(opts.ingress, "^5\\\\d*"),
|
||||||
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
||||||
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
||||||
};
|
};
|
||||||
|
|||||||
@ -75,8 +75,8 @@ export class PrometheusStacklight implements PrometheusProvider {
|
|||||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"),
|
bytesSentSuccess: bytesSent(opts.ingress, "^2\\\\d*"),
|
||||||
bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"),
|
bytesSentFailure: bytesSent(opts.ingress, "^5\\\\d*"),
|
||||||
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`,
|
||||||
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { workspaceStore } from "../common/workspace-store";
|
|||||||
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
import { preferencesURL } from "../renderer/components/+preferences/preferences.route";
|
||||||
import { clusterViewURL } from "../renderer/components/cluster-manager/cluster-view.route";
|
import { clusterViewURL } from "../renderer/components/cluster-manager/cluster-view.route";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import { isDevelopment } from "../common/vars";
|
import { isDevelopment, isWindows } from "../common/vars";
|
||||||
import { exitApp } from "./exit-app";
|
import { exitApp } from "./exit-app";
|
||||||
|
|
||||||
// note: instance of Tray should be saved somewhere, otherwise it disappears
|
// note: instance of Tray should be saved somewhere, otherwise it disappears
|
||||||
@ -29,7 +29,7 @@ export function initTray(windowManager: WindowManager) {
|
|||||||
try {
|
try {
|
||||||
const menu = createTrayMenu(windowManager);
|
const menu = createTrayMenu(windowManager);
|
||||||
|
|
||||||
buildTray(getTrayIcon(), menu);
|
buildTray(getTrayIcon(), menu, windowManager);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`[TRAY]: building failed: ${err}`);
|
logger.error(`[TRAY]: building failed: ${err}`);
|
||||||
}
|
}
|
||||||
@ -42,20 +42,25 @@ export function initTray(windowManager: WindowManager) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildTray(icon: string | NativeImage, menu: Menu) {
|
function buildTray(icon: string | NativeImage, menu: Menu, windowManager: WindowManager) {
|
||||||
if (!tray) {
|
if (!tray) {
|
||||||
tray = new Tray(icon);
|
tray = new Tray(icon);
|
||||||
tray.setToolTip(packageInfo.description);
|
tray.setToolTip(packageInfo.description);
|
||||||
tray.setIgnoreDoubleClickEvents(true);
|
tray.setIgnoreDoubleClickEvents(true);
|
||||||
}
|
|
||||||
|
|
||||||
tray.setImage(icon);
|
tray.setImage(icon);
|
||||||
tray.setContextMenu(menu);
|
tray.setContextMenu(menu);
|
||||||
|
|
||||||
|
if (isWindows) {
|
||||||
|
tray.on("click", () => {
|
||||||
|
windowManager.ensureMainWindow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return tray;
|
return tray;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTrayMenu(windowManager: WindowManager): Menu {
|
function createTrayMenu(windowManager: WindowManager): Menu {
|
||||||
return Menu.buildFromTemplate([
|
return Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: "About Lens",
|
label: "About Lens",
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export const resourceApplierApi = {
|
|||||||
.post<KubeJsonApiData[]>("/stack", { data: resource })
|
.post<KubeJsonApiData[]>("/stack", { data: resource })
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const items = data.map(obj => {
|
const items = data.map(obj => {
|
||||||
const api = apiManager.getApi(obj.metadata.selfLink);
|
const api = apiManager.getApiByKind(obj.kind, obj.apiVersion);
|
||||||
|
|
||||||
if (api) {
|
if (api) {
|
||||||
return new api.objectConstructor(obj);
|
return new api.objectConstructor(obj);
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
height: 18px; // Must be equal to lineHeight variable in pod-log-list.tsx
|
height: 18px; // Must be equal to lineHeight variable in pod-log-list.tsx
|
||||||
font-family: $font-monospace;
|
font-family: $font-monospace;
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
white-space: pre;
|
white-space: nowrap;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $logRowHoverBackground;
|
background: $logRowHoverBackground;
|
||||||
|
|||||||
@ -130,10 +130,17 @@ export class Terminal {
|
|||||||
fit = () => {
|
fit = () => {
|
||||||
// Since this function is debounced we need to read this value as late as possible
|
// Since this function is debounced we need to read this value as late as possible
|
||||||
if (!this.isActive) return;
|
if (!this.isActive) return;
|
||||||
|
|
||||||
|
try {
|
||||||
this.fitAddon.fit();
|
this.fitAddon.fit();
|
||||||
const { cols, rows } = this.xterm;
|
const { cols, rows } = this.xterm;
|
||||||
|
|
||||||
this.api.sendTerminalSize(cols, rows);
|
this.api.sendTerminalSize(cols, rows);
|
||||||
|
} catch(error) {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
return; // see https://github.com/lensapp/lens/issues/1891
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fitLazy = debounce(this.fit, 250);
|
fitLazy = debounce(this.fit, 250);
|
||||||
|
|||||||
@ -2,7 +2,17 @@
|
|||||||
|
|
||||||
Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights!
|
Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights!
|
||||||
|
|
||||||
## 4.0.6 (current version)
|
## 4.0.7 (current version)
|
||||||
|
|
||||||
|
- Fix: typo in Prometheus Ingress metrics
|
||||||
|
- Fix: catch xterm.js fit error
|
||||||
|
- Fix: Windows tray icon click
|
||||||
|
- Fix: error on Kubernetes >= 1.20 on object edit
|
||||||
|
- Fix: multiline log wrapping
|
||||||
|
- Fix: prevent clusters from initializing multiple times
|
||||||
|
- Fix: show default workspace on first boot
|
||||||
|
|
||||||
|
## 4.0.6
|
||||||
|
|
||||||
- Don't open Lens at OS login by default
|
- Don't open Lens at OS login by default
|
||||||
- Disable GPU acceleration by setting an env variable
|
- Disable GPU acceleration by setting an env variable
|
||||||
|
|||||||
@ -7756,9 +7756,9 @@ inherits@2.0.3:
|
|||||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||||
|
|
||||||
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
|
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
|
||||||
version "1.3.5"
|
version "1.3.8"
|
||||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
||||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||||
|
|
||||||
init-package-json@^1.10.3:
|
init-package-json@^1.10.3:
|
||||||
version "1.10.3"
|
version "1.10.3"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user