EnVisageOnline/Beta/Source/EnVisage/Views/CapacityManagement/_capacityManagement.cshtml

556 lines
27 KiB
Plaintext

@using EnVisage.Models
@model Object
@{
var isUOMHoursChecked = "checked";
if (ViewBag.IsUOMHours != null)
{
isUOMHoursChecked = ViewBag.IsUOMHours ? "checked" : string.Empty;
}
}
<div id="erorMsgPlaceholder"></div>
<script type="text/javascript">
var _menuCM;
var _getCMPrefUrl = '@Url.Action("GetPagePreferences", "User")';
var _saveCMPrefUrl = '@Url.Action("SavePagePreferences", "User")';
var _pageCMKey = 'Capacity_Management';
var _pageCMPreferences = [];
var resizeFreezCapacity = function () {
var t = $("#capacity-table");
var thsWidthI = 0;
var thName = t.find("tr:eq(0)>th:eq(0)");
var tr = t.find("tr:eq(2)");
var ths = tr.find("th");
var dateThs = ths.filter(":gt(0):visible");
if (dateThs.length == 0)
return;
var visibleColumns = 0;
//we do not need to account former "grannd totals" column (second column) here
//ths.filter(":visible").each(function (i, o) {
dateThs.each(function (i, o) {
thsWidthI += $(o).innerWidth();
visibleColumns++;
});
//+thName
thsWidthI += thName.innerWidth();
visibleColumns++;
var divWidthI = t.parent().innerWidth();
var longestCategory = 0;
var ltext = "";
t.find("td:nth-child(1)").each(function (i, td) {
var text = $(td).html();
var txtElement = $("<td></td>").html(text).css({
'class': "headcol"
}).prependTo($(td).parent());
longestCategory = Math.max(longestCategory, txtElement.width());
ltext = longestCategory > txtElement.width() ? ltext : txtElement.html();
txtElement.remove();
});
var delta = 0;
if ((thsWidthI - thName.width() + longestCategory) > divWidthI) {
// if width of all columns > visible table then we need to shrink or expand name column to the width of smallest category name
delta = -Math.min(thName.width() - longestCategory, thsWidthI - divWidthI + visibleColumns + 1);
} else if ((thsWidthI - thName.width() + longestCategory) < divWidthI) {
delta = divWidthI - thsWidthI - visibleColumns;
}
if (delta == 0) {
//t.find("tbody tr td:nth-child(1)").each(correctFirstCol, [thName.width()]);
//t.find("th:nth-child(1)").each(correctFirstCol, [thName.width()]);
return;
}
t.find("tbody tr td:nth-child(1)").each(rszObj1, [delta, null, null]);
t.find("th:nth-child(1)").each(rszObj1, [delta, null, null]);
//t.find("tfoot td:first").each(rszObj, [delta, null, null]);
t.find("tbody tr td:nth-child(2)").each(rszObj1, [null, delta, null]);
t.find("th:nth-child(2)").each(rszObj1, [null, delta, null]);
//t.find("tfoot td:eq(1)").each(rszObj, [null, delta, null]);
//var total3Width = ths.eq(0).outerWidth() + ths.eq(1).outerWidth() + ths.eq(2).outerWidth();
t.parent().each(rszObj1, [null, null, thName.outerWidth() - 1]);
};
//function correctFirstCol(width)
//{
// if (width != null && width != 0) {
// var oldWidth = $(this).width();
// if (width != oldWidth)
// $(this).css('width', width);
// }
//}
function rszObj1(deltaWidth, deltaLeft, padLeft) {
if (deltaWidth != null && deltaWidth != 0) {
var oldWidth = $(this).width();
$(this).css('width', oldWidth + deltaWidth);
}
if (deltaLeft != null && deltaLeft != 0) {
var oldLeft = $(this).css('left');
if (oldLeft != null && oldLeft.length > 0) {
var l = parseInt(oldLeft.substr(0, oldLeft.length - 1));
if (!isNaN(l))
$(this).css('left', l + deltaLeft);
}
}
if (padLeft != null && !isNaN(padLeft)) {
$(this).css('padding-left', padLeft);
}
}
function reInitFields1() {
angular.element(window).resize(function () {
resizeFreezCapacity();
});
//$('#chMode').switcher({
// on_state_content: 'Quantity',
// off_state_content: 'Cost'
//});
//$('#chMode').parent().css("width", "90px");
//$('#monthWeekMode').switcher({
// on_state_content: 'Month',
// off_state_content: 'Week'
//});
//$('#monthWeekMode').parent().css("width", "80px");
//$('#uomMode').switcher({
// on_state_content: 'Hours',
// off_state_content: 'Resources'
//});
//$('#uomMode').parent().css("width", "90px");
}
init.push(function () {
reInitFields1();
$("#btnReloadCalendar").click();
var options = {
format: 'm/d/yyyy'
};
$('select[name=selCompany]').val($("select[name=selCompany] option:first").val());
initCM();
//debugger;
});
function changeCapacityView(val)
{
angular.element(document.getElementById('controller1')).scope().changeCapacity(val.value);
}
function switchUOMMode()
{
angular.element(document.getElementById('controller1')).scope().switchUOMMode();
}
function switchBarMode() {
angular.element(document.getElementById('controller1')).scope().switchBarMode();
}
function switchViewMode() {
angular.element(document.getElementById('controller1')).scope().switchViewMode();
}
function switchGroupByTeam() {
angular.element(document.getElementById('controller1')).scope().switchGroupByTeam();
}
function switchShow(upper) {
angular.element(document.getElementById('controller1')).scope().hideCalendarPart(upper);
}
function initCMMenuItems() {
_menuCM.html("");
$.each($("#menuCalendarOptions li"), function (i, o) {
$(o).clone(true).appendTo(_menuCM);
});
}
function initCM() {
$.post(_getCMPrefUrl, { key: _pageCMKey }, function (response) {
console.log(response);
if (response.Data == null || response.Data == '')
_pageCMPreferences = [];
else
_pageCMPreferences = JSON.parse(response.Data);
if (_menuCM == null)
@if(Model is CapacityDetailsOptionsModel){
<text>
_menuCM = $("#@(((CapacityDetailsOptionsModel)Model).MenuId)");
</text>
}else{
<text>
_menuCM = $("#visibilitydropdown_calendar");
</text>
}
initCMMenuItems();
_menuCM.click(function (event) {
event.stopPropagation();
});
//debugger;
var scope = angular.element(document.getElementById('controller1')).scope();
//show tooltips for clipped cells
for (var i = 0; i < _pageCMPreferences.length; i++) {
if (!_pageCMPreferences[i].key)
continue;
var li = _menuCM.find('li[data-key=' + _pageCMPreferences[i].key + ']');
if (li == null)
continue;
var val = _pageCMPreferences[i].val != null ? _pageCMPreferences[i].val : null;
li.find('input[type=checkbox]').prop('checked', val != null ? val : false);
if (li.find('input[type=checkbox]').attr("id") == "showTopMode")
scope.calendarFilters.ShowUpper = val != null ? val : false;
if (li.find('input[type=checkbox]').attr("id") == "showButtomMode")
scope.calendarFilters.ShowLower = val != null ? val : false;
if (li.find('input[type=checkbox]').attr("id") == "uomMode")
scope.calendarFilters.IsUOMHours = val != null ? val : false;
if (li.find('input[type=checkbox]').attr("id") == "capBarMode")
scope.calendarFilters.IsBarMode = val != null ? val : false;
if (li.find('input[type=checkbox]').attr("id") == "defaultView")
scope.calendarFilters.IsViewModeMonth = val != null ? val : false;
@if (!(Model is TeamboardModel))
{
<text>
if (li.find('input[type=checkbox]').attr("id") == "groupByTeam")
scope.calendarFilters.GroupByTeam = val != null ? val : false;
</text>
}
if (li.find('select').attr("id") == "selectOptions") {
//debugger;
var selectVal = _pageCMPreferences[i].val != null ? _pageCMPreferences[i].val : 1; //"Total Allocated/Total Need";
li.find('select').val(selectVal);
scope.calendarFilters.ShowCapacity = selectVal;
}
}
$('#showTopMode').switcher({
on_state_content: 'On',
off_state_content: 'Off'
});
//$('#showTopMode').parent().css("width", "93px");
$('#showButtomMode').switcher({
on_state_content: 'On',
off_state_content: 'Off'
});
//$('#showButtomMode').parent().css("width", "93px");
@if (!(Model is TeamboardModel))
{
<text>
$('#groupByTeam').switcher({
on_state_content: 'On',
off_state_content: 'Off'
});
</text>
}
if (!scope.calendarFilters.ShowLower)
$("#showTopMode").switcher('disable');
if (!scope.calendarFilters.ShowUpper)
$("#showButtomMode").switcher('disable');
$('#uomMode').switcher({
on_state_content: '# Hours',
off_state_content: '# Resources'
});
$('#uomMode').parent().css("width", "93px");
$('#capBarMode').switcher({
on_state_content: 'Bars',
off_state_content: 'Numbers'
});
$('#capBarMode').parent().css("width", "93px");
$('#defaultView').switcher({
on_state_content: 'Month',
off_state_content: 'Week'
});
$('#defaultView').parent().css("width", "93px");
//$("#selectOptions").select2({
// //data: [{id:1, text: "Some Text" }],
// single: true,
// }
//);
}).error(function (h, e) {
console.log("h = " + h);
console.log("e = " + e);
});
}
function onCMPreferencesItemClick(menuItem) {
var postData = { pageKey: _pageCMKey };
var items = [];
_menuCM.children('li').each(function (index, li) {
var key = $(li).data('key');
if (!!key) {
var item = $(li).find('input[type=checkbox]');
if (item.length > 0) {
var val = item.prop('checked');
if (!!val)
items.push({ key: key, val: val });
else
items.push({ key: key, val: false });
} else {
var item = $(li).find('select');
if (item.length > 0) {
var val = item.val();
if (!!val)
items.push({ key: key, val: val });
}
}
}
});
//var colOrder = [];
//$.each(_evdttbl.dataTable().fnSettings().aoColumns, function (i, obj) {
// colOrder.push(obj.mData);
//});
//items.push({ key: 'tblColOrder', val: colOrder });
postData.data = JSON.stringify(items);
$.post(_saveCMPrefUrl, postData, function (data) {
console.log('save: ' + data);
}).error(function (h, e) {
console.log("save. h = " + h);
console.log("save. e = " + e);
});
}
</script>
<style type="text/css">
.validation-error {
color : red;
}
#table thead{
border-collapse: separate;
border-spacing: 0;
}
#table thead tr th{
background-clip: padding-box;
border-top: 1.1px solid;
border-right: 1.1px solid;
}
.editable-input{
width:300px;
}
</style>
<!-- / Large modal -->
<div id="controller1" ng-controller="capacityManagementController">
<div id="menuCalendarOptions" ng-show="false">
<li class="padding-xs-hr" data-key="showChart"><label><span class="switcherLbl">Show top part</span><input type="checkbox" ng-model="calendarFilters.ShowUpper" name="showTopMode" id="showTopMode" class="switcher px" onclick="switchShow(true)"/></label></li>
<li class="padding-xs-hr" data-key="showCriteria"><label><span class="switcherLbl">Show bottom part</span><input type="checkbox" ng-model="calendarFilters.ShowLower" name="showButtomMode" id="showButtomMode" class="switcher px" onclick="switchShow(false)"/></label></li>
<li class="padding-xs-hr" data-key="showOption"><label><span class="switcherLbl">Show ECs in the bottom part as</span>
<select id="selectOptions" class="form-control" style="padding: 3px"
ng-model="calendarFilters.ShowCapacity" onchange="changeCapacityView(this)">
<option value="1">Allocated/Capacity</option>
<option value="2">Need/Capacity</option>
<option value="3">Allocated/Need</option>
</select></label></li>
@*"ng-change="changeCapacity(calendarFilters.ShowCapacity) <li class="padding-xs-hr" data-key="showOption"><div class="checkbox"><label><span class="switcherLbl" style="width:93px">Left Total</span>
<select id="selectOptions" class="form-control"
ng-model="calendarFilters.ShowCapacity"
ng-options="item.subItem as item.label for item in capacityValues track by item.id"
onchange="changeCapacityView()" ng-change="changeCapacity(calendarFilters.ShowCapacity)>
</select></label></div></li>*@
<li class="padding-xs-hr" data-key="uomMode"><label><span class="switcherLbl">Resources Mode</span><input type="checkbox" checked name="uomMode" id="uomMode" class="switcher px" onclick="switchUOMMode()"/></label></li>
<li class="padding-xs-hr" data-key="capBarMode"><label><span class="switcherLbl">Project Mode</span><input ng-model="calendarFilters.IsBarMode" type="checkbox" checked name="capBarMode" id="capBarMode" class="switcher px" onclick="switchBarMode()"/></label></li>
<li class="padding-xs-hr" data-key="defaultView"><label><span class="switcherLbl">Default View</span><input ng-model="calendarFilters.IsViewModeMonth" type="checkbox" checked name="defaultView" id="defaultView" class="switcher px" onclick="switchViewMode()"/></label></li>
@if (!(Model is TeamboardModel))
{
<text>
<li class="padding-xs-hr" data-key="groupByTeam"><label><span class="switcherLbl">Group by Team</span><input ng-model="calendarFilters.GroupByTeam" type="checkbox" checked name="groupByTeam" id="groupByTeam" class="switcher px" onclick="switchGroupByTeam()"/></label></li>
</text>
}
</div>
<div class="form-inline panel-body">
@if (!(Model is TeamboardModel) && !(Model is ViewBoardModel))
{
<div class="form-group" style="margin-right:10px;">
<label for="selCompany">Company</label>
<select ng-model="calendarFilters.CompanyId" name="selCompany" ng-options="s.Value as s.Text for s in companies" ng-change="getCalendar()" class="form-control">
<option value="">--Select option--</option>
</select>
</div>
}
<div class="form-group" style="margin-right:10px;">
<button class="btn btn-default" id="btnReloadCalendar" ng-click="getCalendar()"><i class="fa fa-refresh"></i> Reload</button>
<button class="btn btn-primary" ng-disabled="!anyUpdated()" ng-click="saveChanges()"><i class="fa fa-save"></i> Save Changes</button>
</div>
<div class="form-group" style="margin-right:10px;">
<span id="loader" class="h3"><img class="valign-middle" src="../Content/images/loadFA.gif"/></span>
</div>
</div>
<div class="table-light table-responsive very-big-table freezeTable1">
<table class="table table-striped table-bordered dataTable" style="width:100%" id="capacity-table" ng-if="data != null">
<thead>
<tr>
<th rowspan="3" style="width: 300px;text-align:center; padding-bottom:35px;" class="headcol firstcol">Project/Scenario</th>
<th class="nextcol" style="text-align:center;" ng-repeat="header in (data.YearHeaders)" colspan="{{ header.SpanCount }}">
{{ header.Title }}
</th>
</tr>
<tr>
<th class="headcol" style="visibility:hidden;"></th>
<th ng-repeat="header in (data.Headers | filter : {IsMonth:true})" style="text-align:center;text-decoration:underline;color:#4083a9;cursor:pointer;"
class="nextcol" ng-click="onMonthHeaderClick(header)" colspan="{{header.Collapsed ? 1 : header.Weeks.length}}">
<i class="fa" ng-class="header.CollapsedClass" style="margin-right: 5px;"></i>{{header.Title.substr(0,3)}}
</th>
</tr>
<tr >
<th class="headcol" style="visibility:hidden;"></th>
<th class="nextcol" ng-repeat="header in (data.Headers)" ng-show="header.Show" style="text-align:center;"
colspan="{{header.Collapsed ? 1 : header.Weeks.length}}">
{{ header.IsMonth ? '' : header.Title}}
</th>
</tr>
</thead>
<tbody ng-repeat="row in data.Calendar" ng-if="$index >= 0">
<tr ng-if="row.RowType == 8 && !row.IsUpperHidden" <!--Team = 8-->
<td style="width: 300px;" class="headcol">
<strong>
{{ row.Name || 'empty' }}
</strong>
</td>
<td colspan="{{data.Headers.length + 1}}">
</td>
</tr>
<tr ng-if="row.RowType != 8" ng-show="!row.IsParentCollapsed &&
(((row.ProjectId == null && row.ScenarioId == null && row.ExpCatId != null) && !row.IsLowerHidden) ||
(row.ProjectId != null && !row.IsUpperHidden) || row.RowType == 6 || (row.IsTotals && !row.IsUpperHidden))">
<!--Project, ExpendetureCategories row-->
<td style="width: 300px;color:#4083a9;cursor:pointer;" class="headcol"
ng-click="onParentNodeClick(row); resizeFreezAng();"
ng-if="!row.IsTotals && ((row.ProjectId != null) || (row.ProjectId == null && row.ScenarioId == null && row.ExpCatId != null))" resize-freez>
<a id="id_exp{{row.ExpCatId}}" href="javascript:;" ng-show="!row.EmptyScenario">
<i class="fa" ng-class="row.CollapsedClass" style="margin-right: 5px;" title="Expand">
</i>{{ row.Name || 'empty' }}
</a>
<span style="padding-left:15px;" ng-show="row.EmptyScenario">
{{ row.Name || 'empty' }}
</span>
<!--Scenario row-->
<br ng-if="row.ProjectId != null && row.ScenarioId != null && row.ExpCatId == null" />
<a ng-if="row.ProjectId != null && row.ScenarioId != null && row.ExpCatId == null" style="padding-left:15px;text-decoration:underline;color:#4083a9;cursor:pointer;" id="id_exp{{row.ScenarioId}}" ng-click="CheckLock($event, 'Scenario', row.ScenarioId, '@Url.Action("Details", "Scenarios")')" class="popover-warning popover-dark" href="">
{{ row.Name1 || 'empty' }}
</a>
</td>
<!--Vacation, Training, Loan-outs, Capacity, Totals row-->
<td style="width: 300px;" class="headcol"
ng-if="row.IsTotals">
<strong ng-if="row.RowType == 5 || row.RowType == 6"> <!--Total = 5, Capacity = 6-->
{{ row.Name || 'empty' }}
</strong>
<span ng-if="row.RowType != 5 && row.RowType != 6">
{{ row.Name || 'empty' }}
</span>
</td>
<!--values-->
<td 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">
<strong ng-if="!row.ReadOnly[$index] && row.IsTotals && (row.RowType == 5 || row.RowType == 6)"> <!--Total = 5, Capacity = 6-->
{{ (col || 0 | number:2)}}
</strong>
<span ng-if="(!calendarFilters.IsBarMode || row.RowType != 0) && !row.ReadOnly[$index] && (row.ProjectId != null || (row.IsTotals && row.RowType != 5 && row.RowType != 6))">
{{ (col || 0 | number:2)}}
</span>
<span ng-if="row.ProjectId == null && row.ExpCatId != null && calendarFilters.ShowCapacity == 1">
{{ (row.QuantityValues[$index] || 0 | number:2)}}/{{ (row.QuantityTotalResValue[$index] || 0 | number:2)}}
</span>
<span ng-if="row.ProjectId == null && row.ExpCatId != null && calendarFilters.ShowCapacity == 2">
{{ (row.QuantityExpCatTotalValue[$index] || 0 | number:2)}}/{{ (row.QuantityTotalResValue[$index] || 0 | number:2)}}
</span>
<span ng-if="row.ProjectId == null && row.ExpCatId != null && calendarFilters.ShowCapacity == 3">
{{ (row.QuantityValues[$index] || 0 | number:2)}}/{{ (row.QuantityExpCatTotalValue[$index] || 0 | number:2)}}
</span>
</td>
</tr>
<!--Resources assigned to scenario from top part of the grid -->
<tr ng-repeat="res in row.Resources" ng-show="!row.ExpCatCollapsed && !row.IsParentCollapsed" ng-if="row.RowType != 8 && row.ScenarioId != null && row.ExpCatId != null">
<td ng-style="{'width': res.width || '300px'}" class="headcol">
@*<td style="width: 300px;" class="headcol" resize-freez> *@
<div class="restbl">
<div>
<div style="padding-left:15px;">{{res.Name}}</div>
<div>
<button title="{{res.Title}}" class="btn btn-info btn-xs" ng-disabled="res.ReadOnly || isTakeAllDisabled(row, res)" ng-click="takeAll(row.ScenarioId, res.Id, row.ExpCatId, row.TeamId)"><i class="fa fa-asterisk"></i></button>
<button title="Take remaining" class="btn btn-primary btn-xs" ng-disabled="res.ReadOnly" ng-click="takeRemaining(row.ScenarioId, res.Id, row.ExpCatId, row.TeamId)"><i class="fa fa-plus"></i></button>
<button title="Zero this resource" class="btn btn-success btn-xs" ng-disabled="res.ReadOnly" ng-click="zeroResource(row.ScenarioId, res.Id, row.ExpCatId, row.TeamId)"><i class="fa fa-minus"></i></button>
<button title="Remove this resource"class="btn btn-danger btn-xs" ng-disabled="res.ReadOnly" ng-click="removeResource(row.ScenarioId, res.Id, row.ExpCatId, row.TeamId)"><i class="fa fa-times"></i></button>
</div>
</div>
</div>
</td>
<td style="max-width:40px;"
ng-repeat="col in (data.Headers) track by $index" ng-show="col.Show" ng-class="res.CSSClass[$index]">
<a href="#" ng-click="resizeFreezAng()" editable-text="res.QuantityValues[$index]" e-name="ColValue" e-ng-blur="onTxtBlur(this);" onshow="watchKeyInput(this)" buttons="no" blur="submit"
onbeforesave="checkResourceValue($data, row.ScenarioId, row.ExpCatId, res.Id, row.TeamId, $index)"
ng-if="(!col.IsMonth && !row.ReadOnly[$index] && !res.ReadOnly)" e-required>
{{ (res.QuantityValues[$index] || 0 | number:2) }}
</a>
<span ng-if="!row.ReadOnly[$index] && (col.IsMonth || res.ReadOnly)">
{{ (res.QuantityValues[$index] || 0 | number:2) }}
</span>
</td>
</tr>
<!--Resources assigned to expenditure category from bottom part of the grid -->
<tr ng-repeat="res in row.Resources" ng-show="!row.ExpCatCollapsed && !row.IsParentCollapsed" ng-if="row.RowType != 8 && row.ScenarioId == null && row.ExpCatId != null">
<td ng-style="{'width': res.width || '300px'}" class="headcol">
<span style="padding-left:15px;">
{{res.Name}}
</span>
</td>
<td ng-class="res.CSSClass[$index]" style="max-width:40px;"
ng-repeat="col in (res.QuantityValues) track by $index" ng-show="data.Headers[$index].Show">
<span>
{{ (col || 0 | number:2)}}/{{ (res.QuantityTotalResValue[$index] || 0 | number:2)}}
</span>
</td>
</tr>
<!--Resource Assign-->
<tr ng-show="!row.ExpCatCollapsed && !row.IsParentCollapsed" class="resRow" ng-if="row.RowType != 8 && row.ScenarioId != null && row.ExpCatId != null">
<td style="width: 300px;" class="headcol">
<div class="col-sm-8">
<span>Assign a person:</span>
</div><br />
<div class="col-sm-8">
<select ng-model="row.ResourceToAssignId" style="min-width: 100px;">
<option ng-repeat="item in getExpCatResources(row)" value="{{item.Id}}">{{item.Name}}</option>
</select>
</div>
<div class="col-sm-2">
<button class="btn btn-sm btn-success" ng-disabled="row.ResourceToAssignId == null" ng-click="assignResource(row.ResourceToAssignId, row.ScenarioId, row.ExpCatId, row.TeamId, $event)">Assign</button>
</div>
</td>
<td colspan="{{row.QuantityValues.length}}">
</td>
</tr>
</tbody>
<tfoot>
</tfoot>
</table>
</div>
<table class="table" style="width:100%" 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>