* team customized labels added
* team editor interface minor redesign
This commit is contained in:
parent
0f535881a4
commit
ea05a47086
57
src/app/admin/team-editor/team-editor.component.html
Normal file → Executable file
57
src/app/admin/team-editor/team-editor.component.html
Normal file → Executable file
@ -11,22 +11,33 @@
|
||||
<input id="filter_id" type="number" name="filter_id" [(ngModel)]="team.filterId">
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui header">1st column</h5>
|
||||
<div class="six wide field">
|
||||
<label for="team_name"> </label>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" id="team_is_active" name="team_is_active"
|
||||
[(ngModel)]="team.isActive">
|
||||
<label for="team_is_active">Active</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="ui dividing header">Column configuration</h4>
|
||||
<div class="four fields">
|
||||
<div class="six wide field">
|
||||
<label>Jira status</label>
|
||||
<input type="text" name="column1_js"
|
||||
placeholder="Jira column name" [(ngModel)]="team.backlogColumn.jiraStatusName">
|
||||
</div>
|
||||
<div class="four wide field">
|
||||
<label>Display name</label>
|
||||
<input type="text" name="column1_l"
|
||||
placeholder="Kanban board header" [(ngModel)]="team.backlogColumn.label">
|
||||
</div>
|
||||
<div class="two wide field">
|
||||
<label>WIP limit</label>
|
||||
<input type="text" name="column1_wip"
|
||||
placeholder="WIP limit" [(ngModel)]="team.backlogColumn.wipLimit">
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui header">2nd column</h5>
|
||||
<div class="four fields">
|
||||
<div class="six wide field">
|
||||
<input type="text" name="column2_js"
|
||||
@ -41,7 +52,6 @@
|
||||
placeholder="WIP limit" [(ngModel)]="team.inprogressColumn.wipLimit">
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui header">3rd column</h5>
|
||||
<div class="four fields">
|
||||
<div class="six wide field">
|
||||
<input type="text" name="column3_js"
|
||||
@ -56,7 +66,6 @@
|
||||
placeholder="WIP limit" [(ngModel)]="team.verificationColumn.wipLimit">
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui header">4th column</h5>
|
||||
<div class="four fields">
|
||||
<div class="six wide field">
|
||||
<input type="text" name="column4_js"
|
||||
@ -72,13 +81,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="six wide field">
|
||||
<label for="team_name"> </label>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" id="team_is_active" name="team_is_active"
|
||||
[(ngModel)]="team.isActive">
|
||||
<label for="team_is_active">Active</label>
|
||||
<h4 class="ui dividing header">Labels</h4>
|
||||
<div class="three inline fields">
|
||||
<div class="two wide field">
|
||||
<button type="button" class="ui fluid button"
|
||||
[class.positive]="canAddLabel"
|
||||
[class.disabled]="!canAddLabel"
|
||||
(keydown.enter)="handleEnter($event)"
|
||||
(click)="addLabel()">Add
|
||||
</button>
|
||||
</div>
|
||||
<div class="five wide field">
|
||||
<input type="text" #labelInput
|
||||
name="label_name"
|
||||
placeholder="Label text"
|
||||
(keydown.enter)="handleLabelEnter($event)"
|
||||
[(ngModel)]="label.name">
|
||||
</div>
|
||||
<ng-template let-option #optionTemplate>
|
||||
<span class="ui tiny {{option}} label">{{option}}</span>
|
||||
</ng-template>
|
||||
<sui-select class="ui right floated selection"
|
||||
id="label_color"
|
||||
name="label_color"
|
||||
[(ngModel)]="label.color"
|
||||
[optionTemplate]="optionTemplate"
|
||||
[isSearchable]="false"
|
||||
#labelSelect>
|
||||
<sui-select-option *ngFor="let labelColor of labelColors" [value]="labelColor"></sui-select-option>
|
||||
</sui-select>
|
||||
</div>
|
||||
<div>
|
||||
<span *ngFor="let label of team.labels"
|
||||
class="ui medium {{label.color}} label">{{label.name}}<i class="large delete icon"
|
||||
(click)="removeLabel(label)"></i></span>
|
||||
</div>
|
||||
|
||||
<h4 class="ui dividing header">Team members</h4>
|
||||
@ -106,6 +142,7 @@
|
||||
[(ngModel)]="member.name">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="ui dividing header"></h4>
|
||||
<table class="ui celled definition table" *ngIf="team.members.length">
|
||||
<thead>
|
||||
|
||||
59
src/app/admin/team-editor/team-editor.component.ts
Normal file → Executable file
59
src/app/admin/team-editor/team-editor.component.ts
Normal file → Executable file
@ -1,11 +1,11 @@
|
||||
import { Component, ElementRef, HostBinding, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TeamService } from '../../shared/service/team.service';
|
||||
import { Team } from '../../shared/team';
|
||||
import { Member } from '../../shared/member';
|
||||
import { slideInOutAnimation } from '../../shared/slide-in-out-animation';
|
||||
import { Label } from '../../shared/label';
|
||||
|
||||
@Component({
|
||||
selector: 'app-team-editor',
|
||||
@ -13,8 +13,10 @@ import { slideInOutAnimation } from '../../shared/slide-in-out-animation';
|
||||
styleUrls: ['./team-editor.component.css']
|
||||
})
|
||||
export class TeamEditorComponent implements OnInit {
|
||||
@ViewChild('labelInput') labelInputElement: ElementRef;
|
||||
@ViewChild('signumInput') signumInputElement: ElementRef;
|
||||
public team: Team;
|
||||
public label: Label = new Label();
|
||||
public member: Member = new Member();
|
||||
|
||||
constructor(private teamService: TeamService,
|
||||
@ -28,6 +30,57 @@ export class TeamEditorComponent implements OnInit {
|
||||
this.route.data.subscribe((data: { team: Team }) => this.team = data.team ? data.team : new Team());
|
||||
}
|
||||
|
||||
get labelColors(): Array<string> {
|
||||
return [
|
||||
'red',
|
||||
'orange',
|
||||
'yellow',
|
||||
'olive',
|
||||
'green',
|
||||
'teal',
|
||||
'blue',
|
||||
'violet',
|
||||
'purple',
|
||||
'pink',
|
||||
'brown',
|
||||
'grey',
|
||||
'black',
|
||||
'white'
|
||||
];
|
||||
}
|
||||
|
||||
get canAddLabel(): boolean {
|
||||
try {
|
||||
return [this.label.name, this.label.color].every(field => field.length !== 0)
|
||||
&& this.team.labels.every(label => label.name !== this.label.name);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public addLabel() {
|
||||
this.team.labels = this.team.labels
|
||||
.concat(Object.assign({}, this.label))
|
||||
.sort((a: Label, b: Label) => a.name < b.name ? -1 : 1);
|
||||
this.label = new Label();
|
||||
}
|
||||
|
||||
public removeLabel(label: Label) {
|
||||
this.team.labels = this.team.labels.filter(teamLabel => teamLabel !== label);
|
||||
}
|
||||
|
||||
public handleLabelEnter(ev: KeyboardEvent) {
|
||||
ev.preventDefault();
|
||||
if (this.canAddLabel) {
|
||||
this.addLabel();
|
||||
this.focusLabelField();
|
||||
}
|
||||
}
|
||||
|
||||
public focusLabelField() {
|
||||
this.labelInputElement.nativeElement.focus();
|
||||
}
|
||||
|
||||
get canAddMember(): boolean {
|
||||
try {
|
||||
return [this.member.name, this.member.signum].every(field => field.length !== 0)
|
||||
@ -66,7 +119,7 @@ export class TeamEditorComponent implements OnInit {
|
||||
return [
|
||||
this.team.name.trim(),
|
||||
this.team.members
|
||||
].every(field => field.length > 0);
|
||||
].every(field => field.length > 0) && this.team.filterId > 0;
|
||||
}
|
||||
|
||||
public saveTeam() {
|
||||
|
||||
@ -12,10 +12,8 @@
|
||||
<div class="task-description">
|
||||
<span *ngIf="kanbanEntry.epicName"
|
||||
class="ui mini olive right floated label">{{kanbanEntry.epicName}}</span>
|
||||
<ng-template [ngIf]="hasLabels(kanbanEntry)">
|
||||
<span *ngFor="let label of kanbanEntry.labels"
|
||||
class="ui mini {{labelClass(label)}} right floated label">{{label|uppercase|blockedDays:kanbanEntry.daysBlocked}}</span>
|
||||
</ng-template>
|
||||
<span *ngFor="let label of filteredLabels(kanbanEntry)"
|
||||
class="ui mini {{labelClass(label)}} right floated label">{{label|blockedDays:kanbanEntry.daysBlocked}}</span>
|
||||
<span *ngIf="wasBlocked(kanbanEntry)" class="ui mini {{labelClass('blocked')}} right floated label">{{kanbanEntry.daysBlocked}}D</span>
|
||||
<div *ngIf="!hasMultiAssignee(kanbanEntry)" class="ui jira-avatar floated image">
|
||||
<img src="{{avatarUrl(kanbanEntry.assignee?.avatar)}}" [title]="kanbanEntry.assignee?.name">
|
||||
|
||||
@ -2,23 +2,11 @@ import { Component, Input } from '@angular/core';
|
||||
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { JiraAssignee, KanbanEntry } from '../shared';
|
||||
import { SettingsService } from '../../shared/service/settings.service';
|
||||
|
||||
const DEFAULT_AVATAR = '/assets/riddler.png';
|
||||
const JIRA_BOARD_BASE_HREF = 'https://cc-jira.rnd.ki.sw.ericsson.se/browse/';
|
||||
|
||||
const labelColors = {
|
||||
TSP: 'teal',
|
||||
MTAS: 'orange',
|
||||
INTERNAL: 'yellow',
|
||||
TEAM: 'yellow',
|
||||
BLOCKED: 'red',
|
||||
SPIKE: 'purple',
|
||||
EXPEDITE: 'pink',
|
||||
|
||||
'MTAS-GUARDIAN': 'pink',
|
||||
'MTAS-GUARDIANACTIVE': 'yellow',
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'app-kanban-entry-item,[app-kanban-entry-item]',
|
||||
templateUrl: './kanban-entry-item.component.html',
|
||||
@ -30,8 +18,7 @@ export class KanbanEntryItemComponent {
|
||||
@Input() wipLimit = 0;
|
||||
@Input() wipCount = 0;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
constructor(private settingService: SettingsService) {}
|
||||
|
||||
/**
|
||||
* Returns the full url of the assignee avatar,
|
||||
@ -41,17 +28,9 @@ export class KanbanEntryItemComponent {
|
||||
* @returns {string}
|
||||
*/
|
||||
public avatarUrl(avatarPath: string): string {
|
||||
return environment.apiUrl + (avatarPath ? avatarPath : DEFAULT_AVATAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if issue has any labels attached
|
||||
*
|
||||
* @param {KanbanEntry} entry
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public hasLabels(entry: KanbanEntry): boolean {
|
||||
return entry.labels.length > 0;
|
||||
return environment.apiUrl + (avatarPath
|
||||
? avatarPath
|
||||
: DEFAULT_AVATAR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,11 +40,16 @@ export class KanbanEntryItemComponent {
|
||||
* @returns {string}
|
||||
*/
|
||||
public labelClass(label: string): string {
|
||||
try {
|
||||
return labelColors[label.toUpperCase()];
|
||||
} catch (e) {
|
||||
return 'white';
|
||||
if (this.settingService.team.labels) {
|
||||
const color = this.settingService.team.labels.find(
|
||||
teamLabel => teamLabel.name.toLocaleLowerCase() === label.toLocaleLowerCase()
|
||||
).color;
|
||||
|
||||
if (color !== null) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
return 'white';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,6 +64,15 @@ export class KanbanEntryItemComponent {
|
||||
};
|
||||
}
|
||||
|
||||
public filteredLabels(kanbanEntry: KanbanEntry): Array<string> {
|
||||
if (this.settingService.team.labels) {
|
||||
return kanbanEntry.labels.filter(entryLabel => this.settingService.team.labels.some(
|
||||
teamLabel => teamLabel.name.toLocaleLowerCase() === entryLabel.toLocaleLowerCase()
|
||||
));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate jira issue href
|
||||
*
|
||||
@ -122,4 +115,5 @@ export class KanbanEntryItemComponent {
|
||||
public getAssignees(kanbanEntry: KanbanEntry): Array<JiraAssignee> {
|
||||
return [].concat([kanbanEntry.assignee], kanbanEntry.additionalAssignees);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
:host.preview {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
padding: 30px;
|
||||
}
|
||||
iframe {
|
||||
width: 100%;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Slide } from '../shared/slide';
|
||||
import { SlideService } from '../shared/service/slide.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { SettingsService } from '../shared/service/settings.service';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Slide, SlideVisibility} from '../shared/slide';
|
||||
import {SlideService} from '../shared/service/slide.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {SettingsService} from '../shared/service/settings.service';
|
||||
|
||||
@Injectable()
|
||||
export class SlideShowService {
|
||||
@ -39,7 +39,7 @@ export class SlideShowService {
|
||||
const team = this.settingsService.team;
|
||||
this.slideService.list().subscribe(
|
||||
slides => this.slides = slides.filter(
|
||||
slide => slide.teams === null || slide.teams.some(s => s.id === team.id) && slide.isVisible
|
||||
slide => slide.isVisible && (slide.visibility === SlideVisibility.Public || slide.teams.some(s => s.id === team.id))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
4
src/app/shared/label.ts
Executable file
4
src/app/shared/label.ts
Executable file
@ -0,0 +1,4 @@
|
||||
export class Label {
|
||||
name: string;
|
||||
color: string;
|
||||
}
|
||||
6
src/app/shared/team.ts
Normal file → Executable file
6
src/app/shared/team.ts
Normal file → Executable file
@ -1,16 +1,18 @@
|
||||
import { Member } from './member';
|
||||
import { KanbanColumn } from './kanban-column';
|
||||
import { Label } from './label';
|
||||
|
||||
export class Team {
|
||||
id: number = null;
|
||||
name: String = '';
|
||||
members: Array<Member> = [];
|
||||
filterId: number;
|
||||
filterId = 0;
|
||||
backlogColumn: KanbanColumn = new KanbanColumn();
|
||||
inprogressColumn: KanbanColumn = new KanbanColumn();
|
||||
verificationColumn: KanbanColumn = new KanbanColumn();
|
||||
doneColumn: KanbanColumn = new KanbanColumn();
|
||||
isActive = false;
|
||||
labels: Array<Label> = [];
|
||||
isActive = true;
|
||||
createdAt: String = null;
|
||||
updatedAt: String = null;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user