diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 19f0945c3e..eee88cd6db 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -518,7 +518,8 @@ export class Cluster implements ClusterModel, ClusterState { timeout: 0, resolveWithFullResponse: false, json: true, - qs: queryParams, + method: "POST", + form: queryParams, }); } diff --git a/src/main/node-shell-session.ts b/src/main/node-shell-session.ts index 0799f9f892..c20567363e 100644 --- a/src/main/node-shell-session.ts +++ b/src/main/node-shell-session.ts @@ -26,7 +26,7 @@ export class NodeShellSession extends ShellSession { if (this.createNodeShellPod(this.podId, this.nodeName)) { await this.waitForRunningPod(this.podId).catch(() => { - this.exit(1001); + this.exitAndClean(1001); }); } args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; @@ -49,11 +49,14 @@ export class NodeShellSession extends ShellSession { appEventBus.emit({name: "node-shell", action: "open"}); } - protected exit(code = 1000) { + protected exitAndClean(code = 1000) { if (this.podId) { this.deleteNodeShellPod(); } - super.exit(code); + + if (code != 1000) { + this.sendResponse("Error occurred. "); + } } protected async createNodeShellPod(podId: string, nodeName: string) { @@ -65,6 +68,7 @@ export class NodeShellSession extends ShellSession { namespace: "kube-system" }, spec: { + nodeName, restartPolicy: "Never", terminationGracePeriodSeconds: 0, hostPID: true, @@ -82,9 +86,6 @@ export class NodeShellSession extends ShellSession { command: ["nsenter"], args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"] }], - nodeSelector: { - "kubernetes.io/hostname": nodeName - } } } as k8s.V1Pod; diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index 0aabebaa27..913c78167c 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -134,6 +134,7 @@ export class ClusterIssues extends React.Component { <>Warnings: {warnings.length} ("selected_namespaces"); +const selectedNamespaces = createStorage("selected_namespaces", undefined); export const namespaceUrlParam = createPageParam({ name: "namespaces", diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index affd9f13eb..694d4c2488 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -20,7 +20,7 @@ export class PodSecurityPolicies extends React.Component { return ( {
{
{showTitle && }
{ export function PodTolerations({ tolerations }: Props) { return (
{ reset() { this.data.clear(); - this.storage?.clear(); + this.storage?.reset(); } } diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index ab352361fe..5c7db4cd41 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -413,7 +413,7 @@ export class ItemListLayout extends React.Component { renderList() { const { store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks, detailsItem, - tableProps = {}, + tableProps = {}, tableId } = this.props; const { isReady, removeItemsDialog, items } = this; const { selectedItems } = store; @@ -426,6 +426,7 @@ export class ItemListLayout extends React.Component { )} {isReady && (
; + } +} + +export const tableStorage = createStorage("table_settings", { + sortParams: {} +}); + +export function getSortParams(tableId: string): Partial { + return tableStorage.get().sortParams[tableId]; +} + +export function setSortParams(tableId: string, sortParams: Partial) { + tableStorage.merge(draft => { + draft.sortParams[tableId] = sortParams; + }); +} diff --git a/src/renderer/components/table/table.tsx b/src/renderer/components/table/table.tsx index 19bd5b03e5..e15bfabad2 100644 --- a/src/renderer/components/table/table.tsx +++ b/src/renderer/components/table/table.tsx @@ -3,7 +3,6 @@ import "./table.scss"; import React from "react"; import { orderBy } from "lodash"; import { observer } from "mobx-react"; -import { observable } from "mobx"; import { autobind, cssNames, noop } from "../../utils"; import { TableRow, TableRowElem, TableRowProps } from "./table-row"; import { TableHead, TableHeadElem, TableHeadProps } from "./table-head"; @@ -11,6 +10,8 @@ import { TableCellElem } from "./table-cell"; import { VirtualList } from "../virtual-list"; import { createPageParam } from "../../navigation"; import { ItemObject } from "../../item.store"; +import { getSortParams, setSortParams } from "./table.storage"; +import { computed } from "mobx"; export type TableSortBy = string; export type TableOrderBy = "asc" | "desc" | string; @@ -19,6 +20,7 @@ export type TableSortCallback = (data: D) => string | number | (string export type TableSortCallbacks = { [columnId: string]: TableSortCallback }; export interface TableProps extends React.DOMAttributes { + tableId?: string; items?: ItemObject[]; // Raw items data className?: string; autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0) @@ -62,13 +64,17 @@ export class Table extends React.Component { sortSyncWithUrl: true, }; - @observable sortParams: Partial = Object.assign( - this.props.sortSyncWithUrl ? { - sortBy: sortByUrlParam.get(), - orderBy: orderByUrlParam.get(), - } : {}, - this.props.sortByDefault, - ); + componentDidMount() { + const { sortable, tableId } = this.props; + + if (sortable && !tableId) { + console.error("[Table]: sorted table requires props.tableId to be specified"); + } + } + + @computed get sortParams() { + return Object.assign({}, this.props.sortByDefault, getSortParams(this.props.tableId)); + } renderHead() { const { sortable, children } = this.props; @@ -113,7 +119,7 @@ export class Table extends React.Component { @autobind() protected onSort({ sortBy, orderBy }: TableSortParams) { - this.sortParams = { sortBy, orderBy }; + setSortParams(this.props.tableId, { sortBy, orderBy }); const { sortSyncWithUrl, onSort } = this.props; if (sortSyncWithUrl) { diff --git a/src/renderer/hooks/useStorage.ts b/src/renderer/hooks/useStorage.ts index 6867dcc79a..febda7edb5 100644 --- a/src/renderer/hooks/useStorage.ts +++ b/src/renderer/hooks/useStorage.ts @@ -2,7 +2,7 @@ import { useState } from "react"; import { createStorage } from "../utils"; import { CreateObservableOptions } from "mobx/lib/api/observable"; -export function useStorage(key: string, initialValue?: T, options?: CreateObservableOptions) { +export function useStorage(key: string, initialValue: T, options?: CreateObservableOptions) { const storage = createStorage(key, initialValue, options); const [storageValue, setStorageValue] = useState(storage.get()); const setValue = (value: T) => { diff --git a/src/renderer/utils/__tests__/storageHelper.test.ts b/src/renderer/utils/__tests__/storageHelper.test.ts index 8e13543ccd..bf0f19f114 100644 --- a/src/renderer/utils/__tests__/storageHelper.test.ts +++ b/src/renderer/utils/__tests__/storageHelper.test.ts @@ -142,17 +142,6 @@ describe("renderer/utils/StorageHelper", () => { })); expect(storageHelper.get()).toEqual({ ...storageHelperDefaultValue, message: "updated3" }); }); - - it("clears data in storage", () => { - storageHelper.init(); - - expect(storageHelper.get()).toBeTruthy(); - storageHelper.clear(); - expect(storageHelper.get()).toBeFalsy(); - expect(storageMock[storageKey]).toBeUndefined(); - expect(storageAdapter.removeItem).toHaveBeenCalledWith(storageHelper.key); - }); - }); describe("data in storage-helper is observable (mobx)", () => { diff --git a/src/renderer/utils/createStorage.ts b/src/renderer/utils/createStorage.ts index 623f657461..2caa3736a4 100755 --- a/src/renderer/utils/createStorage.ts +++ b/src/renderer/utils/createStorage.ts @@ -14,7 +14,7 @@ let initialized = false; const loaded = observable.box(false); const storage = observable.map(); -export function createStorage(key: string, defaultValue?: T, observableOptions?: CreateObservableOptions) { +export function createStorage(key: string, defaultValue: T, observableOptions?: CreateObservableOptions) { const clusterId = getHostedClusterId(); const savingFolder = path.resolve((app || remote.app).getPath("userData"), "lens-local-storage"); const jsonFilePath = path.resolve(savingFolder, `${clusterId ?? "app"}.json`); diff --git a/src/renderer/utils/storageHelper.ts b/src/renderer/utils/storageHelper.ts index f6e6a3d5f9..2b2b14464a 100755 --- a/src/renderer/utils/storageHelper.ts +++ b/src/renderer/utils/storageHelper.ts @@ -21,7 +21,7 @@ export interface StorageHelperOptions { autoInit?: boolean; // start preloading data immediately, default: true observable?: CreateObservableOptions; storage: StorageAdapter; - defaultValue?: T; + defaultValue: T; } export class StorageHelper { @@ -133,17 +133,18 @@ export class StorageHelper { } set(value: T) { - this.data.set(value); + if (value == null) { + // This cannot use recursion because defaultValue might be null or undefined + this.data.set(this.defaultValue); + } else { + this.data.set(value); + } } reset() { this.set(this.defaultValue); } - clear() { - this.data.set(null); - } - merge(value: Partial | ((draft: Draft) => Partial | void)) { const nextValue = produce(this.get(), (state: Draft) => { const newValue = isFunction(value) ? value(state) : value;