parent
57131fa32b
commit
b533bbd70a
@ -0,0 +1,29 @@ |
||||
<widget-header |
||||
[name]="widgetName" |
||||
[icon]="'info1'" |
||||
[editable]="isEditable"> |
||||
|
||||
<widget-menu |
||||
[resource]="resource"> |
||||
</widget-menu> |
||||
</widget-header> |
||||
|
||||
<div class="grid--widget-content"> |
||||
<div class="content-grid"> |
||||
<div class="left-column"> |
||||
<div class="traffic-lights"> |
||||
<div class="light" [ngClass]="{'-active':currentStatusCode === 'off_track'}"> |
||||
<div class="bulb -red" [attr.title]="availableStatuses['off_track']"></div> |
||||
</div> |
||||
<div class="light" [ngClass]="{'-active':currentStatusCode === 'at_risk'}" > |
||||
<div class="bulb -yellow" [attr.title]="availableStatuses['at_risk']"></div> |
||||
</div> |
||||
<div class="light" [ngClass]="{'-active':currentStatusCode === 'on_track'}"> |
||||
<div class="bulb -green -active" [attr.title]="availableStatuses['on_track']"></div> |
||||
</div> |
||||
</div> |
||||
<div class="current-status" [innerHtml]="availableStatuses[currentStatusCode]"></div> |
||||
</div> |
||||
<div class="right-column" [innerHtml]="explanation"></div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,83 @@ |
||||
.traffic-lights |
||||
width: 40px |
||||
height: 100px |
||||
padding: 5px |
||||
border: 1px solid gray |
||||
border-radius: 2px |
||||
|
||||
.light |
||||
width: 30px |
||||
height: 30px |
||||
padding: 5px |
||||
&:hover, |
||||
&.-active |
||||
padding: 0px |
||||
animation-name: shrink-padding |
||||
animation-duration: 200ms |
||||
&.-active |
||||
.-green |
||||
background-color: green |
||||
.-yellow |
||||
background-color: orange |
||||
.-red |
||||
background-color: red |
||||
|
||||
.bulb |
||||
width: 20px |
||||
height: 20px |
||||
border-radius: 50% |
||||
border-width: 1px |
||||
border-style: solid |
||||
&.-green |
||||
border-color: green |
||||
&.-yellow |
||||
border-color: orange |
||||
&.-red |
||||
border-color: red |
||||
|
||||
.light |
||||
&:hover, |
||||
&.-active |
||||
.bulb |
||||
width: 30px |
||||
height: 30px |
||||
border-width: 4px |
||||
animation-name: increase-size |
||||
animation-duration: 200ms |
||||
|
||||
.current-status |
||||
margin-top: 10px |
||||
|
||||
.content-grid |
||||
display: flex |
||||
flex-direction: row |
||||
width: 100% |
||||
|
||||
.left-column |
||||
flex: 1 |
||||
flex-direction: column |
||||
flex-basis: content |
||||
max-width: 100px |
||||
padding-right: 20px |
||||
|
||||
.right-column |
||||
flex: 2 |
||||
flex-direction: column |
||||
|
||||
@keyframes shrink-padding |
||||
from |
||||
padding: 5px |
||||
to |
||||
padding: 0px |
||||
|
||||
@keyframes increase-size |
||||
from |
||||
width: 20px |
||||
height: 20px |
||||
border-width: 1px |
||||
background-color: transparent |
||||
to |
||||
width: 30px |
||||
height: 30px |
||||
border-width: 4px |
||||
background-color: transparent |
@ -0,0 +1,115 @@ |
||||
// -- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See doc/COPYRIGHT.rdoc for more details.
|
||||
// ++
|
||||
|
||||
import {Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef, Injector, ViewChild, ElementRef} from '@angular/core'; |
||||
import {AbstractWidgetComponent} from "app/modules/grids/widgets/abstract-widget.component"; |
||||
import {I18nService} from "core-app/modules/common/i18n/i18n.service"; |
||||
import {ProjectDmService} from "core-app/modules/hal/dm-services/project-dm.service"; |
||||
import {CurrentProjectService} from "core-components/projects/current-project.service"; |
||||
import {SchemaResource} from "core-app/modules/hal/resources/schema-resource"; |
||||
import {ProjectResource} from "core-app/modules/hal/resources/project-resource"; |
||||
import {PortalCleanupService} from 'core-app/modules/fields/display/display-portal/portal-cleanup.service'; |
||||
import {WorkPackageViewHighlightingService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-highlighting.service"; |
||||
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space"; |
||||
import {ProjectCacheService} from "core-components/projects/project-cache.service"; |
||||
|
||||
export const emptyPlaceholder = '-'; |
||||
|
||||
@Component({ |
||||
templateUrl: './project-status.component.html', |
||||
styleUrls: ['./project-status.component.sass'], |
||||
changeDetection: ChangeDetectionStrategy.OnPush, |
||||
providers: [ |
||||
// required by the displayField service to render the fields
|
||||
PortalCleanupService, |
||||
WorkPackageViewHighlightingService, |
||||
IsolatedQuerySpace |
||||
] |
||||
}) |
||||
export class WidgetProjectStatusComponent extends AbstractWidgetComponent implements OnInit { |
||||
@ViewChild('contentContainer', { static: true }) readonly contentContainer:ElementRef; |
||||
|
||||
public currentStatusCode:String = 'not_set'; |
||||
public explanation:String = ''; |
||||
public availableStatuses:any = { |
||||
on_track: this.i18n.t('js.grid.widgets.project_status.on_track'), |
||||
off_track: this.i18n.t('js.grid.widgets.project_status.off_track'), |
||||
at_risk: this.i18n.t('js.grid.widgets.project_status.at_risk'), |
||||
not_set: this.i18n.t('js.grid.widgets.project_status.not_set') |
||||
}; |
||||
|
||||
constructor(protected readonly i18n:I18nService, |
||||
protected readonly injector:Injector, |
||||
protected readonly projectDm:ProjectDmService, |
||||
protected readonly projectCache:ProjectCacheService, |
||||
protected readonly currentProject:CurrentProjectService, |
||||
protected readonly cdr:ChangeDetectorRef) { |
||||
super(i18n, injector); |
||||
} |
||||
|
||||
ngOnInit() { |
||||
this.loadAndRender(); |
||||
} |
||||
|
||||
public get isEditable() { |
||||
return false; |
||||
} |
||||
|
||||
private loadAndRender() { |
||||
Promise.all( |
||||
[this.loadCurrentProject(), |
||||
this.loadProjectSchema()] |
||||
) |
||||
.then(([project, schema]) => { |
||||
if (project.status) { |
||||
this.currentStatusCode = project.status.code; |
||||
this.explanation = project.status.explanation; |
||||
} else { |
||||
this.currentStatusCode = 'not_set'; |
||||
this.explanation = ''; |
||||
} |
||||
this.redraw(); |
||||
}); |
||||
} |
||||
|
||||
private loadCurrentProject() { |
||||
return this.projectCache.require(this.currentProject.id as string); |
||||
} |
||||
|
||||
public get isLoaded() { |
||||
return this.projectCache.state(this.currentProject.id as string).value; |
||||
} |
||||
|
||||
private loadProjectSchema() { |
||||
return this.projectDm.schema(); |
||||
} |
||||
|
||||
private redraw() { |
||||
this.cdr.detectChanges(); |
||||
} |
||||
} |
Loading…
Reference in new issue