diff --git a/src/Squidex.Shared/Identity/SquidexRoles.cs b/src/Squidex.Shared/Identity/SquidexRoles.cs
index eb88be6e1..d9815b7c8 100644
--- a/src/Squidex.Shared/Identity/SquidexRoles.cs
+++ b/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";
diff --git a/src/Squidex/app/features/content/declarations.ts b/src/Squidex/app/features/content/declarations.ts
index 9bb9b3c3e..25ee9dac3 100644
--- a/src/Squidex/app/features/content/declarations.ts
+++ b/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';
diff --git a/src/Squidex/app/features/content/module.ts b/src/Squidex/app/features/content/module.ts
index 0b619c2dd..5a605c7ea 100644
--- a/src/Squidex/app/features/content/module.ts
+++ b/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 { }
\ No newline at end of file
diff --git a/src/Squidex/app/features/content/pages/contents/contents-page.component.html b/src/Squidex/app/features/content/pages/contents/contents-page.component.html
index 6111235dd..404cdd0b3 100644
--- a/src/Squidex/app/features/content/pages/contents/contents-page.component.html
+++ b/src/Squidex/app/features/content/pages/contents/contents-page.component.html
@@ -13,9 +13,17 @@
+
+
1">
diff --git a/src/Squidex/app/features/content/pages/contents/contents-page.component.scss b/src/Squidex/app/features/content/pages/contents/contents-page.component.scss
index c1b2bf9f2..f4e81a98e 100644
--- a/src/Squidex/app/features/content/pages/contents/contents-page.component.scss
+++ b/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;
-}
\ No newline at end of file
+ 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;
+}
diff --git a/src/Squidex/app/features/content/pages/contents/contents-page.component.ts b/src/Squidex/app/features/content/pages/contents/contents-page.component.ts
index c53f1c654..998747c61 100644
--- a/src/Squidex/app/features/content/pages/contents/contents-page.component.ts
+++ b/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;
public contentFields: FieldDto[];
public contentsFilter = new FormControl();
diff --git a/src/Squidex/app/features/content/pages/contents/search-form.component.html b/src/Squidex/app/features/content/pages/contents/search-form.component.html
new file mode 100644
index 000000000..8430ffbb9
--- /dev/null
+++ b/src/Squidex/app/features/content/pages/contents/search-form.component.html
@@ -0,0 +1,29 @@
+
\ No newline at end of file
diff --git a/src/Squidex/app/features/content/pages/contents/search-form.component.scss b/src/Squidex/app/features/content/pages/contents/search-form.component.scss
new file mode 100644
index 000000000..a55bc7361
--- /dev/null
+++ b/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;
+}
\ No newline at end of file
diff --git a/src/Squidex/app/features/content/pages/contents/search-form.component.ts b/src/Squidex/app/features/content/pages/contents/search-form.component.ts
new file mode 100644
index 000000000..d891782bd
--- /dev/null
+++ b/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);
+ }
+ }
+}
\ No newline at end of file