Browse Source

Search form.

pull/107/head v1.0
Sebastian Stehle 9 years ago
parent
commit
ea8ac15b30
  1. 2
      src/Squidex.Shared/Identity/SquidexRoles.cs
  2. 1
      src/Squidex/app/features/content/declarations.ts
  3. 6
      src/Squidex/app/features/content/module.ts
  4. 10
      src/Squidex/app/features/content/pages/contents/contents-page.component.html
  5. 28
      src/Squidex/app/features/content/pages/contents/contents-page.component.scss
  6. 3
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  7. 29
      src/Squidex/app/features/content/pages/contents/search-form.component.html
  8. 18
      src/Squidex/app/features/content/pages/contents/search-form.component.scss
  9. 109
      src/Squidex/app/features/content/pages/contents/search-form.component.ts

2
src/Squidex.Shared/Identity/SquidexRoles.cs

@ -10,7 +10,7 @@ namespace Squidex.Shared.Identity
{
public static class SquidexRoles
{
public static readonly string Administrator = "administrator";
public static readonly string Administrator = "ADMINISTRATOR";
public static readonly string AppOwner = "app:owner";

1
src/Squidex/app/features/content/declarations.ts

@ -8,6 +8,7 @@
export * from './pages/content/content-field.component';
export * from './pages/content/content-page.component';
export * from './pages/contents/contents-page.component';
export * from './pages/contents/search-form.component';
export * from './pages/schemas/schemas-page.component';
export * from './shared/assets-editor.component';
export * from './shared/content-item.component';

6
src/Squidex/app/features/content/module.ts

@ -26,7 +26,8 @@ import {
ContentItemComponent,
ContentsPageComponent,
ReferencesEditorComponent,
SchemasPageComponent
SchemasPageComponent,
SearchFormComponent
} from './declarations';
const routes: Routes = [
@ -115,7 +116,8 @@ const routes: Routes = [
ContentPageComponent,
ContentsPageComponent,
ReferencesEditorComponent,
SchemasPageComponent
SchemasPageComponent,
SearchFormComponent
]
})
export class SqxFeatureContentModule { }

10
src/Squidex/app/features/content/pages/contents/contents-page.component.html

@ -13,9 +13,17 @@
<sqx-shortcut keys="ctrl+shift+g" (trigger)="newButton.click()" *ngIf="!isReadOnly"></sqx-shortcut>
<form class="form-inline" (ngSubmit)="search()">
<input class="form-control" #findInput [formControl]="contentsFilter" placeholder="Search for content" />
<input class="form-control form-control-expandable" #findInput [formControl]="contentsFilter" placeholder="Search for content" #searchInput />
<a class="expand-search" (click)="searchModal.toggle()">
<i class="icon-caret-down"></i>
</a>
</form>
<div class="dropdown-menu" *sqxModalView="searchModal" closeAlways="true" [sqxModalTarget]="searchInput" position="right">
<sqx-search-form (queryChanged)="contentsFilter.setValue($event, { emitEvent: false })" [query]="contentsFilter.value"></sqx-search-form>
</div>
<span *ngIf="!isReadOnly && languages.length > 1">
<sqx-language-selector class="languages-buttons" (selectedLanguageChanged)="selectLanguage($event)" [languages]="languages"></sqx-language-selector>
</span>

28
src/Squidex/app/features/content/pages/contents/contents-page.component.scss

@ -1,22 +1,30 @@
@import '_vars';
@import '_mixins';
.languages-buttons {
margin-right: 2rem;
}
.content {
cursor: pointer;
}
.btn-group {
margin-left: 1rem;
}
.icon-plus {
font-size: .8rem;
}
.form-control {
width: 15rem;
}
width: 20rem;
}
.form-inline {
position: relative;
}
.form-control-expandable {
padding-right: 1.5rem;
}
.expand-search {
@include absolute(8px, 8px, auto, auto);
color: $color-border-dark !important;
font-size: .9rem;
font-weight: normal;
cursor: pointer !important;
}

3
src/Squidex/app/features/content/pages/contents/contents-page.component.ts

