File

src/app/issue-detail/issue-contents.component.ts

Description

This component renders the contents of the issue: the issue body, timeline, and comment box.

Implements

OnInit OnDestroy

Metadata

selector app-issue-contents
styleUrls issue-contents.component.scss
templateUrl issue-contents.component.html

Index

Properties
Methods
Inputs

Constructor

constructor(dataService: DataService)
Parameters :
Name Type Optional
dataService DataService No

Inputs

issue$
Type : DataNode<Issue>

The issue to be rendered.

projectId
Type : string

The raw project ID.

Methods

Public closeIssue
closeIssue()

Closes the current issue.

Returns : void
Public commentIssue
commentIssue()

Adds a comment to the current issue with the data provided in the comment box.

Returns : void
Public reopenIssue
reopenIssue()

Reopens the currently closed issue.

Returns : void

Properties

commentEditor
Decorators :
@ViewChild('comment')

The comment editor (app-markdown-editor).

Public savingComment
Default value : false

True if the issue comment is currently being saved.

import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {DataList, DataNode} from '@app/data-dgql/query';
import {Issue} from '../../generated/graphql';
import {Subscription} from 'rxjs';
import DataService from '@app/data-dgql';
import {CURRENT_USER_NODE, ListType} from '@app/data-dgql/id';
import {User} from '../../generated/graphql-dgql';

/**
 * This component renders the contents of the issue: the issue body, timeline, and comment box.
 */
@Component({
  selector: 'app-issue-contents',
  templateUrl: 'issue-contents.component.html',
  styleUrls: ['issue-contents.component.scss']
})
export class IssueContentsComponent implements OnInit, OnDestroy {
  /** The issue to be rendered. */
  @Input() issue$: DataNode<Issue>;
  /** The raw project ID. */
  @Input() projectId: string;

  /** @ignore */
  public linkedIssues$: DataList<Issue, unknown>;
  /** @ignore */
  public linkedIssueSub: Subscription;
  /** @ignore */
  public currentUser$: DataNode<User>;
  /** @ignore */
  public currentUserSub: Subscription;

  /** True if the issue comment is currently being saved. */
  public savingComment = false;
  /** The comment editor (app-markdown-editor). */
  @ViewChild('comment') commentEditor;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.linkedIssues$ = this.dataService.getList({
      node: this.issue$.id,
      type: ListType.LinkedIssues
    });
    this.linkedIssueSub = this.linkedIssues$.subscribe();

    this.currentUser$ = this.dataService.getNode(CURRENT_USER_NODE);
    this.currentUserSub = this.currentUser$.subscribe();
  }

  ngOnDestroy() {
    this.linkedIssueSub.unsubscribe();
    this.currentUserSub.unsubscribe();
  }

  /** Closes the current issue. */
  public closeIssue(): void {
    this.dataService.mutations.closeIssue(Math.random().toString(), this.issue$.id);
  }

  /** Reopens the currently closed issue. */
  public reopenIssue(): void {
    this.dataService.mutations.reopenIssue(Math.random().toString(), this.issue$.id);
  }

  /** Adds a comment to the current issue with the data provided in the comment box. */
  public commentIssue(): void {
    this.savingComment = true;
    this.dataService.mutations
      .addIssueComment(Math.random().toString(), this.issue$.id, this.commentEditor.code)
      .then(() => {
        // only clear if successful
        this.commentEditor.code = '';
      })
      .finally(() => {
        this.savingComment = false;
      });
  }
}
<div class="issue-contents" *ngIf="issue$?.current as issue">
  <!-- Issue body -->
  <app-comment class="issue-body" [commentId]="issue$.id" [isIssueBody]="true"></app-comment>

  <!-- Linked issues -->
  <div *ngIf="linkedIssues$.totalCount > 0" class="timeline-item">
    <div class="item-box">
      <div class="item-header">
        <mat-icon>link</mat-icon>
        <h3 class="item-title">
          <b>Linked Issues</b>
        </h3>
      </div>
      <div class="item-body">
        <div class="linked-issues-container">
          <mat-accordion>
            <ng-container *ngFor="let currentIssue of linkedIssues$.currentItems">
              <app-issue-detail-linked-issue-item [issueStub]="currentIssue" [projectId]="projectId"> </app-issue-detail-linked-issue-item>
            </ng-container>
          </mat-accordion>
        </div>
        <app-cursor-paginator *ngIf="linkedIssues$.totalCount > 10" [list]="linkedIssues$" [pageSizes]="[10]"></app-cursor-paginator>
      </div>
    </div>
  </div>

  <app-timeline [issueId]="issue$.id" [projectID]="projectId"></app-timeline>

  <mat-divider></mat-divider>

  <!-- Comment creation box-->
  <div class="timeline-item comment-form">
    <div class="item-box">
      <div class="item-header">
        <h3 class="item-title">
          Comment this issue as
          <app-user-item [user]="currentUser$.current" [short]="true"></app-user-item>
        </h3>
      </div>
      <div class="item-body">
        <app-markdown-editor #comment></app-markdown-editor>
        <div class="comment-buttons">
          <button *ngIf="issue.isOpen" mat-raised-button color="warn" (click)="this.closeIssue()">Close Issue</button>
          <button *ngIf="!issue.isOpen" mat-raised-button color="accent" (click)="this.reopenIssue()">Reopen Issue</button>
          <button mat-raised-button color="primary" style="margin-left: 6px" [class.spinner]="savingComment" (click)="this.commentIssue()">
            Comment
          </button>
        </div>
      </div>
    </div>
  </div>
</div>

issue-contents.component.scss

@import "src/styles/spinner";

.timeline-item {
  position: relative;
  margin-left: 36px;
  padding: 12px 0;

  &:first-child {
    padding-top: 0;
  }

  &::before {
    content: "";
    position: absolute;
    top: 0;
    left: -1px;
    bottom: 0;
    width: 2px;
    background: rgba(0, 0, 0, 0.12);
  }

  .item-box {
    position: relative;
    background: white;
    border-radius: 4px;
    border: 1px solid rgba(0, 0, 0, 0.1);
    margin-left: -36px;

    .item-header {
      background: rgba(0, 0, 0, 0.06);
      border-bottom: rgba(0, 0, 0, 0.1);
      border-radius: 4px 4px 0 0;
      padding: 8px 16px;
      display: flex;
      align-items: center;

      mat-icon {
        margin-right: 8px;
        margin-left: -8px;
      }

      .item-title {
        flex: 1;
        margin: 0 16px 0 0;
        overflow: hidden;
        font-size: inherit;
        font-weight: inherit;

        .item-edited {
          opacity: 0.5;
        }
      }
    }

    .item-body {
      padding: 16px;

      &.is-editing {
        padding: 8px;
      }

      .edit-body-buttons {
        text-align: right;
        margin-top: 5px;
        margin-bottom: 3px;
      }
    }
  }
}

.comment-form {
  padding-bottom: 0;

  .comment-buttons {
    text-align: right;
  }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""