Browse Source

Progress with comparison

pull/345/head
Sebastian Stehle 7 years ago
parent
commit
72895f897a
  1. 2
      src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts
  2. 4
      src/Squidex/app/features/content/pages/content/content-field.component.html
  3. 41
      src/Squidex/app/features/content/pages/content/content-field.component.ts
  4. 2
      src/Squidex/app/features/content/pages/content/content-history-page.component.html
  5. 6
      src/Squidex/app/features/content/pages/content/content-history-page.component.ts
  6. 4
      src/Squidex/app/features/content/pages/content/content-page.component.html
  7. 25
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  8. 10
      src/Squidex/app/features/content/pages/content/field-languages.component.ts
  9. 2
      src/Squidex/app/features/content/pages/contents/contents-page.component.html
  10. 2
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  11. 3
      src/Squidex/app/features/content/pages/messages.ts
  12. 3
      src/Squidex/app/features/content/shared/array-editor.component.ts
  13. 3
      src/Squidex/app/features/content/shared/array-item.component.ts
  14. 10
      src/Squidex/app/features/content/shared/assets-editor.component.html
  15. 3
      src/Squidex/app/features/content/shared/assets-editor.component.scss
  16. 9
      src/Squidex/app/features/content/shared/assets-editor.component.ts
  17. 10
      src/Squidex/app/features/content/shared/content-item.component.html
  18. 3
      src/Squidex/app/features/content/shared/content-item.component.ts
  19. 2
      src/Squidex/app/features/content/shared/contents-selector.component.html
  20. 2
      src/Squidex/app/features/content/shared/contents-selector.component.ts
  21. 7
      src/Squidex/app/features/content/shared/field-editor.component.html
  22. 8
      src/Squidex/app/features/content/shared/field-editor.component.ts
  23. 3
      src/Squidex/app/features/content/shared/references-editor.component.html
  24. 5
      src/Squidex/app/features/content/shared/references-editor.component.ts
  25. 2
      src/Squidex/app/features/settings/pages/backups/backups-page.component.ts
  26. 2
      src/Squidex/app/framework/angular/forms/autocomplete.component.ts
  27. 10
      src/Squidex/app/framework/angular/forms/control-errors.component.ts
  28. 4
      src/Squidex/app/framework/angular/forms/date-time-editor.component.ts
  29. 2
      src/Squidex/app/framework/angular/forms/iframe-editor.component.ts
  30. 2
      src/Squidex/app/framework/angular/forms/tag-editor.component.ts
  31. 10
      src/Squidex/app/framework/angular/modals/dialog-renderer.component.ts
  32. 6
      src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts
  33. 4
      src/Squidex/app/framework/angular/modals/tooltip.component.ts
  34. 12
      src/Squidex/app/framework/angular/sorted.directive.ts
  35. 4
      src/Squidex/app/framework/angular/stateful.component.ts
  36. 66
      src/Squidex/app/shared/components/asset.component.html
  37. 36
      src/Squidex/app/shared/components/asset.component.scss
  38. 5
      src/Squidex/app/shared/components/asset.component.ts
  39. 2
      src/Squidex/app/shared/components/comments.component.ts
  40. 2
      src/Squidex/app/shell/pages/internal/profile-menu.component.ts

2
src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts

@ -51,7 +51,7 @@ export class EventConsumersPageComponent extends ResourceOwner implements OnInit
this.eventConsumersState.reset(es).pipe(onErrorResumeNext()).subscribe(); this.eventConsumersState.reset(es).pipe(onErrorResumeNext()).subscribe();
} }
public trackByEventConsumer(es: EventConsumerDto) { public trackByEventConsumer(index: number, es: EventConsumerDto) {
return es.name; return es.name;
} }

4
src/Squidex/app/features/content/pages/content/content-field.component.html

@ -20,6 +20,7 @@
[field]="field" [field]="field"
[language]="language" [language]="language"
[languages]="languages" [languages]="languages"
[isCompact]="!!fieldFormCompare"
[control]="fieldForm.controls[language.iso2Code]"> [control]="fieldForm.controls[language.iso2Code]">
</sqx-field-editor> </sqx-field-editor>
</div> </div>
@ -31,6 +32,7 @@
[field]="field" [field]="field"
[language]="language" [language]="language"
[languages]="languages" [languages]="languages"
[isCompact]="!!fieldFormCompare"
[control]="selectedFormControl"> [control]="selectedFormControl">
</sqx-field-editor> </sqx-field-editor>
</ng-template> </ng-template>
@ -61,6 +63,7 @@
[field]="field" [field]="field"
[language]="language" [language]="language"
[languages]="languages" [languages]="languages"
[isCompact]="true"
[control]="fieldFormCompare?.controls[language.iso2Code]"> [control]="fieldFormCompare?.controls[language.iso2Code]">
</sqx-field-editor> </sqx-field-editor>
</div> </div>
@ -71,6 +74,7 @@
[field]="field" [field]="field"
[language]="language" [language]="language"
[languages]="languages" [languages]="languages"
[isCompact]="true"
[control]="selectedFormControlCompare"> [control]="selectedFormControlCompare">
</sqx-field-editor> </sqx-field-editor>
</ng-template> </ng-template>

