implement better hanlding of filter search suggestions
This commit is contained in:
Binary file not shown.
@@ -162,7 +162,6 @@ export function BoardPage(
|
||||
coreViewModel,
|
||||
boardViewModel.searchViewModel,
|
||||
coreViewModel.translations.chatPage.task.filterTasksHeadline,
|
||||
TaskViewModelToEntry,
|
||||
boardViewModel.isPresentingFilterModal,
|
||||
)}
|
||||
<div children:set={taskSettingsModal}></div>
|
||||
|
||||
Binary file not shown.
@@ -9,7 +9,6 @@ export function SearchModal<T>(
|
||||
coreViewModel: CoreViewModel,
|
||||
searchViewModel: SearchViewModel<T>,
|
||||
headline: string,
|
||||
converter: React.StateItemConverter<T>,
|
||||
isOpen: React.State<boolean>,
|
||||
) {
|
||||
function close() {
|
||||
@@ -31,6 +30,7 @@ export function SearchModal<T>(
|
||||
<div class="flex-row">
|
||||
<input
|
||||
id="focused"
|
||||
style="max-width: unset"
|
||||
placeholder={
|
||||
coreViewModel.translations.general.searchLabel
|
||||
}
|
||||
@@ -70,14 +70,15 @@ export function SearchModal<T>(
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr></hr>
|
||||
<hr></hr>
|
||||
|
||||
<h3>{coreViewModel.translations.general.searchSuggestionsLabel}</h3>
|
||||
|
||||
<div
|
||||
class="grid gap"
|
||||
style="grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr))"
|
||||
class="flex-column gap"
|
||||
children:append={[
|
||||
searchViewModel.matchingObjects,
|
||||
converter,
|
||||
searchViewModel.suggestions,
|
||||
(suggestion: string) => SuggestionView(suggestion, searchViewModel, coreViewModel),
|
||||
]}
|
||||
></div>
|
||||
</main>
|
||||
@@ -89,3 +90,34 @@ export function SearchModal<T>(
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SuggestionView<T>(suggestion: string, searchViewModel: SearchViewModel<T>, coreViewModel: CoreViewModel) {
|
||||
const isApplied = React.createProxyState([searchViewModel.appliedQuery], ()=>searchViewModel.appliedQuery.value == suggestion);
|
||||
|
||||
function deleteSuggestion() {
|
||||
searchViewModel.deleteSuggestion(suggestion);
|
||||
}
|
||||
|
||||
function applySuggestion() {
|
||||
searchViewModel.search(suggestion);
|
||||
}
|
||||
|
||||
return <div class="flex-row surface align-center">
|
||||
<span class="width-100 flex-1 padding-h">{suggestion}</span>
|
||||
<button
|
||||
class="danger"
|
||||
aria-label={coreViewModel.translations.general.deleteButton}
|
||||
on:click={deleteSuggestion}
|
||||
>
|
||||
<span class="icon">delete</span>
|
||||
</button>
|
||||
<button
|
||||
class="primary"
|
||||
aria-label={coreViewModel.translations.general.applyButton}
|
||||
on:click={applySuggestion}
|
||||
toggle:disabled={isApplied}
|
||||
>
|
||||
<span class="icon">check</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@ const englishTranslations = {
|
||||
searchButtonClearAudioLabel: "clear search query",
|
||||
|
||||
abortButton: "Abort",
|
||||
applyButton: "Apply",
|
||||
backButton: "Back",
|
||||
cancelButton: "Cancel",
|
||||
closeButton: "Close",
|
||||
backButton: "Back",
|
||||
deleteButton: "Delete",
|
||||
|
||||
continueButton: "Continue",
|
||||
confirmButton: "Confirm",
|
||||
@@ -22,6 +24,7 @@ const englishTranslations = {
|
||||
|
||||
fileVersionLabel: "Version",
|
||||
searchLabel: "Search",
|
||||
searchSuggestionsLabel: "Recent searches",
|
||||
waitingLabel: "Waiting...",
|
||||
|
||||
restoreConnection: "Restore connection",
|
||||
|
||||
Binary file not shown.
@@ -83,9 +83,6 @@ export default class CoreViewModel {
|
||||
|
||||
// SUGGESTIONS
|
||||
// boards & tasks
|
||||
boardFilterStringSuggestions: React.ListState<string> =
|
||||
new React.ListState();
|
||||
|
||||
taskCategorySuggestions: React.ListState<string> = new React.ListState();
|
||||
taskStatusSuggestions: React.ListState<string> = new React.ListState();
|
||||
|
||||
|
||||
Binary file not shown.
@@ -28,6 +28,7 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
isPresentingFilterModal: React.State<boolean> = new React.State(false);
|
||||
|
||||
searchViewModel: SearchViewModel<TaskViewModel>;
|
||||
searchSuggestions = new React.ListState<string>();
|
||||
filteredTaskViewModels: React.ListState<TaskViewModel> =
|
||||
new React.ListState();
|
||||
isFilterActive: React.State<boolean>;
|
||||
@@ -115,17 +116,25 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
];
|
||||
this.coreViewModel.storageModel.write(suggestionPath, "");
|
||||
if (
|
||||
!this.coreViewModel.boardFilterStringSuggestions.value.has(
|
||||
!this.searchSuggestions.value.has(
|
||||
searchTerm,
|
||||
)
|
||||
) && searchTerm != ""
|
||||
) {
|
||||
this.coreViewModel.boardFilterStringSuggestions.add(searchTerm);
|
||||
this.searchSuggestions.add(searchTerm);
|
||||
}
|
||||
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
this.coreViewModel.storageModel.write(lastSearchPath, searchTerm);
|
||||
};
|
||||
|
||||
handleSearchRemoved = (searchTerm: string): void => {
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.coreViewModel.storageModel.remove(suggestionPath);
|
||||
}
|
||||
|
||||
// view
|
||||
showTask = (taskFileContent: TaskFileContent): void => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) {
|
||||
@@ -224,7 +233,7 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
const dirPath: string[] = this.getPreviousSearchesPath();
|
||||
const searches: string[] =
|
||||
this.coreViewModel.storageModel.list(dirPath);
|
||||
this.coreViewModel.boardFilterStringSuggestions.add(...searches);
|
||||
this.searchSuggestions.add(...searches.filter(x => x != ""));
|
||||
};
|
||||
|
||||
restoreSearch = (): void => {
|
||||
@@ -297,12 +306,13 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
this.taskViewModels,
|
||||
this.filteredTaskViewModels,
|
||||
TaskViewModel.getStringsForFilter,
|
||||
this.coreViewModel.boardFilterStringSuggestions,
|
||||
this.searchSuggestions,
|
||||
);
|
||||
this.searchViewModel.appliedQuery.subscribeSilent((newQuery) => {
|
||||
this.handleNewSearch(newQuery);
|
||||
});
|
||||
this.restoreSearch();
|
||||
this.searchSuggestions.handleRemovals(this.handleSearchRemoved);
|
||||
|
||||
this.isFilterActive = React.createProxyState(
|
||||
[this.searchViewModel.appliedQuery],
|
||||
|
||||
Binary file not shown.
@@ -2,16 +2,9 @@ import * as React from "bloatless-react";
|
||||
import { checkDoesObjectMatchSearch } from "../../Model/Utility/utility";
|
||||
|
||||
export default class SearchViewModel<T> {
|
||||
// data
|
||||
allObjects: React.ListState<T> | React.MapState<T>;
|
||||
getStringsOfObject: (object: T) => string[];
|
||||
|
||||
// state
|
||||
appliedQuery = new React.State<string>("");
|
||||
searchInput = new React.State<string>("");
|
||||
matchingObjects: React.ListState<T>;
|
||||
|
||||
suggestions: React.ListState<string>;
|
||||
|
||||
// guards
|
||||
cannotApplySearch: React.State<boolean> = React.createProxyState(
|
||||
@@ -45,18 +38,17 @@ export default class SearchViewModel<T> {
|
||||
this.searchInput.value = "";
|
||||
}
|
||||
|
||||
deleteSuggestion = (suggestion: string): void => {
|
||||
this.suggestions.remove(suggestion);
|
||||
}
|
||||
|
||||
// init
|
||||
constructor(
|
||||
allObjects: React.ListState<T> | React.MapState<T>,
|
||||
matchingObjects: React.ListState<T>,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
suggestions: React.ListState<string>,
|
||||
public allObjects: React.ListState<T> | React.MapState<T>,
|
||||
public matchingObjects: React.ListState<T>,
|
||||
public getStringsOfObject: (object: T) => string[],
|
||||
public suggestions: React.ListState<string>,
|
||||
) {
|
||||
this.allObjects = allObjects;
|
||||
this.matchingObjects = matchingObjects;
|
||||
this.getStringsOfObject = getStringsOfObject;
|
||||
this.suggestions = suggestions;
|
||||
|
||||
// handle new objects
|
||||
this.allObjects.handleAddition((newObject: T) => {
|
||||
const doesMatch: boolean = this.checkDoesMatchSearch(newObject);
|
||||
|
||||
Reference in New Issue
Block a user