-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add edit and delete functions for template details in templates page
- Loading branch information
Showing
7 changed files
with
238 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/app/components-small/ui-template/ui-template.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<mat-card appearance="outlined" class="card" *ngIf="templateData != null"> | ||
<mat-card-title class="t-headline header"> | ||
<div [hidden]="isEditing"> | ||
UI Template: {{templateData.name}} | ||
</div> | ||
<mat-form-field class="name-field" [hidden]="!isEditing"> | ||
<mat-label>UI Template Name:</mat-label> | ||
<input matInput [(ngModel)]="currentName"> | ||
</mat-form-field> | ||
<div class="header-buttons"> | ||
<button mat-stroked-button (click)="updateTemplate()" *ngIf="isDirty"><mat-icon>save</mat-icon>save</button> | ||
<button mat-icon-button (click)="toggleEdit()" *ngIf="templateUpdateLink != null"><mat-icon>{{isEditing ? 'edit_off' : 'edit'}}</mat-icon></button> | ||
<button mat-icon-button (click)="deleteTemplate()" color="warn" *ngIf="templateDeleteLink != null"><mat-icon>delete</mat-icon></button> | ||
</div> | ||
</mat-card-title> | ||
<mat-card-content class="content"> | ||
<mat-chip-set class="tags" [hidden]="isEditing"> | ||
<mat-chip *ngFor="let tag of templateData.tags">{{tag}}</mat-chip> | ||
</mat-chip-set> | ||
<mat-form-field class="tags-field" *ngIf="isEditing"> | ||
<mat-label>Tags</mat-label> | ||
<mat-chip-grid #chipGrid> | ||
@for (tag of currentTags; track tag) { | ||
<mat-chip-row | ||
(removed)="removeTag(tag)" | ||
> | ||
{{tag}} | ||
<button matChipRemove [attr.aria-label]="'remove ' + tag"> | ||
<mat-icon>cancel</mat-icon> | ||
</button> | ||
</mat-chip-row> | ||
} | ||
<input | ||
placeholder="New Tag" | ||
[matChipInputFor]="chipGrid" | ||
(matChipInputTokenEnd)="addTag($event)" | ||
/> | ||
</mat-chip-grid> | ||
</mat-form-field> | ||
<qhana-markdown [editable]="isEditing" [markdown]="templateData.description" (markdownChanges)="currentDescription = $event"></qhana-markdown> | ||
</mat-card-content> | ||
</mat-card> |
23 changes: 23 additions & 0 deletions
23
src/app/components-small/ui-template/ui-template.component.sass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
.header | ||
display: flex | ||
align-items: center | ||
justify-content: space-between | ||
gap: 1rem | ||
|
||
.header-buttons | ||
display: flex | ||
align-items: center | ||
gap: 0.5rem | ||
|
||
.content, .content:last-child | ||
padding: 0 | ||
margin-block-start: 0.5rem | ||
|
||
.name-field | ||
flex-grow: 1 | ||
|
||
.tags | ||
margin-block-end: 0.5rem | ||
|
||
.tags-field | ||
width: 100% |
144 changes: 144 additions & 0 deletions
144
src/app/components-small/ui-template/ui-template.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; | ||
import { CommonModule } from '@angular/common'; | ||
import { ApiLink, ChangedApiObject } from 'src/app/services/api-data-types'; | ||
import { TemplateApiObject } from 'src/app/services/templates.service'; | ||
import { PluginRegistryBaseService } from 'src/app/services/registry.service'; | ||
import { MatChipInputEvent } from '@angular/material/chips'; | ||
import { Subscription } from 'rxjs'; | ||
import { MatDialog } from '@angular/material/dialog'; | ||
import { DeleteDialog } from 'src/app/dialogs/delete-dialog/delete-dialog.dialog'; | ||
|
||
@Component({ | ||
selector: 'qhana-ui-template', | ||
templateUrl: './ui-template.component.html', | ||
styleUrl: './ui-template.component.sass' | ||
}) | ||
export class UiTemplateComponent implements OnChanges, OnInit, OnDestroy { | ||
|
||
@Input() templateLink: ApiLink | null = null; | ||
|
||
|
||
templateData: TemplateApiObject | null = null; | ||
templateUpdateLink: ApiLink | null = null; | ||
templateDeleteLink: ApiLink | null = null; | ||
|
||
isEditing: boolean = false; | ||
|
||
currentName: string | null = null; | ||
currentTags: string[] | null = null; | ||
currentDescription: string | null = null; | ||
|
||
private tagsDirty: boolean = false; | ||
private updateSubscription: Subscription | null = null; | ||
|
||
constructor(private registry: PluginRegistryBaseService, private dialog: MatDialog) { } | ||
|
||
ngOnInit(): void { | ||
this.updateSubscription = this.registry.apiObjectSubject.subscribe((apiObject) => { | ||
if (apiObject.self.href !== this.templateLink?.href) { | ||
return; | ||
} | ||
if (apiObject.self.resourceType === "ui-template") { | ||
this.templateData = apiObject as TemplateApiObject; | ||
if (this.isEditing) { | ||
this.currentTags = [...(apiObject as TemplateApiObject).tags]; | ||
this.tagsDirty = false; | ||
} | ||
} | ||
}); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this.updateSubscription?.unsubscribe(); | ||
} | ||
|
||
ngOnChanges(changes: SimpleChanges): void { | ||
this.loadTemplate(); | ||
} | ||
|
||
private async loadTemplate() { | ||
if (this.templateLink == null) { | ||
this.templateData = null; | ||
return; | ||
} | ||
const templateResponse = await this.registry.getByApiLink<TemplateApiObject>(this.templateLink); | ||
this.templateData = templateResponse?.data ?? null; | ||
|
||
this.templateUpdateLink = templateResponse?.links?.find(link => link.rel.some(rel => rel === "update") && link.resourceType == "ui-template") ?? null; | ||
this.templateDeleteLink = templateResponse?.links?.find(link => link.rel.some(rel => rel === "delete") && link.resourceType == "ui-template") ?? null; | ||
} | ||
|
||
get isDirty() { | ||
if (!this.isEditing) { | ||
return false; | ||
} | ||
if (this.currentName !== this.templateData?.name) { | ||
return true; | ||
} | ||
if (this.currentDescription !== this.templateData?.description) { | ||
return true; | ||
} | ||
if (this.tagsDirty) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
toggleEdit() { | ||
if (this.templateData == null || this.templateUpdateLink == null) { | ||
this.isEditing = false; | ||
} else { | ||
this.isEditing = !this.isEditing; | ||
} | ||
if (this.isEditing) { | ||
this.currentName = this.templateData?.name ?? null; | ||
this.currentTags = [...(this.templateData?.tags ?? [])]; | ||
this.currentDescription = this.templateData?.description ?? null; | ||
this.tagsDirty = false; | ||
} else { | ||
this.currentName = null; | ||
this.currentTags = null; | ||
this.currentDescription = null; | ||
this.tagsDirty = false; | ||
} | ||
} | ||
|
||
removeTag(tag: string) { | ||
this.currentTags = this.currentTags?.filter(t => t !== tag) ?? null; | ||
this.tagsDirty = true; | ||
} | ||
|
||
addTag(event: MatChipInputEvent) { | ||
const tag = event.value; | ||
this.currentTags?.push(tag); | ||
this.tagsDirty = true; | ||
} | ||
|
||
async updateTemplate() { | ||
if (!this.isDirty || this.templateUpdateLink == null) { | ||
return; | ||
} | ||
|
||
this.registry.submitByApiLink(this.templateUpdateLink, { | ||
name: this.currentName, | ||
description: this.currentDescription, | ||
tags: this.currentTags, | ||
}); | ||
} | ||
|
||
async deleteTemplate() { | ||
if (this.templateDeleteLink == null) { | ||
return; | ||
} | ||
|
||
const dialogRef = this.dialog.open(DeleteDialog, { | ||
data: this.templateLink, | ||
}); | ||
|
||
const doDelete = await dialogRef.afterClosed().toPromise(); | ||
if (doDelete) { | ||
this.registry.submitByApiLink(this.templateDeleteLink); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters