mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into preferences-redesign
This commit is contained in:
commit
d0078519cb
@ -518,7 +518,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
timeout: 0,
|
timeout: 0,
|
||||||
resolveWithFullResponse: false,
|
resolveWithFullResponse: false,
|
||||||
json: true,
|
json: true,
|
||||||
qs: queryParams,
|
method: "POST",
|
||||||
|
form: queryParams,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export class NodeShellSession extends ShellSession {
|
|||||||
|
|
||||||
if (this.createNodeShellPod(this.podId, this.nodeName)) {
|
if (this.createNodeShellPod(this.podId, this.nodeName)) {
|
||||||
await this.waitForRunningPod(this.podId).catch(() => {
|
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))"];
|
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"});
|
appEventBus.emit({name: "node-shell", action: "open"});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected exit(code = 1000) {
|
protected exitAndClean(code = 1000) {
|
||||||
if (this.podId) {
|
if (this.podId) {
|
||||||
this.deleteNodeShellPod();
|
this.deleteNodeShellPod();
|
||||||
}
|
}
|
||||||
super.exit(code);
|
|
||||||
|
if (code != 1000) {
|
||||||
|
this.sendResponse("Error occurred. ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async createNodeShellPod(podId: string, nodeName: string) {
|
protected async createNodeShellPod(podId: string, nodeName: string) {
|
||||||
@ -65,6 +68,7 @@ export class NodeShellSession extends ShellSession {
|
|||||||
namespace: "kube-system"
|
namespace: "kube-system"
|
||||||
},
|
},
|
||||||
spec: {
|
spec: {
|
||||||
|
nodeName,
|
||||||
restartPolicy: "Never",
|
restartPolicy: "Never",
|
||||||
terminationGracePeriodSeconds: 0,
|
terminationGracePeriodSeconds: 0,
|
||||||
hostPID: true,
|
hostPID: true,
|
||||||
@ -82,9 +86,6 @@ export class NodeShellSession extends ShellSession {
|
|||||||
command: ["nsenter"],
|
command: ["nsenter"],
|
||||||
args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"]
|
args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"]
|
||||||
}],
|
}],
|
||||||
nodeSelector: {
|
|
||||||
"kubernetes.io/hostname": nodeName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} as k8s.V1Pod;
|
} as k8s.V1Pod;
|
||||||
|
|
||||||
|
|||||||
@ -134,6 +134,7 @@ export class ClusterIssues extends React.Component<Props> {
|
|||||||
<>Warnings: {warnings.length}</>
|
<>Warnings: {warnings.length}</>
|
||||||
</SubHeader>
|
</SubHeader>
|
||||||
<Table
|
<Table
|
||||||
|
tableId="cluster_issues"
|
||||||
items={warnings}
|
items={warnings}
|
||||||
virtual
|
virtual
|
||||||
selectable
|
selectable
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { Namespace, namespacesApi } from "../../api/endpoints/namespaces.api";
|
|||||||
import { createPageParam } from "../../navigation";
|
import { createPageParam } from "../../navigation";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
|
||||||
const selectedNamespaces = createStorage<string[]>("selected_namespaces");
|
const selectedNamespaces = createStorage<string[] | undefined>("selected_namespaces", undefined);
|
||||||
|
|
||||||
export const namespaceUrlParam = createPageParam<string[]>({
|
export const namespaceUrlParam = createPageParam<string[]>({
|
||||||
name: "namespaces",
|
name: "namespaces",
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export class PodSecurityPolicies extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<KubeObjectListLayout
|
<KubeObjectListLayout
|
||||||
isConfigurable
|
isConfigurable
|
||||||
tableId="access_roles"
|
tableId="access_pod_security_policies"
|
||||||
className="PodSecurityPolicies"
|
className="PodSecurityPolicies"
|
||||||
isClusterScoped={true}
|
isClusterScoped={true}
|
||||||
store={podSecurityPoliciesStore}
|
store={podSecurityPoliciesStore}
|
||||||
|
|||||||
@ -64,6 +64,7 @@ export class VolumeDetailsList extends React.Component<Props> {
|
|||||||
<div className="VolumeDetailsList flex column">
|
<div className="VolumeDetailsList flex column">
|
||||||
<DrawerTitle title="Persistent Volumes"/>
|
<DrawerTitle title="Persistent Volumes"/>
|
||||||
<Table
|
<Table
|
||||||
|
tableId="storage_volume_details_list"
|
||||||
items={persistentVolumes}
|
items={persistentVolumes}
|
||||||
selectable
|
selectable
|
||||||
virtual={virtual}
|
virtual={virtual}
|
||||||
|
|||||||
@ -135,6 +135,7 @@ export class PodDetailsList extends React.Component<Props> {
|
|||||||
<div className="PodDetailsList flex column">
|
<div className="PodDetailsList flex column">
|
||||||
{showTitle && <DrawerTitle title="Pods"/>}
|
{showTitle && <DrawerTitle title="Pods"/>}
|
||||||
<Table
|
<Table
|
||||||
|
tableId="workloads_pod_details_list"
|
||||||
items={pods}
|
items={pods}
|
||||||
selectable
|
selectable
|
||||||
virtual={virtual}
|
virtual={virtual}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ const getTableRow = (toleration: IToleration) => {
|
|||||||
export function PodTolerations({ tolerations }: Props) {
|
export function PodTolerations({ tolerations }: Props) {
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
|
tableId="workloads_pod_tolerations"
|
||||||
selectable
|
selectable
|
||||||
scrollable={false}
|
scrollable={false}
|
||||||
sortable={sortingCallbacks}
|
sortable={sortingCallbacks}
|
||||||
|
|||||||
@ -81,6 +81,6 @@ export class DockTabStore<T> {
|
|||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.data.clear();
|
this.data.clear();
|
||||||
this.storage?.clear();
|
this.storage?.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -413,7 +413,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
renderList() {
|
renderList() {
|
||||||
const {
|
const {
|
||||||
store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks, detailsItem,
|
store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks, detailsItem,
|
||||||
tableProps = {},
|
tableProps = {}, tableId
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { isReady, removeItemsDialog, items } = this;
|
const { isReady, removeItemsDialog, items } = this;
|
||||||
const { selectedItems } = store;
|
const { selectedItems } = store;
|
||||||
@ -426,6 +426,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
)}
|
)}
|
||||||
{isReady && (
|
{isReady && (
|
||||||
<Table
|
<Table
|
||||||
|
tableId={tableId}
|
||||||
virtual={virtual}
|
virtual={virtual}
|
||||||
selectable={hasDetailsView}
|
selectable={hasDetailsView}
|
||||||
sortable={sortingCallbacks}
|
sortable={sortingCallbacks}
|
||||||
|
|||||||
22
src/renderer/components/table/table.storage.ts
Normal file
22
src/renderer/components/table/table.storage.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { createStorage } from "../../utils";
|
||||||
|
import { TableSortParams } from "./table";
|
||||||
|
|
||||||
|
export interface TableStorageModel {
|
||||||
|
sortParams: {
|
||||||
|
[tableId: string]: Partial<TableSortParams>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tableStorage = createStorage<TableStorageModel>("table_settings", {
|
||||||
|
sortParams: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
export function getSortParams(tableId: string): Partial<TableSortParams> {
|
||||||
|
return tableStorage.get().sortParams[tableId];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSortParams(tableId: string, sortParams: Partial<TableSortParams>) {
|
||||||
|
tableStorage.merge(draft => {
|
||||||
|
draft.sortParams[tableId] = sortParams;
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -3,7 +3,6 @@ import "./table.scss";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { orderBy } from "lodash";
|
import { orderBy } from "lodash";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { observable } from "mobx";
|
|
||||||
import { autobind, cssNames, noop } from "../../utils";
|
import { autobind, cssNames, noop } from "../../utils";
|
||||||
import { TableRow, TableRowElem, TableRowProps } from "./table-row";
|
import { TableRow, TableRowElem, TableRowProps } from "./table-row";
|
||||||
import { TableHead, TableHeadElem, TableHeadProps } from "./table-head";
|
import { TableHead, TableHeadElem, TableHeadProps } from "./table-head";
|
||||||
@ -11,6 +10,8 @@ import { TableCellElem } from "./table-cell";
|
|||||||
import { VirtualList } from "../virtual-list";
|
import { VirtualList } from "../virtual-list";
|
||||||
import { createPageParam } from "../../navigation";
|
import { createPageParam } from "../../navigation";
|
||||||
import { ItemObject } from "../../item.store";
|
import { ItemObject } from "../../item.store";
|
||||||
|
import { getSortParams, setSortParams } from "./table.storage";
|
||||||
|
import { computed } from "mobx";
|
||||||
|
|
||||||
export type TableSortBy = string;
|
export type TableSortBy = string;
|
||||||
export type TableOrderBy = "asc" | "desc" | string;
|
export type TableOrderBy = "asc" | "desc" | string;
|
||||||
@ -19,6 +20,7 @@ export type TableSortCallback<D = any> = (data: D) => string | number | (string
|
|||||||
export type TableSortCallbacks = { [columnId: string]: TableSortCallback };
|
export type TableSortCallbacks = { [columnId: string]: TableSortCallback };
|
||||||
|
|
||||||
export interface TableProps extends React.DOMAttributes<HTMLDivElement> {
|
export interface TableProps extends React.DOMAttributes<HTMLDivElement> {
|
||||||
|
tableId?: string;
|
||||||
items?: ItemObject[]; // Raw items data
|
items?: ItemObject[]; // Raw items data
|
||||||
className?: string;
|
className?: string;
|
||||||
autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0)
|
autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0)
|
||||||
@ -62,13 +64,17 @@ export class Table extends React.Component<TableProps> {
|
|||||||
sortSyncWithUrl: true,
|
sortSyncWithUrl: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@observable sortParams: Partial<TableSortParams> = Object.assign(
|
componentDidMount() {
|
||||||
this.props.sortSyncWithUrl ? {
|
const { sortable, tableId } = this.props;
|
||||||
sortBy: sortByUrlParam.get(),
|
|
||||||
orderBy: orderByUrlParam.get(),
|
if (sortable && !tableId) {
|
||||||
} : {},
|
console.error("[Table]: sorted table requires props.tableId to be specified");
|
||||||
this.props.sortByDefault,
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
|
@computed get sortParams() {
|
||||||
|
return Object.assign({}, this.props.sortByDefault, getSortParams(this.props.tableId));
|
||||||
|
}
|
||||||
|
|
||||||
renderHead() {
|
renderHead() {
|
||||||
const { sortable, children } = this.props;
|
const { sortable, children } = this.props;
|
||||||
@ -113,7 +119,7 @@ export class Table extends React.Component<TableProps> {
|
|||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
protected onSort({ sortBy, orderBy }: TableSortParams) {
|
protected onSort({ sortBy, orderBy }: TableSortParams) {
|
||||||
this.sortParams = { sortBy, orderBy };
|
setSortParams(this.props.tableId, { sortBy, orderBy });
|
||||||
const { sortSyncWithUrl, onSort } = this.props;
|
const { sortSyncWithUrl, onSort } = this.props;
|
||||||
|
|
||||||
if (sortSyncWithUrl) {
|
if (sortSyncWithUrl) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { useState } from "react";
|
|||||||
import { createStorage } from "../utils";
|
import { createStorage } from "../utils";
|
||||||
import { CreateObservableOptions } from "mobx/lib/api/observable";
|
import { CreateObservableOptions } from "mobx/lib/api/observable";
|
||||||
|
|
||||||
export function useStorage<T>(key: string, initialValue?: T, options?: CreateObservableOptions) {
|
export function useStorage<T>(key: string, initialValue: T, options?: CreateObservableOptions) {
|
||||||
const storage = createStorage(key, initialValue, options);
|
const storage = createStorage(key, initialValue, options);
|
||||||
const [storageValue, setStorageValue] = useState(storage.get());
|
const [storageValue, setStorageValue] = useState(storage.get());
|
||||||
const setValue = (value: T) => {
|
const setValue = (value: T) => {
|
||||||
|
|||||||
@ -142,17 +142,6 @@ describe("renderer/utils/StorageHelper", () => {
|
|||||||
}));
|
}));
|
||||||
expect(storageHelper.get()).toEqual({ ...storageHelperDefaultValue, message: "updated3" });
|
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)", () => {
|
describe("data in storage-helper is observable (mobx)", () => {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ let initialized = false;
|
|||||||
const loaded = observable.box(false);
|
const loaded = observable.box(false);
|
||||||
const storage = observable.map<string/* key */, any /* serializable */>();
|
const storage = observable.map<string/* key */, any /* serializable */>();
|
||||||
|
|
||||||
export function createStorage<T>(key: string, defaultValue?: T, observableOptions?: CreateObservableOptions) {
|
export function createStorage<T>(key: string, defaultValue: T, observableOptions?: CreateObservableOptions) {
|
||||||
const clusterId = getHostedClusterId();
|
const clusterId = getHostedClusterId();
|
||||||
const savingFolder = path.resolve((app || remote.app).getPath("userData"), "lens-local-storage");
|
const savingFolder = path.resolve((app || remote.app).getPath("userData"), "lens-local-storage");
|
||||||
const jsonFilePath = path.resolve(savingFolder, `${clusterId ?? "app"}.json`);
|
const jsonFilePath = path.resolve(savingFolder, `${clusterId ?? "app"}.json`);
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export interface StorageHelperOptions<T> {
|
|||||||
autoInit?: boolean; // start preloading data immediately, default: true
|
autoInit?: boolean; // start preloading data immediately, default: true
|
||||||
observable?: CreateObservableOptions;
|
observable?: CreateObservableOptions;
|
||||||
storage: StorageAdapter<T>;
|
storage: StorageAdapter<T>;
|
||||||
defaultValue?: T;
|
defaultValue: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StorageHelper<T> {
|
export class StorageHelper<T> {
|
||||||
@ -133,17 +133,18 @@ export class StorageHelper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set(value: T) {
|
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() {
|
reset() {
|
||||||
this.set(this.defaultValue);
|
this.set(this.defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.data.set(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
merge(value: Partial<T> | ((draft: Draft<T>) => Partial<T> | void)) {
|
merge(value: Partial<T> | ((draft: Draft<T>) => Partial<T> | void)) {
|
||||||
const nextValue = produce(this.get(), (state: Draft<T>) => {
|
const nextValue = produce(this.get(), (state: Draft<T>) => {
|
||||||
const newValue = isFunction(value) ? value(state) : value;
|
const newValue = isFunction(value) ? value(state) : value;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user