Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
87 changes: 63 additions & 24 deletions extensions/vscode-containers/src/commands/filterTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface TreeFilterState {
}

const treeFilters = new Map<TreePrefix, TreeFilterState>();
const filterMementoKeyPrefix = "vscode-containers.filters";
Comment thread
bwateratmsft marked this conversation as resolved.

// Only support filtering for containers and images
const contextKeys: Partial<Record<TreePrefix, string>> = {
Expand All @@ -25,16 +26,45 @@ export function getTreeFilter(treePrefix: TreePrefix): TreeFilterState {
return treeFilters.get(treePrefix) || { filterText: "", isActive: false };
}

function getFilterMementoKey(treePrefix: TreePrefix): string {
return `${filterMementoKeyPrefix}.${treePrefix}`;
}

function loadPersistedTreeFilter(treePrefix: TreePrefix): void {
const persistedFilter = ext.context.workspaceState
.get<string | undefined>(getFilterMementoKey(treePrefix))
?.toLowerCase();

if (persistedFilter) {
treeFilters.set(treePrefix, {
filterText: persistedFilter,
isActive: true,
});
} else {
clearTreeFilter(treePrefix);
}
}
Comment thread
pdjohntony marked this conversation as resolved.

function setTreeFilter(treePrefix: TreePrefix, filterText: string): void {
const normalizedFilterText = filterText.toLowerCase();

treeFilters.set(treePrefix, {
filterText: filterText.toLowerCase(),
isActive: filterText.length > 0,
filterText: normalizedFilterText,
isActive: normalizedFilterText.length > 0,
});
setFilterContextValue(treePrefix, filterText.length > 0);
void ext.context.workspaceState.update(
getFilterMementoKey(treePrefix),
Comment thread
bwateratmsft marked this conversation as resolved.
normalizedFilterText || undefined
);
setFilterContextValue(treePrefix, normalizedFilterText.length > 0);
}

function clearTreeFilter(treePrefix: TreePrefix): void {
treeFilters.set(treePrefix, { filterText: "", isActive: false });
treeFilters.delete(treePrefix);
void ext.context.workspaceState.update(
getFilterMementoKey(treePrefix),
undefined
);
setFilterContextValue(treePrefix, false);
}

Expand All @@ -47,8 +77,10 @@ function setFilterContextValue(treePrefix: TreePrefix, value: boolean): void {

export function setInitialFilterContextValues(): void {
for (const treePrefix of Object.keys(contextKeys) as TreePrefix[]) {
loadPersistedTreeFilter(treePrefix);
const filter = getTreeFilter(treePrefix);
setFilterContextValue(treePrefix, filter.isActive);
updateTreeViewTitle(treePrefix);
}
}

Expand Down Expand Up @@ -122,24 +154,31 @@ async function filterTreeView(
}

quickPick.onDidAccept(() => {
const value = quickPick.value.trim();
const selectedItem = quickPick.selectedItems[0];

// Check if "Clear Filter" was selected
if (selectedItem?.label === clearFilterLabel) {
clearTreeFilter(treePrefix);
context.telemetry.properties.action = "clearFilter";
} else if (value) {
setTreeFilter(treePrefix, value);
context.telemetry.properties.action = "applyFilter";
context.telemetry.properties.filterLength = value.length.toString();
} else {
clearTreeFilter(treePrefix);
context.telemetry.properties.action = "clearFilter";
}

quickPick.hide();
void refreshTreeView(treePrefix);
void (async () => {
const value = quickPick.value.trim();
const selectedItem = quickPick.selectedItems[0];

// Check if "Clear Filter" was selected
if (selectedItem?.label === clearFilterLabel) {
clearTreeFilter(treePrefix);
context.telemetry.properties.action = "clearFilter";
} else if (value) {
setTreeFilter(treePrefix, value);
context.telemetry.properties.action = "applyFilter";
context.telemetry.properties.filterLength =
value.length.toString();
} else {
clearTreeFilter(treePrefix);
context.telemetry.properties.action = "clearFilter";
}

quickPick.hide();
await refreshTreeView(treePrefix);
})().catch((error) => {
void vscode.window.showErrorMessage(
vscode.l10n.t("Failed to apply filter: {0}", String(error))
);
});
});

quickPick.onDidHide(() => {
Expand Down Expand Up @@ -225,13 +264,13 @@ export async function clearContainersFilter(
): Promise<void> {
clearTreeFilter("containers");
context.telemetry.properties.action = "clearFilter";
void refreshTreeView("containers");
await refreshTreeView("containers");
}

export async function clearImagesFilter(
context: IActionContext
): Promise<void> {
clearTreeFilter("images");
context.telemetry.properties.action = "clearFilter";
void refreshTreeView("images");
await refreshTreeView("images");
}
13 changes: 9 additions & 4 deletions extensions/vscode-containers/src/test/TestMemento.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@
import * as vscode from 'vscode';

export class TestMemento implements vscode.Memento {
private readonly values: { [key: string]: never } = {};
private readonly values: Record<string, unknown> = {};

keys(): readonly string[] {
return Object.keys(this.values);
}

get<T>(key: string, defaultValue?: T): T | undefined {
return this.values[key] ?? defaultValue;
return (this.values[key] as T | undefined) ?? defaultValue;
}

update(key: string, value: never): Thenable<void> {
this.values[key] = value;
update(key: string, value: unknown): Thenable<void> {
if (value === undefined) {
delete this.values[key];
} else {
this.values[key] = value;
}

return Promise.resolve();
}
}
17 changes: 8 additions & 9 deletions extensions/vscode-containers/src/tree/LocalRootTreeItemBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ export abstract class LocalRootTreeItemBase<TItem extends AnyContainerObject, TP
ext.activityMeasurementService.recordActivity('overallnoedit');

this._currentItems = await this.getCachedItems(context, clearCache);
this.groupBySetting = this.getTreeSetting(groupByKey, this.groupBySettingInfo);
context.telemetry.properties.groupBySetting = this.groupBySetting;
this.sortBySetting = this.getTreeSetting(sortByKey, this.sortBySettingInfo);
context.telemetry.properties.sortBySetting = this.sortBySetting;
this.labelSetting = this.getTreeSetting(labelKey, this.labelSettingInfo);
context.telemetry.properties.labelSetting = this.labelSetting;
this.descriptionSetting = this.getTreeArraySetting(descriptionKey, this.descriptionSettingInfo);
context.telemetry.properties.descriptionSetting = this.descriptionSetting.toString();
Comment thread
bwateratmsft marked this conversation as resolved.

const filter = getTreeFilter(this.treePrefix);
if (filter.isActive && this._currentItems) {
Expand All @@ -123,15 +131,6 @@ export abstract class LocalRootTreeItemBase<TItem extends AnyContainerObject, TP
context.telemetry.properties.noItems = 'true';
return this.getTreeItemForEmptyList();
} else {
this.groupBySetting = this.getTreeSetting(groupByKey, this.groupBySettingInfo);
context.telemetry.properties.groupBySetting = this.groupBySetting;
this.sortBySetting = this.getTreeSetting(sortByKey, this.sortBySettingInfo);
context.telemetry.properties.sortBySetting = this.sortBySetting;
this.labelSetting = this.getTreeSetting(labelKey, this.labelSettingInfo);
context.telemetry.properties.labelSetting = this.labelSetting;
this.descriptionSetting = this.getTreeArraySetting(descriptionKey, this.descriptionSettingInfo);
context.telemetry.properties.descriptionSetting = this.descriptionSetting.toString();

return this.groupItems(this._currentItems);
}
}
Expand Down
Loading