Browse Source

Bugfixes.

pull/364/head
Sebastian Stehle 7 years ago
parent
commit
2c1a5ba22a
  1. 2
      src/Squidex.Domain.Apps.Entities/Apps/RoleExtensions.cs
  2. 5
      src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs
  3. 2
      src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs
  4. 2
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  5. 4
      src/Squidex/app/features/content/shared/assets-editor.component.html
  6. 2
      src/Squidex/app/features/settings/pages/backups/backups-page.component.html
  7. 20
      src/Squidex/app/features/settings/pages/clients/client.component.ts
  8. 16
      src/Squidex/app/features/settings/pages/languages/language.component.ts
  9. 18
      src/Squidex/app/features/settings/pages/patterns/pattern.component.ts
  10. 13
      src/Squidex/app/framework/angular/forms/file-drop.directive.ts
  11. 2
      src/Squidex/app/shared/components/asset-dialog.component.ts
  12. 72
      src/Squidex/app/shared/components/asset-uploader.component.html
  13. 12
      src/Squidex/app/shared/components/asset.component.html
  14. 2
      src/Squidex/app/shared/components/assets-list.component.html
  15. 2
      src/Squidex/app/shared/components/markdown-editor.component.html
  16. 2
      src/Squidex/app/shared/components/rich-editor.component.html
  17. 2
      src/Squidex/app/shared/services/apps.service.ts
  18. 6
      src/Squidex/app/shared/services/assets.service.ts
  19. 10
      src/Squidex/app/shared/state/assets.state.ts
  20. 9
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/RoleExtensionsTests.cs

2
src/Squidex.Domain.Apps.Entities/Apps/RoleExtensions.cs

@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
{
return id;
}
}));
}).Where(x => x != "common"));
}
}
}

5
src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs

@ -182,6 +182,11 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models
AddPostLink("schemas/create", controller.Url<SchemasController>(x => nameof(x.PostSchema), values));
}
if (controller.HasPermission(AllPermissions.AppAssetsCreate, Name, permissions: permissions))
{
AddPostLink("assets/create", controller.Url<SchemasController>(x => nameof(x.PostSchema), values));
}
return this;
}
}

2
src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs

@ -59,7 +59,7 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models
response.AddPostLink("create", controller.Url<AssetsController>(x => nameof(x.PostAsset), values));
}
response.AddDeleteLink("tags", controller.Url<AssetsController>(x => nameof(x.GetTags), values));
response.AddGetLink("tags", controller.Url<AssetsController>(x => nameof(x.GetTags), values));
return response;
}

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

