Skip to content

Commit 7a331ce

Browse files
authored
Merge branch 'main' into fifth-patch-5
2 parents bbb2322 + 26c4d83 commit 7a331ce

File tree

8 files changed

+1648
-0
lines changed

8 files changed

+1648
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# 🧾 ServiceNow Change Schedule Enhancement
2+
### _(UI Scripts: `sn_chg_soc.change_soc`, `sn.chg_soc.config`, `sn.chg_soc.data`)_
3+
4+
---
5+
6+
## 📘 Overview
7+
8+
This customization extends the **ServiceNow Change Schedule (Change Calendar)** functionality.
9+
The enhancement adds visibility and interactivity to the Change Calendar by including:
10+
11+
- A **Short Description** column in the Change Schedule view.
12+
- A **configurable UI** allowing users to toggle visibility of columns such as _Configuration Item_, _Short Description_, and _Duration_.
13+
- Integration of additional data services for fetching and rendering change records with enhanced details.
14+
- A **Change Schedule button** that refreshes and displays these changes dynamically.
15+
16+
The result is a more informative and user-friendly Change Schedule interface for Change Managers, CAB members, and ITSM users.
17+
18+
---
19+
20+
## 🧩 Architecture
21+
22+
| Module | Description |
23+
|--------|-------------|
24+
| **`sn_chg_soc.change_soc`** | Main controller and directive for the Change Schedule Gantt Chart UI. Handles initialisation, rendering, zoom, and popovers. |
25+
| **`sn.chg_soc.config`** | Manages configuration settings for displayed columns and schedules (blackout, maintenance). Allows toggling visibility. |
26+
| **`sn.chg_soc.data`** | Provide the data on the gantt chat from the change records
27+
28+
29+
Requirement:
30+
As an ITIL user, you can click the Change Schedule button to navigate directly to the Change Schedule view.
31+
This allows you to see all planned changes and plan your own changes accordingly, especially useful for customers who do not have a well-established CMDB integrated with Discovery.
32+
33+
<img width="1505" height="809" alt="image" src="https://github.com/user-attachments/assets/4af1b6cb-87e6-4a53-a243-6592fbf548c1" />
34+
35+
<img width="1913" height="877" alt="image" src="https://github.com/user-attachments/assets/fc0a6f46-febd-45bb-a741-78462fa1512a" />
36+

Client-Side Components/UI Scripts/Custom Change Schedule/change_soc.js

