diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index 6ee7ea2d57..7c47337591 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -13,17 +13,12 @@ import { kubeWatchApi } from "../../api/kube-watch-api"; interface Props extends SelectProps { showIcons?: boolean; - showClusterOption?: boolean; // show cluster option on the top (default: false) - clusterOptionLabel?: React.ReactNode; // label for cluster option (default: "Cluster") - customizeOptions?(nsOptions: SelectOption[]): SelectOption[]; + customizeOptions?(options: SelectOption[]): SelectOption[]; } const defaultProps: Partial = { showIcons: true, showClusterOption: false, - get clusterOptionLabel() { - return `Cluster`; - }, }; @observer @@ -39,13 +34,11 @@ export class NamespaceSelect extends React.Component { } @computed get options(): SelectOption[] { - const { customizeOptions, showClusterOption, clusterOptionLabel } = this.props; + const { customizeOptions } = this.props; let options: SelectOption[] = namespaceStore.items.map(ns => ({ value: ns.getName() })); - options = customizeOptions ? customizeOptions(options) : options; - - if (showClusterOption) { - options.unshift({ value: null, label: clusterOptionLabel }); + if (customizeOptions) { + options = customizeOptions(options); } return options; @@ -80,32 +73,61 @@ export class NamespaceSelect extends React.Component { @observer export class NamespaceSelectFilter extends React.Component { + @computed get placeholder(): React.ReactNode { + const namespaces = namespaceStore.getContextNamespaces(); + + switch (namespaces.length) { + case 1: + return <>Namespace: {namespaces[0]}; + case 2: + return <>Namespaces: {namespaces.join(", ")}; + default: + return "All Namespaces"; + } + } + + formatOptionLabel = ({ value: namespace, label }: SelectOption) => { + if (namespace) { + const isSelected = namespaceStore.hasContext(namespace); + + return ( +
+ + {namespace} + {isSelected && } +
+ ); + } + + return label; + }; + + customizeOptions = (options: SelectOption[]): SelectOption[] => { + return [ + { value: "", label: "All Namespaces" }, + ...options + ]; + }; + + onChange = ([{ value: namespace }]: SelectOption[]) => { + if (namespace) { + namespaceStore.toggleContext(namespace); + } else { + namespaceStore.toggleAll(); // "All namespaces" option clicked + } + }; + render() { - const { contextNs, hasContext, toggleContext } = namespaceStore; - let placeholder = <>All namespaces; - - if (contextNs.length == 1) placeholder = <>Namespace: {contextNs[0]}; - if (contextNs.length >= 2) placeholder = <>Namespaces: {contextNs.join(", ")}; - return ( false} controlShouldRenderValue={false} - isMulti - onChange={([{ value }]: SelectOption[]) => toggleContext(value)} - formatOptionLabel={({ value: namespace }: SelectOption) => { - const isSelected = hasContext(namespace); - - return ( -
- - {namespace} - {isSelected && } -
- ); - }} + onChange={this.onChange} + formatOptionLabel={this.formatOptionLabel} + customizeOptions={this.customizeOptions} /> ); } diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 63bb7525de..2fd5cb6302 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -1,4 +1,4 @@ -import { action, comparer, IReactionDisposer, IReactionOptions, observable, reaction, toJS, when } from "mobx"; +import { action, comparer, computed, IReactionDisposer, IReactionOptions, observable, reaction, toJS, when } from "mobx"; import { autobind, createStorage } from "../../utils"; import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../kube-object.store"; import { Namespace, namespacesApi } from "../../api/endpoints/namespaces.api"; @@ -79,10 +79,11 @@ export class NamespaceStore extends KubeObjectStore { }); } - get allowedNamespaces(): string[] { + @computed get allowedNamespaces(): string[] { return toJS(getHostedCluster().allowedNamespaces); } + @computed private get initialNamespaces(): string[] { const allowed = new Set(this.allowedNamespaces); const prevSelected = storage.get(); @@ -159,6 +160,21 @@ export class NamespaceStore extends KubeObjectStore { else this.contextNs.push(namespace); } + @action + toggleAll(showAll?: boolean) { + if (typeof showAll === "boolean") { + if (showAll) { + this.contextNs.replace(this.initialNamespaces); + } else { + this.contextNs.clear(); + } + } else { + const showAll = this.contextNs.length < this.initialNamespaces.length; + + this.toggleAll(showAll); + } + } + @action async remove(item: Namespace) { await super.remove(item); diff --git a/src/renderer/components/item-object-list/page-filters.store.ts b/src/renderer/components/item-object-list/page-filters.store.ts index d931cd2575..8f5fa2c9eb 100644 --- a/src/renderer/components/item-object-list/page-filters.store.ts +++ b/src/renderer/components/item-object-list/page-filters.store.ts @@ -30,7 +30,7 @@ export class PageFiltersStore { protected syncWithContextNamespace() { const disposers = [ reaction(() => this.getValues(FilterType.NAMESPACE), filteredNs => { - if (filteredNs.length !== namespaceStore.contextNs.length) { + if (filteredNs.length !== namespaceStore.getContextNamespaces().length) { namespaceStore.setContext(filteredNs); } }),