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

allow to quick select/deselect all namespaces in NamespaceSelect

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2021-02-03 01:12:08 +02:00
parent 068ab855c1
commit d8acc4487d
3 changed files with 72 additions and 34 deletions

View File

@ -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<Props> = {
showIcons: true,
showClusterOption: false,
get clusterOptionLabel() {
return `Cluster`;
},
};
@observer
@ -39,13 +34,11 @@ export class NamespaceSelect extends React.Component<Props> {
}
@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<Props> {
@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 (
<div className="flex gaps align-center">
<FilterIcon type={FilterType.NAMESPACE}/>
<span>{namespace}</span>
{isSelected && <Icon small material="check" className="box right"/>}
</div>
);
}
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 (
<NamespaceSelect
placeholder={placeholder}
isMulti={true}
placeholder={this.placeholder}
closeMenuOnSelect={false}
isOptionSelected={() => false}
controlShouldRenderValue={false}
isMulti
onChange={([{ value }]: SelectOption[]) => toggleContext(value)}
formatOptionLabel={({ value: namespace }: SelectOption) => {
const isSelected = hasContext(namespace);
return (
<div className="flex gaps align-center">
<FilterIcon type={FilterType.NAMESPACE}/>
<span>{namespace}</span>
{isSelected && <Icon small material="check" className="box right"/>}
</div>
);
}}
onChange={this.onChange}
formatOptionLabel={this.formatOptionLabel}
customizeOptions={this.customizeOptions}
/>
);
}

View File

@ -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<Namespace> {
});
}
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<Namespace> {
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);

View File

@ -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);
}
}),