Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only group delete visible items #4798

Merged
merged 3 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/common/item.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ export abstract class ItemStore<Item extends ItemObject> {
@observable isLoading = false;
@observable isLoaded = false;
@observable items = observable.array<Item>([], { deep: false });
@observable selectedItemsIds = observable.map<string, boolean>();
@observable selectedItemsIds = observable.set<string>();

constructor() {
makeObservable(this);
autoBind(this);
}

@computed get selectedItems(): Item[] {
return this.items.filter(item => this.selectedItemsIds.get(item.getId()));
return this.pickOnlySelected(this.items);
}

public pickOnlySelected(items: Item[]): Item[] {
return items.filter(item => this.selectedItemsIds.has(item.getId()));
}

public getItems(): Item[] {
Expand Down Expand Up @@ -152,12 +156,12 @@ export abstract class ItemStore<Item extends ItemObject> {
}

isSelected(item: Item) {
return !!this.selectedItemsIds.get(item.getId());
return this.selectedItemsIds.has(item.getId());
}

@action
select(item: Item) {
this.selectedItemsIds.set(item.getId(), true);
this.selectedItemsIds.add(item.getId());
}

@action
Expand Down Expand Up @@ -207,6 +211,8 @@ export abstract class ItemStore<Item extends ItemObject> {

async removeSelectedItems?(): Promise<any>;

async removeItems?(items: Item[]): Promise<void>;

* [Symbol.iterator]() {
yield* this.items;
}
Expand Down
4 changes: 4 additions & 0 deletions src/common/k8s-api/kube-object.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,10 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
return Promise.all(this.selectedItems.map(this.remove));
}

async removeItems(items: T[]) {
await Promise.all(items.map(this.remove));
}

// collect items from watch-api events to avoid UI blowing up with huge streams of data
protected eventsBuffer = observable.array<IKubeWatchEvent<KubeJsonApiData>>([], { deep: false });

Expand Down
10 changes: 6 additions & 4 deletions src/renderer/components/+helm-releases/releases.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,12 @@ class NonInjectedHelmReleases extends Component<Dependencies & Props> {
return releases.get().filter((release) => release.isSelected);
},

removeSelectedItems() {
return Promise.all(
releases.get().filter((release) => release.isSelected).map((release) => release.delete()),
);
pickOnlySelected: (releases) => {
return releases.filter(release => release.isSelected);
},

removeItems: async (releases) => {
await Promise.all(releases.map(release => release.delete()));
Nokel81 marked this conversation as resolved.
Show resolved Hide resolved
},
} as ItemStore<RemovableHelmRelease>;

Expand Down
32 changes: 22 additions & 10 deletions src/renderer/components/item-object-list/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,19 +136,27 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
}

@boundMethod
removeItemsDialog() {
removeItemsDialog(selectedItems: I[]) {
const { customizeRemoveDialog, store } = this.props;
const { selectedItems, removeSelectedItems } = store;
const visibleMaxNamesCount = 5;
const selectedNames = selectedItems.map(ns => ns.getName()).slice(0, visibleMaxNamesCount).join(", ");
const dialogCustomProps = customizeRemoveDialog ? customizeRemoveDialog(selectedItems) : {};
const selectedCount = selectedItems.length;
const tailCount = selectedCount > visibleMaxNamesCount ? selectedCount - visibleMaxNamesCount : 0;
const tail = tailCount > 0 ? <>, and <b>{tailCount}</b> more</> : null;
const message = selectedCount <= 1 ? <p>Remove item <b>{selectedNames}</b>?</p> : <p>Remove <b>{selectedCount}</b> items <b>{selectedNames}</b>{tail}?</p>;
const tailCount = selectedCount > visibleMaxNamesCount
? selectedCount - visibleMaxNamesCount
: 0;
const tail = tailCount > 0
? <>, and <b>{tailCount}</b> more</>
: null;
const message = selectedCount <= 1
? <p>Remove item <b>{selectedNames}</b>?</p>
: <p>Remove <b>{selectedCount}</b> items <b>{selectedNames}</b>{tail}?</p>;
const onConfirm = store.removeItems
? () => store.removeItems(selectedItems)
: store.removeSelectedItems;

ConfirmDialog.open({
ok: removeSelectedItems,
ok: onConfirm,
labelOk: "Remove",
message,
...dialogCustomProps,
Expand Down Expand Up @@ -225,10 +233,12 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
render() {
const {
store, hasDetailsView, addRemoveButtons = {}, virtual, sortingCallbacks,
detailsItem, className, tableProps = {}, tableId,
detailsItem, className, tableProps = {}, tableId, getItems,
} = this.props;
const selectedItemId = detailsItem && detailsItem.getId();
const classNames = cssNames(className, "box", "grow", ThemeStore.getInstance().activeTheme.type);
const items = getItems();
const selectedItems = store.pickOnlySelected(items);

return (
<div className="items box grow flex column">
Expand All @@ -238,7 +248,7 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
selectable={hasDetailsView}
sortable={sortingCallbacks}
getTableRow={this.getRow}
items={this.props.getItems()}
items={items}
selectedItemId={selectedItemId}
noItems={this.renderNoItems()}
className={classNames}
Expand All @@ -252,9 +262,11 @@ export class ItemListLayoutContent<I extends ItemObject> extends React.Component
{() => (
<AddRemoveButtons
onRemove={
store.selectedItems.length ? this.removeItemsDialog : null
(store.removeItems || store.removeSelectedItems) && selectedItems.length > 0
? () => this.removeItemsDialog(selectedItems)
: null
}
removeTooltip={`Remove selected items (${store.selectedItems.length})`}
removeTooltip={`Remove selected items (${selectedItems.length})`}
{...addRemoveButtons}
/>
)}
Expand Down
11 changes: 5 additions & 6 deletions src/renderer/components/item-object-list/list-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { boundMethod, cssNames, IClassName, noop, StorageHelper } from "../../ut
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
import type { ItemObject, ItemStore } from "../../../common/item.store";
import type { SearchInputUrlProps } from "../input";
import { Filter, FilterType, pageFilters } from "./page-filters.store";
import { FilterType, pageFilters } from "./page-filters.store";
import { PageFiltersList } from "./page-filters-list";
import type { NamespaceStore } from "../+namespaces/namespace-store/namespace.store";
import namespaceStoreInjectable from "../+namespaces/namespace-store/namespace-store.injectable";
Expand Down Expand Up @@ -202,19 +202,18 @@ class NonInjectedItemListLayout<I extends ItemObject> extends React.Component<It
};

@computed get items() {
const filterGroups = groupBy<Filter>(this.filters, ({ type }) => type);

const filterGroups = groupBy(this.filters, ({ type }) => type);
const filterItems: ItemsFilter<I>[] = [];

Object.entries(filterGroups).forEach(([type, filtersGroup]) => {
for (const [type, filtersGroup] of Object.entries(filterGroups)) {
const filterCallback = this.filterCallbacks[type] ?? this.props.filterCallbacks?.[type];

if (filterCallback && filtersGroup.length > 0) {
filterItems.push(filterCallback);
}
});
}

const items = this.props.getItems ? this.props.getItems() : (this.props.items ?? this.props.store.items);
const items = this.props.getItems?.() ?? this.props.items ?? this.props.store.items;

return applyFilters(filterItems.concat(this.props.filterItems), items);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,25 +138,14 @@ class NonInjectedKubeObjectListLayout<K extends KubeObject> extends React.Compon
}
}

const InjectedKubeObjectListLayout = withInjectables<
Dependencies,
KubeObjectListLayoutProps<KubeObject>
>(
NonInjectedKubeObjectListLayout,

{
getProps: (di, props) => ({
clusterFrameContext: di.inject(clusterFrameContextInjectable),
subscribeToStores: di.inject(kubeWatchApiInjectable).subscribeStores,
...props,
}),
},
);


export function KubeObjectListLayout<K extends KubeObject>(
props: KubeObjectListLayoutProps<K>,
) {

const InjectedKubeObjectListLayout = withInjectables<Dependencies, KubeObjectListLayoutProps<KubeObject>>(NonInjectedKubeObjectListLayout, {
getProps: (di, props) => ({
clusterFrameContext: di.inject(clusterFrameContextInjectable),
subscribeToStores: di.inject(kubeWatchApiInjectable).subscribeStores,
...props,
}),
});

export function KubeObjectListLayout<K extends KubeObject>(props: KubeObjectListLayoutProps<K>) {
return <InjectedKubeObjectListLayout {...props} />;
}