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

Add tests for search components #4462

Merged
merged 15 commits into from
Mar 17, 2023
8 changes: 5 additions & 3 deletions app/assets/javascripts/components/filter_button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export class FilterButton extends LitElement {
value: string;
@property({ type: Boolean })
multi = false;
@property({ type: Object })
searchQuery = searchQuery;

static styles = css`
:host {
Expand All @@ -33,11 +35,11 @@ export class FilterButton extends LitElement {

addFilter(): void {
if (this.multi) {
const selected = new Set(searchQuery.arrayQueryParams.params.get(this.param));
const selected = new Set(this.searchQuery.arrayQueryParams.params.get(this.param));
selected.add(this.value);
searchQuery.arrayQueryParams.updateParam(this.param, Array.from(selected));
this.searchQuery.arrayQueryParams.updateParam(this.param, Array.from(selected));
} else {
searchQuery.queryParams.updateParam(this.param, this.value);
this.searchQuery.queryParams.updateParam(this.param, this.value);
}
}

Expand Down
22 changes: 12 additions & 10 deletions app/assets/javascripts/components/filter_collection_element.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { property } from "lit/decorators.js";
import { searchQuery } from "search";
import { SearchQuery, searchQuery } from "search";
import { ShadowlessLitElement } from "components/shadowless_lit_element";

export type Label = {id: string, name: string};
Expand Down Expand Up @@ -30,13 +30,15 @@ export class FilterCollectionElement extends ShadowlessLitElement {
paramVal: (l: Label) => string;
@property({ type: Array })
labels: Array<Label> = [];
@property({ type: Object })
searchQuery: SearchQuery = searchQuery;
@property({ state: true })
private multiSelected: string[] = [];
@property({ state: true })
private singleSelected = "";

update(changedProperties: Map<string, unknown>): void {
if ((changedProperties.has("param") || changedProperties.has("multi")) &&
if ((changedProperties.has("param") || changedProperties.has("multi") || changedProperties.has("searchQuery")) &&
this.param !== undefined && this.multi !== undefined) {
if (this.multi) {
this.multiSubscribeToQueryParams();
Expand All @@ -58,39 +60,39 @@ export class FilterCollectionElement extends ShadowlessLitElement {
}

private multiUnSelect(label: Label): void {
searchQuery.arrayQueryParams.updateParam(this.param, this.multiSelected.filter(s => s !== this.str(label)));
this.searchQuery.arrayQueryParams.updateParam(this.param, this.multiSelected.filter(s => s !== this.str(label)));
}

private multiIsSelected(label: Label): boolean {
return this.multiSelected.includes(this.str(label));
}

private multiSelect(label: Label): void {
searchQuery.arrayQueryParams.updateParam(this.param, [...this.multiSelected, this.str(label)]);
this.searchQuery.arrayQueryParams.updateParam(this.param, [...this.multiSelected, this.str(label)]);
}

private multiSubscribeToQueryParams(): void {
this.multiSelected = searchQuery.arrayQueryParams.params.get(this.param) || [];
searchQuery.arrayQueryParams.subscribeByKey(this.param, (k, o, n) => {
this.multiSelected = this.searchQuery.arrayQueryParams.params.get(this.param) || [];
this.searchQuery.arrayQueryParams.subscribeByKey(this.param, (k, o, n) => {
this.multiSelected = n || [];
});
}

private singleUnSelect(label: Label): void {
searchQuery.queryParams.updateParam(this.param, undefined);
this.searchQuery.queryParams.updateParam(this.param, undefined);
}

private singleSelect(label: Label): void {
searchQuery.queryParams.updateParam(this.param, this.str(label));
this.searchQuery.queryParams.updateParam(this.param, this.str(label));
}

private singleIsSelected(label: Label): boolean {
return this.singleSelected === this.str(label);
}

private singleSubscribeToQueryParams(): void {
this.singleSelected = searchQuery.queryParams.params.get(this.param);
searchQuery.queryParams.subscribeByKey(this.param, (k, o, n) => this.singleSelected = n || "");
this.singleSelected = this.searchQuery.queryParams.params.get(this.param);
this.searchQuery.queryParams.subscribeByKey(this.param, (k, o, n) => this.singleSelected = n || "");
}

isSelected = this.singleIsSelected;
Expand Down
37 changes: 22 additions & 15 deletions app/assets/javascripts/components/search_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { html, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { Toast } from "toast";
import { fetch, ready } from "util.js";
import { searchQuery } from "search";
import { SearchQuery, searchQuery } from "search";
import { ShadowlessLitElement } from "components/shadowless_lit_element";

type SearchOption = {search: Record<string, string>, type: string, text: string};
type SearchAction = {
url: string,
type: string,
export type SearchOption = {search: Record<string, string>, type?: string, text: string};
export type SearchAction = {
url?: string,
type?: string,
text: string,
action: string,
js: string,
confirm: string,
action?: string,
js?: string,
confirm?: string,
icon: string
};

Expand All @@ -34,33 +34,36 @@ export class SearchOptionElement extends ShadowlessLitElement {
searchOption: SearchOption;
@property( { type: Number })
key: number;
@property({ type: Object })
searchQuery: SearchQuery = searchQuery;

@property({ state: true })
private _active = false;

update(changedProperties: Map<string, unknown>): void {
if (changedProperties.has("searchOption") && this.searchOption) {
this.setActive();
Object.keys(this.searchOption.search).forEach(k => {
searchQuery.queryParams.subscribeByKey(k, () => this.setActive());
this.searchQuery.queryParams.subscribeByKey(k, () => this.setActive());
});
}
super.update(changedProperties);
}

setActive(): void {
this._active = Object.entries(this.searchOption.search).every(([key, value]) => {
return searchQuery.queryParams.params.get(key) == value.toString();
return this.searchQuery.queryParams.params.get(key) == value.toString();
});
}

performSearch(): void {
if (!this._active) {
Object.entries(this.searchOption.search).forEach(([key, value]) => {
searchQuery.queryParams.updateParam(key, value.toString());
this.searchQuery.queryParams.updateParam(key, value.toString());
});
} else {
Object.keys(this.searchOption.search).forEach(key => {
searchQuery.queryParams.updateParam(key, undefined);
this.searchQuery.queryParams.updateParam(key, undefined);
});
}
}
Expand Down Expand Up @@ -96,6 +99,8 @@ export class SearchOptionElement extends ShadowlessLitElement {
export class SearchActions extends ShadowlessLitElement {
@property({ type: Array })
actions: (SearchOption|SearchAction)[] = [];
@property({ type: Object })
searchQuery: SearchQuery = searchQuery;

getSearchOptions(): Array<SearchOption> {
return this.actions.filter(isSearchOption);
Expand All @@ -116,7 +121,7 @@ export class SearchActions extends ShadowlessLitElement {
}

if (action.confirm === undefined || window.confirm(action.confirm)) {
const url: string = searchQuery.addParametersToUrl(action.action);
const url: string = this.searchQuery.addParametersToUrl(action.action);

const response = await fetch(url, {
method: "POST",
Expand All @@ -127,7 +132,7 @@ export class SearchActions extends ShadowlessLitElement {
if (data.js) {
eval(data.js);
} else {
searchQuery.resetAllQueryParams();
this.searchQuery.resetAllQueryParams();
}
}

Expand All @@ -153,7 +158,9 @@ export class SearchActions extends ShadowlessLitElement {
<li><h6 class='dropdown-header'>${I18n.t("js.options")}</h6></li>
` : html``}
${this.getSearchOptions().map((opt, id) => html`
<d-search-option .searchOption=${opt} .key=${id}>
<d-search-option .searchOption=${opt}
.key=${id}
.searchQuery=${this.searchQuery}>
</d-search-option>
`)}

