Skip to content

Instantly share code, notes, and snippets.

@AaronMcCaughan
Last active January 16, 2019 08:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AaronMcCaughan/40e70d764e41eb9f4ec025b89eb46814 to your computer and use it in GitHub Desktop.
Save AaronMcCaughan/40e70d764e41eb9f4ec025b89eb46814 to your computer and use it in GitHub Desktop.
Barclays Schedule
imdashboard .barclays-envs-panel {
border-width: 0;
}
imdashboard .barclays-envs-panel .panel-heading {
border-bottom-width: 0;
}
imdashboard .barclays-envs-panel .panel-heading h4 {
font-size: 16px;
line-height: 36px;
}
imdashboard .barclays-envs-panel .panel-heading h4:before {
content: "";
width: 5px;
background-color: #46ade9;
height: 35px;
display: inline-block;
vertical-align: middle;
margin-right: 5px;
}
.barclays-envs {
margin-top: 5px;
font-size: 12px;
position: relative;
}
.barclays-envs > .row {
margin: 0;
float: none;
}
.barclays-envs label {
margin-bottom: 5px;
}
.barclays-envs .fakeLink {
cursor: pointer;
}
.barclays-envs label.required-field:after {
content: "*";
margin-left: 5px;
color: #f00;
}
.barclays-envs button .yellow {
color: #f68a3e;
}
.barclays-envs button .green {
color: #90b24f;
}
.barclays-envs .new-objects {
margin-top: 20px;
}
.barclays-envs .new-objects button {
height: 30px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 15px;
margin-left: 5px;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu {
right: 0;
left: auto;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li .vertical-status {
text-decoration: none;
position: relative;
padding-left: 40px;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li .vertical-status:before {
content: "";
width: 25px;
height: 75%;
position: absolute;
left: 10px;
background-color: #999;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(1) .vertical-status:before {
background-color: #37b030;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(2) .vertical-status:before {
background-color: #db4437;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(3) .vertical-status:before {
background: repeating-linear-gradient(-45deg, #caf982, #caf982 5px, #68ce43 5px, #68ce43 10px);
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(5) .vertical-status:before {
background-color: #37b030;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(6) .vertical-status:before {
background-color: #ffad00;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(7) .vertical-status:before {
background-color: #db4437;
}
.barclays-envs .new-objects .btn-legend .dropdown-menu li:nth-child(8) .vertical-status:before {
background: repeating-linear-gradient(-45deg, #ffad00, #ffad00 5px, #db4437 5px, #db4437 10px);
}
.barclays-envs .form-group {
margin-bottom: 16px;
position: relative;
}
.barclays-envs .form-group span.btn.ui-select-toggle, .barclays-envs .form-group .form-control.ui-select-search {
border-radius: 15px;
background-color: #fff;
padding: 4px 10px;
line-height: 20px;
height: 30px;
font-size: 12px;
box-shadow: none;
}
/*.barclays-envs .ui-select-multiple {
border-radius: 15px;
height: 30px;
padding: 1px 7px;
}
.barclays-envs .ui-select-multiple .btn-xs {
border-radius: 15px;
}*/
.barclays-envs .calendar-mode .btn, .conflict-panel .btn {
border-radius: 15px;
box-shadow: none;
line-height: 20px;
height: 28px;
}
.barclays-envs .calendar-mode .btn.active, .barclays-envs-modal .btn-group .btn.active {
background-color: #266998;
border-color: #266998;
color: #fff;
}
.barclays-envs .schedule-header {
width: 3601px;
display: block;
border-right: 1px solid #ddd;
margin-bottom: 2px;
}
.barclays-envs .schedule-header .row {
padding: 0;
margin: 0;
}
.barclays-envs .schedule-header .sch-year {
width: 1200px;
display: inline-block;
}
.barclays-envs .schedule-header .col-sm-3, .barclays-envs .schedule-header .col-sm-1 {
padding: 0;
text-align: center;
line-height: 24px;
}
.barclays-envs .schedule-header .col-sm-3 {
box-shadow: inset 1px 1px 0px 0px #ddd;
border-bottom: 1px solid #ddd;
}
.barclays-envs .schedule-header .col-sm-1 {
box-shadow: inset 1px -1px 0px 0px #ddd;
}
.barclays-envs .schedule-header .col-sm-1 .m {
font-weight: bold;
text-transform: uppercase;
}
.barclays-envs .schedule-header .col-sm-1 .col-sm-3 {
background-color: #173f5d;
color: #fff;
box-shadow: none;
}
.barclays-envs .project .prj-title {
position: relative;
height: 25px;
}
.barclays-envs .project .prj-title span {
display: inline-block;
background-color: #e4e6e8;
padding: 4px 10px;
border-right: 15px solid #fff;
border-radius: 4px 10px 10px 4px;
font-weight: bold;
position: absolute;
left: 0;
z-index: 1;
}
.barclays-envs .project .prj-title:after {
content: "";
display: inline-block;
width: 100%;
position: absolute;
left: 0;
top: 50%;
background-color: #e2e2e2;
height: 1px;
}
.barclays-envs .project .yellow {
color: #f68a3e;
}
.barclays-envs .project .green {
color: #90b24f;
}
.barclays-envs .project .tecrs, .barclays-envs .project .tebrs {
position: relative;
height: 27px;
line-height: 22px;
margin-top: 8px;
margin-bottom: 3px;
}
.barclays-envs .project .tecr, .barclays-envs .project .tebr {
position: absolute;
left: 0;
top: 0;
background-color: #37b030;
color: #fff;
cursor: pointer;
text-align: center;
border-radius: 1px;
}
.barclays-envs .project .tecr:hover, .barclays-envs .project .tebr:hover {
opacity: 0.7;
}
.barclays-envs .project .tecr.confl, .barclays-envs .project .tebr.confl {
background-color: #db4437;
}
.barclays-envs .ext-dir {
overflow-x: auto;
}
.barclays-envs .ext-dir .gantt-header-columns {
text-transform: uppercase;
}
.barclays-envs .ext-dir .gantt-header-row-last {
background-color: #173f5d;
color: #fff;
}
.barclays-envs .ext-dir .gantt-task-content > span {
display: block;
margin: 0;
}
.barclays-envs .ext-dir .gantt-task-content > span div { /*temp*/
line-height: 23px;
}
/*.barclays-envs .ext-dir .gantt-task:hover {
z-index: 1;
}*/
.barclays-envs .ext-dir .gantt-task:hover span div {
opacity: 0.8;
/*outline: 1px dotted yellow;*/
}
.barclays-envs .ext-dir .gantt-task-content > span div {
cursor: pointer;
}
.barclays-envs .ext-dir .gantt-tree-body .gantt-row-label a.gantt-tree-handle-button {
opacity: 1;
cursor: default;
}
.barclays-envs .ext-dir .gantt-tree-body .gantt-row-label a.gantt-tree-handle-button:not([disabled]) span {
display: none;
}
.barclays-envs .ext-dir .gantt-tree-body .gantt-row-label a.gantt-tree-handle-button[disabled] span.glyphicon-chevron-down {
color: transparent;
}
.barclays-envs .ext-dir .gantt-tree-body .gantt-row-label a.gantt-tree-handle-button[disabled] span.glyphicon-chevron-down:before {
content: "\e074";
}
.barclays-envs .ext-dir .gantt-tree-body ol:not(.gantt-tree-root) .angular-ui-tree-node:nth-child(2) .gantt-row-label a.gantt-tree-handle-button span {
background-color: #f68a3e;
}
.barclays-envs .ext-dir .gantt-tree-body ol:not(.gantt-tree-root) .angular-ui-tree-node:nth-child(1) .gantt-row-label a.gantt-tree-handle-button span {
background-color: #90b24f;
}
.barclays-envs .ext-dir .angular-ui-tree-nodes .angular-ui-tree-nodes {
padding-left: 2px;
}
.barclays-envs .ext-dir .gantt-row-even > .gantt-row-background {
background-color: transparent;
}
.barclays-envs .ext-dir .gantt-scrollable .gantt-row:nth-child(3n+3) {
border-bottom: 1px solid #ddd;
}
.barclays-envs .ui-select-bootstrap .ui-select-toggle>.caret {
display: none;
}
.barclays-envs .environment-group-picker.ui-select-bootstrap>.ui-select-choices, .barclays-envs .environment-picker.ui-select-bootstrap>.ui-select-choices {
width: calc(100% + 130px);
margin-top: 3px;
}
.barclays-envs .environment-group-picker.ui-select-bootstrap .ui-select-choices-row>span {
overflow: hidden;
}
.barclays-envs .environment-group-picker.ui-select-bootstrap .ui-select-choices-row.active>span,
.barclays-envs .environment-picker.ui-select-bootstrap .ui-select-choices-row.active>span {
color: #333;
background-color: #f5f5f5;
}
.barclays-envs .environment-group-picker .ui-select-choices .ui-select-choices-row div {
display: inline-block;
}
.barclays-envs .environment-group-picker .ui-select-choices .small-link, .barclays-envs-modal .modal-body .small-link {
font-size: 12px;
color: #0167DF;
float: right;
cursor: pointer;
}
.barclays-envs .environment-group-picker .ui-select-choices .small-link:hover, .barclays-envs-modal .modal-body .small-link:hover {
text-decoration: underline;
}
/*multiple selectors*/
.barclays-envs .environment-group-picker-control {
display: flex;
padding: 2px 4px;
height: 30px;
border-radius: 15px;
position: relative;
box-shadow: none;
}
/*.barclays-envs .environment-group-picker-control .multiple-selections {
display: inline-flex;
}*/
.barclays-envs .environment-group-picker-control .ui-select-multiple {
border: none;
box-shadow: none;
display: inline-flex;
padding: 0;
position: static;
border-radius: 15px;
}
.barclays-envs .environment-group-picker-control .ui-select-multiple.ui-select-bootstrap input.ui-select-search {
padding-left: 5px;
}
.barclays-envs .environment-group-picker-control .multiple-selections .btn {
border-radius: 10px;
line-height: 18px;
/*max-width: 120px;
text-overflow: ellipsis;
overflow: hidden;*/
}
.barclays-envs .environment-group-picker-control .ui-select-match {
display: none;
}
.barclays-envs .environment-group-picker-control .ui-select-search {
font-size: 12px;
}
.barclays-envs-modal .modal-body .close {
margin-left: 10px;
}
.barclays-envs-modal .modal-body .close span {
width: 15px;
height: 15px;
}
.barclays-envs-modal .modal-lg {
width: 80%;
}
.barclays-envs-modal .modal-center .modal-content {
border-radius: 1px;
}
.barclays-envs-modal .modal-header {
padding: 15px 15px 0 15px;
border-bottom-width: 0;
}
.barclays-envs-modal .modal-header h4 {
font-size: 14px;
color: #0099CC;
font-weight: bold;
}
.barclays-envs-modal .modal-header .icon-close {
background: #e2dddd url("/Content/icons/common/close-black.png") no-repeat center center;
background-size: 20px;
width: 20px;
height: 20px;
cursor: pointer;
border-radius: 1px;
}
.barclays-envs-modal .modal-header .icon-close:hover {
opacity: 0.6;
}
.barclays-envs-modal .conflict-panel {
max-height: 500px;
overflow-y: auto;
}
.barclays-envs-modal .conflict-panel .conflict-alert {
background-color: #fff3f3;
padding: 7px;
margin-bottom: 10px;
}
.barclays-envs-modal .conflict-panel .conflict-alert img {
margin-right: 5px;
}
.barclays-envs-modal .conflict-panel .conflict-alert span, .barclays-envs-modal .conflict-panel .conflict-date {
color: #ff0000;
}
.barclays-envs-modal .conflict-panel table {
margin-bottom: 0;
}
.barclays-envs-modal .conflict-panel table thead tr th {
border-bottom-width: 0;
}
.barclays-envs-modal .conflict-panel table tbody tr:hover {
background-color: #e5f5fa;
}
.barclays-envs-modal .conflict-panel table tbody td {
vertical-align: middle;
border-width: 0;
}
.barclays-envs-modal .conflict-panel table tbody td .form-group {
margin-bottom: 0;
}
.barclays-envs-modal.in-add .modal-center, .barclays-envs-modal.in .modal-center, .barclays-envs-modal.in-remove .modal-center {
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
margin: 0;
}
.barclays-envs .form-group .remove-filter {
bottom: 6px;
position: absolute;
right: 16px;
z-index: 3;
}
.barclays-envs .form-group .remove-filter div {
width: 15px;
height: 15px;
}
.barclays-envs .ext-dir .gantt-task .normal-overlap {
background-color: #db4437;
}
.barclays-envs .ext-dir .gantt-task .approved-overlap {
background: repeating-linear-gradient(-45deg, #caf982, #caf982 5px, #68ce43 5px, #68ce43 10px);
}
.barclays-envs .ext-dir .gantt-task .outaged-overlap {
background: repeating-linear-gradient(-45deg, #ffad00, #ffad00 5px, #db4437 5px, #db4437 10px);
}
.barclays-envs .ext-dir .gantt-task .normal-tecr {
background-color: #37b030;
}
.barclays-envs .ext-dir .gantt-task .outaged-tecr {
/*background-color: #09c;*/
background-color: #ffad00;
}
div#env-map-container {
height: calc(100% - 40px);
}
.barclays-envs .system-picker .level-0 {
}
.barclays-envs .system-picker .level-1 {
}
.barclays-envs .system-picker .level-2 {
text-indent: 5px;
}
.barclays-envs .system-picker .level-3 {
text-indent: 10px;
}
.barclays-envs .system-picker .level-4 {
text-indent: 15px;
}
.barclays-envs .system-picker .level-5 {
text-indent: 20px;
}
.barclays-envs .system-picker .level-6 {
text-indent: 25px;
}
.barclays-envs .ext-dir .gantt .gantt-row[style="height: 50px;"]:not(:first-child) {
border-top: 1px solid #359ae2;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/angular-gantt/1.3.3/angular-gantt.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/angular-gantt/1.3.3/angular-gantt-table-plugin.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/angular-gantt/1.3.3/angular-gantt-tree-plugin.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-tree/2.22.6/angular-ui-tree.min.css">
<div class="barclays-envs" ng-controller="BarclaysWidgetEnvs">
<div class="row">
<div class="col-md-2">
<div class="form-group">
<label class="required-field">Type</label>
<ui-select class="type-picker" ng-model="model.state.selectionType" on-select="resetWidgetState(true)">
<ui-select-match placeholder="Type...">
{{$select.selected.name}}
</ui-select-match>
<ui-select-choices repeat="item in model.selectionTypes | filter: $select.search">
<div ng-bind-html="(item.name | highlight: $select.search)"></div>
</ui-select-choices>
</ui-select>
</div>
</div>
<div class="col-md-2">
<div class="form-group" ng-if="model.state.selectionType.id == 0">
<label>Environment Groups</label>
<div class="form-control environment-group-picker-control">
<div ng-if="model.state.selectedEnvironmentGroupsFilter.length >= 1" class="multiple-selections">
<span ng-if="model.state.selectedEnvironmentGroupsFilter.length == 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironmentGroups()">{{model.state.selectedEnvironmentGroupsFilter[0].Name}}</span>
<span ng-if="model.state.selectedEnvironmentGroupsFilter.length > 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironmentGroups()">{{model.state.selectedEnvironmentGroupsFilter.length}} env. groups total</span>
</div>
<ui-select multiple class="environment-group-picker" ng-model="model.state.selectedEnvironmentGroupsFilter" close-on-select="false" zon-select="onSelectCustomEnvironmentGroups(true, $item)" uis-open-close="onSelectCustomEnvironmentGroups(true, $model, this)">
<ui-select-match allow-clear="true" placeholder="Type Environment Group Name ...">
<span>{{$item.Name}}</span>
</ui-select-match>
<!--<span class="ui-select-match">
<span ng-if="$select.selected.length == 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironmentGroups()">{{$select.selected[0].Name}}</span>
<span ng-if="$select.selected.length > 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironmentGroups()">{{$select.selected.length}} env. groups total</span>
</span>-->
<ui-select-choices repeat="item in model.allenvironmentgroups | filter: $select.search" refresh="funcAsyncEnvironmentGroups($select.search)" refresh-delay="1000">
<div ng-bind-html="(item.Name | highlight: $select.search)"></div><span class="small-link" ng-click="navigateToEnvironmentMap(item.ID, $event)">Go to Env. Map</span>
</ui-select-choices>
</ui-select>
<button type="button" class="remove-filter close" ng-if="model.state.selectedEnvironmentGroupsFilter" ng-click="resetWidgetState()" style="right: 6px;"><div class="x-form-clear-trigger"></div></button>
</div>
</div>
<div class="form-group hidden" ng-if="model.state.selectionType.id == 0">
<label class="required-field">Environment Group</label>
<ui-select class="egroup-picker" ng-model="model.state.selectedEgroup" zon-select="selectEgroup(true)" uis-open-close="selectEgroup(true, this)">
<ui-select-match placeholder="Type Environment Group">
{{$select.selected.Name}}
</ui-select-match>
<ui-select-choices repeat="item in model.egroups | filter: $select.search">
<div ng-bind-html="(item.Name | highlight: $select.search)"></div><span class="small-link" ng-click="navigateToEnvironmentMap(item.ID, $event)">Go to Env. Map</span>
</ui-select-choices>
</ui-select>
<button type="button" class="remove-filter close" ng-if="model.state.selectedEgroup" ng-click="resetWidgetState()" style="right: 26px;"><div class="x-form-clear-trigger"></div></button>
</div>
<div class="form-group" ng-if="model.state.selectionType.id == 2">
<label>Systems</label>
<ui-select class="system-picker" ng-model="model.state.selectedSystemFilter" on-select="onSelectCustomSystem(true)">
<ui-select-match placeholder="Type System Name ...">{{$select.selected.name}}</ui-select-match>
<ui-select-choices repeat="item in model.systems | filter: $select.search" refresh="funcAsyncSystems($select.search)" refresh-delay="1000">
<div ng-bind-html="(item.name | highlight: $select.search)" ng-class="item.tier"></div>
</ui-select-choices>
</ui-select>
<button type="button" class="remove-filter close" ng-if="model.state.selectedSystemFilter" ng-click="model.state.selectedSystemFilter = ''; applyEnvFilter()" style="right: 6px;"><div class="x-form-clear-trigger"></div></button>
</div>
<div class="form-group" ng-if="model.state.selectionType.id == 1">
<label>Environments</label>
<div class="form-control environment-group-picker-control">
<div ng-if="model.state.selectedEnvironmentsFilter.length >= 1" class="multiple-selections">
<span ng-if="model.state.selectedEnvironmentsFilter.length == 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironments()">{{model.state.selectedEnvironmentsFilter[0].Name}}</span>
<span ng-if="model.state.selectedEnvironmentsFilter.length > 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironments()">{{model.state.selectedEnvironmentsFilter.length}} env. groups total</span>
</div>
<ui-select multiple class="environment-picker" ng-model="model.state.selectedEnvironmentsFilter" close-on-select="false" zon-select="onSelectCustomEnvironments(true)" uis-open-close="onSelectCustomEnvironments(true, this)">
<ui-select-match allow-clear="true" placeholder="Type Environment Name ...">
<span>{{$item.Name}}</span>
</ui-select-match>
<!--<span class="ui-select-match" placeholder="Type Environment Name ...">
<span ng-if="$select.selected.length == 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironments()">{{$select.selected[0].Name}}</span>
<span ng-if="$select.selected.length > 1" class="btn btn-default btn-xs" ng-click="showAllSelectedEnvironments()">{{$select.selected.length}} envs total</span>
</span>-->
<ui-select-choices repeat="item in model.allenvironments | filter: $select.search" refresh="funcAsyncEnvironments($select.search)" refresh-delay="1000">
<div ng-bind-html="(item.Name | highlight: $select.search)"></div>
</ui-select-choices>
</ui-select>
<button type="button" class="remove-filter close" ng-if="model.state.selectedEnvironmentsFilter" ng-click="resetWidgetState()" style="right: 6px;"><div class="x-form-clear-trigger"></div></button>
</div>
</div>
<div class="form-group" ng-if="model.state.selectionType.id == 3">
<label>TEBRs</label>
<ui-select class="tebr-picker" ng-model="model.state.selectedTebr" on-select="selectTebr(model.state.selectedTebr)">
<ui-select-match placeholder="Type Tebr Name ...">{{$select.selected.Title}}</ui-select-match>
<ui-select-choices repeat="item in model.alltebrs | filter: $select.search" refresh="funcAsyncTebrs($select.search)" refresh-delay="1000">
<div ng-bind-html="(item.Title | highlight: $select.search)"></div>
</ui-select-choices>
</ui-select>
<button type="button" class="remove-filter close" ng-if="model.state.selectedTebr" ng-click="resetWidgetState()" style="right: 6px;"><div class="x-form-clear-trigger"></div></button>
</div>
<div class="form-group" ng-if="model.state.selectionType.id == 4">
<label>TECRs</label>
<ui-select class="tecr-picker" ng-model="model.state.selectedTecr" on-select="selectTecr(model.state.selectedTecr)">
<ui-select-match placeholder="Type Tecr Name ...">{{$select.selected.Title}}</ui-select-match>
<ui-select-choices repeat="item in model.alltecrs | filter: $select.search" refresh="funcAsyncTecrs($select.search)" refresh-delay="1000">
<div ng-bind-html="(item.Title | highlight: $select.search)"></div>
</ui-select-choices>
</ui-select>
<button type="button" class="remove-filter close" ng-if="model.state.selectedTecr" ng-click="resetWidgetState()" style="right: 6px;"><div class="x-form-clear-trigger"></div></button>
</div>
</div>
<div class="col-md-2">
<label class="required-field">Date Range</label>
<div class="form-group btn-group calendar-mode" role="group">
<button type="button" class="btn btn-default btn-sm" ng-click="openFilterCalendar($event, 'start', prop)" datetime-picker="{{model.dateTimeFormatPicker}}" ng-model="model.state.startDateValue" is-open="model.startDateFilterOpen" datepicker-options="model.dateOptions" enable-time="false" ng-change="updateDateRangeFilter()" datepicker-append-to-body="true">{{model.state.startDateValue | date : model.dateTimeFormat}}<span ng-if="model.state.startDateValue == null">From</span></button>
<button type="button" class="btn btn-default btn-sm" ng-click="openFilterCalendar($event, 'end', prop)" datetime-picker="{{model.dateTimeFormatPicker}}" ng-model="model.state.endDateValue" is-open="model.endDateFilterOpen" datepicker-options="model.dateOptions" enable-time="false" ng-change="updateDateRangeFilter()" datepicker-append-to-body="true">{{model.state.endDateValue | date : model.dateTimeFormat}}<span ng-if="model.state.endDateValue == null">To</span></button>
</div>
</div>
<div class="col-md-3">
<label class="">Show</label>
<div class="form-group btn-group calendar-mode" role="group">
<button type="button" class="btn btn-default btn-sm" ng-click="updateSchedulerZoom(1)" ng-class="{'active' : model.state.showType == 1}">Day</button>
<button type="button" class="btn btn-default btn-sm" ng-click="updateSchedulerZoom(2)" ng-class="{'active' : model.state.showType == 2}">Week</button>
<button type="button" class="btn btn-default btn-sm" ng-click="updateSchedulerZoom(3)" ng-class="{'active' : model.state.showType == 3}">Month</button>
<button type="button" class="btn btn-default btn-sm" ng-click="updateSchedulerZoom(4)" ng-class="{'active' : model.state.showType == 4}">Quarter</button>
<button type="button" class="btn btn-default btn-sm" ng-click="updateSchedulerZoom(5)" ng-class="{'active' : model.state.showType == 5}">Year</button>
</div>
</div>
<div class="col-md-3">
<div class="btn-group new-objects pull-right" role="group">
<button ng-click="newTecr()"><i class="glyphicon glyphicon-stop yellow"></i>&nbsp;&nbsp;Create TECR</button>
<button ng-click="newTebr()"><i class="glyphicon glyphicon-stop green"></i>&nbsp;&nbsp;Create TEBR</button>
<span class="btn-legend">
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Legend
</button>
<ul class="dropdown-menu">
<li><a href="#" class="vertical-status">TEBRs: EnviBooked</a></li>
<li><a href="#" class="vertical-status">Pending Conflict</a></li>
<li><a href="#" class="vertical-status">Accepted Conflicts</a></li>
<li role="separator" class="divider"></li>
<li><a href="#" class="vertical-status">TECRs: Single TECR</a></li>
<li><a href="#" class="vertical-status">Single TECR with Outage</a></li>
<li><a href="#" class="vertical-status">Overlapping TECRs</a></li>
<li><a href="#" class="vertical-status">Overlapping TECRs with Outage</a></li>
</ul>
</span>
</div>
</div>
</div>
<div class="ext-dir" oc-lazy-load="{files: ['https://cdnjs.cloudflare.com/ajax/libs/angular-ui-tree/2.22.6/angular-ui-tree.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/angular-gantt/1.3.3/angular-gantt.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/angular-gantt/1.3.3/angular-gantt-table-plugin.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/angular-gantt/1.3.3/angular-gantt-tree-plugin.min.js'], serie: true}">
<div gantt data="model.bookingSchedulerData" filter-row="ganttEnvironmentFilter" api="registerGantApi" headers-formats="model.scheduleHeadersFormats" view-scale="model.state.scheduleScale" from-date="model.scheduleFromDate" to-date="model.scheduleToDate" class="mame" auto-expand="right" style="width:{{model.scheduleWidth}}%;height:600px;">
<gantt-tree enabled="true" headers="{'model.name': 'Bookings'}"></gantt-tree>
</div>
</div>
</div>
angular.module('plutora.core').controller('BarclaysWidgetEnvs', ['$scope', 'localStorageService', '$uibModal', '$timeout', function($scope, localStorageService, $uibModal, $timeout) {
$('.barclays-envs').closest('.panel').addClass('barclays-envs-panel');
$scope.enums = {
periodModes : {
Day: 1,
Week: 2,
Month: 3,
Quarter: 4,
Year: 5
},
scheduleScales: ['day', 'day', 'week', 'month', 'quarter', 'year'],
};
$scope.model = {
apipoint: null,
egroups: [],
systems: [],
environments: [],
allenvironments: [],
allenvironmentgroups: [],
alltebrs: [],
alltecrs: [],
selectionTypes: [
{id: 0, name: 'Environment Groups'},
{id: 1, name: 'Environments'},
{id: 2, name: 'Systems'},
{id: 3, name: 'TEBRs'},
{id: 4, name: 'TECRs'}
],
dateTimeFormat: 'dd/MM/yyyy',
dateTimeFormatTime: 'dd/MM/yyyy H:mm',
state: {
ganttWidth: 150,
selectionType: null,
selectedEgroup: null,
selectedEnvironment: null,
startDateValue: null,
endDateValue: new Date(),
showType: $scope.enums.periodModes.Week,
scheduleScale: 'week',
selectedTebr: null,
selectedTecr: null,
selectedSystemFilter: null,
selectedEnvironmentsFilter: null,
selectedEnvironmentGroupsFilter: null
},
dateTimeFormatPicker: formatUtil.getDateFormat(PlutoraApp.DateFormat),
startDateFilterOpen: false,
endDateFilterOpen: false,
dateOptions: {
showWeeks: false
},
bookingEvents: [],
bookingEventsAllApproved: [],
tecrBookingEvents: [],
bookingSchedulerData: [],
selectedEnvironmentFilter: null,
exScheduler: null,
ganttApi: null,
scheduleFromDate: null,
scheduleToDate: null,
scheduleHeadersFormats: {
year: 'YYYY',
quarter: '[Q]Q - YYYY',
month: 'MMM',
week: 'D [week]',
day: 'D'
},
scheduleWidth: 100,
showTebrConflictWindow: false,
showTecrConflictWindow: false,
broadcastObj: null
};
// select previous year
$scope.model.state.startDateValue = new Date();
$scope.model.state.startDateValue.setFullYear($scope.model.state.endDateValue.getFullYear() - 1);
// dates for scheduler
$scope.model.scheduleFromDate = moment($scope.model.state.startDateValue, 'YYYY-MM-DD');
$scope.model.scheduleToDate = moment($scope.model.state.endDateValue, 'YYYY-MM-DD');
let defaultKey = 'barclaysWidgetEnvs';
var _getState = function(key) {
let accessKey = key || defaultKey;
return localStorageService.get(accessKey);
};
var _setState = function(value, key) {
let accessKey = key || defaultKey;
localStorageService.set(accessKey, value);
};
var _clearState = function (key) {
let accessKey = key || defaultKey;
localStorageService.remove(accessKey);
};
$scope.updateLocalState = function() {
_setState($scope.model.state);
};
$scope.registerGantApi = function(api) {
api.core.on.ready($scope, function () {
$scope.model.ganttApi = api;
$scope.model.ganttApi.side.on.resizeEnd($scope, function (width) {
if (width > 50) {
$scope.model.state.ganttWidth = width;
$scope.updateLocalState();
}
});
});
};
$scope.openFilterCalendar = function(e, type) {
e.preventDefault();
e.stopPropagation();
switch(type) {
case 'start':
$scope.model.endDateFilterOpen = false;
$scope.model.startDateFilterOpen = true;
break;
case 'end':
$scope.model.startDateFilterOpen = false;
$scope.model.endDateFilterOpen = true;
break;
}
};
$scope.newTebr = function() {
let controller = PlutoraApp.app.getController('PlutoraApp.controller.requests.bookingRequestController');
controller.newBookingRequest(function() {
console.log('new tebr is created');
});
};
$scope.newTecr = function() {
let controller = PlutoraApp.app.getController('PlutoraApp.controller.requests.changeRequestController');
controller.newChangeRequest(function() {
console.log('new tecr is created');
});
};
$scope.openBookingAllocation = function(tebrBooking) {
let controller = PlutoraApp.getApplication().getController('PlutoraApp.controller.requests.bookingRequestController');
controller.openAllocationWindow('booking_' + tebrBooking.envid + '_' + tebrBooking.bookingRequestID, true);
};
$scope.openTebr = function(id) {
let controller = PlutoraApp.app.getController('PlutoraApp.controller.requests.bookingRequestController');
controller.openBookingWindow(id, function() { // onCloseCallback
$timeout(function () {
$scope.loadScheduleBySavedState();
}, 1000);
});
$timeout(function () {
$('#EnvironmentSelectionSubPanel_header .x-title-text').append('<div class="schedule-initiator pull-right"><button class="btn btn-sm btn-default">Save and View Schedule</button></div>');
$('.schedule-initiator').off('click').on('click', function (e) {
//$('.save-btn .x-btn-inner:contains("Save & Close")').click();
var saveButton = controller.getSaveAndCloseBookingRequestButton();
saveButton.fireEvent('click', saveButton);
let tebrWindow = controller.getBookingRequestWindow();
let tebrData = tebrWindow.request.data;
let selectedTebr = {
ID: tebrData.ID,
StartDate: tebrData.StartDate.toISOString(),
DueDate: tebrData.EndDate.toISOString(),
Title: tebrData.Summary
};
$scope.$broadcast('barclays-envs-scheduler-trigger', {
selectedTebr: selectedTebr
});
});
}, 1500);
};
$scope.openTecr = function(id) {
let controller = PlutoraApp.app.getController('PlutoraApp.controller.requests.changeRequestController');
controller.openRequestWindow(id, function() { // onCloseCallback
$timeout(function () {
$scope.loadScheduleBySavedState();
}, 1000);
});
};
$scope.showAllSelectedEnvironmentGroups = function() {
let modalInstance = $uibModal.open({
template: ''+
'<div class="env-map-container-modal zwhite-background-modal">'+
' <div class="modal-header">'+
' <button type="button" class="close" ng-click="$ctrl.close()">&times;</button>'+
' <div class="pull-right hidden"><img class="icon-close" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-qtip="Close" ng-click="$ctrl.close()" /></div>'+
' <h4 class="modal-title">Selected Environment Groups</h4>'+
' </div>'+
' <div class="modal-body">'+
' <ul class="list-group">'+
' <li class="list-group-item" ng-repeat="$env in $ctrl.model.selectedEnvironmentGroupsFilter track by $index">{{$env.Name}} <span class="close"><span class="x-form-clear-trigger pull-right" ng-click="$ctrl.removeEnvironment($env)"></span></span><span class="small-link" ng-click="$ctrl.navigateToEnvironmentMap($env.ID, $event)">Go to Env. Map</span></li>'+
' </ul>'+
' </div>'+
'</div>',
controller: function($uibModalInstance, model, onSelectCustomEnvironmentGroups, navigateToEnvironmentMap) {
let $ctrl = this;
$ctrl.model = model;
$ctrl.onSelectCustomEnvironmentGroups = onSelectCustomEnvironmentGroups;
$ctrl.navigateToEnvironmentMap = navigateToEnvironmentMap;
$ctrl.removeEnvironment = function(env) {
$ctrl.model.selectedEnvironmentGroupsFilter.splice(_.findIndex($ctrl.model.selectedEnvironmentGroupsFilter, function(item) {
return item.ID === env.ID;
}), 1);
$ctrl.onSelectCustomEnvironmentGroups(true);
};
$ctrl.close = function() {
$uibModalInstance.dismiss();
};
},
controllerAs: '$ctrl',
backdrop: 'static', // 'static' disables modal closing by click on the backdrop
keyboard: false, // Indicates whether the dialog should be closable by hitting the ESC key
animation: true,
size: 'mg modal-center',
windowClass:'barclays-envs-modal im-wrap',
resolve: {
model: function() {
return $scope.model.state;
},
onSelectCustomEnvironmentGroups: function() {
return $scope.onSelectCustomEnvironmentGroups;
},
navigateToEnvironmentMap: function() {
return $scope.navigateToEnvironmentMap;
}
}
});
};
$scope.showAllSelectedEnvironments = function() {
let modalInstance = $uibModal.open({
template: ''+
'<div class="env-map-container-modal">'+
' <div class="modal-header">'+
' <button type="button" class="close" ng-click="$ctrl.close()">&times;</button>'+
' <div class="pull-right hidden"><img class="icon-close" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-qtip="Close" ng-click="$ctrl.close()" /></div>'+
' <h4 class="modal-title">Selected Environments</h4>'+
' </div>'+
' <div class="modal-body">'+
' <ul class="list-group">'+
' <li class="list-group-item" ng-repeat="$env in $ctrl.model.selectedEnvironmentsFilter track by $index">{{$env.Name}} <button class="btn btn-xs btn-default pull-right"><i class="glyphicon glyphicon-remove" ng-click="$ctrl.removeEnvironment($env)"></i></button></li>'+
' </ul>'+
' </div>'+
'</div>',
controller: function($uibModalInstance, model, onSelectCustomEnvironments) {
let $ctrl = this;
$ctrl.model = model;
$ctrl.onSelectCustomEnvironments = onSelectCustomEnvironments;
$ctrl.removeEnvironment = function(env) {
$ctrl.model.selectedEnvironmentsFilter.splice(_.findIndex($ctrl.model.selectedEnvironmentsFilter, function(item) {
return item.ID === env.ID;
}), 1);
$ctrl.onSelectCustomEnvironments(true);
};
$ctrl.close = function() {
$uibModalInstance.dismiss();
};
},
controllerAs: '$ctrl',
backdrop: 'static', // 'static' disables modal closing by click on the backdrop
keyboard: false, // Indicates whether the dialog should be closable by hitting the ESC key
animation: true,
size: 'mg modal-center',
windowClass:'barclays-envs-modal im-wrap',
resolve: {
model: function() {
return $scope.model.state;
},
onSelectCustomEnvironments: function() {
return $scope.onSelectCustomEnvironments;
}
}
});
};
$scope.navigateToEnvironmentMap = function(id, e) {
e.preventDefault();
e.stopPropagation();
let viewportController = PlutoraApp.app.getController('PlutoraApp.controller.Viewport');
let envMapPage = null;
if (viewportController && id) {
let modalInstance = $uibModal.open({
template: ''+
'<div class="env-map-container-modal zwhite-background-modal">'+
' <div class="modal-header">'+
' <button type="button" class="close" ng-click="$ctrl.close()">&times;</button>'+
' <div class="pull-right hidden"><img class="icon-close" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-qtip="Close" ng-click="$ctrl.close()" /></div>'+
' <h4 class="modal-title">Environment map</h4>'+
' </div>'+
' <div class="modal-body" id="env-map-container">'+
' </div>'+
'</div>',
controller: function($uibModalInstance, model) {
let $ctrl = this;
$ctrl.model = model;
$ctrl.close = function() {
$uibModalInstance.dismiss();
envMapPage.destroy();
};
},
controllerAs: '$ctrl',
backdrop: 'static', // 'static' disables modal closing by click on the backdrop
keyboard: false, // Indicates whether the dialog should be closable by hitting the ESC key
animation: true,
size: 'limited-full-height modal-full-width',
windowClass:'barclays-envs-modal im-wrap',
resolve: {
model: function() {
return $scope.model;
}
}
});
modalInstance.rendered.then(function() {
$.ajax({
type: 'POST',
url: '/Connectivity/LoadSaveUserData',
data: {
groupID: id,
isShowEnvironmentNames: true,
isShowEnvironmentGroups: false,
isShowConnectivityTypes: true,
isShowMultipleConnections: false,
isLoad: false
},
success: function(data, success) {
envMapPage = Ext.create('plutora.pages.environmentMap.page', {renderTo: 'env-map-container'});
if (envMapPage.panels && envMapPage.panels[0] && envMapPage.panels[0].items.items[1]) {
envMapPage.panels[0].items.items[1].setHeight(window.screen.height - 230);
}
},
error: function (e) { },
xhrFields: {
withCredentials: true
}
});
});
}
};
$scope.funcAsyncSystems = function(keyword) {
if (keyword.length >= 1) {
$scope.loadSystems(keyword);
return;
}
};
$scope.funcAsyncEnvironmentGroups = function(keyword) {
if (keyword.length >= 2) {
$scope.loadAllEnvironmentGroups(keyword);
return;
}
};
$scope.funcAsyncEnvironments = function(keyword) {
if (keyword.length >= 2) {
$scope.loadAllEnvironments(keyword);
return;
}
};
$scope.funcAsyncTebrs = function(keyword) {
if (keyword.length >= 2) {
$scope.loadAllTebrs(keyword);
return;
}
};
$scope.funcAsyncTecrs = function(keyword) {
if (keyword.length >= 2) {
$scope.loadAllTecrs(keyword);
return;
}
};
$scope.processSystemRecurs = function(system, tier) {
let id = system.id;
let systemName = system.SystemName;
let name = system.Name;
let leaf = system.leaf;
let children = system.children;
if (!leaf && children.length) {
children.forEach(function(childSystem) {
$scope.processSystemRecurs(childSystem, tier + 1);
});
} else {
$scope.model.systems.push({id: id, name: systemName, tier: 'level-' + tier});
}
};
$scope.loadSystems = function(keyword, callback) {
loadingIndicator(1);
$.ajax({
type: 'POST', url: '/Systems/GetCompanySystems',
data: {
pageFilter: 'All',
liveSearch: keyword,
firstLoad: null
},
success: function(data, success) {
if (success && data.success && data.data.Item && data.data.Item.children.length) {
$scope.model.systems = [];
$scope.processSystemRecurs(data.data.Item, 0);
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Systems/GetCompanySystems');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Systems/GetCompanySystems');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
};
$scope.loadAllEnvironmentGroups = function(keyword, callback) {
loadingIndicator(1);
$.ajax({
type: 'GET', url: '/Environments/GetAllGroups?page=1&start=0&limit=100&liveSearch='+keyword,
success: function(data, success) {
if (success && data.success && data.data && data.data.length) {
$scope.model.allenvironmentgroups = [];
data.data.forEach(function(child) {
$scope.model.allenvironmentgroups.push({ID: child.ID, Name: child.Name});
});
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Environments/GetAllGroups');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Environments/GetAllGroups');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
};
$scope.loadAllEnvironments = function(keyword, callback) {
loadingIndicator(1);
$.ajax({
type: 'POST', url: '/Environments/GetAll',
data: {
pageFilter: 'All',
groupingType: 'EnvironmentGroupGroupingField',
liveFilterValue: keyword,
environmentUtilizedState: false,
environmentIdleState: false,
isFirstLoad: false,
startDate: null,
endDate: null,
includeDate: false
},
success: function(data, success) {
if (success && data.success && data.data.EnvironmentGridDtos && data.data.EnvironmentGridDtos.length) {
$scope.model.allenvironments = [];
data.data.EnvironmentGridDtos.forEach(function(childEnvironment) {
$scope.model.allenvironments.push({ID: childEnvironment.ID, Name: childEnvironment.Name});
});
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Environments/GetAll');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Environments/GetAll');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
};
$scope.loadAllTebrs = function(keyword, callback) {
loadingIndicator(1);
$.ajax({
type: 'GET', url: '/Requests/GetCompanyBookingRequestsGrid?page=1&start=0&limit=100&liveSearch='+keyword,
success: function(data, success) {
if (success && data.success && data.data.Data && data.data.Data.length) {
$scope.model.alltebrs = [];
data.data.Data.forEach(function(children) {
$scope.model.alltebrs.push({ID: children.ID, Title: children.Title, StartDate: children.StartDate, DueDate: children.DueDate});
});
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Requests/GetCompanyBookingRequestsGrid');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Requests/GetCompanyBookingRequestsGrid');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
};
$scope.loadAllTecrs = function(keyword, callback) {
loadingIndicator(1);
$.ajax({
type: 'GET', url: '/Requests/GetCompanyChangeRequestsGrid?page=1&start=0&limit=100&liveSearch='+keyword,
success: function(data, success) {
if (success && data.success && data.data.Data && data.data.Data.length) {
$scope.model.alltecrs = [];
data.data.Data.forEach(function(children) {
$scope.model.alltecrs.push({ID: children.ID, Title: children.Title, StartDate: children.StartDate, DueDate: children.DueDate});
});
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Requests/GetCompanyChangeRequestsGrid');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Requests/GetCompanyChangeRequestsGrid');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
};
$scope.loadEgroups = function(callback) {
loadingIndicator(1);
$.ajax({
type: 'GET', url: '/Environments/GetAllGroups?page=1&start=0&limit=100',
success: function(data, success) {
if (success) {
let parsedData = data.data; // JSON.parse
Array.prototype.push.apply($scope.model.egroups, parsedData);
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Environments/GetAllGroups');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Environments/GetAllGroups');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
};
$scope.loadEnvironments = function(group, callback) {
if (group) {
loadingIndicator(1);
$.ajax({
type: 'GET',
url: '/Environments/GetEnvironmentInGroup?groupID=' + group.ID + '&page=1&start=0&limit=50',
success: function(data, success) {
if (success) {
data.data.forEach(function(childEnvironment) {
$scope.model.environments.push({ID: childEnvironment.ID, Name: childEnvironment.Name, grpId: group.ID, grpName: group.Name});
});
$scope.$apply();
if (typeof callback === 'function') {
callback();
}
} else {
highlight('Failed to execute Environments/GetEnvironmentInGroup');
}
loadingIndicator(0);
},
error: function (e) {
highlight('Failed to execute Environments/GetEnvironmentInGroup');
loadingIndicator(0);
},
xhrFields: {
withCredentials: true
}
});
}
};
$scope.selectEgroup = function(udpateLocalState, selector, callback) {
if (!selector || (selector && selector.$select.open == false)) {
if (!$scope.model.state.selectedEgroup) {
return;
}
$scope.clearGanttData();
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.state.selectedEnvironmentsFilter = null;
$scope.model.state.selectedTebr = '';
$scope.model.state.selectedTecr = '';
if (udpateLocalState) {
$scope.updateLocalState();
}
$scope.loadEnvironments($scope.model.state.selectedEgroup, function() {
if ($scope.model.state.startDateValue && $scope.model.state.endDateValue) {
$scope.populateScheduler(0);
}
if (typeof callback === 'function') {
callback();
}
});
}
};
$scope.populateScheduler = function(prefix, extraFilter, selectedGroup) {
selectedGroup = selectedGroup || $scope.model.state.selectedEgroup;
extraFilter = extraFilter || {'property':'EnvironmentGroup.ID.List','value':[selectedGroup.ID]};
$scope.model.tecrBookingEvents[prefix] = [];
$.ajax({
type: 'POST',
url: '/Reporting/GetEnvironmentGridData',
data: {
Filters: JSON.stringify([
{'property':'WorkItem.StartEndDate.Range','value': moment($scope.model.state.startDateValue).format('DD/MM/YYYY') + '#' + moment($scope.model.state.endDateValue).format('DD/MM/YYYY')},
extraFilter
]),
TimeScale: 'schedulerHead',
GroupingType: 0,
ShowUnallocatedEnvironments: true
},
success: function(data, success) {
if (success && data.success && data.data && data.data.events) {
let allTebrs = _.uniqBy(data.data.events, 'ID'); // remove duplicates from other integrated environments
let currentEnvNumber = 0 + $scope.model.bookingSchedulerData.length;
let currentEnvNumberOnly = 0;
$scope.model.environments.filter(function(env) {return (selectedGroup) ? env.grpId == selectedGroup.ID : env}).forEach(function(environment) {
let currentEnvironmentName = environment.Name, currentEnvironmentId = environment.ID;
let envGroupName = '', rowHeight = 28;
if (currentEnvNumberOnly == 0 && selectedGroup) {
envGroupName = '<b style="color:#0099cc">' + selectedGroup.Name + ':</b><br />';
rowHeight = 50;
}
$scope.model.bookingSchedulerData.push(
{ id: 'EN ' + currentEnvNumber, name: envGroupName + currentEnvironmentName, content: envGroupName + currentEnvironmentName, children: ['tebr ' + currentEnvNumber, 'tecr ' + currentEnvNumber], enid: currentEnvironmentId, height: rowHeight+'px'},
{ id: 'tebr ' + currentEnvNumber, name: 'TEBRs', height: '28px', tasks: [ ], enid: currentEnvironmentId },
{ id: 'tecr ' + currentEnvNumber, name: 'TECRs', height: '28px', tasks: [ ], enid: currentEnvironmentId }
);
$scope.updateGanttSideWidth();
// TEBRs
let currentEnvTebrs = allTebrs.filter(function(tebrElement) {return tebrElement.EnvironmentName == currentEnvironmentName && tebrElement.BookingRequestID != Guid.empty}); // exclude elements with empty guids
$scope.model.bookingEvents[currentEnvNumber] = currentEnvTebrs;
$scope.model.bookingEventsAllApproved[currentEnvNumber] = false;
let overlapRangesResult = null, overlappedPeriods = null;
let overlapResults = $scope.defineOverlapRanges($scope.model.bookingEvents[currentEnvNumber]);
overlapRangesResult = overlapResults[0];
overlappedPeriods = overlapResults[1];
let tebrsNode = $scope.model.bookingSchedulerData.filter(function(node) {return node.id == 'tebr ' + currentEnvNumber});
if (tebrsNode.length == 1) {
overlapRangesResult.forEach(function(booking, index) {
let bookingColor = '#37b030'; // green
let clickHandler = 'scope.openTebr(task.model.bookingRequestID)';
tebrsNode[0].tasks.push(
{
id: 'b-task ' + currentEnvNumber + index,
resid: booking.ResourceId,
envid: currentEnvironmentId,
bookingRequestID: booking.BookingRequestID,
name: booking.BookingRequestIndex + '_' + booking.BookingRequestSummary,
content: '<div data-qtip="BookingRequestSummary: '+booking.BookingRequestSummary+' in Environment: '+booking.EnvironmentName+'" ng-click="'+clickHandler+'" style="background-color:'+bookingColor+'">&nbsp;</div>',
from: booking.StartDate, to: booking.EndDate
}
);
});
// display tebr conflict overlapped ranges
overlappedPeriods.forEach(function(conflictRange, index) {
let clickHandler = "scope.showTebrConflictWindow("+currentEnvNumber+", '"+currentEnvironmentName+"', '"+currentEnvironmentId+"')";
tebrsNode[0].tasks.push(
{
id: 'overlap-range ' + currentEnvNumber + index,
type: 'overlap-range',
envid: currentEnvironmentId,
content: '<div ng-click="'+clickHandler+'" class="normal-overlap">&nbsp;</div>',
from: conflictRange.StartDate, to: conflictRange.EndDate
}
);
});
}
// run separate process of taking additional information about bookings in order to display tebr status on initial load
$scope.fetchOverlappedTebrBookingInfo(currentEnvNumber, currentEnvironmentId);
// TECRs preparation
$scope.model.tecrBookingEvents[prefix][currentEnvNumberOnly] = [];
currentEnvNumber++;
currentEnvNumberOnly++;
});
// TECRs
// $scope.model.tecrBookingEvents[currentEnvNumber] = [];
//let tecrsNode = $scope.model.bookingSchedulerData.filter(function(node) {return node.id == 'tecr ' + currentEnvNumber});
if (data.data.resources /*&& tecrsNode.length == 1*/) {
let systemIds = [];
data.data.resources.forEach(function(resource) {
//if (resource.Id == currentEnvironmentId) { // or, collect them by name
systemIds[resource.SystemId] = { loaded: false };
//}
});
if (Object.keys(systemIds).length) {
for (let systemId in systemIds) {
let systemInfo = systemIds[systemId];
if (systemInfo.loaded === false) {
$scope.model.state.startDateValue.setHours(0, 0, 0, 0);
$scope.model.state.endDateValue.setHours(23, 59, 59, 999);
let myPrefix = prefix;
$.ajax({
type: 'POST',
url: '/Reporting/GetChangeRequestsBySystem',
data: {
groupID: null,
systemID: systemId,
startDate: $scope.model.state.startDateValue.toISOString(),
endDate: $scope.model.state.endDateValue.toISOString(),
enabled: true
},
success: function(data, success) {
systemInfo.loaded = true;
if (success && data.success) {
$scope.model.environments.filter(function(env) {return (selectedGroup) ? env.grpId == selectedGroup.ID : env}).forEach(function(environment, currentEnvNumber2) {
let currentEnvironmentName = environment.Name; //, currentEnvironmentId = environment.ID;
let currentEnvTecrs = data.data.events.filter(function(ev) { return ev.EnvironmentName === currentEnvironmentName });
if (currentEnvTecrs.length && $scope.model.tecrBookingEvents.length && $scope.model.tecrBookingEvents[myPrefix][currentEnvNumber2]) {
Array.prototype.push.apply($scope.model.tecrBookingEvents[myPrefix][currentEnvNumber2], currentEnvTecrs);
}
});
}
// here we check if all ajax requests are finished, if all finished, we search for overlaps and show results
let allTecrRequestsFinished = true;
for (let sid in systemIds) {
if (systemIds[sid].loaded === false) {
allTecrRequestsFinished = false;
}
}
if (allTecrRequestsFinished) {
$scope.processAllLoadedTecrs(myPrefix, selectedGroup);
}
},
error: function (e) {
highlight('Internal error in GetChangeRequestsBySystem: ' + JSON.parse(e.responseText));
},
xhrFields: {
withCredentials: true
}
});
}
}
}
}
$scope.$apply();
$scope.updateGanttSideWidth();
$scope.applyEnvFilter();
} else {
highlight('Failed to execute Reporting/GetEnvironmentGridData');
}
},
error: function (e) {
highlight('Failed to execute Reporting/GetEnvironmentGridData');
},
xhrFields: {
withCredentials: true
}
});
};
$scope.onSelectCustomSystem = function(udpateLocalState) {
$.ajax({
type: 'POST',
url: '/QuerysBuilder/ApplyFilter',
data: {
parameters: [{
configurationName: 'EnvironmentGrid',
gridOperand: null,
entityQueryID: null,
qbOperand: {
ColumnName: 'LinkedSystem',
ConcreteType: 'System',
Operator: 0,
Type: 'Plutora.Common.IEntity',
Value: $scope.model.state.selectedSystemFilter.name
}
}]
},
success: function(data, success) {
if (success && data.success) {
$.ajax({
type: 'POST',
url: '/Environments/GetAll',
data: {
pageFilter: 'All',
groupingType: 'EnvironmentGroupGroupingField',
liveFilterValue: null,
environmentUtilizedState: false,
environmentIdleState: false,
isFirstLoad: false,
startDate: null,
endDate: null,
includeDate: false
},
success: function(data, success) {
if (success && data.success && data.data && data.data.EnvironmentGridDtos && data.data.EnvironmentGridDtos.length) {
$scope.model.environments = [];
let envIds = [];
data.data.EnvironmentGridDtos.forEach(function(childEnvironment) {
$scope.model.environments.push({ID: childEnvironment.ID, Name: childEnvironment.Name});
envIds.push(childEnvironment.ID);
});
if (envIds.length && $scope.model.state.startDateValue && $scope.model.state.endDateValue) {
$scope.clearGanttData();
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.state.selectedEgroup = null;
if (udpateLocalState) {
$scope.updateLocalState();
}
//Array.prototype.push.apply($scope.model.environmentgroups, $scope.model.state.selectedEnvironmentGroupsFilter);
$scope.model.environmentgroups = $scope.model.state.selectedEnvironmentGroupsFilter;
$scope.populateScheduler(0, {'property': 'Environment.ID.List', 'value': envIds});
} else {
highlight('Please select proper date range to continue');
}
}
},
xhrFields: {
withCredentials: true
}
});
}
},
xhrFields: {
withCredentials: true
}
});
};
$scope.onSelectCustomEnvironmentGroups = function(udpateLocalState, item, selector) {
if (!selector || (selector && selector.$select.open == false)) {
if (!$scope.model.state.selectedEnvironmentGroupsFilter) {
return;
}
//console.log('onSelectCustomEnvironmentGroups');
/*if (item) { // var2 = onselect
delete item.grpLoaded;
}*/
if ($scope.model.state.selectedEnvironmentGroupsFilter.length /*== 1*/) { // var1 = onclose
$scope.model.environments = [];
$scope.clearGanttData();
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.state.selectedEgroup = null;
$scope.model.state.selectedEnvironmentGroupsFilter.forEach(function(environmentGroup, index) { // var1 = onclose
delete environmentGroup.grpLoaded;
});
}
/*if ($scope.model.state.selectedEnvironmentGroupsFilter.length >= 2) {
debugger;
}*/
$scope.model.state.selectedEnvironmentGroupsFilter.forEach(function(environmentGroup, index) {
if (typeof environmentGroup.grpLoaded === "undefined") {
environmentGroup.grpLoaded = false;
$timeout(function () {
$scope.loadEnvironments(environmentGroup, function() {
$scope.populateScheduler(index, null, environmentGroup);
});
}, 1000 * index);
}
});
if (udpateLocalState) {
$scope.updateLocalState();
}
}
};
$scope.onSelectCustomEnvironments = function(udpateLocalState, selector) {
if (!selector || (selector && selector.$select.open == false)) {
if (!$scope.model.state.selectedEnvironmentsFilter) {
return;
}
let envIds = $scope.model.state.selectedEnvironmentsFilter.map(function(a) { return a.ID });
if ($scope.model.state.startDateValue && $scope.model.state.endDateValue) {
$scope.clearGanttData();
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.state.selectedEgroup = null;
if (udpateLocalState) {
$scope.updateLocalState();
}
//Array.prototype.push.apply($scope.model.environments, $scope.model.state.selectedEnvironmentsFilter);
$scope.model.environments = $scope.model.state.selectedEnvironmentsFilter;
$scope.populateScheduler(0, {'property': 'Environment.ID.List', 'value': envIds});
} else {
highlight('Please select proper date range to continue');
}
}
};
$scope.processAllLoadedTecrs = function(prefix, selectedGroup) {
$scope.model.environments.filter(function(env) {return (selectedGroup) ? env.grpId == selectedGroup.ID : env}).forEach(function(environment, currentEnvNumber1) {
let currentEnvironmentName = environment.Name, currentEnvironmentId = environment.ID;
let overlapRangesResult = null, overlappedPeriods = null;
let overlapResults = $scope.defineOverlapRanges($scope.model.tecrBookingEvents[prefix][currentEnvNumber1]);
overlapRangesResult = overlapResults[0];
overlappedPeriods = overlapResults[1];
let tecrsNode = $scope.model.bookingSchedulerData.filter(function(node) {return node.enid == environment.ID && node.name == 'TECRs'});
overlapRangesResult.forEach(function(booking, index) {
let clickHandler = 'scope.openTecr(task.model.tecrBookingRequestID)';
tecrsNode.forEach(function(eachTecrNode, tecrNum) {
eachTecrNode.tasks.push(
{
id: 'c-task ' + prefix + currentEnvNumber1 + index + tecrNum,
resid: booking.ResourceId,
bookingRequestID: booking.BookingRequestID,
tecrBookingRequestID: booking.ID,
name: booking.WorkItemName + '_' + index,
content: '<div data-qtip="TecrName: '+booking.Name+' in Environment: '+booking.EnvironmentName+'" ng-click="'+clickHandler+'" class="normal-tecr">&nbsp;</div>',
from: booking.StartDate, to: booking.EndDate,
}
);
})
});
// display tecr conflict overlapped ranges
overlappedPeriods.forEach(function(conflictRange, index) {
let clickHandler = "scope.showTecrConflictWindow("+prefix+", "+currentEnvNumber1+", '"+currentEnvironmentName+"')";
tecrsNode.forEach(function(eachTecrNode, tecrNum) {
eachTecrNode.tasks.push(
{
id: 'c-overlap-range ' + prefix + currentEnvNumber1 + index + tecrNum,
type: 'overlap-range',
content: '<div ng-click="'+clickHandler+'" class="normal-overlap">&nbsp;</div>',
from: conflictRange.StartDate, to: conflictRange.EndDate,
prevID: conflictRange.prevID, curID: conflictRange.curID
}
);
});
});
$scope.fetchOverlappedTecrBookingInfo(prefix, currentEnvNumber1, currentEnvironmentId);
$scope.$apply();
$scope.updateGanttSideWidth();
$scope.applyEnvFilter();
});
};
$scope.fetchOverlappedTebrBookingInfo = function(currentEnvNumber, currentEnvironmentId) {
$scope.model.bookingEvents[currentEnvNumber].forEach(function(tebrBooking) {
if (tebrBooking.overlap && tebrBooking.BookingRequestID != Guid.empty) {
$.ajax({
type: 'POST',
url: '/Bookings/GetByBookingRequestAndEnv',
data: {
envOrEnvGroupID: currentEnvironmentId,
bookingRequestID: tebrBooking.BookingRequestID
},
success: function(data, success) {
if (success) {
tebrBooking.plutoraModel = data.data;
tebrBooking.bookingStatus = data.data.BookingStatus;
$scope.$apply();
// check if all booking overlaps are approved
if ($scope.model.bookingEvents[currentEnvNumber].filter(function(booking) { return booking.overlap && (booking.bookingStatus == 1 || booking.bookingStatus == 2)}).length == $scope.model.bookingEvents[currentEnvNumber].filter(function(booking) {return booking.overlap}).length ) {
//if ($scope.model.bookingEvents[currentEnvNumber].filter(function(booking) {return booking.overlap && booking.bookingStatus == 0}).length == 0) {
if ($scope.model.ganttApi && $scope.model.ganttApi.data) {
$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == currentEnvironmentId && node.name == 'TEBRs'}).forEach(function(everyTebrNode) {
everyTebrNode.tasks.forEach(function(dataElement) {
if (dataElement.type == 'overlap-range') {
dataElement.content = dataElement.content.replace('normal-overlap', 'approved-overlap');
}
});
});
/*$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == currentEnvironmentId})[1].tasks.forEach(function(dataElement) {
if (dataElement.type == 'overlap-range') {
dataElement.content = dataElement.content.replace('normal-overlap', 'approved-overlap');
}
});*/
}
$scope.model.bookingEventsAllApproved[currentEnvNumber] = true;
}
}
},
error: function (e) {
highlight('Internal error in populateScheduler: ' + JSON.parse(e.responseText));
},
xhrFields: {
withCredentials: true
}
});
}
});
};
$scope.fetchOverlappedTecrBookingInfo = function(prefix, currentEnvNumber, currentEnvironmentId) {
if ($scope.model.tecrBookingEvents && $scope.model.tecrBookingEvents[prefix][currentEnvNumber]) {
// get TECR additional information
$scope.model.tecrBookingEvents[prefix][currentEnvNumber].forEach(function(tecrBooking) {
// new requirement: need to load detailed information for all TECRs
if (/*tecrBooking.overlap &&*/ tecrBooking.ID != Guid.empty) {
let environments = $scope.model.environments.filter(function(env) {return env.Name == tecrBooking.EnvironmentName});
if (environments.length >= 1) {
$.ajax({
type: 'GET',
url: '/Requests/GetRequest/' + tecrBooking.ID,
success: function(data, success) {
if (success && data.success) {
tecrBooking.Outage = data.data.Outage;
tecrBooking.StatusText = data.data.StatusText;
tecrBooking.OutageStartDate = data.data.OutageStartDate;
tecrBooking.OutageEndDate = data.data.OutageEndDate;
$scope.$apply();
// check if all booking overlaps are approved
/*if ($scope.model.tecrBookingEvents[currentEnvNumber].filter((booking) => {return booking.overlap && booking.StatusText != 'Completed'}).length == 0) {
$scope.model.ganttApi.data.get()[currentEnvNumber*3+2].tasks.forEach((dataElement) => {
if (dataElement.type == 'overlap-range') {
dataElement.content = dataElement.content.replace('normal-overlap', 'approved-overlap');
}
});
//$scope.model.bookingEventsAllApproved[currentEnvNumber] = true;
}*/
// The TECR should be displayed in Orange colour if an outage is required
if (tecrBooking.Outage && !tecrBooking.overlap) {
/*let tecrElement = $scope.model.ganttApi.data.get()[currentEnvNumber*3+2].tasks.filter((tecrEl) => {return tecrEl.tecrBookingRequestID == tecrBooking.ID});
if (tecrElement.length && tecrElement[0]) {
//tecrElement[0].content = tecrElement[0].content.replace('#37b030', '#ffad00');
tecrElement[0].content = tecrElement[0].content.replace('normal-tecr', 'outaged-tecr');
console.log('color changed to ' + tecrBooking.Name);
}*/
/*$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == currentEnvironmentId})[2].tasks.forEach(function(dataElement) {
if (dataElement.tecrBookingRequestID == tecrBooking.ID) {
dataElement.content = dataElement.content.replace('normal-tecr', 'outaged-tecr');
}
});*/
$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == currentEnvironmentId && node.name == 'TECRs'}).forEach(function(everyTecrNode) {
everyTecrNode.tasks.forEach(function(dataElement) {
if (dataElement.tecrBookingRequestID == tecrBooking.ID) {
dataElement.content = dataElement.content.replace('normal-tecr', 'outaged-tecr');
}
});
});
$scope.$apply();
}
if (tecrBooking.Outage && tecrBooking.overlap) {
/*$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == currentEnvironmentId})[2].tasks.forEach(function(dataElement) {
if (dataElement.type == 'overlap-range' && (dataElement.prevID == tecrBooking.ID || dataElement.curID == tecrBooking.ID)) {
dataElement.content = dataElement.content.replace('normal-overlap', 'outaged-overlap');
}
});*/
$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == currentEnvironmentId && node.name == 'TECRs'}).forEach(function(everyTecrNode) {
everyTecrNode.tasks.forEach(function(dataElement) {
if (dataElement.type == 'overlap-range' && (dataElement.prevID == tecrBooking.ID || dataElement.curID == tecrBooking.ID)) {
dataElement.content = dataElement.content.replace('normal-overlap', 'outaged-overlap');
}
});
});
$scope.$apply();
}
}
},
error: function (e) {
highlight('Internal error: ' + JSON.parse(e.responseText));
},
xhrFields: {
withCredentials: true
}
});
}
}
});
}
};
$scope.resetWidgetState = function(clearFilter) {
$scope.model.state.ganttWidth = 150;
$scope.model.state.selectedEnvironmentFilter = '';
$scope.model.state.selectedEnvironmentsFilter = '';
$scope.model.state.selectedEgroup = '';
$scope.model.state.selectedEnvironmentGroupsFilter = '';
$scope.model.state.selectedEnvironment = '';
$scope.model.state.selectedSystemFilter = '';
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.environments = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.state.selectedTebr = '';
$scope.model.state.selectedTecr = '';
$scope.clearGanttData();
if (clearFilter) {
$scope.resetActiveEnvironmentFilter();
$scope.resetActiveSystemFilter();
}
};
$scope.ganttEnvironmentFilter = function(row){
return ($scope.model.state.selectedEnvironmentFilter && row.model.enid != $scope.model.state.selectedEnvironmentFilter.ID) ? false : true;
};
$scope.applyEnvFilter = function() {
if ($scope.model.ganttApi && $scope.model.ganttApi.rows) {
$scope.model.ganttApi.rows.refresh();
}
};
$scope.updateGanttSideWidth = function() {
if ($scope.model.ganttApi && $scope.model.ganttApi.side) {
let currentWidth = $scope.model.ganttApi.side.getWidth();
if (currentWidth != $scope.model.state.ganttWidth) {
$scope.model.ganttApi.side.setWidth($scope.model.state.ganttWidth);
}
}
};
$scope.clearGanttData = function() {
if ($scope.model.ganttApi && $scope.model.ganttApi.data) {
$scope.model.ganttApi.data.clear();
}
};
$scope.convertUTCDateToLocalDate = function(date) {
let newDate = new Date(date.getTime() - date.getTimezoneOffset()*60*1000);
return newDate;
};
$scope.defineOverlapRanges = function(dateRanges) { // parse all given date ranges, define overlapped ranges, create array of overlapped periods
let overlappedPeriods = [], sortedRanges = [];
if (dateRanges && dateRanges.length) {
dateRanges.map(function(record) {
record.bookingStatus = -1;
record.StartDate = $scope.convertUTCDateToLocalDate(new Date(record.StartDate));
record.EndDate = $scope.convertUTCDateToLocalDate(new Date(record.EndDate));
});
sortedRanges = dateRanges.sort(function(previous, current) {
let previousTime = previous.StartDate.getTime(); // get the start date from previous and current
let currentTime = current.StartDate.getTime();
if (previousTime < currentTime) { // if the previous is earlier than the current
return -1;
}
if (previousTime === currentTime) { // if the previous time is the same as the current time
return 0;
}
return 1; // if the previous time is later than the current time
});
let result = sortedRanges.reduce(function(result, current, idx, arr) {
if (idx === 0) {
return result;
}
let previous = arr[idx-1]; // get the previous range
// check for any overlap
let previousEnd = previous.EndDate.getTime();
let currentStart = current.StartDate.getTime();
let overlap = (previousEnd >= currentStart);
// store the result
if (overlap) {
previous.overlap = true;
current.overlap = true;
overlappedPeriods.push({
StartDate: current.StartDate, EndDate: previous.EndDate, prevID: previous.ID, curID: current.ID
});
}
return result;
}, {overlap: false, ranges: []}); // seed the reduce*/
}
return [sortedRanges, overlappedPeriods];
};
$scope.updateDateRangeFilter = function() {
if ($scope.model.state.startDateValue && $scope.model.state.endDateValue) {
$scope.model.scheduleFromDate = moment($scope.model.state.startDateValue, 'YYYY-MM-DD');
$scope.model.scheduleToDate = moment($scope.model.state.endDateValue, 'YYYY-MM-DD');
$scope.updateLocalState();
}
$scope.loadScheduleBySavedState();
};
$scope.updateSchedulerZoom = function(i) {
$scope.model.state.showType = i;
$scope.model.state.scheduleScale = $scope.enums.scheduleScales[i];
$scope.updateLocalState();
$scope.applyScheduleScale();
};
$scope.applyScheduleScale = function() {
let value = 100;
switch($scope.model.state.showType) {
case $scope.enums.periodModes.Day:
value = 200;
break;
case $scope.enums.periodModes.Week:
value = 150;
break;
}
$scope.model.scheduleWidth = value;
};
$scope.showTebrConflictWindow = function(id, name, environmentId) {
let modalInstance = $uibModal.open({
// btw: EnumsManager.BookingStatus {Pending: 0, Approved: 1, Rejected: 2}
template: ''+
'<div class="modal-header">'+
' <button type="button" class="close" ng-click="$ctrl.close()">&times;</button>'+
' <div class="pull-right hidden"><img class="icon-close" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-qtip="Close" ng-click="$ctrl.close()" /></div>'+
' <h4 class="modal-title">'+name+'</h4>'+
'</div>'+
'<div class="modal-body conflict-panel">'+
' <div class="conflict-alert"><img src="/Content/icons/deploymentPlan/info-icon-red.png" /> There are <span>{{($ctrl.model.bookingEvents['+id+'] | filter:$ctrl.overlappedFilter).length}} conflicts</span> occurred in this environment.</div>'+
' <table class="table table-hover table-condensed">'+
' <thead>'+
' <tr>'+
' <th>TECR Title</th>'+
' <th>TEBR Title</th>'+
' <th>Release</th>'+
' <th>Environment/Env.Group</th>'+
' <th>Start Date</th>'+
' <th>End Date</th>'+
' <th>Booking status</th>'+
' </tr>'+
' </thead>'+
' <tbody>'+
' <tr ng-repeat="bookingConflict in $ctrl.model.bookingEvents['+id+'] | filter:$ctrl.overlappedFilter">'+
' <td>-</td>'+
' <td><a href="javascript:void(0)" ng-bind="bookingConflict.BookingRequestSummary" ng-click="$ctrl.openTebr(bookingConflict.BookingRequestID)"></a></td>'+
' <td ng-bind="bookingConflict.ReleaseName"></td>'+
' <td ng-bind="bookingConflict.EnvironmentName"></td>'+
' <td ng-bind="bookingConflict.StartDate | date : $ctrl.model.dateTimeFormatTime" class="conflict-date"></td>'+
' <td ng-bind="bookingConflict.EndDate | date : $ctrl.model.dateTimeFormatTime" class="conflict-date"></td>'+
' <td>'+
' <div class="form-group btn-group" role="group" ng-if="bookingConflict.bookingStatus >= 0">'+
' <button type="button" class="btn btn-default btn-sm" ng-class="{\'active\' : bookingConflict.bookingStatus == 1}" ng-click="$ctrl.changeBookingStatus(bookingConflict, 1, '+id+', \''+environmentId+'\')">Approved</button>'+
' <button type="button" class="btn btn-default btn-sm" ng-class="{\'active\' : bookingConflict.bookingStatus == 0}" ng-click="$ctrl.changeBookingStatus(bookingConflict, 0, '+id+', \''+environmentId+'\')">Pending</button>'+
' <button type="button" class="btn btn-default btn-sm" ng-class="{\'active\' : bookingConflict.bookingStatus == 2}" ng-click="$ctrl.changeBookingStatus(bookingConflict, 2, '+id+', \''+environmentId+'\')">Rejected</button>'+
' </div>'+
' </td>'+
' </tr>'+
' </tbody>'+
' </table>'+
'</div>',
controller: function($uibModalInstance, model) {
let $ctrl = this;
$ctrl.model = model;
$ctrl.close = function() {
$uibModalInstance.dismiss();
};
$ctrl.openTebr = function(id) {
let controller = PlutoraApp.app.getController('PlutoraApp.controller.requests.bookingRequestController');
controller.openBookingWindow(id, function() { // onCloseCallback
$timeout(function () {
$scope.loadScheduleBySavedState();
}, 1000);
});
$timeout(function () {
$('#EnvironmentSelectionSubPanel_header .x-title-text').append('<div class="schedule-initiator pull-right"><button class="btn btn-sm btn-default">Save and View Schedule</button></div>');
$('.schedule-initiator').off('click').on('click', function (e) {
$uibModalInstance.dismiss();
//$('.save-btn .x-btn-inner:contains("Save & Close")').click();
var saveButton = controller.getSaveAndCloseBookingRequestButton();
saveButton.fireEvent('click', saveButton);
let tebrWindow = controller.getBookingRequestWindow();
let tebrData = tebrWindow.request.data;
let selectedTebr = {
ID: tebrData.ID,
StartDate: tebrData.StartDate.toISOString(),
DueDate: tebrData.EndDate.toISOString(),
Title: tebrData.Summary
};
$scope.$broadcast('barclays-envs-scheduler-trigger', {
selectedTebr: selectedTebr
});
});
}, 1500);
};
$ctrl.changeBookingStatus = function(booking, status, eventIndexId, environmentId) {
if (booking.bookingStatus != status) {
booking.plutoraModel.BookingStatus = status;
booking.bookingStatus = status;
// model conversion
let updateModel = Ext.create('plutora.pages.projectScheduler.model', booking.plutoraModel);
updateModel.data.BookingRequestEndDate = updateModel.data.BookingRequestEndDate.toISOString().split('Z')[0];
updateModel.data.BookingRequestStartDate = updateModel.data.BookingRequestStartDate.toISOString().split('Z')[0];
updateModel.data.EndDate = updateModel.data.EndDate.toISOString().split('Z')[0];
updateModel.data.StartDate = updateModel.data.StartDate.toISOString().split('Z')[0];
$.ajax({
type: 'PUT',
url: '/Bookings/Update/'+booking.ID,
data: updateModel.data, /*{
ApproverFromSystem: null,
ApproverName: "",
ApproverOrganizationName: "",
BookingRequestEndDate: "2016-04-30T12:36:00",
BookingRequestID: "c50c4034-a79b-4329-96e5-c6384cbd836e",
BookingRequestNumber: "EB127",
BookingRequestStartDate: "2016-04-28T12:36:00",
BookingRequestTitle: "this is a test",
BookingStatus: 0,
Color: "#9F56B3",
CommentsCount: 0,
EndDate: "2016-04-30T12:36:00",
EnvironmentID: "ef61d544-5cbf-43c2-86ac-d5c5f0c15ca1",
EnvironmentName: "Environment :Environment Associated with this release ",
ID: "e5024707-9f8f-4f29-b0da-b643cd461405",
IsAutoApproved: false,
IsBooking: true,
IsEnvironmentOnly: true,
Name: "Environment Associated with this release ",
ReleaseID: "",
StartDate: "2016-04-28T09:36:00",
WorkItemID: "",
WorkItemName: "",
},*/
success: function(data, success) {
if (success) {
booking.bookingStatus = status;
// check if all booking overlaps are approved
if ($scope.model.bookingEvents[eventIndexId].filter(function(booking) {return booking.overlap && booking.bookingStatus == 0}).length == 0) {
$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == environmentId && node.name == 'TEBRs'}).forEach(function(everyTebrNode) {
everyTebrNode.tasks.forEach(function(dataElement) {
if (dataElement.type == 'overlap-range') {
dataElement.content = dataElement.content.replace('normal-overlap', 'approved-overlap');
}
});
});
$scope.model.bookingEventsAllApproved[eventIndexId] = true;
} else {
$scope.model.ganttApi.data.get().filter(function(node) {return node.enid == environmentId && node.name == 'TEBRs'}).forEach(function(everyTebrNode) {
everyTebrNode.tasks.forEach(function(dataElement) {
if (dataElement.type == 'overlap-range') {
dataElement.content = dataElement.content.replace('approved-overlap', 'normal-overlap');
}
});
});
$scope.model.bookingEventsAllApproved[eventIndexId] = false;
}
$scope.$apply();
} else {
highlight('Failed to execute Bookings/GetByBookingRequestAndEnv');
}
},
error: function (e) {
highlight('Internal error in showTebrConflictWindow: ' + JSON.parse(e.responseText));
},
xhrFields: {
withCredentials: true
}
});
}
};
$ctrl.overlappedFilter = function(object) {
return object.overlap === true;
};
},
controllerAs: '$ctrl',
backdrop: 'static', // 'static' disables modal closing by click on the backdrop
keyboard: false, // Indicates whether the dialog should be closable by hitting the ESC key
animation: true,
size: 'lg modal-center',
windowClass:'barclays-envs-modal im-wrap',
resolve: {
model: function() {
return $scope.model;
}
}
});
};
$scope.showTecrConflictWindow = function(prefix, id, name) {
let modalInstance = $uibModal.open({
template: ''+
'<div class="modal-header">'+
' <button type="button" class="close" ng-click="$ctrl.close()">&times;</button>'+
' <div class="pull-right hidden"><img class="icon-close" src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-qtip="Close" ng-click="$ctrl.close()" /></div>'+
' <h4 class="modal-title">'+name+'</h4>'+
'</div>'+
'<div class="modal-body conflict-panel">'+
' <div class="conflict-alert"><img src="/Content/icons/deploymentPlan/info-icon-red.png" /> There are <span>{{($ctrl.model.tecrBookingEvents['+prefix+']['+id+'] | filter:$ctrl.overlappedFilter).length}} TECR conflicts</span> occurred in this environment.</div>'+
' <table class="table table-hover table-condensed">'+
' <thead>'+
' <tr>'+
' <th>TECR Title</th>'+
' <th>TEBR Title</th>'+
' <th>Release</th>'+
' <th>Environment/Env.Group</th>'+
' <th>Start Date</th>'+
' <th>End Date</th>'+
' <th>Outage Start Date</th>'+
' <th>Outage End Date</th>'+
' <th>Status</th>'+
' </tr>'+
' </thead>'+
' <tbody>'+
' <tr ng-repeat="tecrBookingConflict in $ctrl.model.tecrBookingEvents['+prefix+']['+id+'] | filter:$ctrl.overlappedFilter">'+
' <td><a href="javascript:void(0)" ng-bind="tecrBookingConflict.Name" ng-click="$ctrl.openTecr(tecrBookingConflict.ID)"></a></td>'+
' <td>-</td>'+
' <td ng-bind="tecrBookingConflict.ReleaseName"></td>'+
' <td ng-bind="tecrBookingConflict.EnvironmentName"></td>'+
' <td ng-bind="tecrBookingConflict.StartDate | date : $ctrl.model.dateTimeFormatTime" class="conflict-date"></td>'+
' <td ng-bind="tecrBookingConflict.EndDate | date : $ctrl.model.dateTimeFormatTime" class="conflict-date"></td>'+
' <td ng-bind="tecrBookingConflict.OutageStartDate | date : $ctrl.model.dateTimeFormatTime" class="conflict-date"></td>'+
' <td ng-bind="tecrBookingConflict.OutageEndDate | date : $ctrl.model.dateTimeFormatTime" class="conflict-date"></td>'+
' <td ng-bind="tecrBookingConflict.StatusText"></td>'+
' </tr>'+
' </tbody>'+
' </table>'+
'</div>',
controller: function($uibModalInstance, model) {
let $ctrl = this;
$ctrl.model = model;
$ctrl.close = function() {
$uibModalInstance.dismiss();
};
$ctrl.openTecr = function(id) {
let controller = PlutoraApp.app.getController('PlutoraApp.controller.requests.changeRequestController');
controller.openRequestWindow(id, function() { // onCloseCallback
$timeout(function () {
$scope.loadScheduleBySavedState();
}, 1000);
});
};
$ctrl.overlappedFilter = function(object) {
return object.overlap === true;
};
},
controllerAs: '$ctrl',
backdrop: 'static', // 'static' disables modal closing by click on the backdrop
keyboard: false, // Indicates whether the dialog should be closable by hitting the ESC key
animation: true,
size: 'lg modal-center',
windowClass:'barclays-envs-modal im-wrap',
resolve: {
model: function() {
return $scope.model;
}
}
});
};
$scope.overlappedFilter = function(object) {
return object.overlap === true;
};
$scope.UtcToLocalTime = function(time) {
return time ? moment.utc(time).local().format($scope.model.dateTimeFormat) : '';
};
$scope.selectTebr = function(newTebr, loadForce) {
$scope.resetWidgetState();
if ($scope.model.state.selectedTebr != newTebr || loadForce) {
$scope.model.state.selectedTebr = newTebr;
$scope.model.state.selectionType = $scope.model.selectionTypes.filter(function(type){return type.name =='TEBRs'})[0];
$scope.model.state.startDateValue = new Date($scope.model.state.selectedTebr.StartDate);
$scope.model.state.endDateValue = new Date($scope.model.state.selectedTebr.DueDate);
// dates for scheduler
$scope.model.scheduleFromDate = moment($scope.model.state.startDateValue, 'YYYY-MM-DD');
$scope.model.scheduleToDate = moment($scope.model.state.endDateValue, 'YYYY-MM-DD');
/// add/subtract 1 month in both directions
//$scope.model.scheduleFromDate.subtract(1, 'months');
//$scope.model.scheduleToDate.add(1, 'months');
$.ajax({
type: 'GET',
url: '/Requests/GetBookingRequestEnvironments?bookingRequestId='+ $scope.model.state.selectedTebr.ID +'&start=0&limit=20',
success: function(data, success) {
if (success && data && data.data && data.data.length) {
$scope.clearGanttData();
$scope.model.state.selectedEgroup = '';
$scope.model.state.selectedEnvironment = '';
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.environments = [];
data.data.forEach(function(environment) {
$scope.model.environments.push({Name: environment.EnvironmentName, ID: environment.EnvironmentID});
});
let envIds = $scope.model.environments.map(function(a) {return a.ID});
$scope.populateScheduler(0, {'property':'Environment.ID.List','value':envIds});
$scope.updateLocalState();
} else {
highlight('No environments found for this booking');
}
},
error: function (e) {
},
xhrFields: {
withCredentials: true
}
});
}
};
$scope.selectTecr = function(newTecr, loadForce) {
$scope.resetWidgetState();
if ($scope.model.state.selectedTecr != newTecr) {
$scope.model.state.selectedTecr = newTecr;
$scope.model.state.selectionType = $scope.model.selectionTypes.filter(function(type){return type.name =='TECRs'})[0];
// auto-zoom for dates is disabled, temporary
$scope.model.state.startDateValue = new Date($scope.model.state.selectedTecr.StartDate + 'Z');
$scope.model.state.endDateValue = new Date($scope.model.state.selectedTecr.DueDate + 'Z');
// dates for scheduler
//$scope.model.scheduleFromDate = moment($scope.model.state.startDateValue, 'YYYY-MM-DD');
//$scope.model.scheduleToDate = moment($scope.model.state.endDateValue, 'YYYY-MM-DD');
// with attempt to use local dates for scheduler only
$scope.model.scheduleFromDate = moment.utc($scope.model.state.startDateValue).local().format('YYYY-MM-DD');
$scope.model.scheduleToDate = moment.utc($scope.model.state.endDateValue).local().format('YYYY-MM-DD');
/// add/subtract 1 month in both directions
//$scope.model.scheduleFromDate.subtract(1, 'months');
//$scope.model.scheduleToDate.add(1, 'months');
$.ajax({
type: 'POST',
url: '/Requests/GetAllEnvironmentsProgressionChanges',
data: {
ReleaseID: $scope.model.state.selectedTecr.ID,
Ordered: true
},
success: function(data, success) {
if (success && data && data.data && data.data.length) {
$scope.model.state.selectedEgroup = '';
$scope.model.state.selectedEnvironment = '';
$scope.clearGanttData();
$scope.model.bookingSchedulerData = [];
$scope.model.bookingEvents = [];
$scope.model.bookingEventsAllApproved = [];
$scope.model.tecrBookingEvents = [];
$scope.model.environments = [];
data.data.forEach(function(environment) {
$scope.model.environments.push({Name: environment.EnvironmentName, ID: environment.EnvironmentID});
});
let envIds = $scope.model.environments.map(function(a) { return a.ID });
$scope.populateScheduler(0, {'property':'Environment.ID.List','value':envIds});
//$('.barclays-envs').get(0).scrollIntoView();
$scope.updateLocalState();
} else {
highlight('No environments found for this booking');
}
},
error: function (e) {
},
xhrFields: {
withCredentials: true
}
});
}
};
$scope.resetActiveSystemFilter = function(callback) {
$.ajax({
type: 'GET',
url: '/QueryBuilder/GetFilterState?parameters=System',
success: function(data, success) {
if (success && data.success && data.data.length) {
$.ajax({
type: 'POST',
url: '/QuerysBuilder/ClearActiveFilter',
data: {
parameters: 'System'
},
success: function(data, success) {
if (typeof callback === 'function') {
callback();
}
},
error: function (e) {},
xhrFields: {
withCredentials: true
}
});
}
},
error: function (e) {},
xhrFields: {
withCredentials: true
}
});
};
$scope.resetActiveEnvironmentFilter = function(callback) {
$.ajax({
type: 'GET',
url: '/QueryBuilder/GetFilterState?parameters=EnvironmentGrid',
success: function(data, success) {
if (success && data.success && data.data.length) {
$.ajax({
type: 'POST',
url: '/QuerysBuilder/ClearActiveFilter',
data: {
parameters: 'EnvironmentGrid'
},
success: function(data, success) {
if (typeof callback === 'function') {
callback();
}
},
error: function (e) {},
xhrFields: {
withCredentials: true
}
});
}
},
error: function (e) {},
xhrFields: {
withCredentials: true
}
});
};
// Main workflow begin
// _clearState(); // optional - clear local storage state
$scope.loadScheduleBySavedState = function() {
if ($scope.model.state.selectedEnvironmentsFilter) {
$scope.onSelectCustomEnvironments(false);
} else {
if ($scope.model.state.selectedSystemFilter) {
$scope.onSelectCustomSystem(false);
} else {
if ($scope.model.state.selectedEnvironmentGroupsFilter) {
$scope.model.state.selectedEnvironmentGroupsFilter.forEach(function(environmentGroup, index) {
delete environmentGroup.grpLoaded;
});
$scope.onSelectCustomEnvironmentGroups(false);
} else {
if ($scope.model.state.selectedEgroup) {
$scope.selectEgroup(false);
} else {
if ($scope.model.state.selectedTebr) {
$scope.selectTebr($scope.model.state.selectedTebr, true);
} else {
if ($scope.model.state.selectedTecr) {
$scope.selectTecr($scope.model.state.selectedTecr, true);
}
}
}
}
}
}
}
let storedState = _getState();
if (storedState) {
$scope.model.state = storedState;
if ($scope.model.state.startDateValue) {
$scope.model.state.startDateValue = new Date($scope.model.state.startDateValue);
$scope.model.scheduleFromDate = moment($scope.model.state.startDateValue, 'YYYY-MM-DD');
}
if ($scope.model.state.endDateValue) {
$scope.model.state.endDateValue = new Date($scope.model.state.endDateValue);
$scope.model.scheduleToDate = moment($scope.model.state.endDateValue, 'YYYY-MM-DD');
}
if ($scope.model.state.showType) {
$scope.model.state.scheduleScale = $scope.enums.scheduleScales[$scope.model.state.showType];
$scope.applyScheduleScale();
}
$scope.loadScheduleBySavedState();
}
$scope.$on('barclays-envs-scheduler-trigger', function(event, args) {
if (args.selectedTebr) {
$scope.selectTebr(args.selectedTebr);
}
});
$scope.$on('barclays-envs-scheduler-trigger-tecr', function(event, args) {
if (args.selectedTecr) {
$scope.selectTecr(args.selectedTecr);
}
});
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment