Browse Source

Quick links to asset folders. (#603)

pull/604/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
e776b1ffe6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      backend/i18n/frontend_en.json
  2. 1
      backend/i18n/frontend_it.json
  3. 1
      backend/i18n/frontend_nl.json
  4. 1
      backend/i18n/source/frontend_en.json
  5. 36
      frontend/app/shared/components/assets/asset-dialog.component.html
  6. 12
      frontend/app/shared/components/assets/asset-dialog.component.scss
  7. 18
      frontend/app/shared/components/assets/asset-dialog.component.ts
  8. 12
      frontend/app/shared/components/assets/asset-path.component.html
  9. 4
      frontend/app/shared/components/assets/asset-path.component.scss
  10. 5
      frontend/app/shared/components/assets/asset-path.component.ts
  11. 8
      frontend/app/shared/components/assets/asset-uploader.component.html
  12. 21
      frontend/app/shared/components/assets/asset.component.html
  13. 4
      frontend/app/shared/components/assets/asset.component.scss
  14. 3
      frontend/app/shared/components/assets/asset.component.ts
  15. 3
      frontend/app/shared/components/assets/assets-list.component.html
  16. 4
      frontend/app/shared/components/assets/assets-list.component.ts
  17. 4
      frontend/app/shared/components/assets/pipes.ts
  18. 4
      frontend/app/shared/state/assets.state.ts

1
backend/i18n/frontend_en.json

@ -246,6 +246,7 @@
"common.field": "Field",
"common.files": "Files",
"common.filters": "Filters",
"common.folder": "Folder",
"common.folders": "Folders",
"common.generalSettings": "Common",
"common.generate": "Generate",

1
backend/i18n/frontend_it.json

@ -246,6 +246,7 @@
"common.field": "Campo",
"common.files": "Campi",
"common.filters": "Filtri",
"common.folder": "Folder",
"common.folders": "Cartelle",
"common.generalSettings": "Impostazioni generali",
"common.generate": "Genera",

1
backend/i18n/frontend_nl.json

@ -246,6 +246,7 @@
"common.field": "Veld",
"common.files": "Bestanden",
"common.filters": "Filters",
"common.folder": "Folder",
"common.folders": "Mappen",
"common.generalSettings": "Algemeen",
"common.generate": "Genereren",

1
backend/i18n/source/frontend_en.json

@ -246,6 +246,7 @@
"common.field": "Field",
"common.files": "Files",
"common.filters": "Filters",
"common.folder": "Folder",
"common.folders": "Folders",
"common.generalSettings": "Common",
"common.generate": "Generate",

36
frontend/app/shared/components/assets/asset-dialog.component.html

@ -33,7 +33,11 @@
<sqx-image-editor [imageSource]="asset | sqxAssetPreviewUrl"></sqx-image-editor>
<div class="image-progress" *ngIf="progress > 0">
<sqx-progress-bar [strokeWidth]="2" [trailColor]="'transparent'" [trailWidth]="0" [value]="progress">
<sqx-progress-bar
[value]="progress"
[strokeWidth]="2"
[trailColor]="'transparent'"
[trailWidth]="0">
</sqx-progress-bar>
</div>
</div>
@ -43,15 +47,28 @@
<sqx-image-focus-point [imageSource]="asset | sqxAssetPreviewUrl" [focusPoint]="asset.metadata"></sqx-image-focus-point>
<div class="image-progress" *ngIf="progress > 0">
<sqx-progress-bar [strokeWidth]="2" [trailColor]="'transparent'" [trailWidth]="0" [value]="progress">
<sqx-progress-bar
[value]="progress"
[strokeWidth]="2"
[trailColor]="'transparent'"
[trailWidth]="0">
</sqx-progress-bar>
</div>
</div>
</ng-container>
<ng-container *ngSwitchCase="'i18n:assets.tabMetadata'">
<div class="metadata">
<sqx-form-error [error]="annotateForm.error | async"></sqx-form-error>
<div class="form-group no-gutters">
<label for="id">{{ 'common.folder' | sqxTranslate }}</label>
<div class="path">
<sqx-asset-path [path]="path | async" all="true" (navigate)="navigate($event.id)"></sqx-asset-path>
</div>
</div>
<div class="form-group no-gutters">
<label for="id">{{ 'common.id' | sqxTranslate }}</label>
@ -67,6 +84,21 @@
</div>
</div>
<div class="form-group no-gutters">
<label for="url">{{ 'common.url' | sqxTranslate }}</label>
<div class="row no-gutters">
<div class="col">
<input readonly class="form-control" name="url" id="url" value="{{asset | sqxAssetUrl:asset.fileVersion:false}}" #inputUrl>
</div>
<div class="col-auto">
<button type="button" class="btn btn-text" [sqxCopy]="inputUrl">
<i class="icon-copy"></i>
</button>
</div>
</div>
</div>
<div class="form-group">
<label for="fileName">{{ 'common.name' | sqxTranslate }}</label>

12
frontend/app/shared/components/assets/asset-dialog.component.scss

@ -22,16 +22,20 @@
}
}
.invisible {
visibility: hidden;
}
.metadata {
margin: 1rem auto;
max-width: 500px;
min-width: 0;
}
.invisible {
visibility: hidden;
}
.path {
min-height: 2.5rem;
}
.slug {
padding-right: 6rem;
}