Expand Down
18 changes: 12 additions & 6 deletions app/assets/javascripts/components/search_field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { html, TemplateResult } from "lit";
import { createDelayer } from "util.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { ref } from "lit/directives/ref.js";
import { searchQuery } from "search";
import { SearchQuery, searchQuery } from "search";
import { ShadowlessLitElement } from "components/shadowless_lit_element";
import { FilterCollectionElement, Label } from "components/filter_collection_element";

Expand Down Expand Up @@ -47,7 +47,7 @@ export class SearchFieldSuggestion extends FilterCollectionElement {
handleClick(e: Event, label: Label): void {
e.preventDefault();
this.select(label);
searchQuery.queryParams.updateParam("filter", undefined);
this.searchQuery.queryParams.updateParam("filter", undefined);
}

render(): TemplateResult {
Expand Down Expand Up @@ -83,6 +83,8 @@ export class SearchField extends ShadowlessLitElement {
eager: boolean;
@property( { type: Array })
filterCollections: Record<string, { data: Label[], multi: boolean, paramVal: (l: Label) => string, param: string }>;
@property({ type: Object })
searchQuery: SearchQuery = searchQuery;

@property({ state: true })
filter?: string = "";
Expand All @@ -103,14 +105,17 @@ export class SearchField extends ShadowlessLitElement {

constructor() {
super();
searchQuery.queryParams.subscribeByKey("filter", (k, o, n) => this.filter = n || "");
this.filter = searchQuery.queryParams.params.get("filter") || "";
this.delay = createDelayer();
}

firstUpdated(): void {
this.searchQuery.queryParams.subscribeByKey("filter", (k, o, n) => this.filter = n || "");
this.filter = this.searchQuery.queryParams.params.get("filter") || "";
}

update(changedProperties: Map<string, unknown>): void {
if (changedProperties.has("eager") && this.eager) {
searchQuery.search();
this.searchQuery.search();
}
super.update(changedProperties);
}
Expand All @@ -126,7 +131,7 @@ export class SearchField extends ShadowlessLitElement {
if (e.key === "Tab") {
this.tabComplete();
}
this.delay(() => searchQuery.queryParams.updateParam("filter", this.filter), 300);
this.delay(() => this.searchQuery.queryParams.updateParam("filter", this.filter), 300);
}

updated(): void {
Expand Down Expand Up @@ -170,6 +175,7 @@ export class SearchField extends ShadowlessLitElement {
.param=${c.param}
.multi=${c.multi}
.index=${i}
.searchQuery=${this.searchQuery}
${ref(this.suggestionFieldChanged)}
>
</d-search-field-suggestion>
Expand Down
42 changes: 22 additions & 20 deletions app/assets/javascripts/components/sort_button.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "search.ts";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { searchQuery } from "search";
import { searchQuery, SearchQuery } from "search";

/**
* This class is made to manage the currently active sort parameter in the search query
Expand All @@ -10,15 +10,17 @@ export class SortQuery {
active_column: string;
ascending: boolean;
listeners: Array<(c: string, a: boolean) => void> = [];
searchQuery: SearchQuery;

constructor() {
this.active_column = searchQuery.queryParams.params.get("order_by[column]");
this.ascending = searchQuery.queryParams.params.get("order_by[direction]") === "ASC";
searchQuery.queryParams.subscribeByKey("order_by[column]", (k, o, n) => {
constructor(_searchQuery: SearchQuery = searchQuery) {
this.searchQuery = _searchQuery;
this.active_column = this.searchQuery.queryParams.params.get("order_by[column]");
this.ascending = this.searchQuery.queryParams.params.get("order_by[direction]") === "ASC";
this.searchQuery.queryParams.subscribeByKey("order_by[column]", (k, o, n) => {
this.active_column = n;
this.notify();
});
searchQuery.queryParams.subscribeByKey("order_by[direction]", (k, o, n) => {
this.searchQuery.queryParams.subscribeByKey("order_by[direction]", (k, o, n) => {
this.ascending = n === "ASC";
this.notify();
});
Expand All @@ -44,8 +46,8 @@ export class SortQuery {
this.active_column = column;
this.ascending = ascending;
if (this.active_column) {
searchQuery.queryParams.updateParam("order_by[column]", this.active_column);
searchQuery.queryParams.updateParam("order_by[direction]", this.getDirectionValue());
this.searchQuery.queryParams.updateParam("order_by[column]", this.active_column);
this.searchQuery.queryParams.updateParam("order_by[direction]", this.getDirectionValue());
}
}
}
Expand All @@ -71,11 +73,21 @@ export class SortButton extends LitElement {
default: string;
@property({ type: Boolean })
disabled = false;
@property({ type: Object })
sortQuery: SortQuery = sortQuery;

active_column: string;
ascending: boolean;

update(changedProperties: Map<string, unknown>): void {
if (changedProperties.has("sortQuery")) {
this.ascending = this.sortQuery.ascending;
this.active_column = this.sortQuery.active_column;
this.sortQuery.subscribe((c, a) => {
this.active_column = c;
this.ascending = a;
});
}
if ( changedProperties.has("disabled") ) {
if (!this.disabled) {
this.addEventListener("click", this.sort);
Expand Down Expand Up @@ -146,22 +158,12 @@ export class SortButton extends LitElement {

sort(): void {
if (!this.isActive() || !this.ascending) {
sortQuery.sortBy(this.column, true);
this.sortQuery.sortBy(this.column, true);
} else {
sortQuery.sortBy(this.column, false);
this.sortQuery.sortBy(this.column, false);
}
}

constructor() {
super();
this.ascending = sortQuery.ascending;
this.active_column = sortQuery.active_column;
sortQuery.subscribe((c, a) => {
this.active_column = c;
this.ascending = a;
});
}

render(): TemplateResult {
return html`
<slot></slot>
Expand Down
Loading