321 lines
13 KiB
Plaintext
321 lines
13 KiB
Plaintext
@using EnVisage.Models
|
|
@using Microsoft.AspNet.Identity
|
|
@model Object
|
|
@{
|
|
var user = (new EnVisage.Code.Cache.UsersCache()).Value.FirstOrDefault(x => x.Id == new Guid(User.Identity.GetID()));
|
|
var menuId = (Model is CapacityDetailsOptionsModel ? ((CapacityDetailsOptionsModel)Model).MenuId : "acLiteMenuButton");
|
|
CapacityPageInitOption initDataObject = new CapacityPageInitOption()
|
|
{
|
|
IsUOMHours = user != null && !user.PreferredResourceAllocation,
|
|
PreferredTotalsDisplaying = user != null && user.PreferredTotalsDisplaying,
|
|
IsBarMode = false,
|
|
IsViewModeMonth = true,
|
|
IsCapacityModeActuals = false,
|
|
StartDate = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1).ToString("MM/dd/yyyy"),
|
|
EndDate = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1).AddMonths(5).ToString("MM/dd/yyyy"),
|
|
MenuId = menuId,
|
|
ModelType = Model != null ? Model.GetType().ToString() : string.Empty,
|
|
PagePreferences = user.GetPreferences(Request.Url.AbsolutePath, "capacityManagementView"),
|
|
DataSection = "capacityManagementView",
|
|
};
|
|
|
|
initDataObject.TeamId = ((TeamboardModel)Model).SelectedTeamId;
|
|
initDataObject.PageTitle = "dashboard"; // SA. ENV-905. Backurl page name - to return to this page
|
|
|
|
var json = Newtonsoft.Json.JsonConvert.SerializeObject(initDataObject);
|
|
}
|
|
<div id="erorMsgPlaceholder"></div>
|
|
<script type="text/javascript">
|
|
var _menuCM;
|
|
var _pageCMPreferences = [];
|
|
var angularScope;
|
|
function initSwitchers() {
|
|
$('#uomMode').switcher({
|
|
on_state_content: '# Hours',
|
|
off_state_content: '# Resources'
|
|
});
|
|
$('#uomMode').parent().css("width", "93px");
|
|
$('#capBarMode').switcher({
|
|
on_state_content: 'Colors',
|
|
off_state_content: 'Values'
|
|
});
|
|
$('#capBarMode').parent().css("width", "73px");
|
|
|
|
$('#capacityView').switcher({
|
|
on_state_content: 'Actual',
|
|
off_state_content: 'Planned'
|
|
});
|
|
|
|
$('#sortOrder').switcher({
|
|
on_state_content: 'Asc',
|
|
off_state_content: 'Desc'
|
|
});
|
|
$('#capacityView').parent().css("width", "93px");
|
|
}
|
|
|
|
init.push(function () {
|
|
var options = {
|
|
format: 'mm/dd/yyyy',
|
|
autoclose: true,
|
|
orientation: $('body').hasClass('right-to-left') ? "auto right" : 'auto auto'
|
|
};
|
|
|
|
$(window).scroll(function () {
|
|
$('.menuGroup').removeClass('open');
|
|
hideRedundantPopovers($('#capacity-table'), null);
|
|
});
|
|
$(document).click(function (event) {
|
|
if (!$(event.target).is('[data-toggled="popover"]'))
|
|
hideRedundantPopovers($('#capacity-table'), null);
|
|
});
|
|
|
|
initSwitchers();
|
|
angularScope = angular.element(document.getElementById('acController')).scope();
|
|
$('#sortBy').select2();
|
|
});
|
|
|
|
function hideRedundantPopovers(container, currentBtn) {
|
|
var id = null;
|
|
if (currentBtn) {
|
|
if (currentBtn.is('[data-toggle="popover"]'))
|
|
id = currentBtn.attr('id');
|
|
else
|
|
id = currentBtn.closest('[data-toggle="popover"]').attr('id');
|
|
}
|
|
container.find('[data-toggle="popover"]' + (id != null && id != undefined) ? '[id!="' + id + '"]' : '').popover('destroy');
|
|
}
|
|
|
|
function switchUOMMode() {
|
|
angular.element(document.getElementById('acController')).scope().switchUOMMode();
|
|
saveCapacityManagementPreferences();
|
|
}
|
|
|
|
function switchBarMode() {
|
|
angular.element(document.getElementById('acController')).scope().switchBarMode();
|
|
saveCapacityManagementPreferences();
|
|
}
|
|
|
|
function switchCapacityViewMode() {
|
|
angular.element(document.getElementById('acController')).scope().switchCapacityVew();
|
|
saveCapacityManagementPreferences();
|
|
}
|
|
|
|
function changeSortColumn(val) {
|
|
angular.element(document.getElementById('acController')).scope().changeSortBy(val.value);
|
|
saveCapacityManagementPreferences();
|
|
}
|
|
|
|
function switchSortOrder(val) {
|
|
angular.element(document.getElementById('acController')).scope().switchSortOrder();
|
|
saveCapacityManagementPreferences();
|
|
}
|
|
|
|
// SA. ENV-815
|
|
function saveCapacityManagementPreferences() {
|
|
var section = getDataSection($("#menuCalendarOptions"));
|
|
var prefs = collectPreferences(section);
|
|
saveUserPagePreferences(prefs, section);
|
|
}
|
|
|
|
// SA. ENV-815
|
|
function loadCapacityManagementPreferences() {
|
|
var section = getDataSection($("#menuCalendarOptions"));
|
|
_pageCMPreferences = loadUserPagePreferences(section);
|
|
return section;
|
|
}
|
|
|
|
function changeCapacityView(val) {
|
|
angular.element(document.getElementById('acController')).scope().changeCapacity(val.value);
|
|
}
|
|
|
|
</script>
|
|
|
|
<style type="text/css">
|
|
.validation-error {
|
|
color: red;
|
|
}
|
|
|
|
#table thead {
|
|
border-collapse: separate;
|
|
border-spacing: 0;
|
|
}
|
|
|
|
#table thead tr th {
|
|
-moz-background-clip: padding-box;
|
|
-webkit-background-clip: padding-box;
|
|
background-clip: padding-box;
|
|
border-top: 1.1px solid;
|
|
border-right: 1.1px solid;
|
|
}
|
|
|
|
.editable-input {
|
|
width: 300px;
|
|
}
|
|
</style>
|
|
|
|
<!-- / Large modal -->
|
|
<div id="acController" ng-controller="activityCalendarLiteController" ng-init="init(@json)" ng-cloak>
|
|
<div id="menuCalendarOptions" ng-show="false">
|
|
<li class="padding-xs-hr">
|
|
<label><span class="switcherLbl">Mode</span><input type="checkbox" data-key="uomMode" name="uomMode" id="uomMode" class="switcher px" onclick="switchUOMMode()" /></label></li>
|
|
<li class="padding-xs-hr">
|
|
<label><span class="switcherLbl">Projects Displayed as</span><input type="checkbox" data-key="capBarMode" name="capBarMode" id="capBarMode" class="switcher px" onclick="switchBarMode()" /></label></li>
|
|
<li class="padding-xs-hr">
|
|
<label><span class="switcherLbl">Use Capacity</span><input type="checkbox" data-key="capacityView" name="capacityView" id="capacityView" class="switcher px" onclick="switchCapacityViewMode()" /></label></li>
|
|
<li class="divider"></li>
|
|
<li class="padding-xs-hr" style="padding-bottom:3px;">
|
|
|
|
<nobr><span class="switcherLbl" style="padding-top:3px;">Sort By </span><select id="sortBy" data-key="sortBy" class="form-control" style="width:100px;"
|
|
onchange="changeSortColumn(this)">
|
|
<option value="Name">Name</option>
|
|
<option value="Type">Type</option>
|
|
<option value="Date">Date</option>
|
|
<option value="Priority">Priority</option>
|
|
</select>
|
|
</nobr>
|
|
</li>
|
|
<li class="padding-xs-hr">
|
|
<label><span class="switcherLbl">Sort Order</span><input type="checkbox" data-key="sortOrder" name="sortOrder" id="sortOrder" class="switcher px" onclick="switchSortOrder()" /></label></li>
|
|
|
|
<li class="padding-xs-hr">
|
|
|
|
<span class="switcherLbl">Resource Totals as </span><br />
|
|
<select id="selectOptions" data-key="showOption" class="form-control for-select2" style="padding: 3px"
|
|
onchange="changeCapacityView(this)">
|
|
<option value="1">Allocated/Capacity</option>
|
|
<option value="2">Need/Capacity</option>
|
|
<option value="3">Allocated/Need</option>
|
|
</select>
|
|
|
|
</li>
|
|
</div>
|
|
|
|
<div id="acLoader" class="loadRotator">
|
|
<span>
|
|
<img class="valign-middle" src="@Url.Content("~/Content/images/loadFA.gif")" /> loading...</span>
|
|
</div>
|
|
<table class="table table-light table-striped widget-table" id="capacity-table" ng-if="data != null && data.Calendar.length > 0">
|
|
<thead>
|
|
<tr>
|
|
<th class="firstcol layout-cell" style="border: none!important;"></th>
|
|
<th class="data-cell layout-cell" ng-repeat="header in (data.Headers | filter : {IsMonth:true})"></th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<th class="firstcol" rowspan="2">Project/Scenario</th>
|
|
<!-- year header -->
|
|
<th ng-repeat="header in (data.YearHeaders)" colspan="{{ header.SpanCount }}">{{ header.Title }}
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
<th class="data-cell" ng-repeat="header in (data.Headers | filter : {IsMonth:true})"
|
|
ng-click="onMonthHeaderClick(header)">{{header.Title.substr(0,3)}}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 0 }">
|
|
<!-- Project row -->
|
|
<td class="firstcol">
|
|
<span class="project-name" title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</span>
|
|
<!--Scenario row-->
|
|
<br ng-if="row.ScenarioId != null" />
|
|
<span ng-if="row.ScenarioId != null" class="popover-warning popover-dark">{{ row.Name1 || 'empty' }}</span>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<span ng-if="!calendarFilters.IsBarMode && !row.ReadOnly[$index]">{{ (col || 0 | number:2)}}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 2 }">
|
|
<!-- Vacations row-->
|
|
<td class="firstcol" ng-if="row.IsTotals">
|
|
<span title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</span>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<span>{{ (col || 0 | number:2)}}</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 3 }">
|
|
<!-- Trainings row-->
|
|
<td class="firstcol" ng-if="row.IsTotals">
|
|
<span title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</span>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<span>{{ (col || 0 | number:2)}}</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 4 }">
|
|
<!-- Loan-outs row ? -->
|
|
<td class="firstcol" ng-if="row.IsTotals">
|
|
<span title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</span>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<span>{{ (col || 0 | number:2)}}</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 5 }">
|
|
<!-- Totals row (by Active scenarios) -->
|
|
<td class="firstcol" ng-if="row.IsTotals">
|
|
<strong title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</strong>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<strong ng-if="!row.ReadOnly[$index] && row.IsTotals">{{ (col || 0 | number:2)}}</strong>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 6 }">
|
|
<!-- Remaining Capacity row -->
|
|
<td class="firstcol" ng-if="row.IsTotals">
|
|
<strong title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</strong>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<strong ng-if="!row.ReadOnly[$index] && row.IsTotals">{{(CalcRemainingCapacity(col, $index)|| 0 | number:2)}}</strong>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="row in data.Calendar | filter: { RowType: 7 }">
|
|
<!-- ExpCat row -->
|
|
<td class="firstcol">
|
|
<span class="project-name" title="{{ row.Name || 'empty' }}">{{ row.Name || 'empty' }}</span>
|
|
</td>
|
|
<!--values-->
|
|
<td class="data-cell double-cell" ng-class="row.CSSClass[$index]" data-ng-attr-style="{{ row.BarStyle[$index] && row.BarStyle[$index] || '' }}"
|
|
ng-repeat="col in (row.QuantityValues) track by $index" ng-show="data.Headers[$index].Show"
|
|
ng-if="data.Headers[$index].Initialized">
|
|
<span ng-if="calendarFilters.ShowCapacity == 1">{{ (row.QuantityValues[$index] || 0 | number:2)}}/{{ (row.QuantityTotalResValue[$index] || 0 | number:2)}}
|
|
</span>
|
|
<span ng-if="calendarFilters.ShowCapacity == 2">{{ (row.QuantityExpCatTotalValue[$index] || 0 | number:2)}}/{{ (row.QuantityTotalResValue[$index] || 0 | number:2)}}
|
|
</span>
|
|
<span ng-if="calendarFilters.ShowCapacity == 3">{{ (row.QuantityValues[$index] || 0 | number:2)}}/{{ (row.QuantityExpCatTotalValue[$index] || 0 | number:2)}}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<table class="table" style="width: 100%; display: none;" id="capacity-table-empty" ng-if="data == null">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: center;">There is no data available.
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|