mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
34 changed files with 554 additions and 392 deletions
@ -1,38 +1,60 @@ |
|||
<div class="form-horizontal"> |
|||
<div [formGroup]="searchForm"> |
|||
<div class="form-group row"> |
|||
<label class="col col-2 col-form-label" for="odataSearch">Text</label> |
|||
<ng-container *ngIf="enableShortcut"> |
|||
<sqx-shortcut keys="ctrl+shift+f" (trigger)="inputFind.focus()"></sqx-shortcut> |
|||
</ng-container> |
|||
|
|||
<div class="col col-10"> |
|||
<input type="input" class="form-control" id="search" (blur)="updateQuery()" formControlName="odataSearch" placeholder="Fulltext search" /> |
|||
<form class="form-inline search-form" (ngSubmit)="search()"> |
|||
<input class="form-control form-control-expandable" #inputFind [formControl]="contentsFilter" placeholder="Search for content" /> |
|||
|
|||
<a class="expand-search" (click)="searchModal.toggle()" #archive> |
|||
<i class="icon-caret-down"></i> |
|||
</a> |
|||
</form> |
|||
|
|||
<sqx-onboarding-tooltip id="contentArchive" [for]="archive" position="bottomRight" after="60000"> |
|||
Click this icon to show the advanced search menu and to show the archive! |
|||
</sqx-onboarding-tooltip> |
|||
|
|||
<sqx-onboarding-tooltip id="contentFind" [for]="inputFind" position="bottomRight" after="120000"> |
|||
Search for content using full text search over all fields and languages! |
|||
</sqx-onboarding-tooltip> |
|||
|
|||
<div class="dropdown-menu" *sqxModalView="searchModal" [sqxModalTarget]="inputFind"> |
|||
<div class="form-horizontal"> |
|||
<div [formGroup]="searchForm"> |
|||
<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> |
|||
|
|||
<div class="form-group row"> |
|||
<label class="col col-2 col-form-label" for="filter">Filter</label> |
|||
<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 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> |
|||
|
|||
<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 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> |
|||
</div> |
|||
|
|||
<div class="form-check" *ngIf="canArchive"> |
|||
<input class="form-check-input" type="checkbox" id="archivedItems" [ngModel]="archived" (ngModelChange)="archivedChanged.emit($event)" /> |
|||
<label class="form-check-label" for="archivedItems"> |
|||
Archived items |
|||
</label> |
|||
</div> |
|||
|
|||
<div class="form-check" *ngIf="canArchive"> |
|||
<input class="form-check-input" type="checkbox" id="archivedItems" [ngModel]="archived" (ngModelChange)="archivedChanged.emit($event)" /> |
|||
<label class="form-check-label" for="archivedItems"> |
|||
Archived items |
|||
</label> |
|||
</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 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> |
|||
</div> |
|||
@ -0,0 +1,66 @@ |
|||
<sqx-modal-dialog (close)="complete()" large="true" fullHeight="true" contentClass="grid"> |
|||
<ng-container title> |
|||
Select contents |
|||
</ng-container> |
|||
|
|||
<ng-container tabs> |
|||
<div class="text-right"> |
|||
<button class="btn btn-link btn-secondary" (click)="load(true)"> |
|||
<i class="icon-reset"></i> Refresh |
|||
</button> |
|||
|
|||
<sqx-search-form (queryChanged)="search($event)" [canArchive]="false"></sqx-search-form> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<div class="grid-header"> |
|||
<table class="table table-items table-fixed" *ngIf="contentItems"> |
|||
<thead> |
|||
<tr> |
|||
<th class="cell-select"> |
|||
<input type="checkbox" class="form-control" [ngModel]="isAllSelected" (ngModelChange)="selectAll($event)" /> |
|||
</th> |
|||
<th class="cell-auto" *ngFor="let field of schemaFields"> |
|||
<span class="field">{{field.displayName}}</span> |
|||
</th> |
|||
<th class="cell-time"> |
|||
Updated |
|||
</th> |
|||
<th class="cell-user"> |
|||
By |
|||
</th> |
|||
</tr> |
|||
</thead> |
|||
</table> |
|||
</div> |
|||
|
|||
<div class="grid-content"> |
|||
<div sqxIgnoreScrollbar> |
|||
<table class="table table-items table-fixed" *ngIf="contentItems"> |
|||
<tbody> |
|||
<ng-template ngFor let-content [ngForOf]="contentItems" [ngForTrackBy]="trackByContent"> |
|||
<tr [sqxContent]="content" |
|||
[selected]="isItemSelected(content)" |
|||
(selectedChange)="onContentSelected(content)" |
|||
[language]="languageSelected" |
|||
[schemaFields]="schemaFields" |
|||
[schema]="schema" |
|||
isReadOnly="true"></tr> |
|||
<tr class="spacer"></tr> |
|||
</ng-template> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="grid-footer"> |
|||
<sqx-pager [pager]="contentsPager"></sqx-pager> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<button type="reset" class="float-left btn btn-secondary" (click)="complete()">Cancel</button> |
|||
<button type="submit" class="float-right btn btn-success" (click)="select()" [disabled]="selectionCount === 0">Link selected contents ({{selectionCount}})</button> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
@ -0,0 +1,10 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
:host /deep/ .modal-body { |
|||
background: $color-background; |
|||
} |
|||
|
|||
:host /deep/ .modal-tabs { |
|||
background: $color-dark-foreground; |
|||
} |
|||
@ -0,0 +1,145 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; |
|||
|
|||
import { |
|||
AppsState, |
|||
ContentDto, |
|||
ContentsService, |
|||
DialogService, |
|||
FieldDto, |
|||
ImmutableArray, |
|||
ModalView, |
|||
Pager, |
|||
SchemaDetailsDto, |
|||
LanguageDto |
|||
} from '@app/shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-contents-selector', |
|||
styleUrls: ['./contents-selector.component.scss'], |
|||
templateUrl: './contents-selector.component.html' |
|||
}) |
|||
export class ContentsSelectorComponent implements OnInit { |
|||
@Input() |
|||
public language: LanguageDto[]; |
|||
|
|||
@Input() |
|||
public schema: SchemaDetailsDto; |
|||
|
|||
@Input() |
|||
public schemaFields: FieldDto[]; |
|||
|
|||
@Output() |
|||
public selected = new EventEmitter<ContentDto[]>(); |
|||
|
|||
public searchModal = new ModalView(); |
|||
|
|||
public contentItems: ImmutableArray<ContentDto>; |
|||
public contentsQuery = ''; |
|||
public contentsPager = new Pager(0); |
|||
|
|||
public selectedItems: { [id: string]: ContentDto; } = {}; |
|||
public selectionCount = 0; |
|||
|
|||
public isAllSelected = false; |
|||
|
|||
constructor( |
|||
private readonly appsState: AppsState, |
|||
private readonly contentsService: ContentsService, |
|||
private readonly dialogs: DialogService |
|||
) { |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.load(); |
|||
} |
|||
|
|||
public load(showInfo = false) { |
|||
this.contentsService.getContents(this.appsState.appName, this.schema.name, this.contentsPager.pageSize, this.contentsPager.skip, this.contentsQuery, undefined, false) |
|||
.finally(() => { |
|||
this.selectedItems = {}; |
|||
|
|||
this.updateSelectionSummary(); |
|||
}) |
|||
.subscribe(dtos => { |
|||
this.contentItems = ImmutableArray.of(dtos.items); |
|||
this.contentsPager = this.contentsPager.setCount(dtos.total); |
|||
|
|||
if (showInfo) { |
|||
this.dialogs.notifyInfo('Contents reloaded.'); |
|||
} |
|||
}, error => { |
|||
this.dialogs.notifyError(error); |
|||
}); |
|||
} |
|||
|
|||
public search(query: string) { |
|||
this.contentsQuery = query; |
|||
this.contentsPager = new Pager(0); |
|||
|
|||
this.load(); |
|||
} |
|||
|
|||
public goNext() { |
|||
this.contentsPager = this.contentsPager.goNext(); |
|||
|
|||
this.load(); |
|||
} |
|||
|
|||
public goPrev() { |
|||
this.contentsPager = this.contentsPager.goPrev(); |
|||
|
|||
this.load(); |
|||
} |
|||
|
|||
public isItemSelected(content: ContentDto) { |
|||
return this.selectedItems[content.id]; |
|||
} |
|||
|
|||
public complete() { |
|||
this.selected.emit([]); |
|||
} |
|||
|
|||
public select() { |
|||
this.selected.emit(Object.values(this.selectedItems)); |
|||
} |
|||
|
|||
public selectAll(isSelected: boolean) { |
|||
this.selectedItems = {}; |
|||
|
|||
if (isSelected) { |
|||
for (let content of this.contentItems.values) { |
|||
this.selectedItems[content.id] = content; |
|||
} |
|||
} |
|||
|
|||
this.updateSelectionSummary(); |
|||
} |
|||
|
|||
public onContentSelected(content: ContentDto) { |
|||
if (this.selectedItems[content.id]) { |
|||
delete this.selectedItems[content.id]; |
|||
} else { |
|||
this.selectedItems[content.id] = content; |
|||
} |
|||
|
|||
this.updateSelectionSummary(); |
|||
} |
|||
|
|||
private updateSelectionSummary() { |
|||
this.selectionCount = Object.keys(this.selectedItems).length; |
|||
|
|||
this.isAllSelected = this.selectionCount === this.contentItems.length; |
|||
} |
|||
|
|||
public trackByContent(content: ContentDto): string { |
|||
return content.id; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,38 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { allParams } from '@app/framework'; |
|||
|
|||
import { SchemasState } from './../state/schemas.state'; |
|||
|
|||
@Injectable() |
|||
export class SchemaMustExistPublishedGuard implements CanActivate { |
|||
constructor( |
|||
private readonly schemasState: SchemasState, |
|||
private readonly router: Router |
|||
) { |
|||
} |
|||
|
|||
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { |
|||
const schemaName = allParams(route)['schemaName']; |
|||
|
|||
const result = |
|||
this.schemasState.selectSchema(schemaName) |
|||
.do(dto => { |
|||
if (!dto || !dto.isPublished) { |
|||
this.router.navigate(['/404']); |
|||
} |
|||
}) |
|||
.map(s => s !== null && s.isPublished); |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue