Browse Source

Dragging improved

pull/65/head
Sebastian Stehle 9 years ago
parent
commit
6dfcde52da
  1. 3
      src/Squidex/app/features/apps/pages/apps-page.component.ts
  2. 6
      src/Squidex/app/features/assets/pages/assets-page.component.scss
  3. 2
      src/Squidex/app/features/assets/pages/assets-page.component.ts
  4. 6
      src/Squidex/app/features/content/pages/content/content-field.component.html
  5. 7
      src/Squidex/app/features/content/pages/content/content-page.component.html
  6. 10
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  7. 6
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  8. 8
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  9. 2
      src/Squidex/app/features/schemas/pages/schema/types/boolean-validation.component.ts
  10. 4
      src/Squidex/app/features/schemas/pages/schema/types/date-time-validation.component.ts
  11. 4
      src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.ts
  12. 2
      src/Squidex/app/features/schemas/pages/schema/types/number-validation.component.ts
  13. 4
      src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.ts
  14. 8
      src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts
  15. 4
      src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts
  16. 2
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts
  17. 4
      src/Squidex/app/features/settings/pages/clients/client.component.ts
  18. 2
      src/Squidex/app/features/settings/pages/clients/clients-page.component.ts
  19. 4
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts
  20. 2
      src/Squidex/app/features/settings/pages/languages/languages-page.component.ts
  21. 2
      src/Squidex/app/framework/angular/control-errors.component.ts
  22. 2
      src/Squidex/app/framework/angular/date-time-editor.component.ts
  23. 3
      src/Squidex/app/framework/angular/file-drop.directive.ts
  24. 2
      src/Squidex/app/framework/angular/modal-view.directive.ts
  25. 35
      src/Squidex/app/framework/angular/square.directive.ts
  26. 2
      src/Squidex/app/framework/angular/stars.component.ts
  27. 1
      src/Squidex/app/framework/declarations.ts
  28. 3
      src/Squidex/app/framework/module.ts
  29. 4
      src/Squidex/app/framework/services/resource-loader.service.ts
  30. 6
      src/Squidex/app/framework/utils/modal-view.ts
  31. 4
      src/Squidex/app/shared/components/app-form.component.ts
  32. 6
      src/Squidex/app/shared/components/app.component-base.ts
  33. 109
      src/Squidex/app/shared/components/asset.component.html
  34. 5
      src/Squidex/app/shared/components/asset.component.scss
  35. 2
      src/Squidex/app/shared/components/asset.component.ts
  36. 8
      src/Squidex/app/shared/components/assets-editor.component.html
  37. 44
      src/Squidex/app/shared/components/assets-editor.component.scss
  38. 14
      src/Squidex/app/shared/components/assets-editor.component.ts
  39. 2
      src/Squidex/app/shared/components/history.component.ts
  40. 18
      src/Squidex/app/shared/components/pipes.ts
  41. 6
      src/Squidex/app/shared/guards/resolve-app-languages.guard.spec.ts
  42. 4
      src/Squidex/app/shared/guards/resolve-app-languages.guard.ts
  43. 6
      src/Squidex/app/shared/guards/resolve-content.guard.spec.ts
  44. 4
      src/Squidex/app/shared/guards/resolve-content.guard.ts
  45. 8
      src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts
  46. 4
      src/Squidex/app/shared/guards/resolve-published-schema.guard.ts
  47. 6
      src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts
  48. 4
      src/Squidex/app/shared/guards/resolve-schema.guard.ts
  49. 8
      src/Squidex/app/shared/services/app-clients.service.ts
  50. 6
      src/Squidex/app/shared/services/app-contributors.service.ts
  51. 8
      src/Squidex/app/shared/services/app-languages.service.ts
  52. 16
      src/Squidex/app/shared/services/assets.service.spec.ts
  53. 12
      src/Squidex/app/shared/services/assets.service.ts
  54. 2
      src/Squidex/app/shared/services/auth.service.ts
  55. 2
      src/Squidex/app/shared/services/contents.service.spec.ts
  56. 14
      src/Squidex/app/shared/services/contents.service.ts
  57. 34
      src/Squidex/app/shared/services/schemas.service.ts
  58. 2
      src/Squidex/app/shared/services/users.service.ts
  59. 4
      src/Squidex/app/theme/_vars.scss
  60. 26
      src/Squidex/package.json

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

