diff options
Diffstat (limited to 'Timeline/ClientApp/src/app/todo-list-page')
5 files changed, 135 insertions, 8 deletions
diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css index c17267c5..6a603863 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css @@ -1,12 +1,42 @@ +.align-self-bottom { + align-self: flex-end; +} + +.first-item-box { + justify-content: space-between; +} + +.item-box { + display: flex; + width: 100%; + padding: 10px; + box-sizing: border-box; +} + +.sample-box { + box-sizing: border-box; + align-self: flex-start; +} + .item-id { display: inline-block; text-align: center; - background: skyblue; border-radius: 0.2rem; width: 1.2rem; height: 1.2rem; } -mat-list-item { - margin: 10px; +.item-id-sample { + display: inline-block; + border-radius: 0.2em; + width: 1em; + height: 1em; +} + +.item-id-open { + background: red; +} + +.item-id-closed { + background: green; } diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html index 3a80e4eb..ce6eb2ed 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html @@ -1,9 +1,21 @@ <mat-progress-bar *ngIf="!items" mode="indeterminate"></mat-progress-bar> <mat-list> - <mat-list-item *ngFor="let item of items"> - <mat-card> - <span class="item-id">{{item.id}}</span> {{item.title}} - </mat-card> + <mat-list-item *ngFor="let item of items; let i = index" style="height:unset;"> + <div class="item-box" [class.first-item-box]="i === 0"> + <mat-card [class.align-self-bottom]="i === 0"> + <span class="item-id" [class.item-id-closed]="item.closed" + [class.item-id-open]="!item.closed">{{item.id}}</span> + {{item.title}} + </mat-card> + <div class="sample-box" *ngIf="i === 0"> + <div class="mat-caption"> + <span class="item-id-sample item-id-open"></span> means working now. + </div> + <div class="mat-caption"> + <span class="item-id-sample item-id-closed"></span> means completed. + </div> + </div> + </div> </mat-list-item> </mat-list> diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts index 722ecbdc..8af1f5ef 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { TodoListService, WorkItem } from '../todo-list.service'; +import { TodoListService, WorkItem } from './todo-list.service'; @Component({ selector: 'app-todo-list-page', diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts new file mode 100644 index 00000000..529ba8cc --- /dev/null +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { TodoListService } from './todo-list.service'; + +describe('TodoListServiceService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: TodoListService = TestBed.get(TodoListService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts new file mode 100644 index 00000000..0b54653b --- /dev/null +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts @@ -0,0 +1,73 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { switchMap, concatMap, map, toArray } from 'rxjs/operators'; + +interface WiqlWorkItemResult { + id: number; + url: string; +} + +interface WiqlResult { + workItems: WiqlWorkItemResult[]; +} + +interface WorkItemResult { + id: number; + fields: { [name: string]: any }; +} + +export interface WorkItem { + id: number; + title: string; + closed: boolean; +} + +@Injectable({ + providedIn: 'root' +}) +export class TodoListService { + + private username = 'crupest'; + private organization = 'crupest-web'; + private project = 'Timeline'; + private titleFieldName = 'System.Title'; + private stateFieldName = 'System.State'; + + constructor(private client: HttpClient) { } + + private getAzureDevOpsPat(): Observable<string> { + return this.client.get('/api/TodoList/AzureDevOpsPat', { + headers: { + 'Accept': 'text/plain' + }, + responseType: 'text' + }); + } + + getWorkItemList(): Observable<WorkItem[]> { + return this.getAzureDevOpsPat().pipe( + switchMap( + pat => { + const headers = new HttpHeaders({ + 'Accept': 'application/json', + 'Authorization': `Basic ${btoa(this.username + ':' + pat)}` + }); + return this.client.post<WiqlResult>( + `https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/wiql?api-version=5.0`, { + query: 'SELECT [System.Id] FROM workitems WHERE [System.TeamProject] = @project' + }, { headers: headers }).pipe( + switchMap(result => result.workItems), + concatMap(result => this.client.get<WorkItemResult>(result.url, { headers: headers })), + map(result => <WorkItem>{ + id: result.id, + title: <string>result.fields[this.titleFieldName], + closed: ((<string>result.fields[this.stateFieldName]).toLowerCase() === 'closed') + }), + toArray() + ); + } + ) + ); + } +} |