@ -28,6 +28,7 @@ import {
FieldDto,
ImmutableArray,
MessageBus,
ModalView,
Pager,
SchemaDetailsDto
} from 'shared';
@ -43,6 +44,8 @@ export class ContentsPageComponent extends AppComponentBase implements OnDestroy
public schema: SchemaDetailsDto;
public searchModal = new ModalView();
public contentItems: ImmutableArray<ContentDto>;
public contentFields: FieldDto[];
public contentsFilter = new FormControl();

29
src/Squidex/app/features/content/pages/contents/search-form.component.html

@ -0,0 +1,29 @@
<div [formGroup]="searchForm" class="form-horizontal">
<div class="form-group row">
<label class="col col-2 col-form-label" for="odataSearch">Text</label>
<div class="col col-10">
<input type="input" class="form-control" id="search" (blur)="updateQuery()" formControlName="odataSearch" placeholder="Fulltext search" />
</div>
</div>
<div class="form-group row">
<label class="col col-2 col-form-label" for="filter">Filter</label>
<div class="col col-10">
<input type="input" class="form-control" id="filter" (blur)="updateQuery()" formControlName="odataFilter" placeholder="data/[MY_FIELD]/iv eq 100" />
</div>
</div>
<div class="form-group row">
<label class="col col-2 col-form-label" for="orderBy">Order</label>
<div class="col col-10">
<input type="input" class="form-control" id="orderBy" (blur)="updateQuery()" formControlName="odataOrderBy" placeholder="data/[MY_FIELD]/iv desc" />
</div>
</div>
<div class="link">
Read more about filtering in the <a href="https://docs.squidex.io/04-guides/02-api.html" target="_blank">Documentation</a>.
</div>
</div>

18
src/Squidex/app/features/content/pages/contents/search-form.component.scss

@ -0,0 +1,18 @@
@import '_vars';
@import '_mixins';
.form-horizontal {
padding: 1rem 1.5rem;
min-width: 25rem;
max-width: 25rem;
}
.link {
margin-top: 1.5rem;
font-size: .8rem;
font-weight: normal;
}
.col-form-label {
text-align: left;
}

109
src/Squidex/app/features/content/pages/contents/search-form.component.ts

@ -0,0 +1,109 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'sqx-search-form',
styleUrls: ['./search-form.component.scss'],
templateUrl: './search-form.component.html'
})
export class SearchFormComponent implements OnChanges {
private queryValue = '';
@Input()
public query = '';
@Output()
public queryChanged = new EventEmitter();
public searchForm =
this.formBuilder.group({
odataOrderBy: '',
odataFilter: '',
odataSearch: ''
});
constructor(
private readonly formBuilder: FormBuilder
) {
}
public ngOnChanges() {
if (this.query === this.queryValue) {
return;
}
let odataOrderBy = '';
let odataFilter = '';
let odataSearch = '';
const parts = this.query.split('&');
if (parts.length === 1 && parts[0][0] !== '$') {
odataSearch = parts[0];
} else {
for (let part of parts) {
const kvp = part.split('=');
if (kvp.length === 2) {
const key = kvp[0].toLowerCase();
if (key === '$filter') {
odataFilter = kvp[1];
} else if (key === '$orderby') {
odataOrderBy = kvp[1];
} else if (key === '$search') {
odataSearch = kvp[1];
}
}
}
}
this.searchForm.setValue({
odataFilter,
odataSearch,
odataOrderBy
}, { emitEvent: false });
this.queryValue = this.query;
}
public updateQuery() {
const odataOrderBy = this.searchForm.controls['odataOrderBy'].value;
const odataFilter = this.searchForm.controls['odataFilter'].value;
const odataSearch = this.searchForm.controls['odataSearch'].value;
let query = '';
if (odataSearch && !odataOrderBy && !odataFilter) {
query = odataSearch;
} else {
const parts: string[] = [];
if (odataSearch) {
parts.push(`$search=${odataSearch}`);
}
if (odataFilter) {
parts.push(`$filter=${odataFilter}`);
}
if (odataOrderBy) {
parts.push(`$orderby=${odataOrderBy}`);
}
query = parts.join('&');
}
if (query !== this.query) {
this.queryValue = query;
this.queryChanged.emit(query);
}
}
}
Loading…
Cancel
Save