EnVisageOnline/Main/Source/EnVisage/Views/Mix/Index.cshtml

512 lines
28 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@using EnVisage.Code
@using Prevu.Core.Main
@model string
@{
ViewBag.Title = "Roadmap Optimizer";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@section stylesheets
{
@Styles.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_STYLES_BASE_PATH, "prevu-rmostyles"))
}
@section Scripts
{
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "flot-scripts"))
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "prevu-angularservices"))
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "prevu-scenariodetails"))
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "prevu-rmopage"))
<script>
function initMixForm() {
$("div#main-wrapper").attr("data-section", "mixCalendar");
var datePickerOptions = {
format: 'm/d/yyyy',
autoclose: true,
orientation: $('body').hasClass('right-to-left') ? "auto right" : 'auto auto',
startDate: '@(Constants.MIN_SELECTABLE_DATE)',
endDate: '@(Constants.MAX_SELECTABLE_DATE)'
};
$('#bs-datepicker-mix-range').datepicker(datePickerOptions).on('changeDate', function (evt) {
if (evt.target.id === 'MixStartDate' && !$('#MixEndDate').val()) {
$('#bs-datepicker-mix-range').data('datepicker').pickers[1].prepopulate(evt.date);
}
});
$('#mixTeamsAndViews').select2({
allowClear: true
});
$('#mixContributors').select2({
allowClear: true
});
$('#availableMixes').select2({
allowClear: true
});
$('#selectedTeamViews').select2({
allowClear: true
});
$('#selProjects2Add').select2({
allowClear: true
});
$('#mix-edit-scenario-teams-dialog select').select2({
allowClear: true
});
$('#copierProjectId').select2();
$('#btnSaveMix').on('click', function () {
showSaveMixDialog();
});
$('#btnActivateMix').on('click', function () {
showSaveMixDialog();
});
var menu = $('#mixMenu');
$.each($('#mixMenuTemplate').children(), function (i, obj) {
menu.append($(obj));
});
menu.on('click', function (event) {
event.stopPropagation();
});
$('#divMixMenuTemplate').remove();
}
function showSaveMixDialog() {
if (!$('#mix-header').valid())
return;
$('#saveMixModal').modal();
}
function canSaveMix() {
return $('#mix-header').valid() && $('#saveMixForm').valid();
}
function HasRaceScore() {
}
function isValidHeader() {
if ($('#mix-header').valid()) {
$('#mix-header .validation-summary-errors')
.addClass('validation-summary-valid')
.removeClass('validation-summary-errors');
return true;
}
return false;
}
function printPDF(bPrint) {
blockUI();
var mainwrapper = $("#main-wrapper");
var contentwrapper = $("#content-wrapper");
var rmopanel = $("#rmo-panel");
var rmopanelbody = $("#rmo-panel-body");
//prepare blocks to be exported to canvas
mainwrapper.css("transition", "none");
mainwrapper.css("padding-left", "0px");
$("#dvBtns1").hide();
$("#dvBtns2").hide();
$("#dvBtns3").hide();
//calculate required canvas width
//1. calculate total width of RMO table
var requiredWidth = 0;
$("#mix-table tr:first th").each(function (i, e) { requiredWidth += $(e).outerWidth(); });
//2. add upper elements paddings etc
requiredWidth += (rmopanelbody.outerWidth() - rmopanelbody.width());//padding of the panel body
//console.log(rmopanelbody.outerWidth() - rmopanelbody.width());
requiredWidth += (rmopanel.outerWidth() - rmopanel.innerWidth());//border of the panel
//console.log(rmopanel.outerWidth() - rmopanel.innerWidth());
requiredWidth += (contentwrapper.outerWidth() - contentwrapper.width());//padding of the content wrapper
//console.log(contentwrapper.outerWidth() - contentwrapper.width());
//check if we need to resize main wrapper and resize it
console.log("cw: " + mainwrapper.width() + "; rw: " + requiredWidth);
if (mainwrapper.width() < requiredWidth)
mainwrapper.css("width", requiredWidth + "px");
//make sure css applied and do the flush-export
window.setTimeout(function () {
//scroll the page to upper-left corner to make sure canvas rendered correctly in chrome
window.scrollTo(0, 0);
html2canvas(rmopanel, {
onrendered: function (canvas) {
mainwrapper.css("width", "");
mainwrapper.css("padding-left", "");
mainwrapper.css("transition", "");
$("#dvBtns1").show();
$("#dvBtns2").show();
$("#dvBtns3").show();
//check if we need portrait or landscape
var landscape = canvas.width > canvas.height;
//A4 page dimensions
var page = {};
page.w = landscape ? 297 : 210;
page.h = landscape ? 210 : 297;
var hRatio = page.w / canvas.width;
var vRatio = page.h / canvas.height;
var ratio = Math.min(hRatio, vRatio);
var centerShift_x = (page.w - canvas.width * ratio) / 2;
var centerShift_y = (page.h - canvas.height * ratio) / 2;
//console.log("docw: " + docw + "; doch: " + doch + "; imgw: " + imgw + "; imgh: " + imgh);
var imgData = canvas.toDataURL('image/png');
var doc = new jsPDF({
orientation: landscape ? 'l' : 'p',
format: 'a4',
unit: 'mm'
});
doc.addImage(imgData, 'PNG', centerShift_x, 0, canvas.width * ratio, canvas.height * ratio);
unblockUI();
if (bPrint == true) {
doc.autoPrint();
doc.save('autoprint.pdf');
window.open(doc.output('bloburl'), '_blank');//this triggers popup blocker - not a good solution...
}
else {
var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1;
var curr_year = d.getFullYear();
doc.save("Prevu-RMO-" + (curr_year + "-" + curr_month + "-" + curr_date) + ".pdf");
}
}
});
}, 10);
}
function loadTeam(teamId) {
blockUI();
if (teamId != null)
StartEdit('Team', teamId, null, null, 'erorMsgPlaceholder');
var itemUrl = teamId != null ? "?Id=" + teamId : "";
var url = '@Url.Action("EditTeam", "Mix")' + itemUrl;
// SA. ENV-1065. Rewrited to $.Ajax to force turn off request caching
$('#editReload').html("");
$.ajax({
url: url,
cache: false,
dataType: "html",
success: function (data) {
$('#editReload').html(data);
$('#editTeam')
.on('hidden.bs.modal', function () {
if (teamId != null) {
StopEdit();
RemoveLock('Team', teamId);
}
})
.on('shown.bs.modal', function () {
// No actions
})
.modal('show');
initTeam();
},
error: function () {
showErrorModal();
},
complete: function () {
unblockUI();
},
});
}
function editTeam(Id) {
loadTeam(Id);
return true;
}
//fix modal force focus
$.fn.modal.Constructor.prototype.enforceFocus = function () {
var that = this;
$(document).on('focusin.modal', function (e) {
if ($(e.target).hasClass('select2-input')) {
return true;
}
if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
that.$element.focus();
}
});
};
init.push(function () {
saveLastPageVisited(window.location.pathname + window.location.search);
$(document).on('hide.bs.modal', '#editTeam', function (e) {
// skip modal hide event from datepickers
if ($(e.target).attr('id') != 'editTeam')
return true; // close modal form
// check that form has been changed
if (typeof isTeamDataChanged === 'function')
// if form has been changed
if (isTeamDataChanged()) {
// ask user for confirmation of form close
var msg = "Adding Team form contains unsaved changes, do you really want to close the form?";
bootbox.confirm(msg, function (result) {
if (result) {
if (typeof resetTeamDataChanged === 'function') {
resetTeamDataChanged();
}
$('#editTeam').modal('hide');
}
});
return false; // DO NOT close modal form
}
return true; // close modal form
});
});
</script>
}
@section pagemenu
{
<ul class="nav navbar-nav navbar-right">
<li class="dropdown" id="divMixMenu">
<a href="#" class="dropdown-toggle user-menu" data-toggle="dropdown">
<i class="fa fa-bars"></i><span>Page Options</span>&nbsp;<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-menu-right" id="mixMenu">
<!--<li><a href="javascript: printPDF(true);"><i class="dropdown-icon fa fa-print"></i> Print Page</a></li>-->
<li><a href="javascript: printPDF(false);"><i class="dropdown-icon fa fa-file-text-o"></i> Save Page as PDF</a></li>
<li class="divider"></li>
</ul>
</li>
</ul>
}
@{
var userId = SecurityManager.GetUserPrincipal();
var userManager = DependencyResolver.Current.GetService<IUserManager>();
var user = userManager.GetUser(userId);
var pagePreferences = userManager.GetPagePreferences(Url.Action("Index", "Mix"), "mixCalendar", userId);
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
mixId = Model,
showAvgTotals = user.PreferredTotalsDisplaying,
prefs = pagePreferences
});
}
<div>
<div id="erorMsgPlaceholder"></div>
<div class="panel" id="rmo-panel">
<div class="panel-body" id="rmo-panel-body" style="border: 0;">
<fieldset class="form-group-margin">
<div id="mixHeader" ng-controller="mixHeaderController" ng-init="init(@json)" init-form ng-cloak>
@Html.AntiForgeryToken()
<form style="border: 0;" id="mix-header">
<div class="row" ng-if="data.AvailableMixes != null && data.AvailableMixes.length > 0">
<div class="col-sm-6">
<div class="form-group no-margin-hr">
<label class="control-label noprint" for="availableMixes">Select existing Mix</label>
<span class="nodisplay-inline">Mix: </span><select id="availableMixes" name="availableMixes" class="form-control"
ng-model="data.SelectedMix"
ng-options="mix.Value as mix.Text for mix in data.AvailableMixes | orderBy:'Text'"></select>
</div>
</div>
<div class="col-sm-6" id="dvBtns1">
<div class="form-group no-margin-hr">
<label class="control-label">&nbsp;</label><br />
@* Need to show only if selected mix is exists and it is not current opened mix *@
<button type="button" class="btn btn-primary" ng-click="navigateToMix()" ng-show="data.ShowOpen">Open Mix</button>
@* SA. ENV-1138. Delete selected, but unopened mix *@
<button type="button" class="btn btn-danger" ng-click="deleteUnopenedMix()" ng-show="data.ShowOpen">Delete Mix</button>
</div>
</div>
</div>
<div class="row" ng-if="data.AvailableTeamsAndViews != null && data.AvailableTeamsAndViews.length > 0">
<div class="col-sm-6">
<div class="form-group select2-primary no-margin-hr">
<label class="control-label">Team(s) or View(s)</label>
<select id="selectedTeamViews" name="selectedTeamViews" class="form-control" multiple="multiple" selected-data-changed
ng-model="data.SelectedTeamsAndViews"
ng-options="team.TVName group by team.Group.Name for team in data.AvailableTeamsAndViews | orderBy:['Group.Name','TVName']"></select>
<span class="help-block field-validation-valid" data-valmsg-for="mixTeamsAndViews" data-valmsg-replace="true"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group no-margin-hr">
<label class="control-label">Dates</label>
<div class="input-daterange input-group" id="bs-datepicker-mix-range">
<div class="input-daterange input-group date floatdaterange" id="mix-dateStart">
<input type="text" id="MixStartDate" name="MixStartDate" class="form-control"
data-val="true" data-val-date="The field Start Date must be a date."
data-val-required="The Start Date field is required."
ng-model="data.StartDate"
ng-disabled="!data.IsEditable" />
</div>
<div class="pull-left floatdaterange-addon">To</div>
<div class="input-daterange input-group date floatdaterange" id="mix-dateEnd">
<input type="text" id="MixEndDate" name="MixEndDate" class="form-control"
data-val="true" data-val-date="The field End Date must be a date."
data-val-required="The End Date field is required."
data-val-dategreaterthanorequal="Mix End Date should not be less than Start Date"
data-val-dategreaterthanorequal-otherpropertyname="MixStartDate"
ng-model="data.EndDate"
ng-disabled="!data.IsEditable" />
</div>
</div>
<span class="help-block field-validation-valid" data-valmsg-for="MixStartDate" data-valmsg-replace="true"></span>
<span class="help-block field-validation-valid" data-valmsg-for="MixEndDate" data-valmsg-replace="true"></span>
</div>
</div>
</div>
@* Client-side filters by Cost Centers and Project Roles *@
<div class="row" ng-show="data.DataLoaded">
<div class="col-sm-6">
<div class="form-group no-margin-hr" style="width:100%">
<div class="form-group select2-primary no-margin-hr" style="width: 100%;">
<label class="control-label">Cost Centers:</label>
<select ng-select2 ng-model="data.SelectedCostCenters" allowClear="true"
placeholder="All available Cost Centers" minimumResultsForSearch="5" multiple="multiple"
ng-change="filterCostCentersChanged()" option-class-expr="CSSClass" data-val="true">
<option ng-repeat="option in data.AvailableCostCenters track by $index" value="{{option.Value}}">{{option.Text}}</option>
</select>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group no-margin-hr" style="width:100%">
<div class="form-group select2-primary no-margin-hr" style="width: 100%;">
<label class="control-label">Project Roles:</label>
<select ng-select2 ng-model="data.SelectedProjectRoles" allowClear="true"
placeholder="Select items to be displayed" minimumResultsForSearch="5" multiple="multiple"
ng-change="filterProjectRolesChanged()" option-class-expr="CSSClass" data-val="true">
<option ng-repeat="option in data.VisibleProjectRoles track by $index" value="{{option.Value}}">{{option.Text}}</option>
</select>
</div>
</div>
</div>
</div>
@Html.ValidationSummary(false, "The Mix could not be saved due to the following errors:")
<div class="row" id="dvBtns2">
<div class="col-sm-12">
<div class="form-group select2-primary no-margin-hr" id="raceScoreMagnify">
<button type="button" class="btn btn-primary" id="btnApplyFilter" ng-show="data.IsEditable" ng-disabled="!canApplyFilter()" ng-click="applyFilter()">
<i class="fa fa-search"></i>&nbsp;Apply Filter
</button>
<button type="button" class="btn btn-primary" id="btnDoRace2Res" ng-show="data.IsEditable" ng-disabled="!canDoRaceRes()" ng-click="applyRace2Res()">
<i class="fa fa-check-circle-o"></i>&nbsp;Race(Resource)
</button>
<button type="button" class="btn btn-primary" id="btnDoRace2Team" ng-show="data.IsEditable" ng-disabled="!canDoRaceTeam(true)" ng-click="applyRace2Team()">
<i class="fa fa-check-circle-o"></i>&nbsp;Race(Team)
</button>
@if (SecurityManager.CheckSecurityObjectPermission(Areas.Teams, AccessLevel.Write))
{
<a class="btn btn-success noprint" ng-show="data.IsEditable" onclick="return editTeam(null);">
<i class="fa fa-plus"></i>&nbsp;Create Team
</a>
}
<button type="button" class="btn btn-success" id="btnSaveMix" ng-show="canSaveMix()" ng-disabled="!data.DataChanged" ng-click="requestMixSaving()">
<i class="fa fa-save"></i>&nbsp;Save this Mix
</button>
<button type="button" class="btn btn-warning" id="btnActivateMix" ng-show="canActivateMix()" ng-click="requestMixActivation()">
<i class="fa fa-check-circle-o"></i>&nbsp;Activate Mix
</button>
<button type="button" class="btn btn-danger" id="btnDeleteMix" ng-show="canDeleteMix()" ng-disabled="data.DisableDelete" ng-click="deleteCurrentMix()">
<i class="fa fa-trash-o"></i>&nbsp;Delete Mix
</button>
<button type="button" class="btn btn-danger" ng-show="canClearMix()" ng-click="navigateToNewMix()">
<i class="fa fa-times"></i>&nbsp;Clear
</button>
</div>
</div>
</div>
<div class="row" ng-if="data.AvailableUsers != null && data.AvailableUsers.length > 0">
<div class="col-sm-6">
<div class="select2-primary no-margin-hr" ng-show="canSaveMix()">
<label class="control-label">Contributors</label>
<select id="mixContributors" name="mixContributors" class="form-control" data-val="true" data-val-required="You need to select at least one contributor"
ng-disabled="!data.IsEditable"
ng-model="data.Users"
ng-options="user.Value as user.Text for user in data.AvailableUsers | orderBy: 'Text'"
multiple="multiple"></select>
<span class="help-block field-validation-valid" data-valmsg-for="mixContributors" data-valmsg-replace="true"></span>
</div>
</div>
</div>
</form>
<div id="saveMixModal" class="modal fade" tabindex="-1" role="dialog" style="display: none;" data-backdrop="static">
<form id="saveMixForm">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" ng-show="data.SaveMixHasBeenRequested">Save Mix</h4>
<h4 class="modal-title" ng-show="data.ActivateMixHasBeenRequested">Activate Mix</h4>
</div>
<div class="modal-body">
<div class="panel-body form-horizontal" ng-show="data.ShowSaveForm">
<div class="row">
<div class="col-sm-12">
<div class="form-group select2-primary no-margin-hr">
<label class="control-label">Mix Name</label>
<input type="text" id="Name" name="Name" class="form-control"
data-val="true" data-val-required="The Name field is required."
data-val-maxlength="The field Name must be a string or array type with a maximum length of '64'."
data-val-maxlength-max="64"
ng-model="data.Name"
ng-disabled="!data.IsEditable" />
<span class="help-block field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
</div>
</div>
</div>
@Html.ValidationSummary(false, "The Mix could not be saved due to the following errors:")
</div>
<div class="panel-body form-horizontal" ng-show="!data.ShowSaveForm">
<div class="row">
Are you sure you want to activate this mix? This action cannot be undone.
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" ng-show="data.SaveMixHasBeenRequested" ng-disabled="data.DisableScreen" ng-click="saveChanges()">
<i class="fa fa-save"></i>&nbsp;Save
</button>
<button type="button" class="btn btn-warning" ng-show="data.ActivateMixHasBeenRequested" ng-disabled="data.DisableScreen" ng-click="activateMix()">
<i class="fa fa-check-circle-o"></i>&nbsp;Activate
</button>
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="data.DisableScreen">Cancel</button>
</div>
</div>
<!-- / .modal-content -->
</div>
<!-- / .modal-dialog -->
</form>
</div>
<!-- /.modal -->
</div>
</fieldset>
<div>
@Html.Partial("_mixCalendar", json)
</div>
</div>
</div>
</div>
<div id="editTeam" class="modal fade" data-width="1070" tabindex="-1" role="dialog" data-backdrop="static">
<div class="modal-content" id="editReload">
</div>
<!-- / .modal-content -->
</div>
<div id="create-scenario-dialog" class="modal fade" data-width="900" tabindex="-1" role="dialog" data-backdrop="static">
<div class="modal-content" id="create-scenario-dialog-content">
</div>
<!-- / .modal-content -->
</div>
<!-- /.modal -->