41
src/Squidex/app/features/content/pages/content/content-field.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { Component, DoCheck, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms'; import { AbstractControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators'; import { map, startWith } from 'rxjs/operators';
@ -14,7 +14,6 @@ import {
AppLanguageDto, AppLanguageDto,
EditContentForm, EditContentForm,
fieldInvariant, fieldInvariant,
ImmutableArray,
LocalStoreService, LocalStoreService,
RootFieldDto, RootFieldDto,
SchemaDto, SchemaDto,
@ -26,7 +25,7 @@ import {
styleUrls: ['./content-field.component.scss'], styleUrls: ['./content-field.component.scss'],
templateUrl: './content-field.component.html' templateUrl: './content-field.component.html'
}) })
export class ContentFieldComponent implements DoCheck, OnChanges { export class ContentFieldComponent implements OnChanges {
@Input() @Input()
public form: EditContentForm; public form: EditContentForm;
@ -46,7 +45,7 @@ export class ContentFieldComponent implements DoCheck, OnChanges {
public language: AppLanguageDto; public language: AppLanguageDto;
@Input() @Input()
public languages: ImmutableArray<AppLanguageDto>; public languages: AppLanguageDto[];
@Output() @Output()
public languageChange = new EventEmitter<AppLanguageDto>(); public languageChange = new EventEmitter<AppLanguageDto>();
@ -71,25 +70,7 @@ export class ContentFieldComponent implements DoCheck, OnChanges {
if (changes['field']) { if (changes['field']) {
this.showAllControls = this.localStore.getBoolean(this.configKey()); this.showAllControls = this.localStore.getBoolean(this.configKey());
} }
}
public changeShowAllControls(value: boolean) {
this.showAllControls = value;
this.localStore.setBoolean(this.configKey(), this.showAllControls);
}
public copy() {
if (this.selectedFormControlCompare && this.fieldFormCompare) {
if (this.showAllControls) {
this.fieldForm.setValue(this.fieldFormCompare.value);
} else {
this.selectedFormControl.setValue(this.selectedFormControlCompare.value);
}
}
}
public ngDoCheck() {
const control = this.findControl(this.fieldForm); const control = this.findControl(this.fieldForm);
if (this.selectedFormControl !== control) { if (this.selectedFormControl !== control) {
@ -113,6 +94,22 @@ export class ContentFieldComponent implements DoCheck, OnChanges {
} }
} }
public changeShowAllControls(value: boolean) {
this.showAllControls = value;
this.localStore.setBoolean(this.configKey(), this.showAllControls);
}
public copy() {
if (this.selectedFormControlCompare && this.fieldFormCompare) {
if (this.showAllControls) {
this.fieldForm.setValue(this.fieldFormCompare.value);
} else {
this.selectedFormControl.setValue(this.selectedFormControlCompare.value);
}
}
}
private findControl(form: FormGroup) { private findControl(form: FormGroup) {
if (this.field.isLocalizable) { if (this.field.isLocalizable) {
return form.controls[this.language.iso2Code]; return form.controls[this.language.iso2Code];

2
src/Squidex/app/features/content/pages/content/content-history-page.component.html

@ -15,7 +15,7 @@
</div> </div>
<div class="event-created">{{event.created | sqxFromNow}}</div> <div class="event-created">{{event.created | sqxFromNow}}</div>
<a class="event-load force" (click)="loadVersion(event.version)">Load this Version</a> <a class="event-load force" (click)="loadVersion(event.version)">Load</a> &middot; <a class="event-load force" (click)="compareVersion(event.version)">Compare</a>
</div> </div>
</div> </div>
</ng-container> </ng-container>

6
src/Squidex/app/features/content/pages/content/content-history-page.component.ts

@ -62,7 +62,11 @@ export class ContentHistoryPageComponent {
} }
public loadVersion(version: number) { public loadVersion(version: number) {
this.messageBus.emit(new ContentVersionSelected(new Version(version.toString()))); this.messageBus.emit(new ContentVersionSelected(new Version(version.toString()), false));
}
public compareVersion(version: number) {
this.messageBus.emit(new ContentVersionSelected(new Version(version.toString()), true));
} }
public trackByEvent(index: number, event: HistoryEventDto) { public trackByEvent(index: number, event: HistoryEventDto) {

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

@ -1,7 +1,7 @@
<sqx-title message="{app} | {schema} | Content" parameter1="app" parameter2="schema" [value1]="appsState.appName" [value2]="schema.displayName"></sqx-title> <sqx-title message="{app} | {schema} | Content" parameter1="app" parameter2="schema" [value1]="appsState.appName" [value2]="schema.displayName"></sqx-title>
<form [formGroup]="contentForm.form" (ngSubmit)="saveAndPublish()"> <form [formGroup]="contentForm.form" (ngSubmit)="saveAndPublish()">
<sqx-panel desiredWidth="*" minWidth="40rem" [showSidebar]="content"> <sqx-panel desiredWidth="*" minWidth="60rem" [showSidebar]="content">
<ng-container title> <ng-container title>
<a class="btn btn-text" (click)="back()" *ngIf="!schema.isSingleton"> <a class="btn btn-text" (click)="back()" *ngIf="!schema.isSingleton">
<i class="icon-angle-left"></i> <i class="icon-angle-left"></i>
@ -118,7 +118,7 @@
[fieldForm]="contentForm.form.get(field.name)" [fieldForm]="contentForm.form.get(field.name)"
[fieldFormCompare]="contentFormCompare?.form.get(field.name)" [fieldFormCompare]="contentFormCompare?.form.get(field.name)"
[schema]="schema" [schema]="schema"
[languages]="languages" [languages]="languages.mutableValues"
[(language)]="language"> [(language)]="language">
</sqx-content-field> </sqx-content-field>
</div> </div>

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

@ -101,7 +101,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
this.own( this.own(
this.messageBus.of(ContentVersionSelected) this.messageBus.of(ContentVersionSelected)
.subscribe(message => { .subscribe(message => {
this.loadVersion(message.version); this.loadVersion(message.version, message.compare);
})); }));
} }
@ -209,25 +209,36 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
.subscribe(); .subscribe();
} }
private loadVersion(version: Version | null) { private loadVersion(version: Version | null, compare: boolean) {
if (!this.content || version === null || version.eq(this.content.version)) { if (!this.content || version === null || version.eq(this.content.version)) {
this.contentFormCompare = null; this.contentFormCompare = null;
this.contentVersion = null; this.contentVersion = null;
this.contentForm.load(this.content.dataDraft);
} else { } else {
this.contentsState.loadVersion(this.content, version) this.contentsState.loadVersion(this.content, version)
.subscribe(dto => { .subscribe(dto => {
if (this.contentFormCompare === null) { if (compare) {
this.contentFormCompare = new EditContentForm(this.schema, this.languages); if (this.contentFormCompare === null) {
this.contentFormCompare.form.disable(); this.contentFormCompare = new EditContentForm(this.schema, this.languages);
this.contentFormCompare.form.disable();
}
this.contentFormCompare.load(dto.payload);
this.contentForm.load(this.content.dataDraft);
} else {
if (this.contentFormCompare) {
this.contentFormCompare = null;
}
this.contentForm.load(dto.payload);
} }
this.contentFormCompare.load(dto.payload);
this.contentVersion = version; this.contentVersion = version;
}); });
} }
} }
public showLatest() { public showLatest() {
this.loadVersion(null); this.loadVersion(null, false);
} }
} }

10
src/Squidex/app/features/content/pages/content/field-languages.component.ts

@ -7,11 +7,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { import { AppLanguageDto, RootFieldDto } from '@app/shared';
AppLanguageDto,
ImmutableArray,
RootFieldDto
} from '@app/shared';
@Component({ @Component({
selector: 'sqx-field-languages', selector: 'sqx-field-languages',
@ -25,7 +21,7 @@ import {
<sqx-language-selector size="sm" #buttonLanguages <sqx-language-selector size="sm" #buttonLanguages
[selectedLanguage]="language" [selectedLanguage]="language"
(selectedLanguageChange)="languageChange.emit($event)" (selectedLanguageChange)="languageChange.emit($event)"
[languages]="languages.values"> [languages]="languages">
</sqx-language-selector> </sqx-language-selector>
<sqx-onboarding-tooltip helpId="languages" [for]="buttonLanguages" position="topRight" after="120000"> <sqx-onboarding-tooltip helpId="languages" [for]="buttonLanguages" position="topRight" after="120000">
@ -45,7 +41,7 @@ export class FieldLanguagesComponent {
public language: AppLanguageDto; public language: AppLanguageDto;
@Input() @Input()
public languages: ImmutableArray<AppLanguageDto>; public languages: AppLanguageDto[];
@Output() @Output()
public languageChange = new EventEmitter<AppLanguageDto>(); public languageChange = new EventEmitter<AppLanguageDto>();

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

@ -33,7 +33,7 @@
</sqx-search-form> </sqx-search-form>
</div> </div>
<div class="col-auto pl-1" *ngIf="languages.length > 1"> <div class="col-auto pl-1" *ngIf="languages.length > 1">
<sqx-language-selector class="languages-buttons" (selectedLanguageChange)="selectLanguage($event)" [languages]="languages.values"></sqx-language-selector> <sqx-language-selector class="languages-buttons" (selectedLanguageChange)="selectLanguage($event)" [languages]="languages.mutableValues"></sqx-language-selector>
</div> </div>
<div class="col-auto pl-1"> <div class="col-auto pl-1">
<button class="btn btn-success" #newButton routerLink="new" title="New Content (CTRL + SHIFT + G)"> <button class="btn btn-success" #newButton routerLink="new" title="New Content (CTRL + SHIFT + G)">

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

@ -200,7 +200,7 @@ export class ContentsPageComponent extends ResourceOwner implements OnInit {
this.updateSelectionSummary(); this.updateSelectionSummary();
} }
public trackByContent(content: ContentDto): string { public trackByContent(index: number, content: ContentDto): string {
return content.id; return content.id;
} }

3
src/Squidex/app/features/content/pages/messages.ts

@ -9,7 +9,8 @@ import { Version } from '@app/shared';
export class ContentVersionSelected { export class ContentVersionSelected {
constructor( constructor(
public readonly version: Version public readonly version: Version,
public readonly compare: boolean
) { ) {
} }
} }

3
src/Squidex/app/features/content/shared/array-editor.component.ts

@ -11,7 +11,6 @@ import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
import { import {
AppLanguageDto, AppLanguageDto,
EditContentForm, EditContentForm,
ImmutableArray,
RootFieldDto, RootFieldDto,
StatefulComponent StatefulComponent
} from '@app/shared'; } from '@app/shared';
@ -37,7 +36,7 @@ export class ArrayEditorComponent extends StatefulComponent<State> {
public language: AppLanguageDto; public language: AppLanguageDto;
@Input() @Input()
public languages: ImmutableArray<AppLanguageDto>; public languages: AppLanguageDto[];
@Input() @Input()
public arrayControl: FormArray; public arrayControl: FormArray;

3
src/Squidex/app/features/content/shared/array-item.component.ts

@ -14,7 +14,6 @@ import {
AppLanguageDto, AppLanguageDto,
EditContentForm, EditContentForm,
FieldDto, FieldDto,
ImmutableArray,
RootFieldDto RootFieldDto
} from '@app/shared'; } from '@app/shared';
@ -62,7 +61,7 @@ export class ArrayItemComponent implements OnChanges {
public language: AppLanguageDto; public language: AppLanguageDto;
@Input() @Input()
public languages: ImmutableArray<AppLanguageDto>; public languages: AppLanguageDto[];
public isInvalid: Observable<boolean>; public isInvalid: Observable<boolean>;

10
src/Squidex/app/features/content/shared/assets-editor.component.html

@ -4,7 +4,7 @@
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
<div class="drop-area align-items-center" (click)="assetsDialog.show()" (sqxFileDrop)="addFiles($event)"> <div class="drop-area align-items-center" (click)="assetsDialog.show()" (sqxFileDrop)="addFiles($event)">
Drop files or click here to add assets. Drop files or click
</div> </div>
</div> </div>
<div class="col-auto pl-1"> <div class="col-auto pl-1">
@ -26,7 +26,7 @@
<sqx-asset *ngFor="let file of snapshot.assetFiles" [initFile]="file" <sqx-asset *ngFor="let file of snapshot.assetFiles" [initFile]="file"
(failed)="removeLoadingAsset(file)" (loaded)="addAsset(file, $event)"> (failed)="removeLoadingAsset(file)" (loaded)="addAsset(file, $event)">
</sqx-asset> </sqx-asset>
<sqx-asset *ngFor="let asset of snapshot.assets; trackBy: trackByAsset" [asset]="asset" removeMode="true" <sqx-asset *ngFor="let asset of snapshot.assets; trackBy: trackByAsset" [asset]="asset" [isCompact]="isCompact" removeMode="true"
(updated)="notifyOthers($event)" (removing)="removeLoadedAsset($event)"> (updated)="notifyOthers($event)" (removing)="removeLoadedAsset($event)">
</sqx-asset> </sqx-asset>
</div> </div>
@ -39,10 +39,12 @@
</sqx-asset> </sqx-asset>
<div <div
[sqxSortModel]="snapshot.assets.values" [sqxSortModel]="snapshot.assets.mutableValues"
(sqxSorted)="sortAssets($event)"> (sqxSorted)="sortAssets($event)">
<div *ngFor="let asset of snapshot.assets; trackBy: trackByAsset"> <div *ngFor="let asset of snapshot.assets; trackBy: trackByAsset">
<sqx-asset [asset]="asset" removeMode="true" [isListView]="true" <sqx-asset [asset]="asset" removeMode="true"
[isListView]="true"
[isCompact]="isCompact"
(updated)="notifyOthers($event)" (removing)="removeLoadedAsset($event)"> (updated)="notifyOthers($event)" (removing)="removeLoadedAsset($event)">
</sqx-asset> </sqx-asset>
</div> </div>

3
src/Squidex/app/features/content/shared/assets-editor.component.scss

@ -46,9 +46,10 @@
@include border-radius; @include border-radius;
@include truncate-nowidth; @include truncate-nowidth;
border: 2px dashed darken($color-border, 10%); border: 2px dashed darken($color-border, 10%);
padding: 5px .5rem;
font-weight: normal; font-weight: normal;
font-size: 1rem;
text-align: center; text-align: center;
padding: 5px 2rem;
color: darken($color-border, 30%); color: darken($color-border, 30%);
cursor: pointer; cursor: pointer;
} }

9
src/Squidex/app/features/content/shared/assets-editor.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { import {
@ -50,6 +50,9 @@ interface State {
export class AssetsEditorComponent extends StatefulControlComponent<State, string[]> implements OnInit { export class AssetsEditorComponent extends StatefulControlComponent<State, string[]> implements OnInit {
public assetsDialog = new DialogModel(); public assetsDialog = new DialogModel();
@Input()
public isCompact = false;
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly assetsService: AssetsService, private readonly assetsService: AssetsService,
@ -89,7 +92,7 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, strin
} }
public ngOnInit() { public ngOnInit() {
this.takeOver( this.own(
this.messageBus.of(AssetUpdated) this.messageBus.of(AssetUpdated)
.subscribe(event => { .subscribe(event => {
if (event.source !== this) { if (event.source !== this) {
@ -167,7 +170,7 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, strin
this.callChange(ids); this.callChange(ids);
} }
public trackByAsset(asset: AssetDto) { public trackByAsset(index: number, asset: AssetDto) {
return asset.id; return asset.id;
} }
} }

10
src/Squidex/app/features/content/shared/content-item.component.html

@ -59,7 +59,7 @@
{{values[i]}} {{values[i]}}
</div> </div>
</td> </td>
<td class="cell-time" (click)="shouldStop($event)"> <td class="cell-time" *ngIf="!isCompact" (click)="shouldStop($event)">
<sqx-content-status <sqx-content-status
[status]="content.status" [status]="content.status"
[scheduledTo]="content.scheduleJob?.status" [scheduledTo]="content.scheduleJob?.status"
@ -70,6 +70,10 @@
<small class="item-modified">{{content.lastModified | sqxFromNow}}</small> <small class="item-modified">{{content.lastModified | sqxFromNow}}</small>
</td> </td>
<td class="cell-user" *ngIf="!isCompact && patchForm.form.pristine" (click)="shouldStop($event)">
<img class="user-picture" [attr.title]="content.lastModifiedBy | sqxUserNameRef" [attr.src]="content.lastModifiedBy | sqxUserPictureRef" />
</td>
<td class="cell-user" *ngIf="patchForm.form.dirty" (click)="shouldStop($event)"> <td class="cell-user" *ngIf="patchForm.form.dirty" (click)="shouldStop($event)">
<button type="button" class="btn btn-success" (click)="save(); $event.stopPropagation()"> <button type="button" class="btn btn-success" (click)="save(); $event.stopPropagation()">
<i class="icon-checkmark"></i> <i class="icon-checkmark"></i>
@ -81,10 +85,6 @@
</button> </button>
</td> </td>
<td class="cell-user" *ngIf="patchForm.form.pristine" (click)="shouldStop($event)">
<img class="user-picture" [attr.title]="content.lastModifiedBy | sqxUserNameRef" [attr.src]="content.lastModifiedBy | sqxUserPictureRef" />
</td>
<td class="cell-actions" *ngIf="!isReadOnly && patchForm.form.pristine" (click)="shouldStop($event)"> <td class="cell-actions" *ngIf="!isReadOnly && patchForm.form.pristine" (click)="shouldStop($event)">
<div class="dropdown dropdown-options" *ngIf="content"> <div class="dropdown dropdown-options" *ngIf="content">
<button type="button" class="btn btn-text-secondary" (click)="dropdown.toggle(); $event.stopPropagation()" [class.active]="dropdown.isOpen | async" #optionsButton> <button type="button" class="btn btn-text-secondary" (click)="dropdown.toggle(); $event.stopPropagation()" [class.active]="dropdown.isOpen | async" #optionsButton>

3
src/Squidex/app/features/content/shared/content-item.component.ts

@ -69,6 +69,9 @@ export class ContentItemComponent implements OnChanges {
@Input() @Input()
public isReference = false; public isReference = false;
@Input()
public isCompact = false;
@Input('sqxContent') @Input('sqxContent')
public content: ContentDto; public content: ContentDto;

2
src/Squidex/app/features/content/shared/contents-selector.component.html

@ -19,7 +19,7 @@
</div> </div>
<div class="col pl-1" *ngIf="languages.length > 1"> <div class="col pl-1" *ngIf="languages.length > 1">
<sqx-language-selector class="languages-buttons" (selectedLanguageChange)="selectLanguage($event)" [languages]="languages.values"></sqx-language-selector> <sqx-language-selector class="languages-buttons" (selectedLanguageChange)="selectLanguage($event)" [languages]="languages"></sqx-language-selector>
</div> </div>
</div> </div>
</ng-container> </ng-container>

2
src/Squidex/app/features/content/shared/contents-selector.component.ts

@ -115,7 +115,7 @@ export class ContentsSelectorComponent implements OnInit {
this.isAllSelected = this.selectionCount === this.contentsState.snapshot.contents.length; this.isAllSelected = this.selectionCount === this.contentsState.snapshot.contents.length;
} }
public trackByContent(content: ContentDto): string { public trackByContent(index: number, content: ContentDto): string {
return content.id; return content.id;
} }
} }

7
src/Squidex/app/features/content/shared/field-editor.component.html

@ -101,7 +101,7 @@
<sqx-json-editor [formControl]="control"></sqx-json-editor> <sqx-json-editor [formControl]="control"></sqx-json-editor>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'Assets'"> <ng-container *ngSwitchCase="'Assets'">
<sqx-assets-editor [formControl]="control"></sqx-assets-editor> <sqx-assets-editor [formControl]="control" [isCompact]="isCompact"></sqx-assets-editor>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'Tags'"> <ng-container *ngSwitchCase="'Tags'">
<ng-container [ngSwitch]="field.properties['editor']"> <ng-container [ngSwitch]="field.properties['editor']">
@ -122,7 +122,7 @@
<sqx-array-editor <sqx-array-editor
[arrayControl]="control" [arrayControl]="control"
[form]="form" [form]="form"
[field]="field" [field]="field"
[language]="language" [language]="language"
[languages]="languages"> [languages]="languages">
</sqx-array-editor> </sqx-array-editor>
@ -132,7 +132,8 @@
[formControl]="control" [formControl]="control"
[language]="language" [language]="language"
[languages]="languages" [languages]="languages"
[schemaId]="field.properties['schemaId']"> [schemaId]="field.properties['schemaId']"
[isCompact]="isCompact">
</sqx-references-editor> </sqx-references-editor>
</ng-container> </ng-container>
</ng-container> </ng-container>

8
src/Squidex/app/features/content/shared/field-editor.component.ts

@ -11,8 +11,7 @@ import { FormControl } from '@angular/forms';
import { import {
AppLanguageDto, AppLanguageDto,
EditContentForm, EditContentForm,
FieldDto, FieldDto
ImmutableArray
} from '@app/shared'; } from '@app/shared';
@Component({ @Component({
@ -34,7 +33,10 @@ export class FieldEditorComponent {
public language: AppLanguageDto; public language: AppLanguageDto;
@Input() @Input()
public languages: ImmutableArray<AppLanguageDto>; public languages: AppLanguageDto[];
@Input()
public isCompact = false;
@Input() @Input()
public displaySuffix: string; public displaySuffix: string;

3
src/Squidex/app/features/content/shared/references-editor.component.html

@ -7,13 +7,14 @@
</div> </div>
<table class="table table-items table-fixed" [class.disabled]="snapshot.isDisabled" *ngIf="snapshot.schema && snapshot.contentItems && snapshot.contentItems.length > 0" <table class="table table-items table-fixed" [class.disabled]="snapshot.isDisabled" *ngIf="snapshot.schema && snapshot.contentItems && snapshot.contentItems.length > 0"
[sqxSortModel]="snapshot.contentItems.values" [sqxSortModel]="snapshot.contentItems.mutableValues"
(sqxSorted)="sort($event)"> (sqxSorted)="sort($event)">
<tbody *ngFor="let content of snapshot.contentItems"> <tbody *ngFor="let content of snapshot.contentItems">
<tr [sqxContent]="content" <tr [sqxContent]="content"
[language]="language" [language]="language"
[isReadOnly]="true" [isReadOnly]="true"
[isReference]="true" [isReference]="true"
[isCompact]="isCompact"
[schema]="snapshot.schema" [schema]="snapshot.schema"
(deleting)="remove(content)"></tr> (deleting)="remove(content)"></tr>
<tr class="spacer"></tr> <tr class="spacer"></tr>

5
src/Squidex/app/features/content/shared/references-editor.component.ts

@ -48,7 +48,10 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, s
public language: AppLanguageDto; public language: AppLanguageDto;
@Input() @Input()
public languages: ImmutableArray<AppLanguageDto>; public languages: AppLanguageDto[];
@Input()
public isCompact = false;
public selectorDialog = new DialogModel(); public selectorDialog = new DialogModel();

2
src/Squidex/app/features/settings/pages/backups/backups-page.component.ts

@ -49,7 +49,7 @@ export class BackupsPageComponent extends ResourceOwner implements OnInit {
this.backupsState.delete(backup).pipe(onErrorResumeNext()).subscribe(); this.backupsState.delete(backup).pipe(onErrorResumeNext()).subscribe();
} }
public trackByBackup(item: BackupDto) { public trackByBackup(index: number, item: BackupDto) {
return item.id; return item.id;
} }
} }

2
src/Squidex/app/framework/angular/forms/autocomplete.component.ts

@ -66,7 +66,7 @@ export class AutocompleteComponent extends StatefulControlComponent<State, any[]
} }
public ngOnInit() { public ngOnInit() {
this.takeOver( this.own(
this.queryInput.valueChanges.pipe( this.queryInput.valueChanges.pipe(
tap(query => { tap(query => {
this.callChange(query); this.callChange(query);

10
src/Squidex/app/framework/angular/forms/control-errors.component.ts

@ -91,7 +91,7 @@ export class ControlErrorsComponent extends StatefulComponent<State> implements
this.control = control; this.control = control;
if (control) { if (control) {
this.takeOver( this.own(
merge(control.valueChanges, control.statusChanges) merge(control.valueChanges, control.statusChanges)
.subscribe(() => { .subscribe(() => {
this.createMessages(); this.createMessages();
@ -113,7 +113,7 @@ export class ControlErrorsComponent extends StatefulComponent<State> implements
} }
private createMessages() { private createMessages() {
const errorMessages: string[] = []; const errors: string[] = [];
if (this.control && this.control.invalid && ((this.control.touched && !this.submitOnly) || this.submitted) && this.control.errors) { if (this.control && this.control.invalid && ((this.control.touched && !this.submitOnly) || this.submitted) && this.control.errors) {
for (let key in <any>this.control.errors) { for (let key in <any>this.control.errors) {
@ -121,12 +121,14 @@ export class ControlErrorsComponent extends StatefulComponent<State> implements
const message = formatError(this.displayFieldName, key, this.control.errors[key], this.control.value, this.errors); const message = formatError(this.displayFieldName, key, this.control.errors[key], this.control.value, this.errors);
if (message) { if (message) {
errorMessages.push(message); errors.push(message);
} }
} }
} }
} }
this.next(s => ({ ...s, errorMessages })); if (errors.length !== this.snapshot.errorMessages.length || errors.length > 0) {
this.next(s => ({ ...s, errorMessages: errors }));
}
} }
} }

4
src/Squidex/app/framework/angular/forms/date-time-editor.component.ts

@ -60,7 +60,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
} }
public ngOnInit() { public ngOnInit() {
this.takeOver( this.own(
this.timeControl.valueChanges.subscribe(value => { this.timeControl.valueChanges.subscribe(value => {
if (!value || value.length === 0) { if (!value || value.length === 0) {
this.timeValue = null; this.timeValue = null;
@ -71,7 +71,7 @@ export class DateTimeEditorComponent extends StatefulControlComponent<{}, string
this.updateValue(); this.updateValue();
})); }));
this.takeOver( this.own(
this.dateControl.valueChanges.subscribe(value => { this.dateControl.valueChanges.subscribe(value => {
if (!value || value.length === 0) { if (!value || value.length === 0) {
this.dateValue = null; this.dateValue = null;

2
src/Squidex/app/framework/angular/forms/iframe-editor.component.ts

@ -50,7 +50,7 @@ export class IFrameEditorComponent extends ExternalControlComponent<any> impleme
} }
public ngOnInit(): void { public ngOnInit(): void {
this.takeOver( this.own(
this.renderer.listen('window', 'message', (event: MessageEvent) => { this.renderer.listen('window', 'message', (event: MessageEvent) => {
if (event.source === this.plugin.contentWindow) { if (event.source === this.plugin.contentWindow) {
const { type } = event.data; const { type } = event.data;

2
src/Squidex/app/framework/angular/forms/tag-editor.component.ts

@ -146,7 +146,7 @@ export class TagEditorComponent extends StatefulControlComponent<State, any[]> i
} }
public ngOnInit() { public ngOnInit() {
this.takeOver( this.own(
this.addInput.valueChanges.pipe( this.addInput.valueChanges.pipe(
tap(() => { tap(() => {
this.resetSize(); this.resetSize();

10
src/Squidex/app/framework/angular/modals/dialog-renderer.component.ts

@ -45,14 +45,14 @@ export class DialogRendererComponent extends StatefulComponent<State> implements
} }
public ngOnInit() { public ngOnInit() {
this.takeOver( this.own(
this.dialogView.isOpen.subscribe(isOpen => { this.dialogView.isOpen.subscribe(isOpen => {
if (!isOpen) { if (!isOpen) {
this.finishRequest(false); this.finishRequest(false);
} }
})); }));
this.takeOver( this.own(
this.dialogs.notifications.subscribe(notification => { this.dialogs.notifications.subscribe(notification => {
this.next(s => ({ this.next(s => ({
...s, ...s,
@ -60,17 +60,19 @@ export class DialogRendererComponent extends StatefulComponent<State> implements
})); }));
if (notification.displayTime > 0) { if (notification.displayTime > 0) {
this.takeOver(timer(notification.displayTime).subscribe(() => { this.own(timer(notification.displayTime).subscribe(() => {
this.close(notification); this.close(notification);
})); }));
} }
})); }));
this.takeOver( this.own(
this.dialogs.dialogs this.dialogs.dialogs
.subscribe(dialogRequest => { .subscribe(dialogRequest => {
this.cancel(); this.cancel();
this.dialogView.show();
this.next(s => ({ ...s, dialogRequest })); this.next(s => ({ ...s, dialogRequest }));
})); }));
} }

6
src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts

@ -55,7 +55,7 @@ export class OnboardingTooltipComponent extends StatefulComponent implements OnD
public ngOnInit() { public ngOnInit() {
if (this.for && this.helpId && Types.isFunction(this.for.addEventListener)) { if (this.for && this.helpId && Types.isFunction(this.for.addEventListener)) {
this.takeOver( this.own(
timer(this.after).subscribe(() => { timer(this.after).subscribe(() => {
if (this.onboardingService.shouldShow(this.helpId)) { if (this.onboardingService.shouldShow(this.helpId)) {
const forRect = this.for.getBoundingClientRect(); const forRect = this.for.getBoundingClientRect();
@ -68,7 +68,7 @@ export class OnboardingTooltipComponent extends StatefulComponent implements OnD
if (this.isSameOrParent(fromPoint)) { if (this.isSameOrParent(fromPoint)) {
this.tooltipModal.show(); this.tooltipModal.show();
this.takeOver( this.own(
timer(10000).subscribe(() => { timer(10000).subscribe(() => {
this.hideThis(); this.hideThis();
})); }));
@ -78,7 +78,7 @@ export class OnboardingTooltipComponent extends StatefulComponent implements OnD
} }
})); }));
this.takeOver( this.own(
this.renderer.listen(this.for, 'mousedown', () => { this.renderer.listen(this.for, 'mousedown', () => {
this.onboardingService.disable(this.helpId); this.onboardingService.disable(this.helpId);

4
src/Squidex/app/framework/angular/modals/tooltip.component.ts

@ -39,12 +39,12 @@ export class TooltipComponent extends StatefulComponent implements OnDestroy, On
public ngOnInit() { public ngOnInit() {
if (this.target) { if (this.target) {
this.takeOver( this.own(
this.renderer.listen(this.target, 'mouseenter', () => { this.renderer.listen(this.target, 'mouseenter', () => {
this.modal.show(); this.modal.show();
})); }));
this.takeOver( this.own(
this.renderer.listen(this.target, 'mouseleave', () => { this.renderer.listen(this.target, 'mouseleave', () => {
this.modal.hide(); this.modal.hide();
})); }));

12
src/Squidex/app/framework/angular/sorted.directive.ts

@ -5,14 +5,14 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Directive, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
import * as Sortable from 'sortablejs'; import * as Sortable from 'sortablejs';
@Directive({ @Directive({
selector: '[sqxSortModel]' selector: '[sqxSortModel]'
}) })
export class SortedDirective implements OnDestroy, OnInit { export class SortedDirective implements OnDestroy, OnInit, OnChanges {
private sortable: Sortable.Ref; private sortable: Sortable.Ref;
@Input() @Input()
@ -29,6 +29,13 @@ export class SortedDirective implements OnDestroy, OnInit {
) { ) {
} }
public ngOnChanges(changes: SimpleChanges) {
const sortModel = changes['sortModel'].currentValue;
if (sortModel) {
console.log(JSON.stringify(sortModel.map((x: any) => x.fileName)));
}
}
public ngOnDestroy() { public ngOnDestroy() {
if (this.sortable) { if (this.sortable) {
this.sortable.destroy(); this.sortable.destroy();
@ -41,6 +48,7 @@ export class SortedDirective implements OnDestroy, OnInit {
animation: 150, animation: 150,
onSort: (event: { oldIndex: number, newIndex: number }) => { onSort: (event: { oldIndex: number, newIndex: number }) => {
console.log('FOO');
if (this.sortModel && event.newIndex !== event.oldIndex) { if (this.sortModel && event.newIndex !== event.oldIndex) {
const newModel = [...this.sortModel]; const newModel = [...this.sortModel];

4
src/Squidex/app/framework/angular/stateful.component.ts

@ -55,7 +55,7 @@ export abstract class StatefulComponent<T = any> extends State<T> implements OnD
) { ) {
super(state); super(state);
this.takeOver( this.own(
this.changes.pipe(skip(1)).subscribe(() => { this.changes.pipe(skip(1)).subscribe(() => {
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
})); }));
@ -65,7 +65,7 @@ export abstract class StatefulComponent<T = any> extends State<T> implements OnD
this.subscriptions.ngOnDestroy(); this.subscriptions.ngOnDestroy();
} }
public takeOver<R>(subscription: Subscription | UnsubscribeFunction | Observable<R>) { public own<R>(subscription: Subscription | UnsubscribeFunction | Observable<R>) {
this.subscriptions.own(subscription); this.subscriptions.own(subscription);
} }
} }

66
src/Squidex/app/shared/components/asset.component.html

@ -95,39 +95,41 @@
<img class="icon" [attr.src]="asset | sqxFileIcon"> <img class="icon" [attr.src]="asset | sqxFileIcon">
</div> </div>
<div class="row no-gutters" *ngIf="asset && snapshot.progress === 0" @fade> <table class="table-fixed" *ngIf="asset && snapshot.progress === 0" @fade>
<div class="col col-name"> <tr>
<div *ngIf="!snapshot.isRenaming" class="file-name editable" (dblclick)="renameStart()"> <td class="col-name">
{{asset.fileName}} <div *ngIf="!snapshot.isRenaming" class="file-name editable" (dblclick)="renameStart()">
</div> {{asset.fileName}}
<div *ngIf="snapshot.isRenaming"> </div>
<form [formGroup]="renameForm.form" (ngSubmit)="renameAsset()"> <div *ngIf="snapshot.isRenaming">
<sqx-control-errors for="name" [submitted]="renameForm.submitted | async"></sqx-control-errors> <form [formGroup]="renameForm.form" (ngSubmit)="renameAsset()">
<sqx-control-errors for="name" [submitted]="renameForm.submitted | async"></sqx-control-errors>
<input type="text" class="form-control editable form-underlined" id="assetName" formControlName="name" autocomplete="off" spellcheck="false" sqxFocusOnInit (blur)="renameCancel()" /> <input type="text" class="form-control editable form-underlined" id="assetName" formControlName="name" autocomplete="off" spellcheck="false" sqxFocusOnInit (blur)="renameCancel()" />
</form> </form>
</div> </div>
</div> </td>
<div class="col col-info"> <td class="col-info" *ngIf="!isCompact">
<ng-container *ngIf="asset.pixelWidth">{{asset.pixelWidth}}x{{asset.pixelHeight}}px, </ng-container> {{asset.fileSize | sqxFileSize}} <ng-container *ngIf="asset.pixelWidth">{{asset.pixelWidth}}x{{asset.pixelHeight}}px, </ng-container> {{asset.fileSize | sqxFileSize}}
</div> </td>
<div class="col col-user"> <td class="col-user" *ngIf="!isCompact">
<img class="user-picture" [attr.title]="asset.lastModifiedBy | sqxUserNameRef" [attr.src]="asset.lastModifiedBy | sqxUserPictureRef" /> <img class="user-picture" [attr.title]="asset.lastModifiedBy | sqxUserNameRef" [attr.src]="asset.lastModifiedBy | sqxUserPictureRef" />
</div> </td>
<div class="col col-actions text-right"> <td class="col-actions text-right" *ngIf="!isCompact">
<a class="btn btn-text-secondary" [href]="asset | sqxAssetUrl" sqxExternalLink="noicon" (click)="$event.stopPropagation()"> <a class="btn btn-text-secondary" [href]="asset | sqxAssetUrl" sqxExternalLink="noicon" (click)="$event.stopPropagation()">
<i class="icon-download"></i> <i class="icon-download"></i>
</a> </a>
</div> </td>
<div class="col col-actions text-right" *ngIf="!isDisabled || removeMode"> <td class="col-actions text-right" *ngIf="!isDisabled || removeMode">
<button class="btn btn-text-danger" (click)="deleting.emit(asset); $event.stopPropagation()" *ngIf="!isDisabled && !removeMode"> <button class="btn btn-text-danger" (click)="deleting.emit(asset); $event.stopPropagation()" *ngIf="!isDisabled && !removeMode">
<i class="icon-bin2"></i> <i class="icon-bin2"></i>
</button> </button>
<button class="btn btn-text-secondary" (click)="removing.emit(asset); $event.stopPropagation()" *ngIf="removeMode"> <button class="btn btn-text-secondary" (click)="removing.emit(asset); $event.stopPropagation()" *ngIf="removeMode">
<i class="icon-close"></i> <i class="icon-close"></i>
</button> </button>
</div> </td>
</div> </tr>
</table>
<div class="upload-progress" *ngIf="snapshot.progress > 0"> <div class="upload-progress" *ngIf="snapshot.progress > 0">
<sqx-progress-bar [value]="snapshot.progress" [trailWidth]="0.8" [strokeWidth]="0.8" [showText]="false"></sqx-progress-bar> <sqx-progress-bar [value]="snapshot.progress" [trailWidth]="0.8" [strokeWidth]="0.8" [showText]="false"></sqx-progress-bar>

36
src/Squidex/app/shared/components/asset.component.scss

@ -107,8 +107,7 @@ $list-height: 2.375rem;
background: $color-dark-black; background: $color-dark-black;
} }
&-name, &-name, &-info {
&-info {
@include truncate; @include truncate;
} }
@ -187,7 +186,7 @@ $list-height: 2.375rem;
.table-items-row { .table-items-row {
& { & {
position: relative; position: relative;
padding-left: $list-height + 2rem; padding-left: $list-height + 3rem;
height: $list-height + 2rem; height: $list-height + 2rem;
} }
@ -229,36 +228,31 @@ $list-height: 2.375rem;
height: $list-height; height: $list-height;
} }
&-user { &-name {
padding-top: .2rem; width: 100%;
} padding-right: .5rem;
&-actions {
line-height: $list-height;
} }
&-name, &-user {
&-info { width: 3rem;
@include truncate;
padding-right: 1rem;
padding-left: 1rem;
line-height: $list-height;
} }
&-actions, &-actions {
&-user { width: 3rem;
max-width: 3rem;
min-width: 3rem;
} }
&-info { &-info {
color: $color-text-decent; color: $color-text-decent;
font-size: .9rem; font-size: .9rem;
max-width: 12rem; font-weight: normal;
min-width: 12rem; width: 12rem;
} }
} }
table {
width: 100%;
}
.upload-progress { .upload-progress {
padding: .25rem 0; padding: .25rem 0;
} }

5
src/Squidex/app/shared/components/asset.component.ts

@ -51,6 +51,9 @@ export class AssetComponent extends StatefulComponent<State> implements OnChange
@Input() @Input()
public removeMode = false; public removeMode = false;
@Input()
public isCompact = false;
@Input() @Input()
public isDisabled = false; public isDisabled = false;
@ -122,7 +125,7 @@ export class AssetComponent extends StatefulComponent<State> implements OnChange
}); });
} }
this.takeOver( this.own(
this.tagInput.valueChanges.pipe( this.tagInput.valueChanges.pipe(
distinctUntilChanged(), distinctUntilChanged(),
debounceTime(2000) debounceTime(2000)

2
src/Squidex/app/shared/components/comments.component.ts

@ -73,7 +73,7 @@ export class CommentsComponent extends ResourceOwner implements OnDestroy, OnIni
} }
} }
public trackByComment(comment: CommentDto) { public trackByComment(index: number, comment: CommentDto) {
return comment.id; return comment.id;
} }
} }

2
src/Squidex/app/shell/pages/internal/profile-menu.component.ts

@ -44,7 +44,7 @@ export class ProfileMenuComponent extends StatefulComponent<State> implements On
}); });
} }
public ngOnInit() { public ngOnInit() {
this.takeOver( this.own(
this.authService.userChanges.pipe(filter(user => !!user)) this.authService.userChanges.pipe(filter(user => !!user))
.subscribe(user => { .subscribe(user => {
const profileId = user!.id; const profileId = user!.id;

Loading…
Cancel
Save