Skip to content

Commit b0d93f7

Browse files
authored
Merge pull request #3701 from ilandikov/feat-filter-results
feat: Add text box to filter searches by description
2 parents 76c172d + 7f7d4e1 commit b0d93f7

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

src/Renderer/QueryResultsRenderer.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { GlobalQuery } from '../Config/GlobalQuery';
33
import type { IQuery } from '../IQuery';
44
import { PerformanceTracker } from '../lib/PerformanceTracker';
55
import { State } from '../Obsidian/Cache';
6+
import { DescriptionField } from '../Query/Filter/DescriptionField';
67
import { getQueryForQueryRenderer } from '../Query/QueryRendererHelper';
78
import type { QueryResult } from '../Query/QueryResult';
89
import type { TasksFile } from '../Scripting/TasksFile';
@@ -147,29 +148,71 @@ export class QueryResultsRenderer {
147148
}
148149

149150
public async render(state: State, tasks: Task[], content: HTMLDivElement) {
151+
const queryResult = this.performSearch(tasks);
152+
153+
this.addToolbar(queryResult, content);
154+
await this.renderQueryResult(state, queryResult, content);
155+
}
156+
157+
private performSearch(tasks: Task[]) {
150158
const measureSearch = new PerformanceTracker(`Search: ${this.query.queryId} - ${this.filePath}`);
151159
measureSearch.start();
152160
const queryResult = this.query.applyQueryToTasks(tasks);
153161
measureSearch.finish();
162+
return queryResult;
163+
}
154164

165+
private async renderQueryResult(state: State, queryResult: QueryResult, content: HTMLDivElement) {
155166
const measureRender = new PerformanceTracker(`Render: ${this.query.queryId} - ${this.filePath}`);
156167
measureRender.start();
157-
this.addToolbar(queryResult, content);
158168
this.htmlRenderer.content = content;
159169
await this.htmlRenderer.renderQuery(state, queryResult);
160170
measureRender.finish();
161171
}
162172

163-
private addToolbar(queryResult: QueryResult, content: HTMLElement) {
173+
private addToolbar(queryResult: QueryResult, content: HTMLDivElement) {
164174
if (this.query.queryLayoutOptions.hideToolbar) {
165175
return;
166176
}
167177

168178
const toolbar = createAndAppendElement('div', content);
169179
toolbar.classList.add('plugin-tasks-toolbar');
180+
this.addSearchBox(toolbar, queryResult, content);
170181
this.addCopyButton(toolbar, queryResult);
171182
}
172183

184+
private addSearchBox(toolbar: HTMLDivElement, queryResult: QueryResult, content: HTMLDivElement) {
185+
const label = createAndAppendElement('label', toolbar);
186+
setIcon(label, 'lucide-filter');
187+
const searchBox = createAndAppendElement('input', label);
188+
searchBox.placeholder = 'Filter by description...';
189+
setTooltip(searchBox, 'Filter results');
190+
searchBox.addEventListener('input', async () => {
191+
const { filter, error } = new DescriptionField().createFilterOrErrorMessage(
192+
'description includes ' + searchBox.value,
193+
);
194+
if (error) {
195+
new Notice('error searching for ' + searchBox.value + ': ' + error);
196+
return;
197+
}
198+
199+
// We want to retain the Toolbar, to not lose the search string.
200+
// But we need to delete any pre-existing headings, tasks and task count.
201+
// The following while loop relies on the Toolbar being the first element.
202+
while (content.firstElementChild !== content.lastElementChild) {
203+
const lastChild = content.lastChild;
204+
if (lastChild === null) {
205+
break;
206+
}
207+
208+
lastChild.remove();
209+
}
210+
211+
const filteredQueryResult = queryResult.applyFilter(filter!);
212+
await this.renderQueryResult(State.Warm, filteredQueryResult, content);
213+
});
214+
}
215+
173216
private addCopyButton(toolbar: HTMLDivElement, queryResult: QueryResult) {
174217
const copyButton = createAndAppendElement('button', toolbar);
175218
setIcon(copyButton, 'lucide-copy');

src/Renderer/Renderer.scss

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,24 @@
1616
.plugin-tasks-toolbar {
1717
display: flex;
1818
flex-direction: row;
19-
justify-content: flex-end;
19+
justify-content: space-between;
2020
gap: var(--size-4-1);
21+
22+
label {
23+
display: flex;
24+
flex-direction: row;
25+
align-items: center;
26+
27+
input {
28+
height: 100%;
29+
padding-left: 24px;
30+
}
31+
32+
svg {
33+
position: absolute;
34+
transform: translateX(25%);
35+
}
36+
}
2137
}
2238

2339
.tasks-count {

tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_-_rendering_queries_should_render_the_toolbar.approved.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
-->
44

55
<div>
6-
<div class="plugin-tasks-toolbar"><button test-icon="lucide-copy" test-tooltip="Copy results"></button></div>
6+
<div class="plugin-tasks-toolbar">
7+
<label test-icon="lucide-filter">
8+
<input placeholder="Filter by description..." test-tooltip="Filter results" />
9+
</label>
10+
<button test-icon="lucide-copy" test-tooltip="Copy results"></button>
11+
</div>
712
<ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency"></ul>
813
<div class="task-count">0 tasks</div>
914
</div>

0 commit comments

Comments
 (0)