441 lines
20 KiB
Plaintext
441 lines
20 KiB
Plaintext
@using EnVisage.Code
|
|
@using EnVisage.Models
|
|
@model CreateScenarioModel.GeneralInfoModel
|
|
@{
|
|
// need to init cost saving controller
|
|
var jsModel = new
|
|
{
|
|
deadlineDate = Model.ProjectDeadline.HasValue ? Model.ProjectDeadline.Value.ToString("MM/dd/yyyy") : null
|
|
};
|
|
var json = Newtonsoft.Json.JsonConvert.SerializeObject(jsModel);
|
|
}
|
|
|
|
<script type="text/javascript">
|
|
function onStep1Failure(xhr) {
|
|
showErrorModal();
|
|
$('#Action').val('');
|
|
}
|
|
function onStep1Success(result) {
|
|
if (!!result && !!result.Html) {
|
|
$('#generalStep').html(result.Html);
|
|
if (result.Status) {
|
|
initStep1(true);
|
|
_detailsController.init(result.Data, stepSubmitCallback);
|
|
}
|
|
else {
|
|
initStep1(false);
|
|
}
|
|
return;
|
|
}
|
|
$('#Action').val('');
|
|
}
|
|
|
|
function initDatePickers() {
|
|
var options = {
|
|
format: 'mm/dd/yyyy',
|
|
autoclose: true,
|
|
orientation: $('body').hasClass('right-to-left') ? "auto right" : 'auto auto',
|
|
startDate: '@Constants.MIN_SELECTABLE_DATE',
|
|
endDate: '@(!string.IsNullOrWhiteSpace(jsModel.deadlineDate) ? jsModel.deadlineDate : Constants.MAX_SELECTABLE_DATE)'
|
|
};
|
|
|
|
$('#bs-datepicker-scenario-range').datepicker(options);
|
|
$('#bs-datepicker-scenario-range').find('#@Html.IdFor(x=> x.StartDate)').on('change', function (e) {
|
|
|
|
var startDate = new Date($(this).val());
|
|
var endDate = $('#bs-datepicker-scenario-range').find('#@Html.IdFor(x=> x.EndDate)').val();
|
|
//AG: ENV-782. The API of this forked datepicker does not seem to work correct or we use it incorrectly in this particularly case -
|
|
//I cannot access datepicker methods by standard $(selector).datepicker('method', arg1, arg2, ...)
|
|
//Setting date value directly into the textbox does not work as it does not call inline calendar update
|
|
//so we need to use API method for that
|
|
|
|
// SA: We update datepicker component inner date (for scenario finish date) and then reset
|
|
// the inner date. When inner date set, the calendar scrolls to this date and shows it,
|
|
// when expanded. And when we reset inner date then, the control still shows the proper month
|
|
// in its expandable panel
|
|
if (!endDate && startDate.getTime() > 0) {
|
|
$('#bs-datepicker-scenario-range').data('datepicker').pickers[1].viewDate = new Date(startDate.getFullYear(), startDate.getMonth(), 12);
|
|
//$('#bs-datepicker-scenario-range').data('datepicker').pickers[1].update(startDate);
|
|
//$('#bs-datepicker-scenario-range').data('datepicker').pickers[1].update('');
|
|
}
|
|
|
|
triggerScenarioRangeChangedEvent();
|
|
});
|
|
$('#bs-datepicker-scenario-range').find('#@Html.IdFor(x=> x.EndDate)').on('change', function (e) {
|
|
triggerScenarioRangeChangedEvent();
|
|
});
|
|
$('#bs-datepicker-scenario-range span.input-group-addon').hide();
|
|
}
|
|
function triggerScenarioRangeChangedEvent() {
|
|
var startDateEl = $('#bs-datepicker-scenario-range').find('#@Html.IdFor(x=> x.StartDate)'),
|
|
endDateEl = $('#bs-datepicker-scenario-range').find('#@Html.IdFor(x=> x.EndDate)');
|
|
|
|
var eventData = {
|
|
startDate: startDateEl.val(),
|
|
endDate: endDateEl.val()
|
|
};
|
|
|
|
// Check dates and display warnings
|
|
var displayWarning = dateConstraintsViolated(eventData.startDate, eventData.endDate);
|
|
if (displayWarning) {
|
|
$('#dates-constraints-warning').show();
|
|
}
|
|
else {
|
|
$('#dates-constraints-warning').hide();
|
|
}
|
|
|
|
triggerBroadcastFromRootScope('scenarioRangeChanged', eventData);
|
|
}
|
|
function dateConstraintsViolated(startDate, endDate) {
|
|
if (!projectHasDependencies)
|
|
return false;
|
|
|
|
var newScenarioStatusIsActive = $('#@Html.IdFor(x=> x.CreateAsActive)').is(':checked');
|
|
if (!newScenarioStatusIsActive)
|
|
return false;
|
|
|
|
var startDateConstraint = @(Model.StartDateConstraintMs.HasValue ? String.Format("{0}; // {1}", Model.StartDateConstraintMs.Value.ToString(), Model.StartDateConstraint.Value.ToShortDateString()) : "null");
|
|
var endDateConstraint = @(Model.EndDateConstraintMs.HasValue ? String.Format("{0}; // {1}", Model.EndDateConstraintMs.Value.ToString(), Model.EndDateConstraint.Value.ToShortDateString()) : "null");
|
|
|
|
var startDateVioldated = false;
|
|
var endDateVioldated = false;
|
|
|
|
if (startDate && startDateConstraint) {
|
|
var startDateMs = DateTimeConverter.stringToMs(startDate);
|
|
startDateVioldated = startDateMs < startDateConstraint;
|
|
}
|
|
|
|
if (endDate && endDateConstraint) {
|
|
var endDateMs = DateTimeConverter.stringToMs(endDate);
|
|
endDateVioldated = endDateMs > endDateConstraint;
|
|
}
|
|
|
|
return startDateVioldated || endDateVioldated;
|
|
}
|
|
function initSwitchers() {
|
|
$('input.yes-no-switcher').switcher({
|
|
on_state_content: 'Yes',
|
|
off_state_content: 'No'
|
|
}).parent().css("width", "80px");
|
|
|
|
$('#@Html.IdFor(x=> x.IsBottomUp)').switcher({
|
|
on_state_content: 'Bottom Up',
|
|
off_state_content: 'Top Down'
|
|
}).parent().css("width", "100px");
|
|
$('input[type=hidden][name=@Html.NameFor(x=> x.IsBottomUp)]').val(@Model.IsBottomUp.ToString().ToLower());
|
|
|
|
$('#@Html.IdFor(x=> x.IsBottomUp)').on('change', function (e, r) {
|
|
var isBottomUp = $(this).is(':checked');
|
|
$('input[type=hidden][name=@Html.NameFor(x=> x.IsBottomUp)]').val(isBottomUp);
|
|
refreshFormAccordingToScenarioType(isBottomUp);
|
|
refreshSlidersVisibilityAccordingToScenarioType(isBottomUp);
|
|
});
|
|
|
|
$('#@Html.IdFor(x=> x.TemplateId)').on('change', onTemplateChanged);
|
|
|
|
if (projectHasDependencies) {
|
|
$('#@Html.IdFor(x=> x.CreateAsActive)').on('change', onScenarioStatusChanged);
|
|
}
|
|
}
|
|
function triggerScenarioWorkFlowChangedEvent(e) {
|
|
var value = e.val;
|
|
var eventData = {
|
|
WorkFlowSchema: value
|
|
};
|
|
triggerBroadcastFromRootScope('scenarioWorkFlowSchemaChanged', eventData);
|
|
}
|
|
function initStep1(disableSliders, projectId) {
|
|
setTemplatesDataSource(@Model.IsBottomUp.ToString().ToLower());
|
|
|
|
$("#wfSchemaName").select2({
|
|
allowClear: true
|
|
}).on("select2-selecting", function (e) { triggerScenarioWorkFlowChangedEvent(e); }).on("select2-clearing",function(e){triggerScenarioWorkFlowChangedEvent(e);});
|
|
$("#generalStep .forselect2").select2({
|
|
allowClear: true,
|
|
minimumResultsForSearch: 5
|
|
});
|
|
|
|
initDatePickers();
|
|
initSwitchers();
|
|
|
|
compileDynamicAngularHtml($("#teamsContainer"));
|
|
$('#teamsContainer').on('$destroy', destroyAngularForm);
|
|
|
|
$.validator.unobtrusive.parseDynamicContent("#generalStepForm");
|
|
|
|
reloadEC(true);
|
|
if (disableSliders) {
|
|
var slidersController = getSlidersController();
|
|
if (slidersController) {
|
|
slidersController.$apply(function () {
|
|
slidersController.setReadonly();
|
|
});
|
|
}
|
|
}
|
|
refreshSlidersVisibilityAccordingToScenarioType(@Model.IsBottomUp.ToString().ToLower());
|
|
|
|
$('#generalStep').find('input[type=checkbox],input[type=text],select,textarea').on("change", function () {
|
|
if (typeof onScenarioDataChanged === 'function')
|
|
onScenarioDataChanged();
|
|
});
|
|
if (projectHasDependencies) {
|
|
var elem = $('div.date-dependency-constraints');
|
|
|
|
if (elem && elem.length) {
|
|
elem.scenarioDependencyInformer({
|
|
projectId: projectId,
|
|
dataUrl: '@Url.Action("GetDependencies", "Project")'
|
|
});
|
|
}
|
|
|
|
$('#@Html.IdFor(x=> x.CreateAsActive)').trigger('change');
|
|
}
|
|
}
|
|
|
|
function onTemplateChanged(e, skipValidation) {
|
|
$('input[type=hidden][name=@Html.NameFor(x=> x.TemplateId)]').val($(this).val());
|
|
if (!skipValidation) {
|
|
$(this).parents('form').validate().element($(this));
|
|
}
|
|
reloadEC(false);
|
|
}
|
|
function setTemplatesDataSource(isBottomUp) {
|
|
if (isBottomUp) {
|
|
$("#@Html.IdFor(x=> x.TemplateId)").html('@Utils.GetTemplates(Model.TemplateId, true)');
|
|
}
|
|
else {
|
|
$("#@Html.IdFor(x=> x.TemplateId)").html('@Utils.GetTemplates(Model.TemplateId, false)');
|
|
}
|
|
};
|
|
function onScenarioStatusChanged(e) {
|
|
if (!projectHasDependencies)
|
|
return;
|
|
|
|
var newScenarioStatusIsActive = $('#@Html.IdFor(x=> x.CreateAsActive)').is(':checked');
|
|
var elem = $('div.date-dependency-constraints');
|
|
|
|
if (newScenarioStatusIsActive)
|
|
elem.scenarioDependencyInformer('show');
|
|
else
|
|
elem.scenarioDependencyInformer('hide');
|
|
|
|
// Call to hide any dependency warning, if visible any
|
|
triggerScenarioRangeChangedEvent();
|
|
};
|
|
function refreshFormAccordingToScenarioType(isBottomUp) {
|
|
setTemplatesDataSource(isBottomUp);
|
|
if (isBottomUp) {
|
|
$('#@Html.IdFor(x=> x.TemplateId)').attr('disabled', 'disabled');
|
|
$('input[type=hidden][name=@Html.NameFor(x=> x.TemplateId)]').removeAttr('disabled');
|
|
$("#fsCategories").hide();
|
|
$("#@Html.IdFor(x=> x.SelectedExpenditures)").select2('val', []);
|
|
$("#@Html.IdFor(x=> x.TemplateId)").trigger('change');
|
|
}
|
|
else {
|
|
$("#@Html.IdFor(x=> x.TemplateId)").trigger('change', true);
|
|
$('#@Html.IdFor(x=> x.TemplateId)').removeAttr('disabled');
|
|
$('input[type=hidden][name=@Html.NameFor(x=> x.TemplateId)]').attr('disabled', 'disabled');
|
|
$("#fsCategories").show();
|
|
}
|
|
};
|
|
function refreshSlidersVisibilityAccordingToScenarioType(isBottomUp) {
|
|
var slidersController = getSlidersController();
|
|
if (slidersController) {
|
|
slidersController.$apply(function () {
|
|
slidersController.changeSlidersVisibility(!isBottomUp);
|
|
});
|
|
}
|
|
};
|
|
function reloadEC(overrideChecked) {
|
|
var templateId = $('#@Html.IdFor(x=> x.TemplateId)').val();
|
|
if (!templateId)
|
|
return;
|
|
|
|
var selectedCategories = $('#@Html.IdFor(x=> x.SelectedExpenditures)').val();
|
|
var scope = angular.element(document.getElementById('slidersGroupContainer_@(Model.Teams.GroupDisplayId)')).scope();
|
|
var scenarioTeams = scope.getTeamList();
|
|
|
|
blockUI();
|
|
$.post('@Url.Action("GetECsByTemplateId", "Scenarios")', {
|
|
'Id': templateId,
|
|
'selectedExpCats': !!selectedCategories ? selectedCategories.split(',') : [],
|
|
'teams': scenarioTeams,
|
|
'overrideChecked': overrideChecked
|
|
}, function (data) {
|
|
if (!$("#SelectedExpenditures").data('select2')) {
|
|
// Multiselect
|
|
$("#@Html.IdFor(x=> x.SelectedExpenditures)").select2({
|
|
placeholder: "Select an Expenditure",
|
|
data: data.options,
|
|
multiple: true,
|
|
}).on('change', function () {
|
|
$(this).closest('form').validate().element($(this));
|
|
});
|
|
$("#@Html.IdFor(x => x.SelectedExpenditures)").select2('val', data.selected);
|
|
}
|
|
else {
|
|
// we should trigger change event manually because select2 widget does not do it when we set new value programmatically
|
|
$("#@Html.IdFor(x => x.SelectedExpenditures)").select2('val', data.selected).trigger('change');
|
|
}
|
|
$('#s2id_@Html.IdFor(x => x.SelectedExpenditures) input.select2-default').css('width', '200px');
|
|
if (!($("#fsFinancial").is(':visible') || $("#fsDetails").is(':visible'))) {
|
|
$("#fsTeamAllocation").show();
|
|
}
|
|
unblockUI();
|
|
});
|
|
}
|
|
|
|
function lockGeneralForm(needToLock) {
|
|
if (needToLock) {
|
|
$('#@Html.IdFor(x=> x.StartDate)').attr('disabled', 'disabled');
|
|
$('[name=@Html.NameFor(x=> x.StartDate)].hdn').removeAttr('disabled');
|
|
$('#@Html.IdFor(x=> x.EndDate)').attr('disabled', 'disabled');
|
|
$('[name=@Html.NameFor(x=> x.EndDate)].hdn').removeAttr('disabled');
|
|
$('#@Html.IdFor(x=> x.TemplateId)').attr('disabled', 'disabled');
|
|
$('[name=@Html.NameFor(x=> x.TemplateId)].hdn').removeAttr('disabled');
|
|
$('#@Html.IdFor(x=> x.IsBottomUp)').switcher('disable');
|
|
}
|
|
else {
|
|
$('#@Html.IdFor(x=> x.StartDate)').removeAttr('disabled');
|
|
$('[name=@Html.NameFor(x=> x.StartDate)].hdn').attr('disabled', 'disabled');
|
|
$('#@Html.IdFor(x=> x.EndDate)').removeAttr('disabled');
|
|
$('[name=@Html.NameFor(x=> x.EndDate)].hdn').attr('disabled', 'disabled');
|
|
$('#@Html.IdFor(x=> x.TemplateId)').removeAttr('disabled');
|
|
$('[name=@Html.NameFor(x=> x.TemplateId)].hdn').attr('disabled', 'disabled');
|
|
$('#@Html.IdFor(x=> x.IsBottomUp)').switcher('enable');
|
|
}
|
|
};
|
|
function getSlidersController() {
|
|
var slidersGroupContainer = $("#teamsContainer").find('*[data-slider-group]');
|
|
var slidersController = slidersGroupContainer ? angular.element(slidersGroupContainer.get(0)).scope() : undefined;
|
|
|
|
return slidersController;
|
|
};
|
|
</script>
|
|
|
|
@using (Ajax.BeginForm("SubmitCreateScenarioStep1", "Scenarios", new AjaxOptions
|
|
{
|
|
HttpMethod = "Post",
|
|
OnBegin = "blockUI",
|
|
OnSuccess = "onStep1Success",
|
|
OnFailure = "onStep1Failure(xhr)",
|
|
OnComplete = "unblockUI",
|
|
}, new
|
|
{
|
|
@id = "generalStepForm",
|
|
@class = "form-horizontal",
|
|
}))
|
|
{
|
|
@Html.HiddenFor(m => m.ScenarioId)
|
|
@Html.HiddenFor(m => m.ProjectId)
|
|
@Html.HiddenFor(m => m.PartId)
|
|
@Html.HiddenFor(m => m.ProjectDeadline)
|
|
@Html.HiddenFor(m => m.StatusIsEditable)
|
|
@Html.HiddenFor(m => m.HideName)
|
|
@Html.HiddenFor(m => m.SerializedModel)
|
|
@Html.AntiForgeryToken()
|
|
|
|
<fieldset id="fsGeneral" class="form-group-margin">
|
|
<legend class="text-bold">Scenario Information</legend>
|
|
<div class="row">
|
|
<div class="col-sm-7">
|
|
<div class="form-group no-margin-hr">
|
|
@Html.LabelFor(model => model.ProjectName, new { @class = "control-label" })
|
|
@Html.TextBoxFor(model => model.ProjectName, new { @class = "form-control", @readonly = "readonly" })
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
@if (!Model.HideName)
|
|
{
|
|
<div class="col-sm-7">
|
|
<div class="form-group no-margin-hr">
|
|
@Html.LabelFor(model => model.ScenarioName, new { @class = "control-label" })
|
|
@Html.TextBoxFor(model => model.ScenarioName, new { @class = "form-control" })
|
|
@Html.ValidationMessageFor(model => model.ScenarioName)
|
|
</div>
|
|
</div>
|
|
}
|
|
<div class="col-sm-5">
|
|
<div class="form-group no-margin-hr">
|
|
<label class="control-label">Scenario Dates</label>
|
|
<div class="input-daterange input-group" id="bs-datepicker-scenario-range">
|
|
@Html.EditorFor(t => t.StartDate, new { htmlAttributes = new { @class = "form-control date" } })
|
|
<div class="input-group-addon">to</div>
|
|
@Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { @class = "form-control date" } })
|
|
</div>
|
|
<div>
|
|
<input type="hidden" name="@Html.NameFor(t => t.StartDate).ToString()" class="hdn" value="@(Model.StartDate.HasValue ? Model.StartDate.Value.ToShortDateString() : string.Empty)" />
|
|
<input type="hidden" name="@Html.NameFor(t => t.EndDate).ToString()" class="hdn" value="@(Model.EndDate.HasValue ? Model.EndDate.Value.ToShortDateString() : string.Empty)" />
|
|
</div>
|
|
@Html.ValidationMessageFor(model => model.StartDate)
|
|
@Html.ValidationMessageFor(model => model.EndDate)
|
|
@if (Model.ProjectDeadline.HasValue)
|
|
{
|
|
<div><i>Project Deadline: @Model.ProjectDeadline.Value.ToShortDateString()</i></div>
|
|
}
|
|
<div class="date-dependency-constraints"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-sm-4 col-md-5">
|
|
<div class="form-group no-margin-hr">
|
|
@Html.LabelFor(model => model.TemplateId, new { @class = "control-label" })
|
|
@Html.DropDownListFor(model => model.TemplateId, new List<SelectListItem>(), new { @class = "form-control forselect2" })
|
|
<input type="hidden" name="@Html.NameFor(t => t.TemplateId).ToString()" class="hdn" value="@(Model.TemplateId.HasValue ? Model.TemplateId.Value.ToString() : string.Empty)" />
|
|
@Html.ValidationMessageFor(model => model.TemplateId)
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-2 col-md-2">
|
|
<div class="form-group no-margin-hr switcher-block">
|
|
@Html.LabelFor(model => model.IsBottomUp, new { @class = "control-label" })
|
|
@Html.CheckBoxFor(model => model.IsBottomUp, new { @class = "switcher form-control" })
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-3 col-md-2">
|
|
<div class="form-group no-margin-hr switcher-block @(Model.StatusIsEditable ? "" : "hidden")">
|
|
@Html.LabelFor(model => model.CreateAsActive, new { @class = "control-label" })
|
|
@Html.CheckBoxFor(model => model.CreateAsActive, new { @class = "switcher form-control yes-no-switcher" })
|
|
@Html.ValidationMessageFor(model => model.CreateAsActive)
|
|
</div>
|
|
</div>
|
|
@{
|
|
IEnumerable<SelectListItem> workFlowList = Utils.GetWorkFlowSchemas(WorkFlowArea.Scenarios.GetHashCode(), new Guid(User.Identity.GetID()));
|
|
if (workFlowList.Count() > 1)
|
|
{
|
|
<div class="col-sm-4 col-md-3">
|
|
<div class="form-group no-margin-hr">
|
|
@Html.LabelFor(model => model.WorkFlowSchemaCode, new { @class = "control-label" })
|
|
@Html.DropDownListFor(model => model.WorkFlowSchemaCode, workFlowList, new { @class = "form-control", @id = "wfSchemaName" })
|
|
<input type="hidden" name="@Html.NameFor(t => t.WorkFlowSchemaCode).ToString()" class="hdn" value="@(!string.IsNullOrEmpty(Model.WorkFlowSchemaCode) ? Model.WorkFlowSchemaCode : string.Empty)" />
|
|
@Html.ValidationMessageFor(model => model.WorkFlowSchemaCode)
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</fieldset>
|
|
<fieldset id="fsCategories" class="form-group-margin" style="display: @(Model.IsBottomUp ? "none" : "block") ">
|
|
<legend class="text-bold small-bottom-margin">Expenditure Categories</legend>
|
|
<div class="row">
|
|
<div class="form-group no-margin-hr select2-primary">
|
|
@Html.TextBoxFor(x => x.SelectedExpenditures)
|
|
@Html.ValidationMessageFor(model => model.SelectedExpenditures)
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<fieldset id="fsTeamAllocation">
|
|
<legend class="text-bold small-bottom-margin">Teams</legend>
|
|
<div class="row">
|
|
<div class="col-sm-12" id="teamsContainer">
|
|
@Html.EditorFor(x => x.Teams)
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
@Html.ValidationSummary(false, "The scenario could not be saved due to the following errors:")
|
|
<div class="alert alert-warning" id="dates-constraints-warning" style="display: none;">
|
|
Scenario dates violate project's dependencies date constraints
|
|
</div>
|
|
}
|