18
frontend/app/shared/components/assets/asset-dialog.component.ts

@ -7,7 +7,11 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, QueryList, ViewChildren } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { AnnotateAssetDto, AnnotateAssetForm, AssetDto, AssetsState, AssetUploaderState, AuthService, DialogService, Types, UploadCanceled } from '@app/shared/internal';
import { AnnotateAssetDto, AnnotateAssetForm, AppsState, AssetDto, AssetsState, AssetUploaderState, AuthService, DialogService, Types, UploadCanceled } from '@app/shared/internal';
import { AssetsService } from '@app/shared/services/assets.service';
import { AssetPathItem, ROOT_ITEM } from '@app/shared/state/assets.state';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ImageCropperComponent } from './image-cropper.component';
import { ImageFocusPointComponent } from './image-focus-point.component';
@ -48,6 +52,8 @@ export class AssetDialogComponent implements OnChanges {
@ViewChildren(ImageFocusPointComponent)
public imageFocus: QueryList<ImageFocusPointComponent>;
public path: Observable<ReadonlyArray<AssetPathItem>>;
public isEditable = false;
public isEditableAny = false;
public isUploadable = false;
@ -60,8 +66,10 @@ export class AssetDialogComponent implements OnChanges {
public annotateForm = new AnnotateAssetForm(this.formBuilder);
constructor(
private readonly appsState: AppsState,
private readonly assetsState: AssetsState,
private readonly assetUploader: AssetUploaderState,
private readonly assetsService: AssetsService,
private readonly changeDetector: ChangeDetectorRef,
private readonly dialogs: DialogService,
private readonly formBuilder: FormBuilder,
@ -85,6 +93,14 @@ export class AssetDialogComponent implements OnChanges {
if (this.selectableTabs.indexOf(this.selectedTab) < 0) {
this.selectTab(this.selectableTabs[0]);
}
this.path =
this.assetsService.getAssetFolders(this.appsState.appName, this.asset.parentId).pipe(
map(folders => [ROOT_ITEM, ...folders.path]));
}
public navigate(id: string) {
this.assetsState.navigate(id);
}
public selectTab(tab: string) {

12
frontend/app/shared/components/assets/asset-path.component.html

@ -1,12 +1,14 @@
<ng-container *ngIf="path.length === 0; else normalPath">
<ng-container *ngIf="path">
<ng-container *ngIf="path.length === 0; else normalPath">
<span class="btn">{{ 'common.searchResults' | sqxTranslate }}</span>
</ng-container>
<ng-template #normalPath>
</ng-container>
<ng-template #normalPath>
<ng-container *ngFor="let item of path; let i = index">
<i class="icon-angle-right" *ngIf="i > 0"></i>
<a class="btn" (click)="navigate.emit(item)" [class.force]="i < path.length - 1">
<a class="btn" (click)="navigate.emit(item)" [class.force]="i < path.length - 1 || all" [class.first]="i === 0">
{{item.folderName | sqxTranslate}}
</a>
</ng-container>
</ng-template>
</ng-template>
</ng-container>

4
frontend/app/shared/components/assets/asset-path.component.scss

@ -1,3 +1,7 @@
i {
vertical-align: middle;
}
.first {
padding-left: 0;
}

5
frontend/app/shared/components/assets/asset-path.component.ts

@ -19,5 +19,8 @@ export class AssetPathComponent {
public navigate = new EventEmitter<AssetPathItem>();
@Input()
public path: ReadonlyArray<AssetPathItem>;
public path?: ReadonlyArray<AssetPathItem>;
@Input()
public all = false;
}

8
frontend/app/shared/components/assets/asset-uploader.component.html

@ -31,7 +31,13 @@
<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>
<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)">

21
frontend/app/shared/components/assets/asset.component.html

@ -30,10 +30,14 @@
<i class="icon-pencil"></i>
</a>
<a class="file-download ml-2" [href]="asset | sqxAssetUrl" sqxStopClick sqxExternalLink="noicon">
<a class="file-download ml-2" [href]="asset | sqxAssetUrl:asset.fileVersion:false" sqxStopClick sqxExternalLink="noicon">
<i class="icon-download"></i>
</a>
<a class="file-folder ml-2" (click)="selectFolder.emit(asset.parentId)">
<i class="icon-folder"></i>
</a>
<ng-container *ngIf="!isDisabled">
<a class="file-delete ml-2" *ngIf="!removeMode && asset.canDelete"
(sqxConfirmClick)="delete.emit()"
@ -135,13 +139,17 @@
<img class="user-picture" title="{{asset.lastModifiedBy | sqxUserNameRef}}" [src]="asset.lastModifiedBy | sqxUserPictureRef">
</td>
<td class="col-actions text-right">
<a class="btn btn-text-secondary" [href]="asset | sqxAssetUrl" sqxStopClick sqxExternalLink="noicon">
<a class="btn btn-text-secondary" [href]="asset | sqxAssetUrl:asset.fileVersion:false" sqxStopClick sqxExternalLink="noicon">
<i class="icon-download"></i>
</a>
<button type="button" class="btn btn-text-secondary" (click)="selectFolder.emit(asset.parentId)">
<i class="icon-folder"></i>
</button>
</td>
</ng-container>
<td class="col-actions text-right">
<td class="col-delete text-right">
<button type="button" class="btn btn-text-danger" *ngIf="!removeMode && asset.canDelete" [disabled]="isDisabled"
(sqxConfirmClick)="delete.emit()"
confirmTitle="i18n:assets.deleteConfirmTitle"
@ -168,7 +176,12 @@
</ng-container>
<div class="upload-progress" *ngIf="progress > 0">
<sqx-progress-bar [value]="progress" [trailWidth]="0.8" [strokeWidth]="0.8" [showText]="false"></sqx-progress-bar>
<sqx-progress-bar
[value]="progress"
[trailWidth]="0.8"
[strokeWidth]="0.8"
[showText]="false">
</sqx-progress-bar>
</div>
</div>
</ng-template>

4
frontend/app/shared/components/assets/asset.component.scss

@ -235,6 +235,10 @@ $list-height: 2.25rem;
}
&-actions {
width: 6rem;
}
&-delete {
width: 3rem;
}

3
frontend/app/shared/components/assets/asset.component.ts

@ -30,6 +30,9 @@ export class AssetComponent implements OnInit {
@Output()
public select = new EventEmitter();
@Output()
public selectFolder = new EventEmitter<string>();
@Input()
public assetFile: File;

3
frontend/app/shared/components/assets/assets-list.component.html

@ -78,7 +78,8 @@
[isSelectable]="!!selectedIds"
[isSelected]="isSelected(asset)"
[allTags]="tags"
(select)="select.emit(asset)" (delete)="deleteAsset(asset)">
(select)="select.emit(asset)" (delete)="deleteAsset(asset)"
(selectFolder)="selectFolder(asset)">
</sqx-asset>
</div>
</ng-container>

4
frontend/app/shared/components/assets/assets-list.component.ts

@ -70,6 +70,10 @@ export class AssetsListComponent {
}
}
public selectFolder(asset: AssetDto) {
this.state.navigate(asset.parentId);
}
public deleteAsset(asset: AssetDto) {
this.state.deleteAsset(asset);
}

4
frontend/app/shared/components/assets/pipes.ts

@ -18,10 +18,12 @@ export class AssetUrlPipe implements PipeTransform {
) {
}
public transform(asset: AssetDto, version?: number): string {
public transform(asset: AssetDto, version?: number, withQuery = false): string {
let url = asset.fullUrl(this.apiUrl);
if (withQuery) {
url = StringHelper.appendToUrl(url, 'sq', MathHelper.guid());
}
if (Types.isNumber(version)) {
url = StringHelper.appendToUrl(url, 'version', version);

4
frontend/app/shared/state/assets.state.ts

@ -21,7 +21,7 @@ export type Tag = { name: string, count: number; };
const EMPTY_FOLDERS: { canCreate: boolean, items: ReadonlyArray<AssetFolderDto>, path?: ReadonlyArray<AssetFolderDto> } = { canCreate: false, items: [] };
const ROOT_ITEM: AssetPathItem = { id: MathHelper.EMPTY_GUID, folderName: 'i18n:assets.specialFolder.root' };
export const ROOT_ITEM: AssetPathItem = { id: MathHelper.EMPTY_GUID, folderName: 'i18n:assets.specialFolder.root' };
interface Snapshot {
// All assets tags.
@ -367,7 +367,7 @@ export class AssetsState extends State<Snapshot> {
}
public navigate(parentId: string) {
this.next({ parentId });
this.next({ parentId, assetsQuery: undefined, tagsSelected: {} });
return this.loadInternal(false);
}

Loading…
Cancel
Save