@ -24,8 +24,7 @@ import {
export class AppsPageComponent implements OnInit { export class AppsPageComponent implements OnInit {
public addAppDialog = new ModalView(); public addAppDialog = new ModalView();
public apps = public apps = this.appsStore.apps.map(a => a || []);
this.appsStore.apps.map(a => a || []);
constructor( constructor(
private readonly appsStore: AppsStoreService private readonly appsStore: AppsStoreService

6
src/Squidex/app/features/assets/pages/assets-page.component.scss

@ -23,7 +23,7 @@
} }
&-info { &-info {
color: $color-subtext; color: darken($color-border, 30%);
} }
&-button { &-button {
@ -52,8 +52,4 @@
.col-3 { .col-3 {
padding-left: 8px; padding-left: 8px;
padding-right: 8px; padding-right: 8px;
}
.dnd-sortable-drag {
border: 0;
} }

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

@ -56,7 +56,7 @@ export class AssetsPageComponent extends AppComponentBase implements OnInit {
private load() { private load() {
this.appName() this.appName()
.switchMap(app => this.assetsService.getAssets(app, this.assetsPager.pageSize, this.assetsPager.skip, this.assertQuery, null, null)) .switchMap(app => this.assetsService.getAssets(app, this.assetsPager.pageSize, this.assetsPager.skip, this.assertQuery))
.subscribe(dtos => { .subscribe(dtos => {
this.assetsItems = ImmutableArray.of(dtos.items); this.assetsItems = ImmutableArray.of(dtos.items);
this.assetsPager = this.assetsPager.setCount(dtos.total); this.assetsPager = this.assetsPager.setCount(dtos.total);

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

@ -90,11 +90,7 @@
<sqx-json-editor [formControlName]="language"></sqx-json-editor> <sqx-json-editor [formControlName]="language"></sqx-json-editor>
</div> </div>
<div *ngSwitchCase="'Assets'"> <div *ngSwitchCase="'Assets'">
<div class="assets-container"> <sqx-assets-editor [formControlName]="language"></sqx-assets-editor>
<sqx-assets-editor [formControlName]="language"></sqx-assets-editor>
<a routerLink="assets" class="assets-link">Show Assets</a>
</div>
</div> </div>
</div> </div>
</div> </div>

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

@ -40,10 +40,13 @@
<sqx-content-field [field]="field" [fieldForm]="contentForm.controls[field.name]" [languages]="languages" [contentFormSubmitted]="contentFormSubmitted"></sqx-content-field> <sqx-content-field [field]="field" [fieldForm]="contentForm.controls[field.name]" [languages]="languages" [contentFormSubmitted]="contentFormSubmitted"></sqx-content-field>
</div> </div>
</div> </div>
<div class="panel-sidebar" *ngIf="!isNewMode"> <div class="panel-sidebar">
<a class="panel-link" routerLink="history" routerLinkActive="active"> <a class="panel-link" routerLink="history" routerLinkActive="active" *ngIf="!isNewMode">
<i class="icon-time"></i> <i class="icon-time"></i>
</a> </a>
<a class="panel-link" routerLink="assets" routerLinkActive="active">
<i class="icon-media"></i>
</a>
</div> </div>
</div> </div>
</sqx-panel> </sqx-panel>

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

@ -46,7 +46,7 @@ export class ContentPageComponent extends AppComponentBase implements OnDestroy,
public contentFormSubmitted = false; public contentFormSubmitted = false;
public contentForm: FormGroup; public contentForm: FormGroup;
public contentData: any = null; public contentData: any = null;
public contentId: string; public contentId: string | undefined;
public isNewMode = true; public isNewMode = true;
@ -75,12 +75,12 @@ export class ContentPageComponent extends AppComponentBase implements OnDestroy,
} }
}); });
this.route.parent.data.map(p => p['appLanguages']) this.route.parent!.data.map(p => p['appLanguages'])
.subscribe((languages: AppLanguageDto[]) => { .subscribe((languages: AppLanguageDto[]) => {
this.languages = languages; this.languages = languages;
}); });
this.route.parent.data.map(p => p['schema']) this.route.parent!.data.map(p => p['schema'])
.subscribe((schema: SchemaDetailsDto) => { .subscribe((schema: SchemaDetailsDto) => {
this.setupForm(schema); this.setupForm(schema);
}); });
@ -125,9 +125,9 @@ export class ContentPageComponent extends AppComponentBase implements OnDestroy,
}); });
} else { } else {
this.appName() this.appName()
.switchMap(app => this.contentsService.putContent(app, this.schema.name, this.contentId, data, this.version)) .switchMap(app => this.contentsService.putContent(app, this.schema.name, this.contentId!, data, this.version))
.subscribe(() => { .subscribe(() => {
this.messageBus.publish(new ContentUpdated(this.contentId, data, this.version.value)); this.messageBus.publish(new ContentUpdated(this.contentId!, data, this.version.value));
this.notifyInfo('Content saved successfully.'); this.notifyInfo('Content saved successfully.');
this.enable(); this.enable();

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

@ -53,9 +53,7 @@ export class ContentsPageComponent extends AppComponentBase implements OnDestroy
public languages: AppLanguageDto[] = []; public languages: AppLanguageDto[] = [];
public languageSelected: AppLanguageDto; public languageSelected: AppLanguageDto;
public get columnWidth() { public columnWidth: number;
return 100 / this.contentFields.length;
}
constructor(apps: AppsStoreService, notifications: NotificationService, constructor(apps: AppsStoreService, notifications: NotificationService,
private readonly authService: AuthService, private readonly authService: AuthService,
@ -154,6 +152,8 @@ export class ContentsPageComponent extends AppComponentBase implements OnDestroy
private loadFields() { private loadFields() {
this.contentFields = this.schema.fields.filter(x => x.properties.isListField); this.contentFields = this.schema.fields.filter(x => x.properties.isListField);
this.columnWidth = 100 / this.contentFields.length;
if (this.contentFields.length === 0 && this.schema.fields.length > 0) { if (this.contentFields.length === 0 && this.schema.fields.length > 0) {
this.contentFields = [this.schema.fields[0]]; this.contentFields = [this.schema.fields[0]];
} }

8
src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts

@ -221,12 +221,12 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
if (this.addFieldForm.valid) { if (this.addFieldForm.valid) {
this.addFieldForm.disable(); this.addFieldForm.disable();
const properties = createProperties(this.addFieldForm.get('type').value); const properties = createProperties(this.addFieldForm.get('type')!.value);
const requestDto = new AddFieldDto(this.addFieldForm.get('name').value, properties); const requestDto = new AddFieldDto(this.addFieldForm.get('name')!.value, properties);
const reset = () => { const reset = () => {
this.addFieldForm.get('name').reset(); this.addFieldForm.get('name')!.reset();
this.addFieldForm.enable(); this.addFieldForm.enable();
this.addFieldFormSubmitted = false; this.addFieldFormSubmitted = false;
}; };
@ -236,7 +236,7 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
.subscribe(dto => { .subscribe(dto => {
const newField = const newField =
new FieldDto(parseInt(dto.id, 10), new FieldDto(parseInt(dto.id, 10),
this.addFieldForm.get('name').value, this.addFieldForm.get('name')!.value,
false, false,
false, false,
properties); properties);

2
src/Squidex/app/features/schemas/pages/schema/types/boolean-validation.component.ts

@ -30,7 +30,7 @@ export class BooleanValidationComponent implements OnInit {
new FormControl(this.properties.defaultValue)); new FormControl(this.properties.defaultValue));
this.hideDefaultValue = this.hideDefaultValue =
this.editForm.get('isRequired').valueChanges this.editForm.get('isRequired')!.valueChanges
.startWith(this.properties.isRequired) .startWith(this.properties.isRequired)
.map(x => !!x); .map(x => !!x);
} }

4
src/Squidex/app/features/schemas/pages/schema/types/date-time-validation.component.ts

@ -48,12 +48,12 @@ export class DateTimeValidationComponent implements OnInit {
])); ]));
this.hideDefaultValues = this.hideDefaultValues =
this.editForm.get('isRequired').valueChanges this.editForm.get('isRequired')!.valueChanges
.startWith(this.properties.isRequired) .startWith(this.properties.isRequired)
.map(x => !!x); .map(x => !!x);
this.hideDefaultValue = this.hideDefaultValue =
this.editForm.get('calculatedDefaultValue').valueChanges this.editForm.get('calculatedDefaultValue')!.valueChanges
.startWith(this.properties.calculatedDefaultValue) .startWith(this.properties.calculatedDefaultValue)
.map(x => !!x); .map(x => !!x);
} }

4
src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.ts

@ -46,14 +46,14 @@ export class NumberUIComponent implements OnDestroy, OnInit {
new FormControl(this.properties.allowedValues, [])); new FormControl(this.properties.allowedValues, []));
this.hideAllowedValues = this.hideAllowedValues =
this.editForm.get('editor').valueChanges this.editForm.get('editor')!.valueChanges
.startWith(this.properties.editor) .startWith(this.properties.editor)
.map(x => !x || x === 'Input' || x === 'Textarea'); .map(x => !x || x === 'Input' || x === 'Textarea');
this.editorSubscription = this.editorSubscription =
this.hideAllowedValues.subscribe(isSelection => { this.hideAllowedValues.subscribe(isSelection => {
if (isSelection) { if (isSelection) {
this.editForm.get('allowedValues').setValue(undefined); this.editForm.get('allowedValues')!.setValue(undefined);
} }
}); });
} }

2
src/Squidex/app/features/schemas/pages/schema/types/number-validation.component.ts

@ -36,7 +36,7 @@ export class NumberValidationComponent implements OnInit {
new FormControl(this.properties.defaultValue)); new FormControl(this.properties.defaultValue));
this.hideDefaultValue = this.hideDefaultValue =
this.editForm.get('isRequired').valueChanges this.editForm.get('isRequired')!.valueChanges
.startWith(this.properties.isRequired) .startWith(this.properties.isRequired)
.map(x => !!x); .map(x => !!x);
} }

4
src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.ts

@ -46,7 +46,7 @@ export class StringUIComponent implements OnDestroy, OnInit {
new FormControl(this.properties.allowedValues)); new FormControl(this.properties.allowedValues));
this.hideAllowedValues = this.hideAllowedValues =
this.editForm.get('editor').valueChanges this.editForm.get('editor')!.valueChanges
.startWith(this.properties.editor) .startWith(this.properties.editor)
.map(x => !x || x === 'Input' || x === 'TextArea' || x === 'RichText' || x === 'Markdown'); .map(x => !x || x === 'Input' || x === 'TextArea' || x === 'RichText' || x === 'Markdown');
@ -54,7 +54,7 @@ export class StringUIComponent implements OnDestroy, OnInit {
this.hideAllowedValues this.hideAllowedValues
.subscribe(isSelection => { .subscribe(isSelection => {
if (isSelection) { if (isSelection) {
this.editForm.get('allowedValues').setValue(undefined); this.editForm.get('allowedValues')!.setValue(undefined);
} }
}); });
} }

8
src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts

@ -49,19 +49,19 @@ export class StringValidationComponent implements OnDestroy, OnInit {
new FormControl(this.properties.defaultValue)); new FormControl(this.properties.defaultValue));
this.hideDefaultValue = this.hideDefaultValue =
this.editForm.get('isRequired').valueChanges this.editForm.get('isRequired')!.valueChanges
.startWith(this.properties.isRequired) .startWith(this.properties.isRequired)
.map(x => !!x); .map(x => !!x);
this.hidePatternMessage = this.hidePatternMessage =
this.editForm.get('pattern').valueChanges this.editForm.get('pattern')!.valueChanges
.startWith('') .startWith('')
.map(x => !x || x.trim().length === 0); .map(x => !x || x.trim().length === 0);
this.patternSubscription = this.patternSubscription =
this.editForm.get('pattern').valueChanges.subscribe((value: string) => { this.editForm.get('pattern')!.valueChanges.subscribe((value: string) => {
if (!value || value.length === 0) { if (!value || value.length === 0) {
this.editForm.get('patternMessage').setValue(undefined); this.editForm.get('patternMessage')!.setValue(undefined);
} }
}); });
} }

4
src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts

