1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

fix clusters staying in previously icon reordered workspaces

Signed-off-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
Sebastian Malton 2020-09-04 11:29:55 -04:00
parent 85a7f1e323
commit eb1a2a07e0
6 changed files with 102 additions and 34 deletions

View File

@ -198,8 +198,8 @@
"openid-client": "^3.15.2",
"path-to-regexp": "^6.1.0",
"proper-lockfile": "^4.1.1",
"react-router": "^5.2.0",
"react-beautiful-dnd": "^13.0.0",
"react-router": "^5.2.0",
"request": "^2.88.2",
"request-promise-native": "^1.0.8",
"semver": "^7.3.2",
@ -318,4 +318,4 @@
"xterm": "^4.6.0",
"xterm-addon-fit": "^0.4.0"
}
}
}

View File

@ -11,6 +11,9 @@ import { tracker } from "./tracker";
import { dumpConfigYaml } from "./kube-helpers";
import { saveToAppFiles } from "./utils/saveToAppFiles";
import { KubeConfig } from "@kubernetes/client-node";
import _ from "lodash";
import move from "array-move";
import { is } from "immer/dist/internal";
export interface ClusterIconUpload {
clusterId: string;
@ -18,14 +21,9 @@ export interface ClusterIconUpload {
path: string;
}
interface ClusterIconOrdering {
[workspaceId: string]: ClusterId[]
}
export interface ClusterStoreModel {
activeCluster?: ClusterId; // last opened cluster
clusters?: ClusterModel[]
iconOrder?: ClusterIconOrdering,
}
export type ClusterId = string;
@ -53,6 +51,7 @@ export interface ClusterPreferences {
prometheusProvider?: {
type: string;
};
iconOrder?: number;
icon?: string;
httpsProxy?: string;
}
@ -88,7 +87,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
@observable activeClusterId: ClusterId;
@observable removedClusters = observable.map<ClusterId, Cluster>();
@observable clusters = observable.map<ClusterId, Cluster>();
@observable clusterOrders: ClusterIconOrdering = {};
@computed get activeCluster(): Cluster | null {
return this.getById(this.activeClusterId);
@ -107,6 +105,20 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
this.activeClusterId = id;
}
@action
swapIconOrders(workspace: WorkspaceId, from: number, to: number) {
const clusters = this.getByWorkspaceId(workspace);
if (from < 0 || to < 0 || from >= clusters.length || to >= clusters.length || isNaN(from) || isNaN(to)) {
throw new Error(`invalid from<->to arguments`)
}
move.mutate(clusters, from, to);
for (const i in clusters) {
// This resets the iconOrder to the current display order
clusters[i].preferences.iconOrder = +i;
}
}
hasClusters() {
return this.clusters.size > 0;
}
@ -120,10 +132,9 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
}
getByWorkspaceId(workspaceId: string): Cluster[] {
this.clusterOrders[workspaceId] ??= Array.from(this.clusters.values())
.filter(cluster => cluster.workspace === workspaceId)
.map(cluster => cluster.id);
return this.clusterOrders[workspaceId].map(clusterId => this.clusters.get(clusterId));
const clusters = Array.from(this.clusters.values())
.filter(cluster => cluster.workspace === workspaceId);
return _.sortBy(clusters, cluster => cluster.preferences.iconOrder)
}
@action
@ -159,13 +170,11 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
}
@action
protected fromStore({ activeCluster, clusters = [], iconOrder = {} }: ClusterStoreModel = {}) {
protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) {
const currentClusters = this.clusters.toJS();
const newClusters = new Map<ClusterId, Cluster>();
const removedClusters = new Map<ClusterId, Cluster>();
this.clusterOrders = iconOrder;
// update new clusters
for (const clusterModel of clusters) {
let cluster = currentClusters.get(clusterModel.id);
@ -175,13 +184,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
cluster = new Cluster(clusterModel);
}
newClusters.set(clusterModel.id, cluster);
if (!this.clusterOrders[cluster.workspace]) {
this.clusterOrders[cluster.workspace] = [];
}
if (!this.clusterOrders[cluster.workspace].includes(cluster.id)) {
this.clusterOrders[cluster.workspace].push(cluster.id);
}
}
// update removed clusters
@ -200,7 +202,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
return toJS({
activeCluster: this.activeClusterId,
clusters: this.clustersList.map(cluster => cluster.toJSON()),
iconOrder: this.clusterOrders,
}, {
recurseEverything: true
})

View File

