Skip to content

Commit

Permalink
feat(admin-ui): Implement Asset deletion UI
Browse files Browse the repository at this point in the history
Closes #285
  • Loading branch information
michaelbromley committed Apr 7, 2020
1 parent c80662a commit 4912a29
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<vdr-asset-gallery
[assets]="(items$ | async)! | paginate: (paginationConfig$ | async) || {}"
[multiSelect]="true"
[canDelete]="'DeleteCatalog' | hasPermission"
(deleteAsset)="deleteAsset($event)"
></vdr-asset-gallery>

<div class="paging-controls">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { BaseListComponent, DataService, GetAssetList, NotificationService } from '@vendure/admin-ui/core';
import {
Asset,
BaseListComponent,
DataService,
DeletionResult,
GetAssetList,
ModalService,
NotificationService,
} from '@vendure/admin-ui/core';
import { SortOrder } from '@vendure/common/lib/generated-shop-types';
import { PaginationInstance } from 'ngx-pagination';
import { combineLatest, Observable } from 'rxjs';
import { debounceTime, map, takeUntil } from 'rxjs/operators';
import { combineLatest, EMPTY, Observable } from 'rxjs';
import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators';

@Component({
selector: 'vdr-asset-list',
Expand All @@ -20,14 +28,15 @@ export class AssetListComponent extends BaseListComponent<GetAssetList.Query, Ge

constructor(
private notificationService: NotificationService,
private modalService: ModalService,
private dataService: DataService,
router: Router,
route: ActivatedRoute,
) {
super(router, route);
super.setQueryFn(
(...args: any[]) => this.dataService.product.getAssetList(...args),
data => data.assets,
(data) => data.assets,
(skip, take) => ({
options: {
skip,
Expand All @@ -51,21 +60,62 @@ export class AssetListComponent extends BaseListComponent<GetAssetList.Query, Ge
map(([itemsPerPage, currentPage, totalItems]) => ({ itemsPerPage, currentPage, totalItems })),
);
this.searchTerm.valueChanges
.pipe(
debounceTime(250),
takeUntil(this.destroy$),
)
.pipe(debounceTime(250), takeUntil(this.destroy$))
.subscribe(() => this.refresh());
}

filesSelected(files: File[]) {
if (files.length) {
this.dataService.product.createAssets(files).subscribe(res => {
this.dataService.product.createAssets(files).subscribe((res) => {
super.refresh();
this.notificationService.success(_('asset.notify-create-assets-success'), {
count: files.length,
});
});
}
}

deleteAsset(asset: Asset) {
this.showModalAndDelete(asset.id)
.pipe(
switchMap((response) => {
if (response.result === DeletionResult.DELETED) {
return [true];
} else {
return this.showModalAndDelete(asset.id, response.message || '').pipe(
map((r) => r.result === DeletionResult.DELETED),
);
}
}),
)
.subscribe(
() => {
this.notificationService.success(_('common.notify-delete-success'), {
entity: 'Asset',
});
this.refresh();
},
(err) => {
this.notificationService.error(_('common.notify-delete-error'), {
entity: 'Asset',
});
},
);
}

private showModalAndDelete(assetId: string, message?: string) {
return this.modalService
.dialog({
title: _('catalog.confirm-delete-facet'),
body: message,
buttons: [
{ type: 'secondary', label: _('common.cancel') },
{ type: 'danger', label: _('common.delete'), returnValue: true },
],
})
.pipe(
switchMap((res) => (res ? this.dataService.product.deleteAsset(assetId, !!message) : EMPTY)),
map((res) => res.deleteAsset),
);
}
}
20 changes: 20 additions & 0 deletions packages/admin-ui/src/lib/core/src/common/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4982,6 +4982,20 @@ export type UpdateAssetMutation = (
) }
);

export type DeleteAssetMutationVariables = {
id: Scalars['ID'];
force?: Maybe<Scalars['Boolean']>;
};


export type DeleteAssetMutation = (
{ __typename?: 'Mutation' }
& { deleteAsset: (
{ __typename?: 'DeletionResponse' }
& Pick<DeletionResponse, 'result' | 'message'>
) }
);

export type SearchProductsQueryVariables = {
input: SearchInput;
};
Expand Down Expand Up @@ -6933,6 +6947,12 @@ export namespace UpdateAsset {
export type UpdateAsset = AssetFragment;
}

export namespace DeleteAsset {
export type Variables = DeleteAssetMutationVariables;
export type Mutation = DeleteAssetMutation;
export type DeleteAsset = DeleteAssetMutation['deleteAsset'];
}

export namespace SearchProducts {
export type Variables = SearchProductsQueryVariables;
export type Query = SearchProductsQuery;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,15 @@ export const UPDATE_ASSET = gql`
${ASSET_FRAGMENT}
`;

export const DELETE_ASSET = gql`
mutation DeleteAsset($id: ID!, $force: Boolean) {
deleteAsset(id: $id, force: $force) {
result
message
}
}
`;

export const SEARCH_PRODUCTS = gql`
query SearchProducts($input: SearchInput!) {
search(input: $input) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
CreateProductOptionInput,
CreateProductVariantInput,
CreateProductVariants,
DeleteAsset,
DeleteProduct,
DeleteProductVariant,
GetAsset,
Expand Down Expand Up @@ -45,6 +46,7 @@ import {
CREATE_PRODUCT,
CREATE_PRODUCT_OPTION_GROUP,
CREATE_PRODUCT_VARIANTS,
DELETE_ASSET,
DELETE_PRODUCT,
DELETE_PRODUCT_VARIANT,
GET_ASSET,
Expand Down Expand Up @@ -272,7 +274,7 @@ export class ProductDataService {

createAssets(files: File[]) {
return this.baseDataService.mutate<CreateAssets.Mutation, CreateAssets.Variables>(CREATE_ASSETS, {
input: files.map(file => ({ file })),
input: files.map((file) => ({ file })),
});
}

Expand All @@ -282,6 +284,13 @@ export class ProductDataService {
});
}

deleteAsset(id: string, force: boolean) {
return this.baseDataService.mutate<DeleteAsset.Mutation, DeleteAsset.Variables>(DELETE_ASSET, {
id,
force,
});
}

assignProductsToChannel(input: AssignProductsToChannelInput) {
return this.baseDataService.mutate<
AssignProductsToChannel.Mutation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,19 @@
</div>
<div>
<button (click)="previewAsset(lastSelected())" class="btn btn-link">
{{ 'asset.preview' | translate }}
<clr-icon shape="eye"></clr-icon> {{ 'asset.preview' | translate }}
</button>
</div>
<div>
<a [routerLink]="['./', lastSelected().id]" class="btn btn-link">
{{ 'common.edit' | translate }}
<clr-icon shape="pencil"></clr-icon> {{ 'common.edit' | translate }}
</a>
</div>
<div *ngIf="selection.length === 1 && canDelete">
<button (click)="deleteAsset.emit(lastSelected())" class="btn btn-link">
<clr-icon shape="trash" class="is-danger"></clr-icon> {{ 'common.delete' | translate }}
</button>
</div>
</div>
</div>
<div class="card stack" [class.visible]="selection.length > 1"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ export class AssetGalleryComponent implements OnChanges {
* If true, allows multiple assets to be selected by ctrl+clicking.
*/
@Input() multiSelect = false;
@Input() canDelete = false;
@Output() selectionChange = new EventEmitter<Asset[]>();
@Output() deleteAsset = new EventEmitter<Asset>();

selection: Asset[] = [];

Expand All @@ -26,7 +28,7 @@ export class AssetGalleryComponent implements OnChanges {
if (this.assets) {
for (const asset of this.selection) {
// Update and selected assets with any changes
const match = this.assets.find(a => a.id === asset.id);
const match = this.assets.find((a) => a.id === asset.id);
if (match) {
Object.assign(asset, match);
}
Expand All @@ -35,7 +37,7 @@ export class AssetGalleryComponent implements OnChanges {
}

toggleSelection(event: MouseEvent, asset: Asset) {
const index = this.selection.findIndex(a => a.id === asset.id);
const index = this.selection.findIndex((a) => a.id === asset.id);
if (index === -1) {
if (this.multiSelect && event.ctrlKey) {
this.selection.push(asset);
Expand All @@ -55,7 +57,7 @@ export class AssetGalleryComponent implements OnChanges {
}

isSelected(asset: Asset): boolean {
return !!this.selection.find(a => a.id === asset.id);
return !!this.selection.find((a) => a.id === asset.id);
}

lastSelected(): Asset {
Expand Down

0 comments on commit 4912a29

Please sign in to comment.