@ -53,7 +53,7 @@ export class SchemaFormComponent {
}); });
public schemaName = public schemaName =
this.createForm.get('name').valueChanges.map(n => n || FALLBACK_NAME) this.createForm.get('name')!.valueChanges.map(n => n || FALLBACK_NAME)
.startWith(FALLBACK_NAME); .startWith(FALLBACK_NAME);
constructor( constructor(
@ -76,7 +76,7 @@ export class SchemaFormComponent {
this.createForm.disable(); this.createForm.disable();
const schemaVersion = new Version(); const schemaVersion = new Version();
const schemaName = this.createForm.get('name').value; const schemaName = this.createForm.get('name')!.value;
const requestDto = new CreateSchemaDto(schemaName); const requestDto = new CreateSchemaDto(schemaName);

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

@ -112,7 +112,7 @@ export class SchemasPageComponent extends AppComponentBase implements OnDestroy,
query = query || this.schemaQuery; query = query || this.schemaQuery;
if (query && query.length > 0) { if (query && query.length > 0) {
schemas = schemas.filter(t => t.name.indexOf(query) >= 0); schemas = schemas.filter(t => t.name.indexOf(query!) >= 0);
} }
schemas = schemas =

4
src/Squidex/app/features/settings/pages/clients/client.component.ts

@ -73,7 +73,7 @@ export class ClientComponent {
} }
public resetForm() { public resetForm() {
this.renameForm.get('name').setValue(this.clientName); this.renameForm.get('name')!.setValue(this.clientName);
} }
public cancelRename() { public cancelRename() {
@ -94,7 +94,7 @@ export class ClientComponent {
public rename() { public rename() {
try { try {
const newName = this.renameForm.get('name').value; const newName = this.renameForm.get('name')!.value;
if (newName !== this.clientName) { if (newName !== this.clientName) {
this.renaming.emit(newName); this.renaming.emit(newName);

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

@ -103,7 +103,7 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
if (this.addClientForm.valid) { if (this.addClientForm.valid) {
this.addClientForm.disable(); this.addClientForm.disable();
const requestDto = new CreateAppClientDto(this.addClientForm.get('name').value); const requestDto = new CreateAppClientDto(this.addClientForm.get('name')!.value);
const reset = () => { const reset = () => {
this.addClientFormSubmitted = false; this.addClientFormSubmitted = false;

4
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts

@ -43,7 +43,7 @@ export class UsersDataSource implements AutocompleteSource {
new AutocompleteItem( new AutocompleteItem(
user.displayName, user.displayName,
user.email, user.email,
user.pictureUrl, user.pictureUrl!,
user)); user));
} }
} }
@ -117,7 +117,7 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
} }
public assignContributor() { public assignContributor() {
const newContributor = new AppContributorDto(this.addContributorForm.get('user').value.model.id, 'Editor'); const newContributor = new AppContributorDto(this.addContributorForm.get('user')!.value.model.id, 'Editor');
this.appName() this.appName()
.switchMap(app => this.appContributorsService.postContributor(app, newContributor, this.version)) .switchMap(app => this.appContributorsService.postContributor(app, newContributor, this.version))

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

@ -87,7 +87,7 @@ export class LanguagesPageComponent extends AppComponentBase implements OnInit {
} }
public addLanguage() { public addLanguage() {
const request = new AddAppLanguageDto(this.addLanguageForm.get('language').value.iso2Code); const request = new AddAppLanguageDto(this.addLanguageForm.get('language')!.value.iso2Code);
this.appName() this.appName()
.switchMap(app => this.appLanguagesService.postLanguages(app, request, this.version)) .switchMap(app => this.appLanguagesService.postLanguages(app, request, this.version))

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

@ -55,7 +55,7 @@ export class ControlErrorsComponent implements OnChanges {
return null; return null;
} }
if (this.control.invalid && ((this.control.touched && !this.submitOnly) || this.submitted)) { if (this.control.invalid && ((this.control.touched && !this.submitOnly) || this.submitted) && this.control.errors) {
const errors: string[] = []; const errors: string[] = [];
for (let key in <any>this.control.errors) { for (let key in <any>this.control.errors) {

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

@ -156,7 +156,7 @@ export class DateTimeEditorComponent implements ControlValueAccessor, OnInit, Af
} }
private updateValue() { private updateValue() {
let result: string = null; let result: string | null = null;
if ((this.dateValue && !this.dateValue.isValid()) || (this.timeValue && !this.timeValue.isValid())) { if ((this.dateValue && !this.dateValue.isValid()) || (this.timeValue && !this.timeValue.isValid())) {
result = 'Invalid DateTime'; result = 'Invalid DateTime';

3
src/Squidex/app/framework/angular/file-drop.directive.ts

@ -22,8 +22,9 @@ export class FileDropDirective {
) { ) {
} }
@HostListener('dragend', ['$event'])
@HostListener('dragleave', ['$event']) @HostListener('dragleave', ['$event'])
public onDragLeave(event: DragDropEvent) { public onDragEnd(event: DragDropEvent) {
const hasFiles = this.hasFiles(event.dataTransfer.types); const hasFiles = this.hasFiles(event.dataTransfer.types);
if (hasFiles) { if (hasFiles) {

2
src/Squidex/app/framework/angular/modal-view.directive.ts

@ -14,7 +14,7 @@ import { ModalView } from './../utils/modal-view';
selector: '[sqxModalView]' selector: '[sqxModalView]'
}) })
export class ModalViewDirective implements OnChanges, OnInit, OnDestroy { export class ModalViewDirective implements OnChanges, OnInit, OnDestroy {
private subscription: Subscription; private subscription: Subscription | null;
private isEnabled = true; private isEnabled = true;
private clickHandler: Function | null; private clickHandler: Function | null;
private renderedView: EmbeddedViewRef<any> | null = null; private renderedView: EmbeddedViewRef<any> | null = null;

35
src/Squidex/app/framework/angular/square.directive.ts

@ -1,35 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Directive, ElementRef, HostListener, OnInit, Renderer } from '@angular/core';
@Directive({
selector: '[sqxSquare]'
})
export class SquareDirective implements OnInit {
constructor(
private readonly element: ElementRef,
private readonly renderer: Renderer
) {
}
public ngOnInit() {
this.resize();
}
@HostListener('resize')
public onResize() {
this.resize();
}
private resize() {
const size = this.element.nativeElement.getBoundingClientRect();
this.renderer.setElementStyle(this.element.nativeElement, 'height', size.width + 'px');
}
}

2
src/Squidex/app/framework/angular/stars.component.ts

@ -84,7 +84,7 @@ export class StarsComponent implements ControlValueAccessor {
return; return;
} }
this.stars = this.value; this.stars = this.value || 0;
} }
public reset() { public reset() {

1
src/Squidex/app/framework/declarations.ts

@ -33,7 +33,6 @@ export * from './angular/rich-editor.component';
export * from './angular/scroll-active.directive'; export * from './angular/scroll-active.directive';
export * from './angular/shortcut.component'; export * from './angular/shortcut.component';
export * from './angular/slider.component'; export * from './angular/slider.component';
export * from './angular/square.directive';
export * from './angular/stars.component'; export * from './angular/stars.component';
export * from './angular/tag-editor.component'; export * from './angular/tag-editor.component';
export * from './angular/title.component'; export * from './angular/title.component';

3
src/Squidex/app/framework/module.ts

@ -50,7 +50,6 @@ import {
ShortDatePipe, ShortDatePipe,
ShortTimePipe, ShortTimePipe,
SliderComponent, SliderComponent,
SquareDirective,
StarsComponent, StarsComponent,
TagEditorComponent, TagEditorComponent,
TitleService, TitleService,
@ -99,7 +98,6 @@ import {
ShortDatePipe, ShortDatePipe,
ShortTimePipe, ShortTimePipe,
SliderComponent, SliderComponent,
SquareDirective,
StarsComponent, StarsComponent,
TagEditorComponent, TagEditorComponent,
TitleComponent, TitleComponent,
@ -138,7 +136,6 @@ import {
ShortDatePipe, ShortDatePipe,
ShortTimePipe, ShortTimePipe,
SliderComponent, SliderComponent,
SquareDirective,
StarsComponent, StarsComponent,
TagEditorComponent, TagEditorComponent,
TitleComponent, TitleComponent,

4
src/Squidex/app/framework/services/resource-loader.service.ts

@ -52,7 +52,9 @@ export class ResourceLoaderService {
const node = document.getElementsByTagName('script')[0]; const node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(script, node); if (node.parentNode) {
node.parentNode.insertBefore(script, node);
}
}); });
this.cache[key] = result; this.cache[key] = result;

6
src/Squidex/app/framework/utils/modal-view.ts

@ -9,16 +9,18 @@ import { BehaviorSubject, Observable } from 'rxjs';
export class ModalView { export class ModalView {
private readonly isOpen$: BehaviorSubject<boolean>; private readonly isOpen$: BehaviorSubject<boolean>;
private static openView: ModalView; private readonly isOpenChanges$: Observable<boolean>;
private static openView: ModalView | null = null;
public get isOpen(): Observable<boolean> { public get isOpen(): Observable<boolean> {
return this.isOpen$.distinctUntilChanged(); return this.isOpenChanges$;
} }
constructor(isOpen = false, constructor(isOpen = false,
public readonly closeAlways: boolean = false public readonly closeAlways: boolean = false
) { ) {
this.isOpen$ = new BehaviorSubject(isOpen); this.isOpen$ = new BehaviorSubject(isOpen);
this.isOpenChanges$ = this.isOpen$.distinctUntilChanged();
} }
public show() { public show() {

4
src/Squidex/app/shared/components/app-form.component.ts

@ -43,7 +43,7 @@ export class AppFormComponent {
}); });
public appName = public appName =
this.createForm.get('name').valueChanges.map(n => n || FALLBACK_NAME) this.createForm.get('name')!.valueChanges.map(n => n || FALLBACK_NAME)
.startWith(FALLBACK_NAME); .startWith(FALLBACK_NAME);
constructor( constructor(
@ -64,7 +64,7 @@ export class AppFormComponent {
if (this.createForm.valid) { if (this.createForm.valid) {
this.createForm.disable(); this.createForm.disable();
const request = new CreateAppDto(this.createForm.get('name').value); const request = new CreateAppDto(this.createForm.get('name')!.value);
this.appsStore.createApp(request) this.appsStore.createApp(request)
.subscribe(dto => { .subscribe(dto => {

6
src/Squidex/app/shared/components/app.component-base.ts

@ -12,14 +12,18 @@ import { AppsStoreService, NotificationService } from './../declarations-base';
import { ComponentBase } from './component-base'; import { ComponentBase } from './component-base';
export abstract class AppComponentBase extends ComponentBase { export abstract class AppComponentBase extends ComponentBase {
private appName$: Observable<string>;
constructor(notifications: NotificationService, constructor(notifications: NotificationService,
private readonly appsStore: AppsStoreService private readonly appsStore: AppsStoreService
) { ) {
super(notifications); super(notifications);
this.appName$ = this.appsStore.selectedApp.map(a => a!.name).take(1);
} }
public appName(): Observable<string> { public appName(): Observable<string> {
return this.appsStore.selectedApp.map(a => a!.name).take(1); return this.appName$;
} }
} }

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

@ -1,68 +1,67 @@
<div class="asset"> <div class="card" (sqxFileDrop)="updateFile($event)" dnd-draggable [dragEnabled]="!!asset" [dragData]="asset">
<div class="card" (sqxFileDrop)="updateFile($event)" sqxSquare dnd-draggable [dragEnabled]="!!asset" [dragData]="asset"> <div class="card-block">
<div class="card-block"> <div class="file-preview" *ngIf="asset && progress == 0" [@fade]>
<div class="file-preview" *ngIf="asset && progress == 0" [@fade]> <span class="file-type" *ngIf="fileType">
<span class="file-type" *ngIf="fileType"> {{fileType}}
{{fileType}} </span>
</span>
<div *ngIf="asset.isImage" class="file-image">
<img [sqxImageSource]="previewUrl">
</div>
<div *ngIf="!asset.isImage" class="file-icon-container">
<img class="file-icon" [attr.src]="fileIcon">
</div>
<div class="file-overlay">
<div class="file-overlay-background"></div>
<div *ngIf="asset.isImage" class="file-image"> <a class="file-edit" (click)="renameDialog.show()">
<img [sqxImageSource]="previewUrl"> <i class="icon-pencil"></i>
</div> </a>
<div *ngIf="!asset.isImage" class="file-icon-container"> <a class="file-download" [attr.href]="fileUrl" target="_blank">
<img class="file-icon" [attr.src]="fileIcon"> <i class="icon-download"></i>
</div> </a>
<div class="file-overlay"> <span *ngIf="!closeMode">
<div class="file-overlay-background"></div> <a class="file-delete" (click)="deleting.emit(asset)">
<i class="icon-delete"></i>
<a class="file-edit" (click)="renameDialog.show()">
<i class="icon-pencil"></i>
</a> </a>
<a class="file-download" [attr.href]="fileUrl" target="_blank"> </span>
<i class="icon-download"></i> <span *ngIf="closeMode">
<a class="file-delete" (click)="closing.emit(asset)">
<i class="icon-close"></i>
</a> </a>
</span>
<span *ngIf="!closeMode"> <span class="file-overlay-type" *ngIf="fileType">
<a class="file-delete" (click)="deleting.emit(asset)"> {{fileType}}
<i class="icon-delete"></i> </span>
</a> <span class="file-user">
</span> <i class="icon-user"></i> {{asset.lastModifiedBy | userNameRef}}
<span *ngIf="closeMode"> </span>
<a class="file-delete" (click)="closing.emit(asset)"> <span class="file-modified">
<i class="icon-close"></i> {{asset.lastModified | fromNow}}
</a> </span>
</span>
<span class="file-overlay-type" *ngIf="fileType">
{{fileType}}
</span>
<span class="file-user">
<i class="icon-user"></i> {{asset.lastModifiedBy | userNameRef}}
</span>
<span class="file-modified">
{{asset.lastModified | fromNow}}
</span>
</div>
</div> </div>
</div> </div>
<div class="card-footer"> </div>
<div class="file-name" [attr.title]="fileName"> <div class="card-footer" dnd-draggable-handle>
{{fileName}} <div class="file-name" [attr.title]="fileName">
</div> {{fileName}}
<div class="file-info">
{{fileInfo}}
</div>
</div> </div>
<div class="file-info">
<div *ngIf="progress > 0"> {{fileInfo}}
<sqx-progress-bar class="upload-progress" style="width: 120px; height: 120px" mode="Circle" [value]="progress"></sqx-progress-bar>
</div> </div>
<div class="drop-overlay"> </div>
<div class="drop-overlay-background"></div>
<span class="drop-overlay-text">Drop to update</span> <div class="upload-progress" *ngIf="progress > 0">
</div> <sqx-progress-bar mode="Circle" [value]="progress"></sqx-progress-bar>
</div>
<div class="drop-overlay">
<div class="drop-overlay-background"></div>
<span class="drop-overlay-text">Drop to update</span>
</div> </div>
</div> </div>

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

@ -9,7 +9,7 @@
@mixin overlay { @mixin overlay {
& { & {
@include transition(opacity.4s ease); @include transition(opacity .4s ease);
@include absolute(0, 0, 0, 0); @include absolute(0, 0, 0, 0);
@include opacity(0); @include opacity(0);
color: $color-dark-foreground; color: $color-dark-foreground;
@ -70,6 +70,7 @@
.card { .card {
& { & {
@include overlay-container; @include overlay-container;
height: $asset-height;
} }
&.drag { &.drag {
@ -92,7 +93,7 @@
} }
.upload-progress { .upload-progress {
margin: 60px 70px; @include absolute(2rem, 2rem, 2rem, 2rem);
} }
.file { .file {

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

@ -109,8 +109,6 @@ export class AssetComponent extends AppComponentBase implements OnInit {
result.pixelWidth, result.pixelWidth,
result.pixelHeight, result.pixelHeight,
result.version); result.version);
this.updateAsset(asset);
this.loaded.emit(asset); this.loaded.emit(asset);
} else { } else {
this.progress = result; this.progress = result;

8
src/Squidex/app/shared/components/assets-editor.component.html

@ -1,5 +1,11 @@
<div class="assets-container" (sqxFileDrop)="addFiles($event)" dnd-droppable (onDropSuccess)="onAssetDropped($event.dragData)"> <div class="assets-container">
<div class="row"> <div class="row">
<div class="col-4 drop-area-container">
<div class="drop-area" dnd-droppable (onDropSuccess)="onAssetDropped($event.dragData)" (sqxFileDrop)="addFiles($event)">
Drop files or assets here to add them.
</div>
</div>
<sqx-asset class="col-4" *ngFor="let file of newAssets" [initFile]="file" <sqx-asset class="col-4" *ngFor="let file of newAssets" [initFile]="file"
(failed)="onAssetFailed(file)" (failed)="onAssetFailed(file)"
(loaded)="onAssetLoaded(file, $event)"> (loaded)="onAssetLoaded(file, $event)">

44
src/Squidex/app/shared/components/assets-editor.component.scss

@ -4,29 +4,47 @@
.assets { .assets {
&-container { &-container {
& { & {
border: 2px solid $color-input; background: $color-background;
background: $color-input;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: scroll;
padding: 1rem; padding: 1rem;
padding-bottom: 0; padding-bottom: 0;
height: 240px; height: $asset-height + 2rem;
} }
}
}
&.drag { .drop-area {
border-color: darken($color-border, 10%); & {
border-style: dashed; @include transition(border-color .4s ease);
cursor: copy; border: 2px dashed $color-border;
} height: $asset-height;
font-size: 1.2rem;
font-weight: normal;
text-align: center;
padding: 3rem 2rem;
color: darken($color-border, 30%);
}
&-container {
padding-bottom: 1rem;
}
&.drag,
&.dnd-drag-over,
&.dnd-drag-enter {
border-color: darken($color-border, 10%);
cursor: copy;
color: darken($color-border, 40%);
} }
} }
.row { .row {
margin-left: -8px; margin-left: -.5rem;
margin-right: -8px; margin-right: -.5rem;
} }
.col-4 { .col-4 {
padding-left: 8px; padding-left: .5rem;
padding-right: 8px; padding-right: .5rem;
} }

14
src/Squidex/app/shared/components/assets-editor.component.ts

@ -48,11 +48,11 @@ export class AssetsEditorComponent extends AppComponentBase implements ControlVa
} }
public writeValue(value: any) { public writeValue(value: any) {
if (!value) { this.oldAssets = ImmutableArray.empty<AssetDto>();
this.oldAssets = ImmutableArray.empty<AssetDto>();
} else { if (value) {
this.appName() this.appName()
.switchMap(app => this.assetsService.getAssets(app, 10000, 0, null, null, value)) .switchMap(app => this.assetsService.getAssets(app, 10000, 0, undefined, undefined, value))
.subscribe(dtos => { .subscribe(dtos => {
this.oldAssets = ImmutableArray.of(dtos.items); this.oldAssets = ImmutableArray.of(dtos.items);
}); });
@ -79,13 +79,13 @@ export class AssetsEditorComponent extends AppComponentBase implements ControlVa
public onAssetLoaded(file: File, asset: AssetDto) { public onAssetLoaded(file: File, asset: AssetDto) {
this.newAssets = this.newAssets.remove(file); this.newAssets = this.newAssets.remove(file);
this.oldAssets = this.oldAssets.push(asset); this.oldAssets = this.oldAssets.pushFront(asset);
this.updateValue(); this.updateValue();
} }
public onAssetDropped(asset: AssetDto) { public onAssetDropped(asset: AssetDto) {
this.oldAssets = this.oldAssets.push(asset); this.oldAssets = this.oldAssets.pushFront(asset);
this.updateValue(); this.updateValue();
} }
@ -99,7 +99,7 @@ export class AssetsEditorComponent extends AppComponentBase implements ControlVa
} }
private updateValue() { private updateValue() {
let ids = this.oldAssets.values.map(x => x.id); let ids: string[] | null = this.oldAssets.values.map(x => x.id);
if (ids.length === 0) { if (ids.length === 0) {
ids = null; ids = null;

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

@ -31,7 +31,7 @@ const REPLACEMENT_TEMP = '$TEMP$';
export class HistoryComponent extends AppComponentBase { export class HistoryComponent extends AppComponentBase {
public get channel(): string { public get channel(): string {
let result = this.route.snapshot.data['channel']; let result = this.route.snapshot.data['channel'];
let params = this.route.parent.snapshot.params; let params = this.route.parent!.snapshot.params;
for (let key in params) { for (let key in params) {
if (params.hasOwnProperty(key)) { if (params.hasOwnProperty(key)) {

18
src/Squidex/app/shared/components/pipes.ts

@ -12,7 +12,7 @@ import { UsersProviderService } from './../declarations-base';
class UserAsyncPipe implements OnDestroy { class UserAsyncPipe implements OnDestroy {
private lastUserId: string; private lastUserId: string;
private lastValue: string; private lastValue: string | null = null;
private subscription: Subscription; private subscription: Subscription;
constructor( constructor(
@ -27,7 +27,7 @@ class UserAsyncPipe implements OnDestroy {
} }
} }
protected transformInternal(userId: string, transform: (users: UsersProviderService) => Observable<string>): string { protected transformInternal(userId: string, transform: (users: UsersProviderService) => Observable<string | null>): string | null {
if (this.lastUserId !== userId) { if (this.lastUserId !== userId) {
this.lastUserId = userId; this.lastUserId = userId;
@ -55,7 +55,7 @@ export class UserNamePipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector); super(users, changeDetector);
} }
public transform(userId: string, placeholder = 'Me'): string { public transform(userId: string, placeholder = 'Me'): string | null {
return super.transformInternal(userId, users => users.getUser(userId, placeholder).map(u => u.displayName)); return super.transformInternal(userId, users => users.getUser(userId, placeholder).map(u => u.displayName));
} }
} }
@ -69,7 +69,7 @@ export class UserNameRefPipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector); super(users, changeDetector);
} }
public transform(userId: string, placeholder = 'Me'): string { public transform(userId: string, placeholder = 'Me'): string | null {
return super.transformInternal(userId, users => { return super.transformInternal(userId, users => {
const parts = userId.split(':'); const parts = userId.split(':');
@ -95,7 +95,7 @@ export class UserEmailPipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector); super(users, changeDetector);
} }
public transform(userId: string): string { public transform(userId: string): string | null {
return super.transformInternal(userId, users => users.getUser(userId).map(u => u.email)); return super.transformInternal(userId, users => users.getUser(userId).map(u => u.email));
} }
} }
@ -109,14 +109,14 @@ export class UserEmailRefPipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector); super(users, changeDetector);
} }
public transform(userId: string): string { public transform(userId: string): string | null {
return super.transformInternal(userId, users => { return super.transformInternal(userId, users => {
const parts = userId.split(':'); const parts = userId.split(':');
if (parts[0] === 'subject') { if (parts[0] === 'subject') {
return users.getUser(parts[1]).map(u => u.email); return users.getUser(parts[1]).map(u => u.email);
} else { } else {
return null; return Observable.of(null);
} }
}); });
} }
@ -131,7 +131,7 @@ export class UserPicturePipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector); super(users, changeDetector);
} }
public transform(userId: string): string { public transform(userId: string): string | null {
return super.transformInternal(userId, users => users.getUser(userId).map(u => u.pictureUrl)); return super.transformInternal(userId, users => users.getUser(userId).map(u => u.pictureUrl));
} }
} }
@ -145,7 +145,7 @@ export class UserPictureRefPipe extends UserAsyncPipe implements PipeTransform {
super(users, changeDetector); super(users, changeDetector);
} }
public transform(userId: string): string { public transform(userId: string): string | null {
return super.transformInternal(userId, users => { return super.transformInternal(userId, users => {
const parts = userId.split(':'); const parts = userId.split(':');

6
src/Squidex/app/shared/guards/resolve-app-languages.guard.spec.ts

@ -33,7 +33,7 @@ describe('ResolveAppLanguagesGuard', () => {
}); });
it('should navigate to 404 page if languages are not found', (done) => { it('should navigate to 404 page if languages are not found', (done) => {
appLanguagesService.setup(x => x.getLanguages('my-app', null)) appLanguagesService.setup(x => x.getLanguages('my-app'))
.returns(() => Observable.of(null!)); .returns(() => Observable.of(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -49,7 +49,7 @@ describe('ResolveAppLanguagesGuard', () => {
}); });
it('should navigate to 404 page if languages loading fails', (done) => { it('should navigate to 404 page if languages loading fails', (done) => {
appLanguagesService.setup(x => x.getLanguages('my-app', null)) appLanguagesService.setup(x => x.getLanguages('my-app'))
.returns(() => Observable.throw(null!)); .returns(() => Observable.throw(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -67,7 +67,7 @@ describe('ResolveAppLanguagesGuard', () => {
it('should return schema if loading succeeded', (done) => { it('should return schema if loading succeeded', (done) => {
const languages: AppLanguageDto[] = []; const languages: AppLanguageDto[] = [];
appLanguagesService.setup(x => x.getLanguages('my-app', null)) appLanguagesService.setup(x => x.getLanguages('my-app'))
.returns(() => Observable.of(languages)); .returns(() => Observable.of(languages));
const router = new RouterMockup(); const router = new RouterMockup();

4
src/Squidex/app/shared/guards/resolve-app-languages.guard.ts

@ -26,7 +26,7 @@ export class ResolveAppLanguagesGuard implements Resolve<AppLanguageDto[]> {
} }
const result = const result =
this.appLanguagesService.getLanguages(appName, null).toPromise() this.appLanguagesService.getLanguages(appName).toPromise()
.then(dto => { .then(dto => {
if (!dto) { if (!dto) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
@ -50,7 +50,7 @@ export class ResolveAppLanguagesGuard implements Resolve<AppLanguageDto[]> {
while (route) { while (route) {
result = route.params[name]; result = route.params[name];
if (result) { if (result || !route.parent) {
break; break;
} }

6
src/Squidex/app/shared/guards/resolve-content.guard.spec.ts

@ -43,7 +43,7 @@ describe('ResolveContentGuard', () => {
}); });
it('should navigate to 404 page if schema is not found', (done) => { it('should navigate to 404 page if schema is not found', (done) => {
appsStore.setup(x => x.getContent('my-app', 'my-schema', '123', null)) appsStore.setup(x => x.getContent('my-app', 'my-schema', '123'))
.returns(() => Observable.of(null!)); .returns(() => Observable.of(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -59,7 +59,7 @@ describe('ResolveContentGuard', () => {
}); });
it('should navigate to 404 page if schema loading fails', (done) => { it('should navigate to 404 page if schema loading fails', (done) => {
appsStore.setup(x => x.getContent('my-app', 'my-schema', '123', null)) appsStore.setup(x => x.getContent('my-app', 'my-schema', '123'))
.returns(() => Observable.throw(null!)); .returns(() => Observable.throw(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -77,7 +77,7 @@ describe('ResolveContentGuard', () => {
it('should return schema if loading succeeded', (done) => { it('should return schema if loading succeeded', (done) => {
const schema = {}; const schema = {};
appsStore.setup(x => x.getContent('my-app', 'my-schema', '123', null)) appsStore.setup(x => x.getContent('my-app', 'my-schema', '123'))
.returns(() => Observable.of(schema)); .returns(() => Observable.of(schema));
const router = new RouterMockup(); const router = new RouterMockup();

4
src/Squidex/app/shared/guards/resolve-content.guard.ts

@ -28,7 +28,7 @@ export class ResolveContentGuard implements Resolve<ContentDto> {
} }
const result = const result =
this.contentsService.getContent(appName, schemaName, contentId, null).toPromise() this.contentsService.getContent(appName, schemaName, contentId).toPromise()
.then(dto => { .then(dto => {
if (!dto) { if (!dto) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
@ -52,7 +52,7 @@ export class ResolveContentGuard implements Resolve<ContentDto> {
while (route) { while (route) {
result = route.params[name]; result = route.params[name];
if (result) { if (result || !route.parent) {
break; break;
} }

8
src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts

@ -38,7 +38,7 @@ describe('ResolvePublishedSchemaGuard', () => {
}); });
it('should navigate to 404 page if schema is not found', (done) => { it('should navigate to 404 page if schema is not found', (done) => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(null!)); .returns(() => Observable.of(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -54,7 +54,7 @@ describe('ResolvePublishedSchemaGuard', () => {
}); });
it('should navigate to 404 page if schema loading fails', (done) => { it('should navigate to 404 page if schema loading fails', (done) => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.throw(null)); .returns(() => Observable.throw(null));
const router = new RouterMockup(); const router = new RouterMockup();
@ -72,7 +72,7 @@ describe('ResolvePublishedSchemaGuard', () => {
it('should navigate to 404 page if schema not published', (done) => { it('should navigate to 404 page if schema not published', (done) => {
const schema = { isPublished: false }; const schema = { isPublished: false };
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(schema)); .returns(() => Observable.of(schema));
const router = new RouterMockup(); const router = new RouterMockup();
@ -90,7 +90,7 @@ describe('ResolvePublishedSchemaGuard', () => {
it('should return schema if loading succeeded', (done) => { it('should return schema if loading succeeded', (done) => {
const schema = { isPublished: true }; const schema = { isPublished: true };
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(schema)); .returns(() => Observable.of(schema));
const router = new RouterMockup(); const router = new RouterMockup();

4
src/Squidex/app/shared/guards/resolve-published-schema.guard.ts

@ -27,7 +27,7 @@ export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto> {
} }
const result = const result =
this.schemasService.getSchema(appName, schemaName, null).toPromise() this.schemasService.getSchema(appName, schemaName).toPromise()
.then(dto => { .then(dto => {
if (!dto || !dto.isPublished) { if (!dto || !dto.isPublished) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
@ -51,7 +51,7 @@ export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto> {
while (route) { while (route) {
result = route.params[name]; result = route.params[name];
if (result) { if (result || !route.parent) {
break; break;
} }

6
src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts

@ -38,7 +38,7 @@ describe('ResolveSchemaGuard', () => {
}); });
it('should navigate to 404 page if schema is not found', (done) => { it('should navigate to 404 page if schema is not found', (done) => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(null!)); .returns(() => Observable.of(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -54,7 +54,7 @@ describe('ResolveSchemaGuard', () => {
}); });
it('should navigate to 404 page if schema loading fails', (done) => { it('should navigate to 404 page if schema loading fails', (done) => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.throw(null!)); .returns(() => Observable.throw(null!));
const router = new RouterMockup(); const router = new RouterMockup();
@ -72,7 +72,7 @@ describe('ResolveSchemaGuard', () => {
it('should return schema if loading succeeded', (done) => { it('should return schema if loading succeeded', (done) => {
const schema = {}; const schema = {};
schemasService.setup(x => x.getSchema('my-app', 'my-schema', null)) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(schema)); .returns(() => Observable.of(schema));
const router = new RouterMockup(); const router = new RouterMockup();

4
src/Squidex/app/shared/guards/resolve-schema.guard.ts

@ -27,7 +27,7 @@ export class ResolveSchemaGuard implements Resolve<SchemaDetailsDto> {
} }
const result = const result =
this.schemasService.getSchema(appName, schemaName, null).toPromise() this.schemasService.getSchema(appName, schemaName).toPromise()
.then(dto => { .then(dto => {
if (!dto) { if (!dto) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
@ -51,7 +51,7 @@ export class ResolveSchemaGuard implements Resolve<SchemaDetailsDto> {
while (route) { while (route) {
result = route.params[name]; result = route.params[name];
if (result) { if (result || !route.parent) {
break; break;
} }

8
src/Squidex/app/shared/services/app-clients.service.ts

@ -54,7 +54,7 @@ export class AppClientsService {
) { ) {
} }
public getClients(appName: string, version: Version): Observable<AppClientDto[]> { public getClients(appName: string, version?: Version): Observable<AppClientDto[]> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients`);
return this.authService.authGet(url, version) return this.authService.authGet(url, version)
@ -72,7 +72,7 @@ export class AppClientsService {
.catchError('Failed to load clients. Please reload.'); .catchError('Failed to load clients. Please reload.');
} }
public postClient(appName: string, dto: CreateAppClientDto, version: Version): Observable<AppClientDto> { public postClient(appName: string, dto: CreateAppClientDto, version?: Version): Observable<AppClientDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients`);
return this.authService.authPost(url, dto, version) return this.authService.authPost(url, dto, version)
@ -86,14 +86,14 @@ export class AppClientsService {
.catchError('Failed to add client. Please reload.'); .catchError('Failed to add client. Please reload.');
} }
public updateClient(appName: string, id: string, dto: UpdateAppClientDto, version: Version): Observable<any> { public updateClient(appName: string, id: string, dto: UpdateAppClientDto, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`);
return this.authService.authPut(url, dto, version) return this.authService.authPut(url, dto, version)
.catchError('Failed to revoke client. Please reload.'); .catchError('Failed to revoke client. Please reload.');
} }
public deleteClient(appName: string, id: string, version: Version): Observable<any> { public deleteClient(appName: string, id: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients/${id}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)

6
src/Squidex/app/shared/services/app-contributors.service.ts

@ -29,7 +29,7 @@ export class AppContributorsService {
) { ) {
} }
public getContributors(appName: string, version: Version): Observable<AppContributorDto[]> { public getContributors(appName: string, version?: Version): Observable<AppContributorDto[]> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`);
return this.authService.authGet(url, version) return this.authService.authGet(url, version)
@ -46,14 +46,14 @@ export class AppContributorsService {
.catchError('Failed to load contributors. Please reload.'); .catchError('Failed to load contributors. Please reload.');
} }
public postContributor(appName: string, dto: AppContributorDto, version: Version): Observable<any> { public postContributor(appName: string, dto: AppContributorDto, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`);
return this.authService.authPost(url, dto, version) return this.authService.authPost(url, dto, version)
.catchError('Failed to add contributors. Please reload.'); .catchError('Failed to add contributors. Please reload.');
} }
public deleteContributor(appName: string, contributorId: string, version: Version): Observable<any> { public deleteContributor(appName: string, contributorId: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors/${contributorId}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors/${contributorId}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)

8
src/Squidex/app/shared/services/app-languages.service.ts

@ -44,7 +44,7 @@ export class AppLanguagesService {
) { ) {
} }
public getLanguages(appName: string, version: Version): Observable<AppLanguageDto[]> { public getLanguages(appName: string, version?: Version): Observable<AppLanguageDto[]> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages`);
return this.authService.authGet(url, version) return this.authService.authGet(url, version)
@ -62,7 +62,7 @@ export class AppLanguagesService {
.catchError('Failed to load languages. Please reload.'); .catchError('Failed to load languages. Please reload.');
} }
public postLanguages(appName: string, dto: AddAppLanguageDto, version: Version): Observable<AppLanguageDto> { public postLanguages(appName: string, dto: AddAppLanguageDto, version?: Version): Observable<AppLanguageDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages`);
return this.authService.authPost(url, dto, version) return this.authService.authPost(url, dto, version)
@ -76,14 +76,14 @@ export class AppLanguagesService {
.catchError('Failed to add language. Please reload.'); .catchError('Failed to add language. Please reload.');
} }
public updateLanguage(appName: string, languageCode: string, dto: UpdateAppLanguageDto, version: Version): Observable<any> { public updateLanguage(appName: string, languageCode: string, dto: UpdateAppLanguageDto, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`);
return this.authService.authPut(url, dto, version) return this.authService.authPut(url, dto, version)
.catchError('Failed to change language. Please reload.'); .catchError('Failed to change language. Please reload.');
} }
public deleteLanguage(appName: string, languageCode: string, version: Version): Observable<any> { public deleteLanguage(appName: string, languageCode: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages/${languageCode}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)

16
src/Squidex/app/shared/services/assets.service.spec.ts

@ -37,7 +37,7 @@ describe('AssetsService', () => {
} }
}; };
progressHttp = Mock.ofInstance(new ProgressHttp(null, null, factory, null)); progressHttp = Mock.ofInstance(new ProgressHttp(null!, null!, factory, null!));
progressHttp.setup(x => x.withUploadProgressListener(It.isAny())).returns(() => <any> progressHttp.object); progressHttp.setup(x => x.withUploadProgressListener(It.isAny())).returns(() => <any> progressHttp.object);
authService = Mock.ofType(AuthService); authService = Mock.ofType(AuthService);
@ -90,7 +90,7 @@ describe('AssetsService', () => {
let assets: AssetsDto | null = null; let assets: AssetsDto | null = null;
assetsService.getAssets('my-app', 17, 13, null, null, null).subscribe(result => { assetsService.getAssets('my-app', 17, 13).subscribe(result => {
assets = result; assets = result;
}).unsubscribe(); }).unsubscribe();
@ -151,7 +151,7 @@ describe('AssetsService', () => {
let assets: AssetDto | null = null; let assets: AssetDto | null = null;
assetsService.getAsset('my-app', '123', null).subscribe(result => { assetsService.getAsset('my-app', '123').subscribe(result => {
assets = result; assets = result;
}).unsubscribe(); }).unsubscribe();
@ -188,7 +188,7 @@ describe('AssetsService', () => {
let assets: AssetsDto | null = null; let assets: AssetsDto | null = null;
assetsService.getAssets('my-app', 17, 13, 'my-query', null, null).subscribe(result => { assetsService.getAssets('my-app', 17, 13, 'my-query').subscribe(result => {
assets = result; assets = result;
}).unsubscribe(); }).unsubscribe();
@ -211,7 +211,7 @@ describe('AssetsService', () => {
let assets: AssetsDto | null = null; let assets: AssetsDto | null = null;
assetsService.getAssets('my-app', 17, 13, null, ['text/plain', 'image/png'], null).subscribe(result => { assetsService.getAssets('my-app', 17, 13, undefined, ['text/plain', 'image/png']).subscribe(result => {
assets = result; assets = result;
}).unsubscribe(); }).unsubscribe();
@ -234,7 +234,7 @@ describe('AssetsService', () => {
let assets: AssetsDto | null = null; let assets: AssetsDto | null = null;
assetsService.getAssets('my-app', 17, 13, null, null, ['12', '23']).subscribe(result => { assetsService.getAssets('my-app', 17, 13, undefined, undefined, ['12', '23']).subscribe(result => {
assets = result; assets = result;
}).unsubscribe(); }).unsubscribe();
@ -264,7 +264,7 @@ describe('AssetsService', () => {
let asset: AssetCreatedDto | null = null; let asset: AssetCreatedDto | null = null;
assetsService.uploadFile('my-app', null).subscribe(result => { assetsService.uploadFile('my-app', null!).subscribe(result => {
asset = <AssetCreatedDto>result; asset = <AssetCreatedDto>result;
}); });
@ -303,7 +303,7 @@ describe('AssetsService', () => {
let asset: AssetReplacedDto | null = null; let asset: AssetReplacedDto | null = null;
assetsService.replaceFile('my-app', '123', null, version).subscribe(result => { assetsService.replaceFile('my-app', '123', null!, version).subscribe(result => {
asset = <AssetReplacedDto>result; asset = <AssetReplacedDto>result;
}); });

12
src/Squidex/app/shared/services/assets.service.ts

@ -89,7 +89,7 @@ export class AssetsService {
) { ) {
} }
public getAssets(appName: string, take: number, skip: number, query: string, mimeTypes: string[], ids: string[]): Observable<AssetsDto> { public getAssets(appName: string, take: number, skip: number, query?: string, mimeTypes?: string[], ids?: string[]): Observable<AssetsDto> {
let queries: string[] = []; let queries: string[] = [];
if (mimeTypes && mimeTypes.length > 0) { if (mimeTypes && mimeTypes.length > 0) {
@ -142,7 +142,7 @@ export class AssetsService {
const content = new FormData(); const content = new FormData();
const headers = new Headers({ const headers = new Headers({
'Authorization': `${this.authService.user.user.token_type} ${this.authService.user.user.access_token}` 'Authorization': `${this.authService.user!.user.token_type} ${this.authService.user!.user.access_token}`
}); });
content.append('file', file); content.append('file', file);
@ -173,7 +173,7 @@ export class AssetsService {
}); });
} }
public getAsset(appName: string, id: string, version: Version): Observable<AssetDto> { public getAsset(appName: string, id: string, version?: Version): Observable<AssetDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`);
return this.authService.authGet(url) return this.authService.authGet(url)
@ -203,7 +203,7 @@ export class AssetsService {
const content = new FormData(); const content = new FormData();
const headers = new Headers({ const headers = new Headers({
'Authorization': `${this.authService.user.user.token_type} ${this.authService.user.user.access_token}` 'Authorization': `${this.authService.user!.user.token_type} ${this.authService.user!.user.access_token}`
}); });
if (version && version.value.length > 0) { if (version && version.value.length > 0) {
@ -236,14 +236,14 @@ export class AssetsService {
}); });
} }
public putAsset(appName: string, id: string, dto: UpdateAssetDto, version: Version): Observable<any> { public putAsset(appName: string, id: string, dto: UpdateAssetDto, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`);
return this.authService.authPut(url, dto, version) return this.authService.authPut(url, dto, version)
.catchError('Failed to delete asset. Please reload.'); .catchError('Failed to delete asset. Please reload.');
} }
public deleteAsset(appName: string, id: string, version: Version): Observable<any> { public deleteAsset(appName: string, id: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)

2
src/Squidex/app/shared/services/auth.service.ts

@ -196,7 +196,7 @@ export class AuthService {
private checkResponse(responseStream: Observable<Response>, version?: Version) { private checkResponse(responseStream: Observable<Response>, version?: Version) {
return responseStream return responseStream
.do((response: Response) => { .do((response: Response) => {
if (version && response.status.toString().indexOf('2') === 0) { if (version && response.status.toString().indexOf('2') === 0 && response.headers) {
const etag = response.headers.get('etag'); const etag = response.headers.get('etag');
if (etag) { if (etag) {

2
src/Squidex/app/shared/services/contents.service.spec.ts

@ -63,7 +63,7 @@ describe('ContentsService', () => {
let contents: ContentsDto | null = null; let contents: ContentsDto | null = null;
contentsService.getContents('my-app', 'my-schema', 17, 13, null).subscribe(result => { contentsService.getContents('my-app', 'my-schema', 17, 13).subscribe(result => {
contents = result; contents = result;
}).unsubscribe(); }).unsubscribe();

14
src/Squidex/app/shared/services/contents.service.ts

@ -48,7 +48,7 @@ export class ContentsService {
) { ) {
} }
public getContents(appName: string, schemaName: string, take: number, skip: number, query: string): Observable<ContentsDto> { public getContents(appName: string, schemaName: string, take: number, skip: number, query?: string): Observable<ContentsDto> {
let fullQuery = query ? query.trim() : ''; let fullQuery = query ? query.trim() : '';
if (fullQuery.length > 0) { if (fullQuery.length > 0) {
@ -91,7 +91,7 @@ export class ContentsService {
.catchError('Failed to load contents. Please reload.'); .catchError('Failed to load contents. Please reload.');
} }
public getContent(appName: string, schemaName: string, id: string, version: Version): Observable<ContentDto> { public getContent(appName: string, schemaName: string, id: string, version?: Version): Observable<ContentDto> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}?hidden=true`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}?hidden=true`);
return this.authService.authGet(url, version) return this.authService.authGet(url, version)
@ -110,7 +110,7 @@ export class ContentsService {
.catchError('Failed to load content. Please reload.'); .catchError('Failed to load content. Please reload.');
} }
public postContent(appName: string, schemaName: string, dto: any, publish: boolean, version: Version): Observable<ContentDto> { public postContent(appName: string, schemaName: string, dto: any, publish: boolean, version?: Version): Observable<ContentDto> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?publish=${publish}`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?publish=${publish}`);
return this.authService.authPost(url, dto, version) return this.authService.authPost(url, dto, version)
@ -129,28 +129,28 @@ export class ContentsService {
.catchError('Failed to create content. Please reload.'); .catchError('Failed to create content. Please reload.');
} }
public putContent(appName: string, schemaName: string, id: string, dto: any, version: Version): Observable<any> { public putContent(appName: string, schemaName: string, id: string, dto: any, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`);
return this.authService.authPut(url, dto, version) return this.authService.authPut(url, dto, version)
.catchError('Failed to update content. Please reload.'); .catchError('Failed to update content. Please reload.');
} }
public publishContent(appName: string, schemaName: string, id: string, version: Version): Observable<any> { public publishContent(appName: string, schemaName: string, id: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/publish`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/publish`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to publish content. Please reload.'); .catchError('Failed to publish content. Please reload.');
} }
public unpublishContent(appName: string, schemaName: string, id: string, version: Version): Observable<any> { public unpublishContent(appName: string, schemaName: string, id: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/unpublish`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/unpublish`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to unpublish content. Please reload.'); .catchError('Failed to unpublish content. Please reload.');
} }
public deleteContent(appName: string, schemaName: string, id: string, version: Version): Observable<any> { public deleteContent(appName: string, schemaName: string, id: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`); const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)

34
src/Squidex/app/shared/services/schemas.service.ts

@ -113,9 +113,9 @@ export class FieldDto {
export abstract class FieldPropertiesDto { export abstract class FieldPropertiesDto {
constructor( constructor(
public readonly fieldType: string, public readonly fieldType: string,
public readonly label: string, public readonly label: string | undefined,
public readonly hints: string, public readonly hints: string | undefined,
public readonly placeholder: string, public readonly placeholder: string | undefined,
public readonly isRequired: boolean, public readonly isRequired: boolean,
public readonly isListField: boolean, public readonly isListField: boolean,
public readonly isLocalizable: boolean public readonly isLocalizable: boolean
@ -275,7 +275,7 @@ export class SchemasService {
.catchError('Failed to load schemas. Please reload.'); .catchError('Failed to load schemas. Please reload.');
} }
public getSchema(appName: string, id: string, version: Version): Observable<SchemaDetailsDto> { public getSchema(appName: string, id: string, version?: Version): Observable<SchemaDetailsDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${id}`);
return this.authService.authGet(url) return this.authService.authGet(url)
@ -311,7 +311,7 @@ export class SchemasService {
.catchError('Failed to load schema. Please reload.'); .catchError('Failed to load schema. Please reload.');
} }
public postSchema(appName: string, dto: CreateSchemaDto, version: Version): Observable<EntityCreatedDto> { public postSchema(appName: string, dto: CreateSchemaDto, version?: Version): Observable<EntityCreatedDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas`);
return this.authService.authPost(url, dto, version) return this.authService.authPost(url, dto, version)
@ -322,7 +322,7 @@ export class SchemasService {
.catchError('Failed to create schema. Please reload.'); .catchError('Failed to create schema. Please reload.');
} }
public postField(appName: string, schemaName: string, dto: AddFieldDto, version: Version): Observable<EntityCreatedDto> { public postField(appName: string, schemaName: string, dto: AddFieldDto, version?: Version): Observable<EntityCreatedDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields`);
return this.authService.authPost(url, dto, version) return this.authService.authPost(url, dto, version)
@ -333,77 +333,77 @@ export class SchemasService {
.catchError('Failed to add field. Please reload.'); .catchError('Failed to add field. Please reload.');
} }
public putSchema(appName: string, schemaName: string, dto: UpdateSchemaDto, version: Version): Observable<any> { public putSchema(appName: string, schemaName: string, dto: UpdateSchemaDto, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`);
return this.authService.authPut(url, dto, version) return this.authService.authPut(url, dto, version)
.catchError('Failed to update schema. Please reload.'); .catchError('Failed to update schema. Please reload.');
} }
public putFieldOrdering(appName: string, schemaName: string, dto: number[], version: Version): Observable<any> { public putFieldOrdering(appName: string, schemaName: string, dto: number[], version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/ordering`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/ordering`);
return this.authService.authPut(url, { fieldIds: dto }, version) return this.authService.authPut(url, { fieldIds: dto }, version)
.catchError('Failed to reorder fields. Please reload.'); .catchError('Failed to reorder fields. Please reload.');
} }
public publishSchema(appName: string, schemaName: string, version: Version): Observable<any> { public publishSchema(appName: string, schemaName: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to publish schema. Please reload.'); .catchError('Failed to publish schema. Please reload.');
} }
public unpublishSchema(appName: string, schemaName: string, version: Version): Observable<any> { public unpublishSchema(appName: string, schemaName: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/unpublish`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/unpublish`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to unpublish schema. Please reload.'); .catchError('Failed to unpublish schema. Please reload.');
} }
public putField(appName: string, schemaName: string, fieldId: number, dto: UpdateFieldDto, version: Version): Observable<any> { public putField(appName: string, schemaName: string, fieldId: number, dto: UpdateFieldDto, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`);
return this.authService.authPut(url, dto, version) return this.authService.authPut(url, dto, version)
.catchError('Failed to update field. Please reload.'); .catchError('Failed to update field. Please reload.');
} }
public enableField(appName: string, schemaName: string, fieldId: number, version: Version): Observable<any> { public enableField(appName: string, schemaName: string, fieldId: number, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/enable`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/enable`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to enable field. Please reload.'); .catchError('Failed to enable field. Please reload.');
} }
public disableField(appName: string, schemaName: string, fieldId: number, version: Version): Observable<any> { public disableField(appName: string, schemaName: string, fieldId: number, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/disable`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/disable`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to disable field. Please reload.'); .catchError('Failed to disable field. Please reload.');
} }
public showField(appName: string, schemaName: string, fieldId: number, version: Version): Observable<any> { public showField(appName: string, schemaName: string, fieldId: number, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/show`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/show`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to show field. Please reload.'); .catchError('Failed to show field. Please reload.');
} }
public hideField(appName: string, schemaName: string, fieldId: number, version: Version): Observable<any> { public hideField(appName: string, schemaName: string, fieldId: number, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/hide`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/hide`);
return this.authService.authPut(url, {}, version) return this.authService.authPut(url, {}, version)
.catchError('Failed to hide field. Please reload.'); .catchError('Failed to hide field. Please reload.');
} }
public deleteField(appName: string, schemaName: string, fieldId: number, version: Version): Observable<any> { public deleteField(appName: string, schemaName: string, fieldId: number, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)
.catchError('Failed to delete field. Please reload.'); .catchError('Failed to delete field. Please reload.');
} }
public deleteSchema(appName: string, schemaName: string, version: Version): Observable<any> { public deleteSchema(appName: string, schemaName: string, version?: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`);
return this.authService.authDelete(url, version) return this.authService.authDelete(url, version)

2
src/Squidex/app/shared/services/users.service.ts

@ -26,7 +26,7 @@ export class UserDto {
public readonly id: string, public readonly id: string,
public readonly email: string, public readonly email: string,
public readonly displayName: string, public readonly displayName: string,
public readonly pictureUrl: string, public readonly pictureUrl: string | null,
public readonly isLocked: boolean public readonly isLocked: boolean
) { ) {
} }

4
src/Squidex/app/theme/_vars.scss

@ -59,4 +59,6 @@ $size-sidebar-width: 7rem;
$panel-padding: 1.5rem; $panel-padding: 1.5rem;
$panel-header: 5.4rem; $panel-header: 5.4rem;
$panel-sidebar: 3.75rem; $panel-sidebar: 3.75rem;
$panel-light-background: #fff; $panel-light-background: #fff;
$asset-height: 13rem;

26
src/Squidex/package.json

@ -15,15 +15,15 @@
"build:clean": "rimraf wwwroot/build" "build:clean": "rimraf wwwroot/build"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "4.0.2", "@angular/animations": "4.1.0",
"@angular/common": "4.0.2", "@angular/common": "4.1.0",
"@angular/compiler": "4.0.2", "@angular/compiler": "4.1.0",
"@angular/core": "4.0.2", "@angular/core": "4.1.0",
"@angular/forms": "4.0.2", "@angular/forms": "4.1.0",
"@angular/http": "4.0.2", "@angular/http": "4.1.0",
"@angular/platform-browser": "4.0.2", "@angular/platform-browser": "4.1.0",
"@angular/platform-browser-dynamic": "4.0.2", "@angular/platform-browser-dynamic": "4.1.0",
"@angular/router": "4.0.2", "@angular/router": "4.1.0",
"angular-progress-http": "0.5.0", "angular-progress-http": "0.5.0",
"babel-polyfill": "6.23.0", "babel-polyfill": "6.23.0",
"bootstrap": "4.0.0-alpha.6", "bootstrap": "4.0.0-alpha.6",
@ -36,11 +36,11 @@
"progressbar.js": "1.0.1", "progressbar.js": "1.0.1",
"redoc": "1.14.0", "redoc": "1.14.0",
"rxjs": "5.3.0", "rxjs": "5.3.0",
"zone.js": "0.8.8" "zone.js": "0.8.9"
}, },
"devDependencies": { "devDependencies": {
"@angular/compiler-cli": "4.0.2", "@angular/compiler-cli": "4.1.0",
"@angular/tsc-wrapped": "4.0.2", "@angular/tsc-wrapped": "4.1.0",
"@ngtools/webpack": "1.3.1", "@ngtools/webpack": "1.3.1",
"@types/core-js": "0.9.35", "@types/core-js": "0.9.35",
"@types/jasmine": "2.5.43", "@types/jasmine": "2.5.43",
@ -79,7 +79,7 @@
"tslint": "4.5.1", "tslint": "4.5.1",
"tslint-loader": "3.5.3", "tslint-loader": "3.5.3",
"typemoq": "1.5.0", "typemoq": "1.5.0",
"typescript": "2.2.2", "typescript": "2.3.1",
"underscore": "1.8.3", "underscore": "1.8.3",
"webpack": "2.4.1", "webpack": "2.4.1",
"webpack-dev-server": "2.4.5", "webpack-dev-server": "2.4.5",

Loading…
Cancel
Save