Browse Source

Asset field.

pull/65/head
Sebastian Stehle 10 years ago
parent
commit
795b0a7116
  1. 4
      src/Squidex.Read.MongoDb/Assets/MongoAssetEntity.cs
  2. 5
      src/Squidex.Read.MongoDb/Assets/MongoAssetRepository.cs
  3. 5
      src/Squidex.Read.MongoDb/Assets/MongoAssetRepository_EventHandling.cs
  4. 2
      src/Squidex.Read/Assets/IAssetEntity.cs
  5. 4
      src/Squidex.Write/Assets/AssetCommandHandler.cs
  6. 3
      src/Squidex/Controllers/Api/Assets/AssetController.cs
  7. 3
      src/Squidex/app/features/assets/pages/assets-page.component.html
  8. 28
      src/Squidex/app/features/assets/pages/assets-page.component.ts
  9. 2
      src/Squidex/app/features/schemas/pages/schema/field.component.html
  10. 13
      src/Squidex/app/features/schemas/pages/schema/field.component.scss
  11. 20
      src/Squidex/app/shared/components/asset.component.html
  12. 15
      src/Squidex/app/shared/components/asset.component.ts
  13. 3
      src/Squidex/app/shared/components/assets-editor.component.html
  14. 1
      src/Squidex/app/shared/components/assets-editor.component.scss
  15. 30
      src/Squidex/app/shared/components/assets-editor.component.ts
  16. 12
      src/Squidex/app/shared/services/auth.service.ts
  17. 12
      src/Squidex/app/shared/utils/messages.ts
  18. 4
      src/Squidex/package.json

4
src/Squidex.Read.MongoDb/Assets/MongoAssetEntity.cs

@ -28,6 +28,10 @@ namespace Squidex.Read.MongoDb.Assets
[BsonElement]
public bool IsImage { get; set; }
[BsonRequired]
[BsonElement]
public bool IsDeleted { get; set; }
[BsonRequired]
[BsonElement]
public long Version { get; set; }

5
src/Squidex.Read.MongoDb/Assets/MongoAssetRepository.cs

@ -34,7 +34,7 @@ namespace Squidex.Read.MongoDb.Assets
protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetEntity> collection)
{
return collection.Indexes.CreateOneAsync(IndexKeys.Descending(x => x.LastModified).Ascending(x => x.AppId).Ascending(x => x.FileName).Ascending(x => x.MimeType));
return collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.AppId).Ascending(x => x.IsDeleted).Descending(x => x.LastModified).Ascending(x => x.FileName).Ascending(x => x.MimeType));
}
public async Task<bool> IsValidAsync(Guid assetId)
@ -74,7 +74,8 @@ namespace Squidex.Read.MongoDb.Assets
{
var filters = new List<FilterDefinition<MongoAssetEntity>>
{
Filter.Eq(x => x.AppId, appId)
Filter.Eq(x => x.AppId, appId),
Filter.Eq(x => x.IsDeleted, false)
};
if (ids != null && ids.Count > 0)

5
src/Squidex.Read.MongoDb/Assets/MongoAssetRepository_EventHandling.cs

@ -58,7 +58,10 @@ namespace Squidex.Read.MongoDb.Assets
protected Task On(AssetDeleted @event, EnvelopeHeaders headers)
{
return Collection.DeleteOneAsync(Filter.Eq(x => x.Id, @event.AssetId));
return Collection.UpdateAsync(@event, headers, a =>
{
a.IsDeleted = true;
});
}
}
}

2
src/Squidex.Read/Assets/IAssetEntity.cs

@ -20,6 +20,8 @@ namespace Squidex.Read.Assets
bool IsImage { get; }
bool IsDeleted { get; }
int? PixelWidth { get; }
int? PixelHeight { get; }

4
src/Squidex.Write/Assets/AssetCommandHandler.cs