@ -183,7 +183,7 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
private loadContent(data: any) {
this.contentForm.loadContent(data);
this.contentForm.setEnabled(!this.content || this.content.canUpdate);
this.contentForm.setEnabled(this.content && !this.content.canUpdate);
}
public discardChanges() {

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

@ -1,9 +1,9 @@
<div class="assets-container" [class.disabled]="snapshot.isDisabled" (sqxFileDrop)="addFiles($event)" tabindex="1000">
<div class="assets-container" [class.disabled]="snapshot.isDisabled" (sqxDropFile)="addFiles($event)" tabindex="1000">
<div class="header list">
<div class="row no-gutters">
<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()" (sqxDropFile)="addFiles($event)">
Drop files or click
</div>
</div>

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

@ -52,7 +52,7 @@
Duration:
</div>
</div>
<div class="col-auto">
<div class="col-3">
<div>
{{backup.started | sqxFromNow}}
</div>

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

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnChanges } from '@angular/core';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import {
@ -58,16 +58,18 @@ export class ClientComponent implements OnChanges {
) {
}
public ngOnChanges() {
this.renameForm.load(this.client);
public ngOnChanges(changes: SimpleChanges) {
if (changes['client']) {
this.renameForm.load(this.client);
const app = this.appsState.appName;
const app = this.appsState.appName;
this.connectHttpText = connectHttpText(this.apiUrl, app, this.client);
this.connectCLINetText = connectCLINetText(app, this.client, this.apiUrl);
this.connectCLINixText = connectCLINixText(app, this.client, this.apiUrl);
this.connectCLIWinText = connectCLIWinText(app, this.client, this.apiUrl);
this.connectLibraryText = connectLibrary(this.apiUrl, app, this.client);
this.connectHttpText = connectHttpText(this.apiUrl, app, this.client);
this.connectCLINetText = connectCLINetText(app, this.client, this.apiUrl);
this.connectCLINixText = connectCLINixText(app, this.client, this.apiUrl);
this.connectCLIWinText = connectCLIWinText(app, this.client, this.apiUrl);
this.connectLibraryText = connectLibrary(this.apiUrl, app, this.client);
}
}
public revoke() {

16
src/Squidex/app/features/settings/pages/languages/language.component.ts

@ -48,7 +48,12 @@ export class LanguageComponent implements OnChanges {
}
public ngOnChanges() {
this.resetForm();
this.isEditable = this.language.canUpdate;
this.editForm.load(this.language);
this.editForm.setEnabled(this.isEditable);
this.otherLanguage = this.fallbackLanguagesNew.at(0);
}
public toggleEditing() {
@ -94,15 +99,6 @@ export class LanguageComponent implements OnChanges {
this.otherLanguage = this.fallbackLanguagesNew.at(0);
}
private resetForm() {
this.isEditable = this.language.canUpdate;
this.editForm.load(this.language);
this.editForm.setEnabled(this.isEditable);
this.otherLanguage = this.fallbackLanguagesNew.at(0);
}
public trackByLanguage(index: number, language: AppLanguageDto) {
return language.iso2Code;
}

18
src/Squidex/app/features/settings/pages/patterns/pattern.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import {
@ -19,7 +19,7 @@ import {
styleUrls: ['./pattern.component.scss'],
templateUrl: './pattern.component.html'
})
export class PatternComponent implements OnInit {
export class PatternComponent implements OnChanges {
@Input()
public pattern: PatternDto;
@ -34,12 +34,14 @@ export class PatternComponent implements OnInit {
) {
}
public ngOnInit() {
this.isEditable = !this.pattern || this.pattern.canUpdate;
this.isDeletable = this.pattern && this.pattern.canDelete;
public ngOnChanges(changes: SimpleChanges) {
if (changes['pattern']) {
this.isEditable = !this.pattern || this.pattern.canUpdate;
this.isDeletable = this.pattern && this.pattern.canDelete;
this.editForm.load(this.pattern);
this.editForm.setEnabled(this.isEditable);
this.editForm.load(this.pattern);
this.editForm.setEnabled(this.isEditable);
}
}
public cancel() {
@ -61,7 +63,7 @@ export class PatternComponent implements OnInit {
if (this.pattern) {
this.patternsState.update(this.pattern, value)
.subscribe(newPattern => {
this.editForm.submitCompleted({ newValue: newPattern });
this.editForm.submitCompleted(newPattern);
}, error => {
this.editForm.submitFailed(error);
});

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

@ -19,7 +19,7 @@ const ImageTypes = [
];
@Directive({
selector: '[sqxFileDrop]'
selector: '[sqxDropFile]'
})
export class FileDropDirective {
private dragCounter = 0;
@ -33,7 +33,10 @@ export class FileDropDirective {
@Input()
public noDrop: boolean;
@Output('sqxFileDrop')
@Input('sqxDropDisabled')
public disabled = false;
@Output('sqxDropFile')
public drop = new EventEmitter<File[]>();
constructor(
@ -60,7 +63,7 @@ export class FileDropDirective {
}
}
if (result.length > 0) {
if (result.length > 0 && !this.disabled) {
this.drop.emit(result);
}
@ -127,7 +130,7 @@ export class FileDropDirective {
private dragStart() {
this.dragCounter++;
if (this.dragCounter === 1) {
if (this.dragCounter === 1 && !this.disabled) {
this.renderer.addClass(this.element.nativeElement, 'drag');
}
}
@ -135,7 +138,7 @@ export class FileDropDirective {
private dragEnd(number?: number ) {
this.dragCounter = number || this.dragCounter - 1;
if (this.dragCounter === 0) {
if (this.dragCounter === 0 && !this.disabled) {
this.renderer.removeClass(this.element.nativeElement, 'drag');
}
}

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

@ -55,7 +55,7 @@ export class AssetDialogComponent extends StatefulComponent implements OnInit {
this.isEditable = this.asset.canUpdate;
this.annotateForm.load(this.asset);
this.annotateForm.setEnabled(!this.isEditable);
this.annotateForm.setEnabled(this.isEditable);
}
public generateSlug() {

72
src/Squidex/app/shared/components/asset-uploader.component.html

@ -1,44 +1,46 @@
<ng-container *ngIf="appsState.selectedValidApp | async">
<ul class="nav navbar-nav" *ngIf="assetUploader.uploads | async; let uploads" (sqxFileDrop)="addFiles($event)">
<li class="nav-item dropdown">
<span class="nav-link dropdown-toggle" (click)="modalMenu.toggle()">
<i class="icon-upload-3"></i>
<ng-container *ngIf="appsState.selectedValidApp | async; let selectedApp">
<ng-container *ngIf="selectedApp.canUploadAssets">
<ul class="nav navbar-nav" *ngIf="assetUploader.uploads | async; let uploads" (sqxDropFile)="addFiles($event)">
<li class="nav-item dropdown">
<span class="nav-link dropdown-toggle" (click)="modalMenu.toggle()">
<i class="icon-upload-3"></i>
<span>{{uploads.length}}</span>
</span>
<span>{{uploads.length}}</span>
</span>
<div class="dropdown-menu container" *ngIf="modalMenu.isOpen | async" (sqxFileDrop)="addFiles($event)" @fade>
<div class="uploads">
<small class="uploads-empty text-muted" *ngIf="uploads.length === 0">
No upload in progress, drop files here.
</small>
<div class="upload row no-gutters" *ngFor="let upload of uploads; trackBy: trackByUpload">
<div class="col-auto" [ngSwitch]="upload.status">
<div *ngSwitchCase="'Failed'" class="upload-status upload-status-failed">
<i class="icon-exclamation"></i>
<div class="dropdown-menu container" *ngIf="modalMenu.isOpen | async" (sqxDropFile)="addFiles($event)" @fade>
<div class="uploads">
<small class="uploads-empty text-muted" *ngIf="uploads.length === 0">
No upload in progress, drop files here.
</small>
<div class="upload row no-gutters" *ngFor="let upload of uploads; trackBy: trackByUpload">
<div class="col-auto" [ngSwitch]="upload.status">
<div *ngSwitchCase="'Failed'" class="upload-status upload-status-failed">
<i class="icon-exclamation"></i>
</div>
<div *ngSwitchCase="'Completed'" class="upload-status upload-status-success">
<i class="icon-checkmark"></i>
</div>
<div *ngSwitchDefault class="upload-status upload-status-running">
<i class="icon-hour-glass"></i>
</div>
</div>
<div *ngSwitchCase="'Completed'" class="upload-status upload-status-success">
<i class="icon-checkmark"></i>
<div class="col-6">
<div class="upload-name">{{upload.name}}</div>
</div>
<div *ngSwitchDefault class="upload-status upload-status-running">
<i class="icon-hour-glass"></i>
<div class="col">
<sqx-progress-bar [value]="upload.progress" [trailWidth]="1.5" [strokeWidth]="1.5" [showText]="false" [animated]="false"></sqx-progress-bar>
</div>
<div class="col-auto">
<button type="button" class="btn btn-text-secondary" (click)="stopUpload(upload)">
<i class="icon-close"></i>
</button>
</div>
</div>
<div class="col-6">
<div class="upload-name">{{upload.name}}</div>
</div>
<div class="col">
<sqx-progress-bar [value]="upload.progress" [trailWidth]="1.5" [strokeWidth]="1.5" [showText]="false" [animated]="false"></sqx-progress-bar>
</div>
<div class="col-auto">
<button type="button" class="btn btn-text-secondary" (click)="stopUpload(upload)">
<i class="icon-close"></i>
</button>
</div>
</div>
</div>
</div>
</li>
</ul>
</li>
</ul>
</ng-container>
</ng-container>

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

@ -1,5 +1,8 @@
<ng-container *ngIf="!isListView; else listTemplate">
<div class="card" [class.selectable]="isSelectable" [class.border-primary]="isSelected" (click)="emitSelect()" (sqxFileDrop)="updateFile($event)" [noDrop]="true">
<div class="card" [class.selectable]="isSelectable" [class.border-primary]="isSelected" (click)="emitSelect()"
(sqxDropFile)="updateFile($event)"
[sqxDropDisabled]="!asset || !asset.canUpload"
[noDrop]="true">
<div class="card-body">
<div class="file-preview" *ngIf="asset && snapshot.progress === 0" @fade>
<span class="file-type" *ngIf="asset.fileType">
@ -74,7 +77,10 @@
</ng-container>
<ng-template #listTemplate>
<div class="table-items-row" [class.selectable]="isSelectable" (click)="emitSelect()" (sqxFileDrop)="updateFile($event)" [noDrop]="true">
<div class="table-items-row" [class.selectable]="isSelectable" (click)="emitSelect()"
(sqxDropFile)="updateFile($event)"
[sqxDropDisabled]="!asset || !asset.canUpload"
[noDrop]="true">
<div class="left-border" [class.hidden]="!isSelectable" [class.selected]="isSelected" ></div>
<div *ngIf="asset && asset.canPreview && snapshot.progress === 0" class="image drag-handle" [class.image-left]="!isSelectable" @fade>
@ -125,7 +131,7 @@
</ng-template>
<ng-container *ngIf="asset">
<sqx-asset-dialog *sqxModalView="editDialog;onRoot:true"
<sqx-asset-dialog *sqxModalView="editDialog;onRoot:true"
[asset]="asset" [allTags]="allTags"
(cancel)="cancelEdit()"
(complete)="updateAsset($event, true)">

2
src/Squidex/app/shared/components/assets-list.component.html

@ -1,4 +1,4 @@
<div class="file-drop" (sqxFileDrop)="addFiles($event)" *ngIf="!isDisabled">
<div class="file-drop" (sqxDropFile)="addFiles($event)" *ngIf="!isDisabled && state.canCreate | async">
<h3 class="file-drop-header">Drop files here to upload</h3>
<div class="file-drop-or">or</div>

2
src/Squidex/app/shared/components/markdown-editor.component.html

@ -1,4 +1,4 @@
<div #container class="drop-container" (sqxFileDrop)="insertFiles($event)" [onlyImages]="true">
<div #container class="drop-container" (sqxDropFile)="insertFiles($event)" [onlyImages]="true">
<div #inner [class.fullscreen]="snapshot.isFullscreen">
<textarea class="form-control" #editor></textarea>
</div>

2
src/Squidex/app/shared/components/rich-editor.component.html

@ -1,4 +1,4 @@
<div class="drop-container" (sqxFileDrop)="insertFiles($event)" [onlyImages]="true">
<div class="drop-container" (sqxDropFile)="insertFiles($event)" [onlyImages]="true">
<div class="editor" #editor></div>
</div>

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

@ -35,6 +35,7 @@ export class AppDto {
public readonly canReadRoles: boolean;
public readonly canReadRules: boolean;
public readonly canReadSchemas: boolean;
public readonly canUploadAssets: boolean;
constructor(links: ResourceLinks,
public readonly id: string,
@ -61,6 +62,7 @@ export class AppDto {
this.canReadRoles = hasAnyLink(links, 'roles');
this.canReadRules = hasAnyLink(links, 'rules');
this.canReadSchemas = hasAnyLink(links, 'schemas');
this.canUploadAssets = hasAnyLink(links, 'assets/create');
}
}

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

@ -27,7 +27,11 @@ import {
Versioned
} from '@app/framework';
export class AssetsDto extends ResultSet<AssetDto> {}
export class AssetsDto extends ResultSet<AssetDto> {
public get canCreate() {
return hasAnyLink(this._links, 'create');
}
}
export class AssetDto {
public readonly _meta: Metadata = {};

10
src/Squidex/app/shared/state/assets.state.ts

@ -39,6 +39,9 @@ interface Snapshot {
// Indicates if the assets are loaded.
isLoaded?: boolean;
// Indicates if the user can create assets.
canCreate?: boolean;
}
@Injectable()
@ -64,6 +67,9 @@ export class AssetsState extends State<Snapshot> {
public isLoaded =
this.project(x => !!x.isLoaded);
public canCreate =
this.project(x => !!x.canCreate);
constructor(
private readonly appsState: AppsState,
private readonly assetsService: AssetsService,
@ -89,7 +95,7 @@ export class AssetsState extends State<Snapshot> {
Object.keys(this.snapshot.tagsSelected)),
this.assetsService.getTags(this.appName)
).pipe(
tap(([ { items, total }, tags ]) => {
tap(([ { items, total, canCreate }, tags ]) => {
if (isReload) {
this.dialogs.notifyInfo('Assets reloaded.');
}
@ -98,7 +104,7 @@ export class AssetsState extends State<Snapshot> {
const assets = ImmutableArray.of(items);
const assetsPager = s.assetsPager.setCount(total);
return { ...s, assets, assetsPager, isLoaded: true, tags };
return { ...s, assets, assetsPager, isLoaded: true, tags, canCreate };
});
}),
shareSubscribed(this.dialogs));

9
tests/Squidex.Domain.Apps.Entities.Tests/Apps/RoleExtensionsTests.cs

@ -67,5 +67,14 @@ namespace Squidex.Domain.Apps.Entities.Apps
Assert.Equal(Permission.Any, result.First().Id);
}
[Fact]
public void Should_remove_common_permission()
{
var source = new PermissionSet("squidex.apps.my-app.common");
var result = source.WithoutApp("my-app");
Assert.Empty(result);
}
}
}

Loading…
Cancel
Save