mirror of
https://github.com/clearml/clearml-web
synced 2025-03-13 07:08:17 +00:00
Add delete artifact button. Refactor for updated Angular.
This commit is contained in:
parent
e4af78213d
commit
a982ad6c45
@ -27,6 +27,11 @@ import {MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltipDefaultOptions} from '@angular/ma
|
||||
import {UpdateNotifierComponent} from '@common/shared/ui-components/overlay/update-notifier/update-notifier.component';
|
||||
import {ChooseColorModule} from '@common/shared/ui-components/directives/choose-color/choose-color.module';
|
||||
import {SpinnerComponent} from '@common/shared/ui-components/overlay/spinner/spinner.component';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { UploadArtifactDialogComponent } from '@common/shared/ui-components/overlay/upload-artifact-dialog/upload-artifact-dialog.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations : [AppComponent],
|
||||
@ -61,6 +66,10 @@ import {SpinnerComponent} from '@common/shared/ui-components/overlay/spinner/spi
|
||||
UpdateNotifierComponent,
|
||||
ChooseColorModule,
|
||||
SpinnerComponent,
|
||||
MatButtonModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
UploadArtifactDialogComponent
|
||||
],
|
||||
providers : [
|
||||
UserPreferences,
|
||||
|
@ -18,6 +18,7 @@
|
||||
</sm-labeled-row>
|
||||
<sm-labeled-row label="FILE SIZE" data-id="fileSizeId">{{(artifact?.content_size | filesize : fileSizeConfigStorage) || ''}}</sm-labeled-row>
|
||||
<sm-labeled-row label="HASH" data-id="hashId">{{artifact?.hash}}</sm-labeled-row>
|
||||
<sm-labeled-row label="MODE" data-id="modeId">{{artifact?.mode | titlecase}}</sm-labeled-row>
|
||||
<sm-labeled-row *ngFor="let data of artifact?.display_data" [label]="data[0]| uppercase">{{data[1]}}</sm-labeled-row>
|
||||
</div>
|
||||
</sm-editable-section>
|
||||
@ -32,5 +33,5 @@
|
||||
[formData]="artifact?.type_data?.preview"
|
||||
></sm-scroll-textarea>
|
||||
</sm-editable-section>
|
||||
|
||||
<button *ngIf="enableDeleteButton()" class="btn btn-neon" style="margin: auto;" (click)="deleteArtifact(artifact?.key, artifact?.mode)">DELETE ARTIFACT</button>
|
||||
|
||||
|
@ -1,12 +1,27 @@
|
||||
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, Input, Inject} from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import {Artifact} from '~/business-logic/model/tasks/artifact';
|
||||
import {BaseClickableArtifactComponent} from '../base-clickable-artifact.component';
|
||||
import {fileSizeConfigStorage} from '@common/shared/pipes/filesize.pipe';
|
||||
import { ApiTasksService } from '~/business-logic/api-services/tasks.service';
|
||||
import { ConfirmDialogComponent } from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { addMessage } from '@common/core/actions/layout.actions';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { IExperimentInfo } from '~/features/experiments/shared/experiment-info.model';
|
||||
import { selectExperimentInfoData } from '~/features/experiments/reducers';
|
||||
import { ArtifactId } from '~/business-logic/model/tasks/artifactId';
|
||||
import { deleteS3Sources } from '@common/shared/entity-page/entity-delete/common-delete-dialog.actions';
|
||||
import { EXPERIMENTS_STATUS_LABELS } from '~/features/experiments/shared/experiments.const';
|
||||
|
||||
@Component({
|
||||
selector: 'sm-experiment-artifact-item-view',
|
||||
templateUrl: './experiment-artifact-item-view.component.html',
|
||||
styleUrls: ['./experiment-artifact-item-view.component.scss'],
|
||||
providers: [
|
||||
{ provide: MAT_DIALOG_DATA, useValue: {} },
|
||||
{ provide: MatDialogRef, useValue: {} }
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ExperimentArtifactItemViewComponent extends BaseClickableArtifactComponent{
|
||||
@ -14,11 +29,28 @@ export class ExperimentArtifactItemViewComponent extends BaseClickableArtifactCo
|
||||
public isLinkable: boolean;
|
||||
public fileSizeConfigStorage = fileSizeConfigStorage;
|
||||
public inMemorySize: boolean;
|
||||
public experimentInfo$: Observable<IExperimentInfo>;
|
||||
private _artifact: Artifact;
|
||||
private artifactId: ArtifactId;
|
||||
private _experiment: any;
|
||||
|
||||
@Input() editable: boolean;
|
||||
@Input() downloading: boolean;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data: ConfirmDialogComponent,
|
||||
public dialogRef: MatDialogRef<ConfirmDialogComponent>,
|
||||
private dialog: MatDialog,
|
||||
private tasksApi: ApiTasksService,
|
||||
){
|
||||
super();
|
||||
this.experimentInfo$ = this.store.select(selectExperimentInfoData);
|
||||
this.artifactId = {key: '', mode: 'output'};
|
||||
this.experimentInfo$.subscribe((res) => {
|
||||
this._experiment = res;
|
||||
});
|
||||
}
|
||||
|
||||
@Input() set artifact(artifact: Artifact) {
|
||||
this._artifact = artifact;
|
||||
if(artifact){
|
||||
@ -39,6 +71,14 @@ export class ExperimentArtifactItemViewComponent extends BaseClickableArtifactCo
|
||||
return this._artifact;
|
||||
}
|
||||
|
||||
getStatusLabel() {
|
||||
return EXPERIMENTS_STATUS_LABELS[this._experiment?.status] || '';
|
||||
}
|
||||
|
||||
enableDeleteButton() {
|
||||
return this.getStatusLabel() === 'Draft';
|
||||
}
|
||||
|
||||
linkClicked(event: Event) {
|
||||
this.signUrl(this.artifact.uri).subscribe(signed => {
|
||||
const a = document.createElement('a');
|
||||
@ -48,4 +88,34 @@ export class ExperimentArtifactItemViewComponent extends BaseClickableArtifactCo
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
deleteArtifact(key, mode) {
|
||||
this.artifactId = {key: key, mode: mode};
|
||||
const confirmDialogRef: MatDialogRef<any, boolean> = this.dialog.open(ConfirmDialogComponent, {
|
||||
data: {
|
||||
title: 'Delete Artifact',
|
||||
body: 'Are you sure you want to delete artifact ' + key + ' from the experiment and S3?<br /><strong>This cannot be undone.</strong>',
|
||||
yes: 'Delete',
|
||||
no: 'Cancel',
|
||||
iconClass: 'al-icon al-ico-trash al-color blue-300',
|
||||
}
|
||||
});
|
||||
|
||||
confirmDialogRef.afterClosed().pipe(take(1)).subscribe((confirmed) => {
|
||||
if (confirmed) {
|
||||
this.tasksApi.tasksDeleteArtifacts({
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
task: this._experiment.id,
|
||||
artifacts: [this.artifactId]
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
}, null, 'body', true).subscribe({
|
||||
next: () => {
|
||||
this.store.dispatch(deleteS3Sources({files: [this.artifact.uri]}))
|
||||
},
|
||||
error: err => this.store.dispatch(addMessage('error', `Error ${err.error?.meta?.result_msg}`)),
|
||||
complete: () => this.store.dispatch(addMessage('success', 'Artifact deleted successfully.')),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ export class BaseAdminService {
|
||||
Bucket: bucketKeyEndpoint.Bucket,
|
||||
Delete: {
|
||||
Quiet: true,
|
||||
Objects: files.map(file => ({Key: file} as ObjectIdentifier))
|
||||
Objects: files.map(() => ({Key: bucketKeyEndpoint.Key} as ObjectIdentifier))
|
||||
}
|
||||
});
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component, Inject, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { FormsModule, ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { addMessage } from '@common/core/actions/layout.actions';
|
||||
import { UploadArtifactDialogConfig, ArtifactType } from './upload-artifact-dialog.model';
|
||||
@ -15,11 +15,30 @@ import { getSignedUrl } from '@common/core/actions/common-auth.actions';
|
||||
import { selectExperimentExecutionInfoData } from '@common/experiments/reducers';
|
||||
import { ArtifactModeEnum } from '~/business-logic/model/tasks/artifactModeEnum';
|
||||
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component';
|
||||
import { DialogTemplateComponent } from '@common/shared/ui-components/overlay/dialog-template/dialog-template.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { SafePipe } from '@common/shared/pipes/safe.pipe';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
|
||||
@Component({
|
||||
selector: 'sm-upload-artifact-dialog',
|
||||
templateUrl: './upload-artifact-dialog.component.html',
|
||||
styleUrls: ['./upload-artifact-dialog.component.scss']
|
||||
styleUrls: ['./upload-artifact-dialog.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
SafePipe,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
DialogTemplateComponent,
|
||||
CommonModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
MatRadioModule,
|
||||
]
|
||||
})
|
||||
export class UploadArtifactDialogComponent implements OnInit, OnDestroy {
|
||||
artifactType: ArtifactType[] = [
|
||||
@ -216,7 +235,7 @@ export class UploadArtifactDialogComponent implements OnInit, OnDestroy {
|
||||
type: this.uploadForm.controls['artType'].value,
|
||||
content_size: item.size,
|
||||
timestamp: ts,
|
||||
hash: 'SHA256: ' + fileHash,
|
||||
hash: fileHash,
|
||||
uri: this.uploadUrl + item.name,
|
||||
mode: this.uploadForm.controls['mode'].value as ArtifactModeEnum
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user