mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
parent
162b4108dd
commit
c1dc1e6463
@ -12,6 +12,7 @@ import isEqual from "lodash/isEqual";
|
|||||||
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
||||||
autoLoad?: boolean;
|
autoLoad?: boolean;
|
||||||
syncEnabled?: boolean;
|
syncEnabled?: boolean;
|
||||||
|
syncDelayMs?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BaseStore<T = any> extends Singleton {
|
export class BaseStore<T = any> extends Singleton {
|
||||||
@ -27,6 +28,7 @@ export class BaseStore<T = any> extends Singleton {
|
|||||||
this.params = {
|
this.params = {
|
||||||
autoLoad: false,
|
autoLoad: false,
|
||||||
syncEnabled: true,
|
syncEnabled: true,
|
||||||
|
syncDelayMs: 100,
|
||||||
...params,
|
...params,
|
||||||
}
|
}
|
||||||
this.init();
|
this.init();
|
||||||
@ -73,7 +75,9 @@ export class BaseStore<T = any> extends Singleton {
|
|||||||
|
|
||||||
enableSync() {
|
enableSync() {
|
||||||
this.syncDisposers.push(
|
this.syncDisposers.push(
|
||||||
reaction(() => this.toJSON(), model => this.onModelChange(model)),
|
reaction(() => this.toJSON(), model => this.onModelChange(model), {
|
||||||
|
delay: this.params.syncDelayMs,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
const callback = (event: IpcMainEvent, model: T) => {
|
const callback = (event: IpcMainEvent, model: T) => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { app, ipcRenderer, remote, webFrame, webContents } from "electron";
|
import { app, ipcRenderer, remote, webFrame } from "electron";
|
||||||
import { unlink } from "fs-extra";
|
import { unlink } from "fs-extra";
|
||||||
import { action, computed, observable, toJS } from "mobx";
|
import { action, computed, observable, toJS } from "mobx";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
@ -108,7 +108,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
setActive(id: ClusterId) {
|
setActive(id: ClusterId) {
|
||||||
this.activeClusterId = id;
|
this.activeClusterId = this.clusters.has(id) ? id : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -155,7 +155,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
if (cluster) {
|
if (cluster) {
|
||||||
this.clusters.delete(clusterId);
|
this.clusters.delete(clusterId);
|
||||||
if (this.activeClusterId === clusterId) {
|
if (this.activeClusterId === clusterId) {
|
||||||
this.activeClusterId = null;
|
this.setActive(null);
|
||||||
}
|
}
|
||||||
// remove only custom kubeconfigs (pasted as text)
|
// remove only custom kubeconfigs (pasted as text)
|
||||||
if (cluster.kubeConfigPath == ClusterStore.getCustomKubeConfigPath(clusterId)) {
|
if (cluster.kubeConfigPath == ClusterStore.getCustomKubeConfigPath(clusterId)) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import packageInfo from "../../package.json"
|
import packageInfo from "../../package.json"
|
||||||
import { app, dialog, Menu, nativeImage, Tray } from "electron"
|
import { dialog, Menu, nativeImage, Tray } from "electron"
|
||||||
import { isDevelopment, isMac } from "../common/vars";
|
import { isDevelopment, isMac } from "../common/vars";
|
||||||
import { autorun } from "mobx";
|
import { autorun } from "mobx";
|
||||||
import { showAbout } from "./menu";
|
import { showAbout } from "./menu";
|
||||||
@ -21,17 +21,39 @@ export const trayIcon = isDevelopment
|
|||||||
: path.resolve(__static, "logo.svg") // electron-builder's extraResources
|
: path.resolve(__static, "logo.svg") // electron-builder's extraResources
|
||||||
|
|
||||||
export function initTray(windowManager: WindowManager) {
|
export function initTray(windowManager: WindowManager) {
|
||||||
return autorun(() => buildTrayMenu(windowManager), {
|
return autorun(() => {
|
||||||
delay: 100
|
const menu = createTrayMenu(windowManager);
|
||||||
|
buildTray(menu);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function buildTrayMenu(windowManager: WindowManager) {
|
export async function buildTray(menu: Menu) {
|
||||||
// note: browserWindow not available within menuItem.click() as argument[1] when app is not focused / hidden
|
logger.info("[TRAY]: build start");
|
||||||
const trayMenu = Menu.buildFromTemplate([
|
const iconSize = isMac ? 16 : 32; // todo: verify on windows/linux
|
||||||
|
const pngIcon = await sharp(trayIcon).png().toBuffer();
|
||||||
|
const icon = nativeImage.createFromBuffer(pngIcon).resize({
|
||||||
|
width: iconSize,
|
||||||
|
height: iconSize
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tray) {
|
||||||
|
tray.destroy(); // remove old tray on update
|
||||||
|
}
|
||||||
|
|
||||||
|
tray = new Tray(icon)
|
||||||
|
tray.setToolTip(packageInfo.description)
|
||||||
|
tray.setIgnoreDoubleClickEvents(true);
|
||||||
|
tray.setContextMenu(menu);
|
||||||
|
|
||||||
|
return tray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTrayMenu(windowManager: WindowManager): Menu {
|
||||||
|
return Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: "About Lens",
|
label: "About Lens",
|
||||||
click() {
|
click() {
|
||||||
|
// note: argument[1] (browserWindow) not available when app is not focused / hidden
|
||||||
windowManager.bringToTop();
|
windowManager.bringToTop();
|
||||||
showAbout(windowManager.mainView);
|
showAbout(windowManager.mainView);
|
||||||
},
|
},
|
||||||
@ -45,22 +67,25 @@ export async function buildTrayMenu(windowManager: WindowManager) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Clusters",
|
label: "Clusters",
|
||||||
submenu: workspaceStore.workspacesList.map(workspace => {
|
submenu: workspaceStore.workspacesList
|
||||||
const clusters = clusterStore.getByWorkspaceId(workspace.id);
|
.filter(workspace => clusterStore.getByWorkspaceId(workspace.id).length > 0) // hide empty workspaces
|
||||||
return {
|
.map(workspace => {
|
||||||
label: workspace.name,
|
const clusters = clusterStore.getByWorkspaceId(workspace.id);
|
||||||
toolTip: workspace.description,
|
return {
|
||||||
submenu: clusters.map(({ id: clusterId, contextName: label }) => {
|
label: workspace.name,
|
||||||
return {
|
toolTip: workspace.description,
|
||||||
label,
|
submenu: clusters.map(({ id: clusterId, preferences: { clusterName: label }, online }) => {
|
||||||
click() {
|
return {
|
||||||
windowManager.bringToTop();
|
label: `${label}${online ? " (online)" : ""}`,
|
||||||
windowManager.navigate(clusterViewURL({ params: { clusterId } }));
|
toolTip: clusterId,
|
||||||
|
click() {
|
||||||
|
windowManager.bringToTop();
|
||||||
|
windowManager.navigate(clusterViewURL({ params: { clusterId } }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}
|
}),
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Check for updates",
|
label: "Check for updates",
|
||||||
@ -76,26 +101,4 @@ export async function buildTrayMenu(windowManager: WindowManager) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// note: all "await"-s must be defined *AFTER* getting observables for proper mobx reactions
|
|
||||||
await app.whenReady();
|
|
||||||
logger.info('[TRAY]: building tray icon and menu');
|
|
||||||
|
|
||||||
const iconSize = isMac ? 16 : 32; // todo: verify on windows/linux
|
|
||||||
const pngIcon = await sharp(trayIcon).png().toBuffer();
|
|
||||||
const icon = nativeImage.createFromBuffer(pngIcon).resize({
|
|
||||||
width: iconSize,
|
|
||||||
height: iconSize
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tray) {
|
|
||||||
tray.destroy(); // remove old tray on update
|
|
||||||
}
|
|
||||||
|
|
||||||
tray = new Tray(icon)
|
|
||||||
tray.setToolTip(packageInfo.description)
|
|
||||||
tray.setIgnoreDoubleClickEvents(true);
|
|
||||||
tray.setContextMenu(trayMenu);
|
|
||||||
|
|
||||||
return tray;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import "./add-cluster.scss"
|
|||||||
import os from "os";
|
import os from "os";
|
||||||
import React, { Fragment } from "react";
|
import React, { Fragment } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { action, observable, runInAction } from "mobx";
|
import { action, observable } from "mobx";
|
||||||
import { remote } from "electron";
|
import { remote } from "electron";
|
||||||
import { KubeConfig } from "@kubernetes/client-node";
|
import { KubeConfig } from "@kubernetes/client-node";
|
||||||
import { _i18n } from "../../i18n";
|
import { _i18n } from "../../i18n";
|
||||||
@ -45,6 +45,7 @@ export class AddCluster extends React.Component {
|
|||||||
@observable dropAreaActive = false;
|
@observable dropAreaActive = false;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
clusterStore.setActive(null);
|
||||||
this.setKubeConfig(userStore.kubeConfigPath);
|
this.setKubeConfig(userStore.kubeConfigPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +118,7 @@ export class AddCluster extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
addClusters = () => {
|
addClusters = () => {
|
||||||
try {
|
try {
|
||||||
if (!this.selectedContexts.length) {
|
if (!this.selectedContexts.length) {
|
||||||
@ -125,6 +127,7 @@ export class AddCluster extends React.Component {
|
|||||||
}
|
}
|
||||||
this.error = ""
|
this.error = ""
|
||||||
this.isWaiting = true
|
this.isWaiting = true
|
||||||
|
|
||||||
const newClusters: ClusterModel[] = this.selectedContexts.map(context => {
|
const newClusters: ClusterModel[] = this.selectedContexts.map(context => {
|
||||||
const clusterId = uuid();
|
const clusterId = uuid();
|
||||||
const kubeConfig = this.kubeContexts.get(context);
|
const kubeConfig = this.kubeContexts.get(context);
|
||||||
@ -142,19 +145,17 @@ export class AddCluster extends React.Component {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
runInAction(() => {
|
|
||||||
clusterStore.addCluster(...newClusters);
|
clusterStore.addCluster(...newClusters);
|
||||||
if (newClusters.length === 1) {
|
|
||||||
const clusterId = newClusters[0].id;
|
if (newClusters.length === 1) {
|
||||||
clusterStore.setActive(clusterId);
|
const clusterId = newClusters[0].id;
|
||||||
navigate(clusterViewURL({ params: { clusterId } }));
|
navigate(clusterViewURL({ params: { clusterId } }));
|
||||||
} else {
|
} else {
|
||||||
Notifications.ok(
|
Notifications.ok(
|
||||||
<Trans>Successfully imported <b>{newClusters.length}</b> cluster(s)</Trans>
|
<Trans>Successfully imported <b>{newClusters.length}</b> cluster(s)</Trans>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
|
||||||
this.refreshContexts();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.error = String(err);
|
this.error = String(err);
|
||||||
Notifications.error(<Trans>Error while adding cluster(s): {this.error}</Trans>);
|
Notifications.error(<Trans>Error while adding cluster(s): {this.error}</Trans>);
|
||||||
@ -206,7 +207,7 @@ export class AddCluster extends React.Component {
|
|||||||
<Tab
|
<Tab
|
||||||
value={KubeConfigSourceTab.FILE}
|
value={KubeConfigSourceTab.FILE}
|
||||||
label={<Trans>Select kubeconfig file</Trans>}
|
label={<Trans>Select kubeconfig file</Trans>}
|
||||||
active={this.sourceTab == KubeConfigSourceTab.FILE} />
|
active={this.sourceTab == KubeConfigSourceTab.FILE}/>
|
||||||
<Tab
|
<Tab
|
||||||
value={KubeConfigSourceTab.TEXT}
|
value={KubeConfigSourceTab.TEXT}
|
||||||
label={<Trans>Paste as text</Trans>}
|
label={<Trans>Paste as text</Trans>}
|
||||||
@ -320,8 +321,8 @@ export class AddCluster extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className={cssNames("kube-context flex gaps align-center", context)}>
|
<div className={cssNames("kube-context flex gaps align-center", context)}>
|
||||||
<span>{context}</span>
|
<span>{context}</span>
|
||||||
{isNew && <Icon small material="fiber_new" />}
|
{isNew && <Icon small material="fiber_new"/>}
|
||||||
{isSelected && <Icon small material="check" className="box right" />}
|
{isSelected && <Icon small material="check" className="box right"/>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import "./cluster-settings.scss";
|
import "./cluster-settings.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer, disposeOnUnmount } from "mobx-react";
|
import { reaction } from "mobx";
|
||||||
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
|
import { RouteComponentProps } from "react-router";
|
||||||
import { Features } from "./features";
|
import { Features } from "./features";
|
||||||
import { Removal } from "./removal";
|
import { Removal } from "./removal";
|
||||||
import { Status } from "./status";
|
import { Status } from "./status";
|
||||||
@ -13,30 +15,35 @@ import { Icon } from "../icon";
|
|||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
import { IClusterSettingsRouteParams } from "./cluster-settings.route";
|
import { IClusterSettingsRouteParams } from "./cluster-settings.route";
|
||||||
import { clusterStore } from "../../../common/cluster-store";
|
import { clusterStore } from "../../../common/cluster-store";
|
||||||
import { RouteComponentProps } from "react-router";
|
|
||||||
import { clusterIpc } from "../../../common/cluster-ipc";
|
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||||
import { autorun } from "mobx";
|
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<IClusterSettingsRouteParams> {
|
interface Props extends RouteComponentProps<IClusterSettingsRouteParams> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ClusterSettings extends React.Component<Props> {
|
export class ClusterSettings extends React.Component<Props> {
|
||||||
|
get clusterId() {
|
||||||
|
return this.props.match.params.clusterId
|
||||||
|
}
|
||||||
|
|
||||||
get cluster(): Cluster {
|
get cluster(): Cluster {
|
||||||
return clusterStore.getById(this.props.match.params.clusterId);
|
return clusterStore.getById(this.clusterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
window.addEventListener('keydown', this.onEscapeKey);
|
window.addEventListener("keydown", this.onEscapeKey);
|
||||||
disposeOnUnmount(this,
|
disposeOnUnmount(this, [
|
||||||
autorun(() => {
|
reaction(() => this.cluster, this.refreshCluster, {
|
||||||
this.refreshCluster();
|
fireImmediately: true,
|
||||||
|
}),
|
||||||
|
reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), {
|
||||||
|
fireImmediately: true,
|
||||||
})
|
})
|
||||||
)
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
window.removeEventListener('keydown', this.onEscapeKey);
|
window.removeEventListener("keydown", this.onEscapeKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
onEscapeKey = (evt: KeyboardEvent) => {
|
onEscapeKey = (evt: KeyboardEvent) => {
|
||||||
@ -46,10 +53,9 @@ export class ClusterSettings extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshCluster = () => {
|
refreshCluster = (cluster: Cluster) => {
|
||||||
if(this.cluster) {
|
if (!cluster) return;
|
||||||
clusterIpc.refresh.invokeFromRenderer(this.cluster.id);
|
clusterIpc.refresh.invokeFromRenderer(cluster.id);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
|||||||
@ -1,14 +1,37 @@
|
|||||||
import "./cluster-view.scss"
|
import "./cluster-view.scss"
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { reaction } from "mobx";
|
||||||
import { getMatchedCluster } from "./cluster-view.route";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
|
import { IClusterViewRouteParams } from "./cluster-view.route";
|
||||||
import { ClusterStatus } from "./cluster-status";
|
import { ClusterStatus } from "./cluster-status";
|
||||||
import { hasLoadedView } from "./lens-views";
|
import { hasLoadedView } from "./lens-views";
|
||||||
|
import { Cluster } from "../../../main/cluster";
|
||||||
|
import { clusterStore } from "../../../common/cluster-store";
|
||||||
|
import { RouteComponentProps } from "react-router";
|
||||||
|
|
||||||
|
interface Props extends RouteComponentProps<IClusterViewRouteParams> {
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ClusterView extends React.Component {
|
export class ClusterView extends React.Component<Props> {
|
||||||
|
get clusterId() {
|
||||||
|
return this.props.match.params.clusterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
get cluster(): Cluster {
|
||||||
|
return clusterStore.getById(this.clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
disposeOnUnmount(this, [
|
||||||
|
reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), {
|
||||||
|
fireImmediately: true,
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const cluster = getMatchedCluster();
|
const { cluster } = this;
|
||||||
const showStatus = cluster && (!cluster.available || !hasLoadedView(cluster.id))
|
const showStatus = cluster && (!cluster.available || !hasLoadedView(cluster.id))
|
||||||
return (
|
return (
|
||||||
<div className="ClusterView">
|
<div className="ClusterView">
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import "./clusters-menu.scss"
|
import "./clusters-menu.scss"
|
||||||
|
|
||||||
|
import type { Cluster } from "../../../main/cluster";
|
||||||
import { remote } from "electron"
|
import { remote } from "electron"
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { DragDropContext, Draggable, DraggableProvided, Droppable, DroppableProvided, DropResult } from "react-beautiful-dnd";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { _i18n } from "../../i18n";
|
import { _i18n } from "../../i18n";
|
||||||
import { t, Trans } from "@lingui/macro";
|
import { t, Trans } from "@lingui/macro";
|
||||||
@ -9,7 +12,7 @@ import { ClusterId, clusterStore } from "../../../common/cluster-store";
|
|||||||
import { workspaceStore } from "../../../common/workspace-store";
|
import { workspaceStore } from "../../../common/workspace-store";
|
||||||
import { ClusterIcon } from "../cluster-icon";
|
import { ClusterIcon } from "../cluster-icon";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { cssNames, IClassName, autobind } from "../../utils";
|
import { autobind, cssNames, IClassName } from "../../utils";
|
||||||
import { Badge } from "../badge";
|
import { Badge } from "../badge";
|
||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
import { addClusterURL } from "../+add-cluster";
|
import { addClusterURL } from "../+add-cluster";
|
||||||
@ -19,8 +22,6 @@ import { Tooltip } from "../tooltip";
|
|||||||
import { ConfirmDialog } from "../confirm-dialog";
|
import { ConfirmDialog } from "../confirm-dialog";
|
||||||
import { clusterIpc } from "../../../common/cluster-ipc";
|
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||||
import { clusterViewURL } from "./cluster-view.route";
|
import { clusterViewURL } from "./cluster-view.route";
|
||||||
import { DragDropContext, Droppable, Draggable, DropResult, DroppableProvided, DraggableProvided } from "react-beautiful-dnd";
|
|
||||||
import type { Cluster } from "../../../main/cluster";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: IClassName;
|
className?: IClassName;
|
||||||
@ -29,13 +30,11 @@ interface Props {
|
|||||||
@observer
|
@observer
|
||||||
export class ClustersMenu extends React.Component<Props> {
|
export class ClustersMenu extends React.Component<Props> {
|
||||||
showCluster = (clusterId: ClusterId) => {
|
showCluster = (clusterId: ClusterId) => {
|
||||||
clusterStore.setActive(clusterId);
|
|
||||||
navigate(clusterViewURL({ params: { clusterId } }));
|
navigate(clusterViewURL({ params: { clusterId } }));
|
||||||
}
|
}
|
||||||
|
|
||||||
addCluster = () => {
|
addCluster = () => {
|
||||||
navigate(addClusterURL());
|
navigate(addClusterURL());
|
||||||
clusterStore.setActive(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showContextMenu = (cluster: Cluster) => {
|
showContextMenu = (cluster: Cluster) => {
|
||||||
@ -45,7 +44,6 @@ export class ClustersMenu extends React.Component<Props> {
|
|||||||
menu.append(new MenuItem({
|
menu.append(new MenuItem({
|
||||||
label: _i18n._(t`Settings`),
|
label: _i18n._(t`Settings`),
|
||||||
click: () => {
|
click: () => {
|
||||||
clusterStore.setActive(cluster.id);
|
|
||||||
navigate(clusterSettingsURL({
|
navigate(clusterSettingsURL({
|
||||||
params: {
|
params: {
|
||||||
clusterId: cluster.id
|
clusterId: cluster.id
|
||||||
@ -110,35 +108,29 @@ export class ClustersMenu extends React.Component<Props> {
|
|||||||
<div className="clusters flex column gaps">
|
<div className="clusters flex column gaps">
|
||||||
<DragDropContext onDragEnd={this.swapClusterIconOrder}>
|
<DragDropContext onDragEnd={this.swapClusterIconOrder}>
|
||||||
<Droppable droppableId="cluster-menu" type="CLUSTER">
|
<Droppable droppableId="cluster-menu" type="CLUSTER">
|
||||||
{(provided: DroppableProvided) => (
|
{({ innerRef, droppableProps, placeholder }: DroppableProvided) => (
|
||||||
<div
|
<div ref={innerRef} {...droppableProps}>
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.droppableProps}
|
|
||||||
>
|
|
||||||
{clusters.map((cluster, index) => {
|
{clusters.map((cluster, index) => {
|
||||||
const isActive = cluster.id === clusterStore.activeClusterId;
|
const isActive = cluster.id === clusterStore.activeClusterId;
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={cluster.id} index={index} key={cluster.id}>
|
<Draggable draggableId={cluster.id} index={index} key={cluster.id}>
|
||||||
{(provided: DraggableProvided) => (
|
{({ draggableProps, dragHandleProps, innerRef }: DraggableProvided) => (
|
||||||
<div
|
<div ref={innerRef} {...draggableProps} {...dragHandleProps}>
|
||||||
ref={provided.innerRef}
|
<ClusterIcon
|
||||||
{...provided.draggableProps}
|
key={cluster.id}
|
||||||
{...provided.dragHandleProps}
|
showErrors={true}
|
||||||
>
|
cluster={cluster}
|
||||||
<ClusterIcon
|
isActive={isActive}
|
||||||
key={cluster.id}
|
onClick={() => this.showCluster(cluster.id)}
|
||||||
showErrors={true}
|
onContextMenu={() => this.showContextMenu(cluster)}
|
||||||
cluster={cluster}
|
/>
|
||||||
isActive={isActive}
|
</div>
|
||||||
onClick={() => this.showCluster(cluster.id)}
|
)}
|
||||||
onContextMenu={() => this.showContextMenu(cluster)}
|
</Draggable>
|
||||||
/>
|
)
|
||||||
</div>
|
}
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
)}
|
|
||||||
)}
|
)}
|
||||||
{provided.placeholder}
|
{placeholder}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
@ -148,9 +140,9 @@ export class ClustersMenu extends React.Component<Props> {
|
|||||||
<Tooltip targetId="add-cluster-icon">
|
<Tooltip targetId="add-cluster-icon">
|
||||||
<Trans>Add Cluster</Trans>
|
<Trans>Add Cluster</Trans>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Icon big material="add" id="add-cluster-icon" />
|
<Icon big material="add" id="add-cluster-icon"/>
|
||||||
{newContexts.size > 0 && (
|
{newContexts.size > 0 && (
|
||||||
<Badge className="counter" label={newContexts.size} tooltip={<Trans>new</Trans>} />
|
<Badge className="counter" label={newContexts.size} tooltip={<Trans>new</Trans>}/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user