Skip to content

Commit

Permalink
feat(hint): display hint about fulltext search (DEV-901) (#734)
Browse files Browse the repository at this point in the history
* docs(data): update documentation

* docs(results): display search syntax hint

* docs(search): display search syntax hint

* feat(hint): new component to display hints

* style: resolve responsive style issues

* feat(search): display fulltext search hint

* style(hint): resolve highlight style

* style(search): resolve responsive design issue
  • Loading branch information
kilchenmann committed May 12, 2022
1 parent 404f1f6 commit f54dafc
Show file tree
Hide file tree
Showing 16 changed files with 198 additions and 34 deletions.
22 changes: 12 additions & 10 deletions docs/user-guide/data.md
Expand Up @@ -35,14 +35,15 @@ Full text search performs queries including one or more terms or phrases, and re

![Filter your full text search by specific project](../assets/images/search-fulltext-filterByProject.png)*<https://admin.dasch.swiss> - Search 1: Full text search*

When clicking on the search bar, the search history panel is displayed. The **10** last searches are registered. It is also possible to clear the search history list (*Clear list* button at the bottom of the panel).
When clicking on the search bar, the search history panel is displayed. The **10** last searches are registered. It is also possible to clear the search history list (*Clear list* button at the bottom of the panel or the *x* at the end of each line).

![Search history panel](../assets/images/search-history.png)*Search history list is accessible for the full text search from any webpage.*

Special syntax:

- asterisk* can be used as a wildcard symbol
- "quotation marks" searches for the whole pattern
- question mark? can be used as wildcard symbol for a single character.
- asterisk* can be used as a wildcard symbol for zero, one or multiple characters.
- "quotation marks" searches for the whole pattern.

---

Expand All @@ -54,6 +55,7 @@ The advanced search allows for the creation of complex queries using a graphical
The widget's contents are then turned into a string representing a Gravsearch (SPARQL) query to be sent to DSP-API.

A query consists of the following elements:

- data model selection
- selection of a resource class belonging to the selected data model (optional)
- specification of properties, comparison operators, and values (optional).
Expand Down Expand Up @@ -106,14 +108,14 @@ This search finds "Jacob" as well as "Jakob".

Used with a linking property, the `matches` operator lets the user search for a linked resource that matches the specified properties.
In this example, the user writes a query looking for all letters that have an author that:

1. was born after January 1st 1650
2. whose family name is "Bernoulli"
1. whose family name is "Bernoulli"

This is different from the "is equal to" operator that lets the user specify a certain person (selected from a list).

![Advanced search panel with a search example](../assets/images/advanced-search-linked-resource.png)


---

### Expert search
Expand Down Expand Up @@ -166,7 +168,7 @@ Each column of the table corresponds to one metadata.
Once you have found the desired sources, you can (re)view them and annotate the source itself, the media file, or single metadata values. If you select more than one source, you can compare them in a side-by-side view, link them, edit them all at once, or save them in a collection. A collection is similar to a playlist in a music app or shopping basket in an online store.

### Display a source
&#9888; *WORK IN PROGRESS*
<!-- &#9888; *WORK IN PROGRESS* -->

The DSP-APP offers different source views for different media types. There's a viewer for still images, moving images, audio and document files. You can open them from the list of search results. Depending on the media type, DSP-APP offers different tools to work on the source.

Expand All @@ -187,17 +189,17 @@ Additionally, you can work on the source directly, e.g, transcribe a moving imag
---

### Select more than one source
&#9888; *NOT YET IMPLEMENTED*
<!-- &#9888; *NOT YET IMPLEMENTED* -->

![Three sources selected; what do you want to do with them?](../assets/images/source-selected-three.png)*Three sources are selected; what do you want to do with them?*

By selecting more than one source, you will be able to edit them all at once, add them to a collection, share or connect them.
By selecting more than one source, you will be able to edit them all at once, add them to a collection, share or connect them.
Or you could compare the sources (see [Compare the sources](/user-guide/data/#compare-the-sources)).

---

### Compare the sources
&#9888; *NOT YET IMPLEMENTED*
<!-- &#9888; *NOT YET IMPLEMENTED* -->

You will be able to compare from two to six source objects at the same time side by side.

Expand All @@ -206,7 +208,7 @@ You will be able to compare from two to six source objects at the same time side
---

### Annotate and connect your data (sources and/or metadata)
&#9888; *NOT YET IMPLEMENTED*
<!-- &#9888; *NOT YET IMPLEMENTED* -->

A main feature of the flexible data storage that DSP-APP uses is the possibility to annotate and link sources and their metadata. An annotation can be a small note about a date like "Not sure about the birthdate of this person. There's another date mentioned in the source XYZ". Inside the note, it will be possible to link to another source.

Expand Down
4 changes: 3 additions & 1 deletion src/app/app.module.ts
Expand Up @@ -159,6 +159,7 @@ import { SearchSelectOntologyComponent } from './workspace/search/advanced-searc
import { ExpertSearchComponent } from './workspace/search/expert-search/expert-search.component';
import { FulltextSearchComponent } from './workspace/search/fulltext-search/fulltext-search.component';
import { SearchPanelComponent } from './workspace/search/search-panel/search-panel.component';
import { HintComponent } from './main/action/hint/hint.component';

// translate: AoT requires an exported function for factories
export function httpLoaderFactory(httpClient: HttpClient) {
Expand Down Expand Up @@ -304,7 +305,8 @@ export function httpLoaderFactory(httpClient: HttpClient) {
UsersComponent,
UsersListComponent,
VideoComponent,
VideoPreviewComponent
VideoPreviewComponent,
HintComponent
],
imports: [
AngularSplitModule.forRoot(),
Expand Down
5 changes: 5 additions & 0 deletions src/app/main/action/hint/hint.component.html
@@ -0,0 +1,5 @@
<div class="hint" [innerHtml]="content"></div>

<a mat-button [href]="documentation" target="_blank" color="primary" class="external-url">
Read more in the user guide<mat-icon class="suffix">launch</mat-icon>
</a>
7 changes: 7 additions & 0 deletions src/app/main/action/hint/hint.component.scss
@@ -0,0 +1,7 @@
a {
margin: 16px auto;

.mat-icon.suffix {
margin-left: 16px;
}
}
31 changes: 31 additions & 0 deletions src/app/main/action/hint/hint.component.spec.ts
@@ -0,0 +1,31 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatIconModule } from '@angular/material/icon';

import { HintComponent } from './hint.component';

describe('HintComponent', () => {
let component: HintComponent;
let fixture: ComponentFixture<HintComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
HintComponent
],
imports: [
MatIconModule
]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(HintComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
52 changes: 52 additions & 0 deletions src/app/main/action/hint/hint.component.ts
@@ -0,0 +1,52 @@
import { Component, Input, OnInit } from '@angular/core';

@Component({
selector: 'app-hint',
templateUrl: './hint.component.html',
styleUrls: ['./hint.component.scss']
})
export class HintComponent implements OnInit {

@Input() topic: string;

content: string;

documentation: string;

constructor() { }

ngOnInit(): void {
this.content = this._getHint(this.topic);
}

/**
* get correct hint depending on the topic
* @param topic
* @returns hint as html
*
* todo: the hint should be written in markdown in different languages. Maybe stored in docs.
*/
private _getHint(topic: string): string {
switch(topic) {
case 'search':
this.documentation = 'https://docs.dasch.swiss/DSP-APP/user-guide/data/#search-and-browse';
return `<p>Use special syntax:</p>
<ul>
<li>question mark<strong>?</strong> can be used as wildcard symbol for a single character.<br>
<code class="">Example: <i>be?r</i> will find <i>beer</i> but also <i>bear</i></code>
</li><br>
<li>asterisk<strong>*</strong> can be used as a wildcard symbol for zero, one or multiple characters.<br>
<code class="">Example: <i>b*r</i> will find <i>beer</i> but also <i>bear</i></code>
</li><br>
<li><strong>"</strong>quotation marks<strong>"</strong> searches for the whole pattern.<br>
<code class="">Example: <i>"Lorem ipsum"</i> will find texts with exact content <i>Lorem ipsum</i></code>
</li>
</ul>`;
break;

default:
return `There's no hint implemented for the topic <strong>${topic}<strong>.`;
}
}

}
2 changes: 1 addition & 1 deletion src/app/main/grid/grid.component.scss
Expand Up @@ -53,7 +53,7 @@
a {
margin: 0 auto;

.mat-icon {
.mat-icon.suffix {
margin-left: 16px;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/app/workspace/results/list-view/list-view.component.html
Expand Up @@ -55,6 +55,8 @@
<li>Try more general keywords.</li>
<li>Try fewer keywords.</li>
</ul>
<mat-divider></mat-divider>
<app-hint [topic]="'search'"></app-hint>
</div>

</div>
Expand Down
4 changes: 0 additions & 4 deletions src/app/workspace/results/list-view/list-view.component.scss
Expand Up @@ -32,10 +32,6 @@ button.active {
background-color: $black-12-opacity;
}

.no-results {
margin: 64px;
}

.link:hover {
background-color: $black-12-opacity;
}
Expand Down
Expand Up @@ -35,7 +35,6 @@

<!-- full-text search menu -->
<ng-template #fulltextSearchMenu>

<div class="app-search-menu" [class.with-project-filter]="projectfilter">
<div class="app-menu-content">
<mat-list class="app-previous-search-list">
Expand Down Expand Up @@ -103,8 +102,7 @@ <h4 mat-line (click)="doPrevSearch(item)" class="app-previous-search-item">
<input #fulltextSearchInputMobile class="app-fulltext-search-input" type="search" [(ngModel)]="searchQuery"
name="fulltext-search" minlength="3" autocomplete="off" [placeholder]="'Search'" (click)="setFocus()"
(keyup.esc)="resetSearch()" (keyup.enter)="doSearch()">
<button mat-button color="primary" class="app-fulltext-search-button"
(click)="doSearch()" type="submit">
<button mat-button color="primary" class="app-fulltext-search-button" (click)="doSearch()" type="submit">
Search
</button>
</div>
Expand Down
32 changes: 24 additions & 8 deletions src/app/workspace/search/search-panel/search-panel.component.html
Expand Up @@ -7,14 +7,26 @@
</app-fulltext-search>

<!-- Do not display advanced and expert search on mobile devices smaller than tablet -->
<div class="advanced-expert-buttons">
<div class="advanced-expert-buttons" [class.with-project-filter]="projectfilter">
<button mat-flat-button class="hint" [class.active]="showHint"
(click)="openPanelWithBackdrop('hint')">
<mat-icon matPrefix>lightbulb</mat-icon>
<span class="desktop-only">How to search</span>
</button>
<span class="fill-remaining-space"></span>
<!-- advanced search button: if advanced === true -->
<button mat-flat-button *ngIf="advanced" [class.active]="showAdvanced"
(click)="openPanelWithBackdrop('advanced')">advanced</button>
(click)="openPanelWithBackdrop('advanced')">
<mat-icon matPrefix>manage_search</mat-icon>
<span class="desktop-only">advanced</span>
</button>

<!-- expert search button: if expert === true -->
<button mat-flat-button *ngIf="expert" [class.active]="showExpert"
(click)="openPanelWithBackdrop('expert')">expert</button>
(click)="openPanelWithBackdrop('expert')">
<mat-icon matPrefix>school</mat-icon>
<span class="desktop-only">expert</span>
</button>
</div>

</div>
Expand All @@ -24,8 +36,11 @@
<div class="app-search-menu with-advanced-search" [class.with-project-filter]="projectfilter">
<div class="app-menu-header">
<span class="app-menu-title">
<h4 *ngIf="showAdvanced">Advanced search</h4>
<h4 *ngIf="!showAdvanced">Expert search</h4>
<h4 [ngSwitch]="true">
<span *ngSwitchCase="showAdvanced">Advanced search</span>
<span *ngSwitchCase="showExpert">Expert search</span>
<span *ngSwitchCase="showHint">How to search</span>
</h4>
</span>
<span class="fill-remaining-space"></span>
<span class="app-menu-close">
Expand All @@ -34,9 +49,10 @@ <h4 *ngIf="!showAdvanced">Expert search</h4>
</button>
</span>
</div>
<div class="app-menu-content">
<app-advanced-search *ngIf="showAdvanced" [limitToProject]="limitToProject" (search)="emitSearch($event)"></app-advanced-search>
<app-expert-search *ngIf="!showAdvanced" (search)="emitSearch($event)"></app-expert-search>
<div class="app-menu-content" [ngSwitch]="true">
<app-advanced-search *ngSwitchCase="showAdvanced" [limitToProject]="limitToProject" (search)="emitSearch($event)"></app-advanced-search>
<app-expert-search *ngSwitchCase="showExpert" (search)="emitSearch($event)"></app-expert-search>
<app-hint *ngSwitchCase="showHint" [topic]="'search'"></app-hint>
</div>
</div>
</ng-template>
20 changes: 18 additions & 2 deletions src/app/workspace/search/search-panel/search-panel.component.scss
Expand Up @@ -5,8 +5,8 @@
height: 72px;

.advanced-expert-buttons {
display: table;
height: 20px;
display: flex;
height: 24px;
margin-left: auto;

button {
Expand All @@ -18,10 +18,26 @@
border-top-right-radius: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
padding-top: 4px;

&.active {
background-color: $black-12-opacity;
}

&.hint {
color: $accent_200;

&.active {
color: $dark;
}
}

.mat-icon {
margin-top: -2px;
font-size: 18px;
width: 18px;
height: 18px;
}
}
}

Expand Down
Expand Up @@ -61,6 +61,7 @@ export class SearchPanelComponent implements OnInit {
// show advanced or expert search
showAdvanced: boolean;
showExpert: boolean;
showHint: boolean;

constructor(
private _overlay: Overlay,
Expand All @@ -75,6 +76,7 @@ export class SearchPanelComponent implements OnInit {

this.showAdvanced = (type === 'advanced');
this.showExpert = (type === 'expert');
this.showHint = (type === 'hint');

const config = new OverlayConfig({
hasBackdrop: true,
Expand All @@ -88,6 +90,7 @@ export class SearchPanelComponent implements OnInit {
this.overlayRef.backdropClick().subscribe(() => {
this.showAdvanced = false;
this.showExpert = false;
this.showHint = false;
this.overlayRef.detach();
});
}
Expand Down Expand Up @@ -124,6 +127,7 @@ export class SearchPanelComponent implements OnInit {
closeMenu(): void {
this.showAdvanced = false;
this.showExpert = false;
this.showHint = false;
if (this.overlayRef) {
this.overlayRef.detach();
}
Expand Down
6 changes: 4 additions & 2 deletions src/assets/style/_elements.scss
Expand Up @@ -396,8 +396,10 @@ a,
}

.no-results {
margin: 64px auto;
width: 400px;
margin: 64px;
min-width: 400px;
max-width: calc(70vw - 128px);
line-height: 1.5;
}

// --------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/assets/style/_responsive.scss
Expand Up @@ -43,7 +43,7 @@ $grid-breakpoints: (
}
.advanced-expert-buttons {
font-size: smaller !important;
margin-top: -6px !important;
margin-top: -2px !important;
}
}

Expand Down

0 comments on commit f54dafc

Please sign in to comment.