@ -44,7 +44,7 @@ namespace Squidex.Write.Assets
c.Create(command);
await assetStore.UploadAsync(c.Id, 1, null, command.File.OpenRead());
await assetStore.UploadAsync(c.Id, c.Version, null, command.File.OpenRead());
context.Succeed(EntityCreatedResult.Create(c.Id, c.Version));
});
@ -58,7 +58,7 @@ namespace Squidex.Write.Assets
c.Update(command);
await assetStore.UploadAsync(c.Id, 2, null, command.File.OpenRead());
await assetStore.UploadAsync(c.Id, c.Version, null, command.File.OpenRead());
});
}

3
src/Squidex/Controllers/Api/Assets/AssetController.cs

@ -17,7 +17,6 @@ using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using NSwag.Annotations;
using Squidex.Controllers.Api.Assets.Models;
using Squidex.Controllers.Api.Schemas.Models;
using Squidex.Core.Identity;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Commands;
@ -122,7 +121,7 @@ namespace Squidex.Controllers.Api.Assets
{
var entity = await assetRepository.FindAssetAsync(id);
if (entity == null)
if (entity == null || entity.IsDeleted)
{
return NotFound();
}

3
src/Squidex/app/features/assets/pages/assets-page.component.html

@ -41,7 +41,8 @@
(loaded)="onAssetLoaded(file, $event)">
</sqx-asset>
<sqx-asset class="col-3" *ngFor="let asset of assetsItems" [asset]="asset"
(deleting)="onAssetDeleting($event)">
(deleting)="onAssetDeleting($event)"
(updated)="onAssetUpdated($event)">
</sqx-asset>
</div>

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

@ -7,16 +7,19 @@
// tslint:disable:prefer-for-of
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import {
AppComponentBase,
AppsStoreService,
AssetDto,
AssetsService,
AssetUpdated,
fadeAnimation,
ImmutableArray,
MessageBus,
NotificationService,
Pager
} from 'shared';
@ -29,7 +32,9 @@ import {
fadeAnimation
]
})
export class AssetsPageComponent extends AppComponentBase implements OnInit {
export class AssetsPageComponent extends AppComponentBase implements OnDestroy, OnInit {
private assetUpdatedSubscription: Subscription;
public newFiles = ImmutableArray.empty<File>();
public assetsItems = ImmutableArray.empty<AssetDto>();
@ -38,15 +43,28 @@ export class AssetsPageComponent extends AppComponentBase implements OnInit {
public assertQuery = '';
constructor(apps: AppsStoreService, notifications: NotificationService,
private readonly assetsService: AssetsService
private readonly assetsService: AssetsService,
private readonly messageBus: MessageBus
) {
super(notifications, apps);
}
public ngOnInit() {
this.assetUpdatedSubscription =
this.messageBus.of(AssetUpdated)
.subscribe(event => {
if (event.sender !== this) {
this.assetsItems = this.assetsItems.map(x => x.id === event.assetDto.id ? event.assetDto : x);
}
});
this.load();
}
public ngOnDestroy() {
this.assetUpdatedSubscription.unsubscribe();
}
public search() {
this.assetsPager = new Pager(0, 0, 12);
this.assertQuery = this.assetsFilter.value;
@ -83,6 +101,10 @@ export class AssetsPageComponent extends AppComponentBase implements OnInit {
this.assetsPager = this.assetsPager.incrementCount();
}
public onAssetUpdated(asset: AssetDto) {
this.messageBus.publish(new AssetUpdated(asset, this));
}
public onAssetFailed(file: File) {
this.newFiles = this.newFiles.remove(file);
}

2
src/Squidex/app/features/schemas/pages/schema/field.component.html

@ -1,5 +1,7 @@
<div class="table-items-row field">
<div class="field-summary">
<i class="icon-drag field-drag"></i>
<div class="row">
<div class="col col-6">
<span class="field-name">

13
src/Squidex/app/features/schemas/pages/schema/field.component.scss

@ -9,10 +9,21 @@ $field-header: #e7ebef;
.field {
&-summary {
padding: 1rem 1.25rem;
padding: 1rem 1.25rem 1rem 1.5rem;
position: relative;
line-height: 2.5rem;
}
&-drag {
@include absolute(0, auto, 0, 0);
z-index: 1000;
font-size: 1.4rem;
font-weight: normal;
line-height: 4.8rem;
cursor: move;
color: $color-border;
}
&-icon {
margin-right: 1rem;
color: $color-border-dark;

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

@ -22,16 +22,12 @@
<i class="icon-download"></i>
</a>
<span *ngIf="!closeMode">
<a class="file-delete" (click)="deleting.emit(asset)">
<i class="icon-delete"></i>
</a>
</span>
<span *ngIf="closeMode">
<a class="file-delete" (click)="closing.emit(asset)">
<i class="icon-close"></i>
</a>
</span>
<a class="file-delete" (click)="deleting.emit(asset)" *ngIf="!closeMode">
<i class="icon-delete"></i>
</a>
<a class="file-delete" (click)="closing.emit(asset)" *ngIf="closeMode">
<i class="icon-close"></i>
</a>
<span class="file-overlay-type" *ngIf="fileType">
{{fileType}}
@ -45,7 +41,7 @@
</div>
</div>
</div>
<div class="card-footer" dnd-draggable-handle>
<div class="card-footer" dnd-draggable-handle *ngIf="asset && progress == 0">
<div class="file-name" [attr.title]="fileName">
{{fileName}}
</div>
@ -58,7 +54,7 @@
<sqx-progress-bar mode="Circle" [value]="progress"></sqx-progress-bar>
</div>
<div class="drop-overlay">
<div class="drop-overlay" *ngIf="asset && progress == 0">
<div class="drop-overlay-background"></div>
<span class="drop-overlay-text">Drop to update</span>

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

@ -63,6 +63,9 @@ export class AssetComponent extends AppComponentBase implements OnInit {
@Output()
public closing = new EventEmitter<AssetDto>();
@Output()
public updated = new EventEmitter<AssetDto>();
@Output()
public deleting = new EventEmitter<AssetDto>();
@ -119,7 +122,7 @@ export class AssetComponent extends AppComponentBase implements OnInit {
this.notifyError(error);
});
} else {
this.updateAsset(this.asset);
this.updateAsset(this.asset, false);
}
}
@ -143,7 +146,7 @@ export class AssetComponent extends AppComponentBase implements OnInit {
result.pixelWidth,
result.pixelHeight,
result.version);
this.updateAsset(asset);
this.updateAsset(asset, true);
} else {
this.progress = result;
}
@ -181,7 +184,7 @@ export class AssetComponent extends AppComponentBase implements OnInit {
this.asset.pixelHeight,
this.asset.version);
this.updateAsset(asset);
this.updateAsset(asset, true);
this.resetRename();
}, error => {
this.notifyError(error);
@ -198,7 +201,7 @@ export class AssetComponent extends AppComponentBase implements OnInit {
this.renameDialog.hide();
}
private updateAsset(asset: AssetDto) {
private updateAsset(asset: AssetDto, emitEvent: boolean) {
this.asset = asset;
this.fileUrl = FileHelper.assetUrl(this.apiUrl, asset);
this.fileInfo = FileHelper.assetInfo(asset);
@ -209,6 +212,10 @@ export class AssetComponent extends AppComponentBase implements OnInit {
this.previewUrl = FileHelper.assetPreviewUrl(this.apiUrl, asset);
this.version = asset.version;
if (emitEvent) {
this.updated.emit(asset);
}
this.resetRename();
}
}

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

@ -11,7 +11,8 @@
(loaded)="onAssetLoaded(file, $event)">
</sqx-asset>
<sqx-asset class="col-4" *ngFor="let asset of oldAssets" [asset]="asset" [closeMode]="true"
(closing)="onAssetRemoving($event)">
(closing)="onAssetRemoving($event)"
(updated)="onAssetUpdated($event)">
</sqx-asset>
</div>
</div>

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

@ -17,6 +17,7 @@
.drop-area {
& {
@include transition(border-color .4s ease);
@include border-radius;
border: 2px dashed $color-border;
height: $asset-height;
font-size: 1.2rem;

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

@ -7,8 +7,9 @@
// tslint:disable:prefer-for-of
import { Component, forwardRef } from '@angular/core';
import { Component, forwardRef, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subscription } from 'rxjs';
import { AppComponentBase } from './app.component-base';
@ -16,7 +17,9 @@ import {
AppsStoreService,
AssetDto,
AssetsService,
AssetUpdated,
ImmutableArray,
MessageBus,
NotificationService
} from './../declarations-base';
@ -32,7 +35,9 @@ export const SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
templateUrl: './assets-editor.component.html',
providers: [SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR]
})
export class AssetsEditorComponent extends AppComponentBase implements ControlValueAccessor {
export class AssetsEditorComponent extends AppComponentBase implements ControlValueAccessor, OnDestroy, OnInit {
private assetUpdatedSubscription: Subscription;
public newAssets = ImmutableArray.empty<File>();
public oldAssets = ImmutableArray.empty<AssetDto>();
@ -42,11 +47,26 @@ export class AssetsEditorComponent extends AppComponentBase implements ControlVa
public isDisabled = false;
constructor(apps: AppsStoreService, notifications: NotificationService,
private readonly assetsService: AssetsService
private readonly assetsService: AssetsService,
private readonly messageBus: MessageBus
) {
super(notifications, apps);
}
public ngOnInit() {
this.assetUpdatedSubscription =
this.messageBus.of(AssetUpdated)
.subscribe(event => {
if (event.sender !== this) {
this.oldAssets = this.oldAssets.map(x => x.id === event.assetDto.id ? event.assetDto : x);
}
});
}
public ngOnDestroy() {
this.assetUpdatedSubscription.unsubscribe();
}
public writeValue(value: any) {
this.oldAssets = ImmutableArray.empty<AssetDto>();
@ -90,6 +110,10 @@ export class AssetsEditorComponent extends AppComponentBase implements ControlVa
this.updateValue();
}
public onAssetUpdated(asset: AssetDto) {
this.messageBus.publish(new AssetUpdated(asset, this));
}
public onAssetRemoving(asset: AssetDto) {
this.oldAssets = this.oldAssets.remove(asset);
}

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

@ -7,7 +7,6 @@
import { Injectable } from '@angular/core';
import { Headers, Http, RequestOptions, Response } from '@angular/http';
import { Router } from '@angular/router';
import { Observable, Subject } from 'rxjs';
import {
@ -67,8 +66,7 @@ export class AuthService {
}
constructor(apiUrl: ApiUrlConfig,
private readonly http: Http,
private readonly router: Router
private readonly http: Http
) {
if (!apiUrl) {
return;
@ -205,14 +203,16 @@ export class AuthService {
}
})
.catch((error: Response) => {
if (error.status === 401) {
if (error.status >= 401 && error.status <= 404 && (!this.user || this.user.user.expired)) {
this.logoutRedirect();
return Observable.empty<Response>();
} else if (error.status === 403) {
this.router.navigate(['/404']);
} else if (error.status === 401) {
this.logoutRedirect();
return Observable.empty<Response>();
} else if (error.status === 403) {
error.status = 404;
}
return Observable.throw(error);
});

12
src/Squidex/app/shared/utils/messages.ts

@ -5,4 +5,14 @@
* Copyright (c) Sebastian Stehle. All rights reserved
*/
export class HistoryChannelUpdated { }
import { AssetDto } from './../services/assets.service';
export class HistoryChannelUpdated { }
export class AssetUpdated {
constructor(
public readonly assetDto: AssetDto,
public readonly sender: any
) {
}
}

4
src/Squidex/package.json

@ -48,7 +48,7 @@
"@types/node": "7.0.5",
"angular2-router-loader": "0.3.5",
"angular2-template-loader": "0.6.2",
"awesome-typescript-loader": "3.1.2",
"awesome-typescript-loader": "3.1.3",
"cpx": "1.5.0",
"css-loader": "0.28.0",
"exports-loader": "0.6.4",
@ -79,7 +79,7 @@
"tslint": "4.5.1",
"tslint-loader": "3.5.3",
"typemoq": "1.5.0",
"typescript": "2.3.1",
"typescript": "2.3.2",
"underscore": "1.8.3",
"webpack": "2.4.1",
"webpack-dev-server": "2.4.5",

Loading…
Cancel
Save