Lines changed: 1018 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
angular.module("sn.chg_soc.config", ["sn.common"])
2+
.service("configService", ["dataService", "ganttChart", "urlService", "SOC", function(dataService, ganttChart, urlService, SOC) {
3+
var configService = this;
4+
5+
configService.showConfigItem = true;
6+
configService.showDuration = true;
7+
configService.showShortDesc=true;
8+
configService.showBlackoutOption = true;
9+
configService.showBlackoutSchedules = true;
10+
configService.showMaintOption = true;
11+
configService.showMaintSchedules = true;
12+
13+
configService.childRecords = {};
14+
15+
configService.setChildRecords = function(childTables) {
16+
for (var tableName in childTables)
17+
configService.childRecords[tableName] = {
18+
inputId: tableName + "Option",
19+
label: childTables[tableName].__label,
20+
name: tableName + "Show",
21+
show: true,
22+
change: updateChildRecords
23+
};
24+
};
25+
26+
function updateChildRecords(tableName) {
27+
var gantt = ganttChart.getGantt(urlService.socId);
28+
var ganttTasks = gantt.getTaskByTime();
29+
for (var i = 0; i < ganttTasks.length; i++)
30+
if (ganttTasks[i].parent && ganttTasks[i].table === tableName)
31+
ganttTasks[i].__visible = configService.childRecords[tableName].show;
32+
gantt.attachEvent("onBeforeTaskDisplay", function(id, task) {
33+
if (task.parent)
34+
return task.__visible;
35+
return true;
36+
});
37+
gantt.templates.grid_open = gridOpen;
38+
gantt.render();
39+
}
40+
41+
function gridOpen(task) {
42+
var gantt = ganttChart.getGantt(urlService.socId);
43+
var children = gantt.getChildren(task.id);
44+
45+
for (var i = 0; i < children.length; i++) {
46+
var childTask = gantt.getTask(children[i]);
47+
if (childTask.__visible)
48+
return "<div class='gantt_tree_icon gantt_" + (task.$open ? "close" : "open") +
49+
" icon-vcr-" + (task.$open ? "down" : "right") + "'></div>";
50+
}
51+
52+
return "<div class='gantt_tree_icon gantt_blank'></div>";
53+
}
54+
}])
55+
.directive("socAsideConfig", ["getTemplateUrl", "configService", "ganttChart", "dataService", "objectKeysLengthFilter", "SOC", "i18n", function(getTemplateUrl, configService, ganttChart, dataService, objectKeysLengthFilter, SOC, i18n) {
56+
"use strict";
57+
return {
58+
restrict: "A",
59+
templateUrl: getTemplateUrl("sn_chg_soc_aside_config_body.xml"),
60+
scope: {
61+
socDefId: "="
62+
},
63+
controller: function($scope, objectKeysLengthFilter) {
64+
// $scope.showConfigItem = configService.showConfigItem;
65+
// $scope.showDuration = configService.showDuration;
66+
$scope.showBlackoutOption = configService.showBlackoutOption;
67+
$scope.showShortDesc = configService.showShortDesc;
68+
$scope.showBlackoutSchedules = configService.showBlackoutSchedules;
69+
$scope.showMaintOption = configService.showMaintOption;
70+
$scope.showMaintSchedules = configService.showMaintSchedules;
71+
$scope.childRecords = configService.childRecords;
72+
$scope.objectKeysLengthFilter = objectKeysLengthFilter;
73+
$scope.messages = {
74+
"Child Records": i18n.getMessage("Child Records"),
75+
"Columns": i18n.getMessage("Columns"),
76+
"Configuration Item": i18n.getMessage("Configuration Item"),
77+
"Short Description": i18n.getMessage("Short Description"),
78+
"Duration": i18n.getMessage("Duration"),
79+
"Related Records": i18n.getMessage("Related Records"),
80+
"Schedules": i18n.getMessage("Schedules"),
81+
"Blackout": i18n.getMessage("Blackout"),
82+
"Maintenance": i18n.getMessage("Maintenance")
83+
};
84+
85+
$scope.updateColumnLayout = function(columnId) {
86+
var gantt = ganttChart.getGantt($scope.socDefId);
87+
var column = gantt.getGridColumn(columnId);
88+
if (SOC.COLUMN.CONFIG_ITEM === columnId) {
89+
configService.showConfigItem = !configService.showConfigItem;
90+
column.hide = !configService.showConfigItem;
91+
} else if (SOC.COLUMN.DURATION === columnId) {
92+
configService.showDuration = !configService.showDuration;
93+
column.hide = !configService.showDuration;
94+
} else if (SOC.COLUMN.SHORT_DESCRIPTION === columnId) {
95+
configService.showShortDesc = !configService.showShortDesc;
96+
column.hide = !configService.showShortDesc;
97+
} else
98+
return;
99+
gantt.render();
100+
};
101+
102+
function getScheduleEvent(task, startDate, endDate, styleClass) {
103+
var gantt = ganttChart.getGantt($scope.socDefId);
104+
startDate = gantt.date.parseDate(startDate, "xml_date");
105+
endDate = gantt.date.parseDate(endDate, "xml_date");
106+
var sizes = gantt.getTaskPosition(task, startDate, endDate);
107+
var el = document.createElement("div");
108+
el.className = "schedule-bar " + styleClass;
109+
el.style.left = sizes.left + "px";
110+
el.style.width = sizes.width + "px";
111+
el.style.top = sizes.top + "px";
112+
return el;
113+
}
114+
115+
var scheduleTaskLayer = function(task) {
116+
if ((!this.show_blackout && !this.show_maint) || (task.blackout_spans.length === 0 && task.maint_spans.length === 0))
117+
return;
118+
var wrapper = document.createElement("div");
119+
if (this.show_blackout && dataService.definition.show_blackout.value)
120+
task.blackout_spans.forEach(function(blackoutSpan) {
121+
wrapper.appendChild(getScheduleEvent(task, blackoutSpan.start, blackoutSpan.end, "blackout"));
122+
});
123+
if (this.show_maint && dataService.definition.show_maintenance.value)
124+
task.maint_spans.forEach(function(maintSpan) {
125+
wrapper.appendChild(getScheduleEvent(task, maintSpan.start, maintSpan.end, "maint"));
126+
});
127+
return wrapper;
128+
};
129+
130+
$scope.updateScheduleLayer = function() {
131+
configService.showBlackoutSchedules = $scope.showBlackoutSchedules;
132+
configService.showMaintSchedules = $scope.showMaintSchedules;
133+
var ganttInstance = ganttChart.getInstance($scope.socDefId);
134+
ganttInstance.removeTaskLayer();
135+
136+
if ($scope.showBlackoutSchedules || $scope.showMaintSchedules) {
137+
ganttInstance.addTaskLayer(scheduleTaskLayer.bind({
138+
show_blackout: $scope.showBlackoutSchedules,
139+
show_maint: $scope.showMaintSchedules
140+
}));
141+
ganttInstance.gantt.render();
142+
}
143+
};
144+
}
145+
};
146+
}]);

0 commit comments

Comments
 (0)