Compare commits
No commits in common. "master" and "emakazi_dev" have entirely different histories.
master
...
emakazi_de
42
README.md
42
README.md
@ -1,36 +1,28 @@
|
||||
# TaurusTv
|
||||
|
||||
## Tools used for development
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.2.6.
|
||||
|
||||
- [deployer](https://deployer.org/download)
|
||||
- [nodeJS](https://nodejs.org/en/download/)
|
||||
- [php7.1](http://php.net) - [installation on ELX](https://www.colinodell.com/blog/2016-12/installing-php-7-1)
|
||||
- [phpStorm](https://www.jetbrains.com/phpstorm/download/)
|
||||
|
||||
Install the latest versions, add them to your $PATH.
|
||||
|
||||
## Prepare for development
|
||||
|
||||
### Install required node packages
|
||||
```bash
|
||||
sudo npm -g i typescript gulp @angular/cli
|
||||
# Inside your project root
|
||||
npm install
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Run `dep deploy` in the project root, to deploy the application to `vasgyuro.tsp`. The application will automatically reload on the TV when a new version is deployed.
|
||||
|
||||
## Angular cli
|
||||
### Development server
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
### Code scaffolding
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|module`.
|
||||
|
||||
### Further help
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
Before running the tests make sure you are serving the app via `ng serve`.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
||||
8
htaccess
8
htaccess
@ -22,11 +22,3 @@ RewriteRule ^(.*)$ %{ENV:BASE}index.html [NC,L]
|
||||
<LimitExcept GET POST PUT DELETE HEAD OPTIONS>
|
||||
Require all denied
|
||||
</LimitExcept>
|
||||
|
||||
<Files revision.json>
|
||||
FileETag None
|
||||
Header unset ETag
|
||||
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
|
||||
Header set Pragma "no-cache"
|
||||
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
|
||||
</Files>
|
||||
|
||||
@ -28,13 +28,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Initialize application timers:
|
||||
* - selfUpdateCheckerTimer is used to see if there is a newer revision deployed on the server
|
||||
* - reloadJiraIssueTimer is used to refresh the status of the jira board
|
||||
* - pageSwitchTimer handles switching back and forth between page views
|
||||
* @todo: pageSwitchTimer
|
||||
*/
|
||||
public ngOnInit() {
|
||||
let timer0 = TimerObservable.create(TIMER_DEPLOY_REFRESH, TIMER_JIRA_REFRESH);
|
||||
this.selfUpdateCheckerTimer = timer0.subscribe(() => {
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
:host {
|
||||
display: inline-block;
|
||||
height: 100vh;
|
||||
overflow: scroll;
|
||||
}
|
||||
@ -1,18 +1,12 @@
|
||||
<div class="ui main fullwide-container">
|
||||
<div class="ui grid">
|
||||
<div app-kanban-entry-item class="four wide column"
|
||||
rowHeading="INBOX"
|
||||
[kanbanEntries]="kanbanBoard.inbox"></div>
|
||||
rowHeading="INBOX" [kanbanEntries]="kanbanBoard.inbox"></div>
|
||||
<div app-kanban-entry-item class="four wide column" [ngClass]="inprogressWipClass"
|
||||
rowHeading="INPROGRESS"
|
||||
[wipLimit]="inprogressWipLimit" [wipCount]="inprogressWipCount"
|
||||
[kanbanEntries]="kanbanBoard.inProgress"></div>
|
||||
rowHeading="INPROGRESS" [kanbanEntries]="kanbanBoard.inProgress"></div>
|
||||
<div app-kanban-entry-item class="four wide column" [ngClass]="verificationWipClass"
|
||||
rowHeading="VERIFICATION"
|
||||
[wipLimit]="verificationWipLimit" [wipCount]="verificationWipCount"
|
||||
[kanbanEntries]="kanbanBoard.verification"></div>
|
||||
rowHeading="VERIFICATION" [kanbanEntries]="kanbanBoard.verification"></div>
|
||||
<div app-kanban-entry-item class="four wide column"
|
||||
rowHeading="DÖNER"
|
||||
[kanbanEntries]="kanbanBoard.done"></div>
|
||||
rowHeading="DÖNER" [kanbanEntries]="kanbanBoard.done"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,19 +1,15 @@
|
||||
import {Component, HostBinding, HostDecorator, HostListener, OnInit} from '@angular/core';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Title} from '@angular/platform-browser';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
|
||||
import {
|
||||
KanbanBoard,
|
||||
KanbanService,
|
||||
KanbanEntry,
|
||||
KanbanBoard
|
||||
} from "../shared";
|
||||
import {KanbanService} from "../shared/kanban.service";
|
||||
|
||||
const WIP_LIMIT_INPROGRESS = 12;
|
||||
const WIP_LIMIT_VERIFICATION = 8;
|
||||
|
||||
const STYLE_HIDDEN = 'hidden';
|
||||
const STYLE_VISIBLE = 'scroll';
|
||||
|
||||
@Component({
|
||||
selector: 'app-kanban-board',
|
||||
templateUrl: './kanban-board.component.html',
|
||||
@ -21,16 +17,11 @@ const STYLE_VISIBLE = 'scroll';
|
||||
})
|
||||
export class KanbanBoardComponent implements OnInit {
|
||||
|
||||
@HostBinding('style.overflow') hostOverflow = STYLE_HIDDEN;
|
||||
|
||||
constructor(private titleService: Title,
|
||||
private route: ActivatedRoute,
|
||||
private kanbanService: KanbanService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set page title, and handle preloaded kanbanBoard data
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle('TaurusXFT : Kanban board');
|
||||
this.route.data.subscribe((data: { kanbanBoard: KanbanBoard }) => this.kanbanBoard = data.kanbanBoard);
|
||||
@ -44,61 +35,15 @@ export class KanbanBoardComponent implements OnInit {
|
||||
this.kanbanService.kanbanBoard = kanbanBoard;
|
||||
}
|
||||
|
||||
get inprogressWipLimit(): number {
|
||||
return WIP_LIMIT_INPROGRESS;
|
||||
}
|
||||
|
||||
get inprogressWipCount(): number {
|
||||
return this.kanbanBoard.inProgress.filter(
|
||||
(entry: KanbanEntry) => entry.labels.every(
|
||||
label => label.toUpperCase() != 'BLOCKED'
|
||||
)
|
||||
).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 'over-wip' class on inprogress row if its over the wip limit
|
||||
* This excludes issues marked as BLOCKED with labels
|
||||
*
|
||||
* @returns {{over-wip: boolean}}
|
||||
*/
|
||||
get inprogressWipClass() {
|
||||
return {
|
||||
'over-wip': this.inprogressWipCount > WIP_LIMIT_INPROGRESS,
|
||||
'over-wip': this.kanbanBoard.inProgress.length > WIP_LIMIT_INPROGRESS,
|
||||
};
|
||||
}
|
||||
|
||||
get verificationWipLimit(): number {
|
||||
return WIP_LIMIT_VERIFICATION;
|
||||
}
|
||||
|
||||
get verificationWipCount(): number {
|
||||
return this.kanbanBoard.verification.filter(
|
||||
(entry: KanbanEntry) => entry.labels.every(
|
||||
label => label.toUpperCase() != 'BLOCKED'
|
||||
)
|
||||
).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 'over-wip' class on verification row if its over the wip limit
|
||||
* This excludes issues marked as BLOCKED with labels
|
||||
*
|
||||
* @returns {{over-wip: boolean}}
|
||||
*/
|
||||
get verificationWipClass() {
|
||||
return {
|
||||
'over-wip': this.verificationWipCount > WIP_LIMIT_VERIFICATION,
|
||||
'over-wip': this.kanbanBoard.verification.length > WIP_LIMIT_VERIFICATION,
|
||||
};
|
||||
}
|
||||
|
||||
@HostListener('mouseover')
|
||||
private onMouseOver() {
|
||||
this.hostOverflow = STYLE_VISIBLE;
|
||||
}
|
||||
|
||||
@HostListener('mouseout')
|
||||
private onMouseOut() {
|
||||
this.hostOverflow = STYLE_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
a {
|
||||
color: #eeeeee !important;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #4183C4 !important;
|
||||
}
|
||||
|
||||
.task-description {
|
||||
font-size: 14pt;
|
||||
line-height: 1.25em;
|
||||
@ -38,19 +30,19 @@ a:hover {
|
||||
}
|
||||
|
||||
.ui.divided.items > .item.blocker.bottom-separator {
|
||||
border-bottom: 3px double rgba(219, 40, 40, 0.5);
|
||||
border-bottom: 1px solid rgba(219, 40, 40, 0.5);
|
||||
}
|
||||
|
||||
.ui.divided.items > .item.critical.bottom-separator {
|
||||
border-bottom: 3px double rgba(242, 113, 28, 0.5);
|
||||
border-bottom: 1px solid rgba(242, 113, 28, 0.5);
|
||||
}
|
||||
|
||||
.ui.divided.items > .item.major.bottom-separator {
|
||||
border-bottom: 3px double rgba(181, 204, 24, 0.5);
|
||||
border-bottom: 1px solid rgba(181, 204, 24, 0.5);
|
||||
}
|
||||
|
||||
.ui.divided.items > .item.minor.bottom-separator {
|
||||
border-bottom: 3px double rgba(0, 181, 173, 0.5);
|
||||
border-bottom: 1px solid rgba(0, 181, 173, 0.5);
|
||||
}
|
||||
|
||||
/*Nothing below trivial, no separator needed*/
|
||||
|
||||
@ -1,21 +1,15 @@
|
||||
<h1>
|
||||
{{rowHeading}}
|
||||
<ng-template [ngIf]="wipCount">
|
||||
- {{wipCount}}/{{wipLimit}}
|
||||
</ng-template>
|
||||
</h1>
|
||||
<h1>{{rowHeading}}</h1>
|
||||
<div class="ui divided items">
|
||||
<div class="item {{kanbanEntry.issuePriority|lowercase}}" [ngClass]="entryClass(kanbanEntry)" *ngFor="let kanbanEntry of kanbanEntries">
|
||||
<div class="content">
|
||||
<div class="task-description">
|
||||
<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>
|
||||
<a *ngFor="let label of kanbanEntry.labels" class="ui mini {{labelClass(label)}} right floated label">{{label}}</a>
|
||||
</ng-template>
|
||||
<span *ngIf="wasBlocked(kanbanEntry)" class="ui mini {{labelClass('blocked')}} right floated label">{{kanbanEntry.daysBlocked}}D</span>
|
||||
<div class="ui jira-avatar floated image">
|
||||
<img src="{{avatarUrl(kanbanEntry.assignee?.avatar)}}" [title]="kanbanEntry.assignee?.name">
|
||||
<img src="{{avatarUrl(kanbanEntry.assignee?.avatar)}}">
|
||||
</div>
|
||||
<a [href]="jiraHref(kanbanEntry)" target="_blank" [innerHTML]="kanbanEntry.summary|shortenText|priorityColor:kanbanEntry.issuePriorityIcon:kanbanEntry.worklog" [title]="kanbanEntry.summary"></a>
|
||||
<span [innerHTML]="kanbanEntry.summary|shortenText|priorityColor:kanbanEntry.issuePriorityIcon:kanbanEntry.worklog" [title]="kanbanEntry.summary"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,19 +1,16 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
import {environment} from "../../../environments/environment";
|
||||
import {KanbanEntry} from "../shared";
|
||||
import {KanbanEntry} from "../shared/kanban-entry.model";
|
||||
|
||||
const DEFAULT_AVATAR = '/assets/riddler.png';
|
||||
const JIRA_BOARD_BASE_HREF = 'https://jirapducc.mo.ca.am.ericsson.se/browse/';
|
||||
|
||||
const labelColors = {
|
||||
TSP: 'teal',
|
||||
MTAS: 'orange',
|
||||
INTERNAL: 'yellow',
|
||||
TEAM: 'yellow',
|
||||
Internal: 'yellow',
|
||||
Team: 'yellow',
|
||||
BLOCKED: 'red',
|
||||
SPIKE: 'purple',
|
||||
EXPEDITE: 'pink',
|
||||
};
|
||||
|
||||
@Component({
|
||||
@ -21,80 +18,33 @@ const labelColors = {
|
||||
templateUrl: './kanban-entry-item.component.html',
|
||||
styleUrls: ['./kanban-entry-item.component.css']
|
||||
})
|
||||
export class KanbanEntryItemComponent {
|
||||
export class KanbanEntryItemComponent implements OnInit {
|
||||
@Input() kanbanEntries: Array<KanbanEntry>;
|
||||
@Input() rowHeading: string = "";
|
||||
@Input() wipLimit: number = 0;
|
||||
@Input() wipCount: number = 0;
|
||||
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Returns the full url of the assignee avatar,
|
||||
* or the default riddler avatar if there is no assignee
|
||||
*
|
||||
* @param {string} avatarPath
|
||||
* @returns {string}
|
||||
*/
|
||||
ngOnInit() {}
|
||||
|
||||
public avatarUrl(avatarPath: string): string {
|
||||
return environment.apiUri + ( 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set label colors
|
||||
*
|
||||
* @param {string} label
|
||||
* @returns {string}
|
||||
*/
|
||||
public labelClass(label: string): string {
|
||||
try {
|
||||
return labelColors[label.toUpperCase()];
|
||||
return labelColors[label];
|
||||
} catch(e) {
|
||||
return 'white';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add 'bottom-separator' class to every item that is the last of its priority type
|
||||
*
|
||||
* @param {KanbanEntry} entry
|
||||
* @returns {{bottom-separator: boolean}}
|
||||
*/
|
||||
public entryClass(entry: KanbanEntry) {
|
||||
return {
|
||||
'bottom-separator': entry.isLastOfPriority,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate jira issue href
|
||||
*
|
||||
* @param {KanbanEntry} kanbanEntry
|
||||
* @returns {string}
|
||||
*/
|
||||
public jiraHref(kanbanEntry: KanbanEntry): string {
|
||||
return JIRA_BOARD_BASE_HREF + kanbanEntry.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if issue has blocked days logged at any point of time,
|
||||
* but is not in BLOCKED state any more.
|
||||
*
|
||||
* @param {KanbanEntry} kanbanEntry
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public wasBlocked(kanbanEntry: KanbanEntry): boolean {
|
||||
return kanbanEntry.daysBlocked > 0
|
||||
&& kanbanEntry.labels.every(label => label.toUpperCase() != 'BLOCKED');
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ import { KanbanEntryItemComponent } from './kanban-entry-item/kanban-entry-item.
|
||||
import { PriorityColorPipe } from './shared/priority-color.pipe';
|
||||
import { ShortenTextPipe } from './shared/shorten-text.pipe';
|
||||
import { SelfUpdaterService } from './shared/self-updater.service';
|
||||
import { BlockedDaysPipe } from './shared/blocked-days.pipe';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -21,7 +20,6 @@ import { BlockedDaysPipe } from './shared/blocked-days.pipe';
|
||||
KanbanEntryItemComponent,
|
||||
PriorityColorPipe,
|
||||
ShortenTextPipe,
|
||||
BlockedDaysPipe,
|
||||
],
|
||||
providers: [
|
||||
KanbanService,
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import { BlockedDaysPipe } from './blocked-days.pipe';
|
||||
|
||||
describe('BlockedDaysPipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new BlockedDaysPipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -1,21 +0,0 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'blockedDays'
|
||||
})
|
||||
export class BlockedDaysPipe implements PipeTransform {
|
||||
|
||||
/**
|
||||
* Format the BLOCKED label, including days since the task is blocked
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {number} days
|
||||
* @returns {any}
|
||||
*/
|
||||
transform(value: string, days: number): any {
|
||||
return ( value.toUpperCase() == 'BLOCKED' && days > 0 )
|
||||
? `${value} - ${days}D`
|
||||
: value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -24,5 +24,4 @@ export class KanbanEntry {
|
||||
public answerCode: string;
|
||||
public isLastOfPriority: boolean;
|
||||
public worklog: number;
|
||||
public daysBlocked: number;
|
||||
}
|
||||
|
||||
@ -17,28 +17,14 @@ export class KanbanService {
|
||||
|
||||
constructor(private httpService: Http) {}
|
||||
|
||||
/**
|
||||
* Returns an observable instance to the kanban board api
|
||||
*
|
||||
* @returns {Observable<KanbanBoard>}
|
||||
*/
|
||||
public getList(): Observable<KanbanBoard> {
|
||||
return this.httpService.get(this.url).map(res => this.preprocessPriorities(<KanbanBoard>res.json()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Route preload resolver
|
||||
*
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @returns {Promise<KanbanBoard>}
|
||||
*/
|
||||
public resolve(route: ActivatedRouteSnapshot): Promise<KanbanBoard> {
|
||||
return this.getList().toPromise().then(result => result ? result : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the board
|
||||
*/
|
||||
public reload() {
|
||||
this.getList().subscribe(result => this.cachedKanbanBoard = result);
|
||||
}
|
||||
@ -51,21 +37,20 @@ export class KanbanService {
|
||||
this.cachedKanbanBoard = kanbanBoard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to preprocess all the entries, mark last item of every priority type for display formatting
|
||||
*
|
||||
* @param {KanbanBoard} kanbanBoard
|
||||
* @returns {KanbanBoard}
|
||||
*/
|
||||
private preprocessPriorities(kanbanBoard: KanbanBoard): KanbanBoard {
|
||||
['inbox','inProgress','verification'].map(progress => {
|
||||
['inbox','inProgress','verification','done'].map(progress => {
|
||||
kanbanBoard[progress].map(entry => entry.isLastOfPriority = false);
|
||||
['Trivial',
|
||||
'Minor',
|
||||
'Major',
|
||||
'Critical',
|
||||
'Blocker'].map(prio => {
|
||||
let prioLastIndex = kanbanBoard[progress].reduce((accumulator, value, idx) => value.issuePriority==prio ? idx : accumulator, -1);
|
||||
let prioLastIndex = -1;
|
||||
kanbanBoard[progress].map( (entry, idx) => {
|
||||
if(entry.issuePriority == prio) {
|
||||
prioLastIndex = idx;
|
||||
}
|
||||
});
|
||||
try {
|
||||
kanbanBoard[progress][prioLastIndex].isLastOfPriority = true;
|
||||
} catch(e) {}
|
||||
|
||||
@ -5,15 +5,7 @@ import {Pipe, PipeTransform} from '@angular/core';
|
||||
})
|
||||
export class PriorityColorPipe implements PipeTransform {
|
||||
|
||||
/**
|
||||
* Format the []-tags in the issue summary
|
||||
*
|
||||
* @param value
|
||||
* @param {string} prioIcon
|
||||
* @param {number} worklog
|
||||
* @returns {string}
|
||||
*/
|
||||
transform(value: string, prioIcon: string = "", worklog: number = 0): string {
|
||||
transform(value: any, prioIcon: string = "", worklog: number = 0): any {
|
||||
let mhrMatch = /(\[(.*)mhr\])/ig;
|
||||
value = value.replace(mhrMatch, (fullMatch: string, mhrMatched: string, hoursMatch: number) => {
|
||||
return `<span class="match-mhr">[${worklog}/${hoursMatch} mhr] </span> `;
|
||||
|
||||
@ -10,12 +10,6 @@ export class SelfUpdaterService {
|
||||
private appRevision: number = 0;
|
||||
private initFailed: boolean = false;
|
||||
|
||||
/**
|
||||
* Load current revision data from the server on initialization
|
||||
*
|
||||
* @param {Http} httpService
|
||||
* @param {Location} locationService
|
||||
*/
|
||||
constructor(
|
||||
private httpService: Http,
|
||||
private locationService: Location,
|
||||
@ -32,17 +26,10 @@ export class SelfUpdaterService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return observable instance to the installed version on the server
|
||||
* @returns {Observable<number>}
|
||||
*/
|
||||
private getDeployedRevision(): Observable<number> {
|
||||
return this.httpService.get(this.locationService.prepareExternalUrl("/revision.json")).map(result => result.json());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the application if the server revision is newer than the current running revision
|
||||
*/
|
||||
public checkAndReloadIfNecessary() {
|
||||
if (!this.initFailed) {
|
||||
this.getDeployedRevision().subscribe(
|
||||
|
||||
@ -5,13 +5,6 @@ import {Pipe, PipeTransform} from '@angular/core';
|
||||
})
|
||||
export class ShortenTextPipe implements PipeTransform {
|
||||
|
||||
/**
|
||||
* Shorten long text, postfixing it with '...'
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {number} length
|
||||
* @returns {any}
|
||||
*/
|
||||
transform(value: string, length: number = 120): any {
|
||||
return value.length > length
|
||||
? (value.substring(0,length) + '...')
|
||||
|
||||
@ -1,20 +1,11 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
html,
|
||||
body {
|
||||
height: 100% !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #303030 !important;
|
||||
color: #eeeeee !important;
|
||||
margin-top: 1em !important;
|
||||
margin-bottom: 1em !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
app-kanban-board {
|
||||
overflow: hidden;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.ui.fullwide-container {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user