@ -93,6 +93,34 @@ describe("empty config", () => {
expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig");
})
it("check if reorderring works for same from and to", () => {
clusterStore.swapIconOrders("workstation", 1, 1)
const clusters = clusterStore.getByWorkspaceId("workstation");
expect(clusters[0].id).toBe("prod")
expect(clusters[0].preferences.iconOrder).toBe(0)
expect(clusters[1].id).toBe("dev")
expect(clusters[1].preferences.iconOrder).toBe(1)
});
it("check if reorderring works for different from and to", () => {
clusterStore.swapIconOrders("workstation", 0, 1)
const clusters = clusterStore.getByWorkspaceId("workstation");
expect(clusters[0].id).toBe("dev")
expect(clusters[0].preferences.iconOrder).toBe(0)
expect(clusters[1].id).toBe("prod")
expect(clusters[1].preferences.iconOrder).toBe(1)
});
it("check if after icon reordering, changing workspaces still works", () => {
clusterStore.swapIconOrders("workstation", 1, 1)
clusterStore.getById("prod").workspace = "default"
expect(clusterStore.getByWorkspaceId("workstation").length).toBe(1);
expect(clusterStore.getByWorkspaceId("default").length).toBe(2);
});
it("removes cluster from store", async () => {
await clusterStore.removeById("foo");
expect(clusterStore.getById("foo")).toBeUndefined();

View File

@ -2,7 +2,7 @@ import type { ClusterId, ClusterModel, ClusterPreferences } from "../common/clus
import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api";
import type { WorkspaceId } from "../common/workspace-store";
import type { FeatureStatusMap } from "./feature"
import { action, computed, observable, reaction, toJS, when } from "mobx";
import { action, computed, intercept, observable, reaction, toJS, when } from "mobx";
import { apiKubePrefix } from "../common/vars";
import { broadcastIpc } from "../common/ipc";
import { ContextHandler } from "./context-handler"

View File

@ -21,7 +21,6 @@ import { ConfirmDialog } from "../confirm-dialog";
import { clusterIpc } from "../../../common/cluster-ipc";
import { clusterViewURL, getMatchedClusterId } from "./cluster-view.route";
import { DragDropContext, Droppable, Draggable, DropResult, DroppableProvided, DraggableProvided } from "react-beautiful-dnd";
import move from "array-move";
// fixme: allow to rearrange clusters with drag&drop
@ -93,10 +92,11 @@ export class ClustersMenu extends React.Component<Props> {
swapClusterIconOrder(result: DropResult) {
if (result.reason === "DROP") {
const { currentWorkspaceId } = workspaceStore;
const clusters = clusterStore.getByWorkspaceId(currentWorkspaceId);
move.mutate(clusters, result.source.index, result.destination.index);
clusterStore.clusterOrders[currentWorkspaceId] = clusters.map(c => c.id);
const {
source: { index: from },
destination: { index: to },
} = result
clusterStore.swapIconOrders(currentWorkspaceId, from, to)
}
}

View File

@ -1350,6 +1350,17 @@
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@jest/types@^26.3.0":
version "26.3.0"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71"
integrity sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@kubernetes/client-node@^0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@kubernetes/client-node/-/client-node-0.12.0.tgz#79120311bced206ac8fa36435fb4cc2c1828fff2"
@ -1846,6 +1857,21 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
"@types/istanbul-reports@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821"
integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@26.x":
version "26.0.13"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.13.tgz#5a7b9d5312f5dd521a38329c38ee9d3802a0b85e"
integrity sha512-sCzjKow4z9LILc6DhBvn5AkIfmQzDZkgtVVKmGwVrs5tuid38ws281D4l+7x1kP487+FlKDh5kfMZ8WSPAdmdA==
dependencies:
jest-diff "^25.2.1"
pretty-format "^25.2.1"
"@types/jest@^25.2.3":
version "25.2.3"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf"
@ -7144,6 +7170,18 @@ jest-snapshot@^26.0.1:
pretty-format "^26.0.1"
semver "^7.3.2"
jest-util@26.x:
version "26.3.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e"
integrity sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw==
dependencies:
"@jest/types" "^26.3.0"
"@types/node" "*"
chalk "^4.0.0"
graceful-fs "^4.2.4"
is-ci "^2.0.0"
micromatch "^4.0.2"
jest-util@^26.0.1:
version "26.0.1"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.0.1.tgz#72c4c51177b695fdd795ca072a6f94e3d7cef00a"
@ -7903,7 +7941,7 @@ messageformat-parser@^4.1.3:
resolved "https://registry.yarnpkg.com/messageformat-parser/-/messageformat-parser-4.1.3.tgz#b824787f57fcda7d50769f5b63e8d4fda68f5b9e"
integrity sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg==
micromatch@4.0.2, micromatch@4.x, micromatch@^4.0.0, micromatch@^4.0.2:
micromatch@4.0.2, micromatch@^4.0.0, micromatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
@ -11285,17 +11323,18 @@ truncate-utf8-bytes@^1.0.0:
utf8-byte-length "^1.0.1"
ts-jest@^26.1.0:
version "26.1.0"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.0.tgz#e9070fc97b3ea5557a48b67c631c74eb35e15417"
integrity sha512-JbhQdyDMYN5nfKXaAwCIyaWLGwevcT2/dbqRPsQeh6NZPUuXjZQZEfeLb75tz0ubCIgEELNm6xAzTe5NXs5Y4Q==
version "26.3.0"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.3.0.tgz#6b2845045347dce394f069bb59358253bc1338a9"
integrity sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q==
dependencies:
"@types/jest" "26.x"
bs-logger "0.x"
buffer-from "1.x"
fast-json-stable-stringify "2.x"
jest-util "26.x"
json5 "2.x"
lodash.memoize "4.x"
make-error "1.x"
micromatch "4.x"
mkdirp "1.x"
semver "7.x"
yargs-parser "18.x"