src/app/issue-detail/linked-issue-item.component.ts
Displays a linked issue in a list.
By default, only information from #issueStub will be displayed. When the user expands the accordion card, the issue's body will be loaded separately.
selector | app-issue-detail-linked-issue-item |
styleUrls | linked-issue-item.component.scss |
templateUrl | linked-issue-item.component.html |
Properties |
|
Methods |
Inputs |
constructor(dataService: DataService, router: Router)
|
|||||||||
Parameters :
|
issueStub | |
Type : Issue
|
|
Cursory information about the linked issue. |
projectId | |
Type : string
|
|
The raw project ID. |
didOpen |
didOpen()
|
Event handler for when the accordion is opened. Loads the full issue if it hasn't been loaded yet.
Returns :
void
|
Public fullIssueLink |
Type : string
|
Link to the full issue page. |
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {Issue} from '../../generated/graphql-dgql';
import {DataNode} from '@app/data-dgql/query';
import DataService from '@app/data-dgql';
import {NodeType} from '@app/data-dgql/id';
import {Subscription} from 'rxjs';
import {Router} from '@angular/router';
/**
* Displays a linked issue in a list.
*
* By default, only information from {@link #issueStub} will be displayed. When the user expands
* the accordion card, the issue's body will be loaded separately.
*/
@Component({
selector: 'app-issue-detail-linked-issue-item',
templateUrl: 'linked-issue-item.component.html',
styleUrls: ['linked-issue-item.component.scss']
})
export class LinkedIssueItemComponent implements OnInit, OnDestroy {
/** The raw project ID. */
@Input() projectId: string;
/** Cursory information about the linked issue. */
@Input() issueStub: Issue;
/** Link to the full issue page. */
public fullIssueLink: string;
/** @ignore */
public fullIssue?: DataNode<Issue>;
/** @ignore */
private fullIssueSub: Subscription;
constructor(private dataService: DataService, private router: Router) {}
ngOnInit() {
this.fullIssueLink = this.router.serializeUrl(this.router.createUrlTree(['/projects', this.projectId, 'issues', this.issueStub.id]));
}
/** Event handler for when the accordion is opened. Loads the full issue if it hasn't been loaded yet. */
didOpen(): void {
if (!this.fullIssue) {
this.fullIssue = this.dataService.getNode({
type: NodeType.Issue,
id: this.issueStub.id
});
this.fullIssueSub = this.fullIssue.subscribe();
}
}
ngOnDestroy() {
this.fullIssueSub?.unsubscribe();
}
}
<mat-expansion-panel (opened)="didOpen()">
<mat-expansion-panel-header>
<mat-panel-title> {{ issueStub.title }} </mat-panel-title>
<mat-panel-description class="linked-issue-components">
<span class="linked-issue-component" *ngFor="let component of issueStub.components.nodes">{{ component.name }}</span>
</mat-panel-description>
</mat-expansion-panel-header>
<div class="body-loading" *ngIf="fullIssue?.loading">Loading…</div>
<app-markdown-preview *ngIf="fullIssue?.hasData" [displayedCode]="fullIssue.current.body"></app-markdown-preview>
<div class="issue-buttons">
<a mat-button [href]="fullIssueLink">View Issue <mat-icon>chevron_right</mat-icon></a>
</div>
</mat-expansion-panel>
linked-issue-item.component.scss
.linked-issue-components {
overflow: hidden;
text-overflow: ellipsis;
.linked-issue-component {
&::after {
content: ",";
margin-right: 0.3em;
}
&:last-child::after {
content: none;
}
}
}
.body-loading {
min-height: 56px; // some sort of body height so that the animation doesn't glitch out *too* badly
text-align: center;
opacity: 0.7;
}
.issue-buttons {
text-align: right;
margin-top: 8px;
}