Skip to content

Commit d890f1b

Browse files
Portal widget - My Reminders (#2033)
* Create reminders.html * Create reminders.scss * Create reminders_client.js * Create reminders_server.js * Create README.md * Update README.md Added screenshots
1 parent 4f2f200 commit d890f1b

File tree

5 files changed

+225
-0
lines changed

5 files changed

+225
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Service Portal Reminder Widget
2+
3+
A simple custom ServiceNow Service Portal widget for viewing and creating personal reminders.
4+
5+
## Features
6+
7+
- This uses **ServiceNow's OOB Reminder table**. Table name : 'reminder'
8+
- Displays a list of reminders for the current user.
9+
- Provides a form to create new reminders.
10+
- Allows associating reminders with any Task record.
11+
- Auto-refreshes the list after a new reminder is created.
12+
13+
14+
## How to create
15+
16+
1. Navigate to **Service Portal > Widgets**.
17+
2. Click **Create a new widget**.
18+
3. Set the **Widget Name** (e.g. 'My Reminders') and **ID** (e.g., 'reminder-widget').
19+
4. Copy and paste the provided HTML, CSS, Client Script, and Server Script into their respective tabs.
20+
5. Save the widget.
21+
22+
## How to Use
23+
24+
1. Open your target portal page in the Service Portal Designer.
25+
2. Find your widget in the "Widgets" filter on the left.
26+
3. Drag and dropp the widget onto the page.
27+
28+
## Screenshots
29+
<img width="1831" height="396" alt="image" src="https://github.com/user-attachments/assets/bdb124a8-9634-4884-8d4b-cfb79225f07e" />
30+
<img width="1728" height="731" alt="image" src="https://github.com/user-attachments/assets/9bef4295-0321-4806-a4e5-465d80881bdc" />
31+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<div class="panel panel-default">
2+
<div class="panel-heading">
3+
<h3 class="panel-title">My Reminders</h3>
4+
</div>
5+
<div class="panel-body">
6+
<div ng-if="!c.data.reminders.length" class="alert alert-info text-center">
7+
You have no active reminders.
8+
</div>
9+
10+
<ul class="list-group" ng-if="c.data.reminders.length > 0">
11+
<li class="list-group-item reminder-item" ng-repeat="reminder in c.data.reminders">
12+
<h4>{{reminder.subject}}</h4>
13+
<p class="text-muted">
14+
<strong>Task:</strong> {{reminder.task_display || 'N/A'}} <br/>
15+
<strong>Action:</strong> Send an {{reminder.using}} {{reminder.remind_me}} minutes before {{reminder.field_display}}.
16+
</p>
17+
<p ng-if="reminder.notes"><strong>Notes:</strong> {{reminder.notes}}</p>
18+
</li>
19+
</ul>
20+
21+
<hr/>
22+
23+
<div class="reminder-form-container">
24+
<h4>Create a New Reminder</h4>
25+
<form name="reminderForm" ng-submit="c.createReminder()">
26+
<div class="form-group">
27+
<label for="task">Task (Optional)</label>
28+
<sn-record-picker field="c.taskField" table="'task'" display-field="'number'" value-field="'sys_id'" search-fields="'number,short_description'" page-size="10" placeholder="Search for a task..."></sn-record-picker>
29+
</div>
30+
31+
<div class="form-group">
32+
<label for="subject">Subject <span class="text-danger">*</span></label>
33+
<input type="text" id="subject" class="form-control" ng-model="c.newReminder.subject" required>
34+
</div>
35+
36+
<div class="form-group">
37+
<label for="notes">Notes</label>
38+
<textarea id="notes" class="form-control" ng-model="c.newReminder.notes" rows="3"></textarea>
39+
</div>
40+
41+
<div class="row">
42+
<div class="col-md-6">
43+
<div class="form-group">
44+
<label for="remind_me">Remind Me... <span class="text-danger">*</span></label>
45+
<select id="remind_me" class="form-control" ng-model="c.newReminder.remind_me" required>
46+
<option value="" disabled selected>-- Select Time --</option>
47+
<option value="15">15 Minutes</option>
48+
<option value="30">30 Minutes</option>
49+
<option value="60">1 Hour</option>
50+
<option value="120">2 Hours</option>
51+
</select>
52+
</div>
53+
</div>
54+
<div class="col-md-6">
55+
<div class="form-group">
56+
<label for="field">...Before <span class="text-danger">*</span></label>
57+
<select id="field" class="form-control" ng-model="c.newReminder.field" required>
58+
<option value="" disabled selected>-- Select Date Field --</option>
59+
<option value="activity_due">Activity Due</option>
60+
<option value="due_date">Due Date</option>
61+
<option value="follow_up">Follow Up</option>
62+
<option value="sla_due">SLA Due</option>
63+
</select>
64+
</div>
65+
</div>
66+
</div>
67+
68+
<div class="form-group">
69+
<label for="using">Using... <span class="text-danger">*</span></label>
70+
<select id="using" class="form-control" ng-model="c.newReminder.using" required>
71+
<option value="" disabled selected>-- Select Method --</option>
72+
<option value="email">Send an email</option>
73+
<option value="outlook">Outlook calendar invite</option>
74+
</select>
75+
</div>
76+
77+
<div class="form-group">
78+
<button type="submit" class="btn btn-primary" ng-disabled="reminderForm.$invalid">
79+
<i class="fa fa-plus-circle"></i> Create Reminder
80+
</button>
81+
</div>
82+
</form>
83+
</div>
84+
</div>
85+
</div>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
.reminder-item {
2+
border-left: 4px solid #337ab7;
3+
margin-bottom: 10px;
4+
padding: 10px 15px;
5+
}
6+
7+
.reminder-item h4 {
8+
margin-top: 0;
9+
font-weight: bold;
10+
color: #333;
11+
}
12+
13+
.reminder-item p {
14+
margin-bottom: 5px;
15+
}
16+
17+
.reminder-form-container {
18+
margin-top: 20px;
19+
padding-top: 15px;
20+
border-top: 1px solid #eee;
21+
}
22+
23+
.form-group {
24+
margin-bottom: 15px;
25+
}
26+
27+
.panel-heading + .panel-body {
28+
padding-top: 20px;
29+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
function($scope) {
2+
var c = this;
3+
4+
// Object to hold data for the new reminder form
5+
c.newReminder = {};
6+
7+
// Special object for the sn-record-picker directive
8+
c.taskField = {
9+
displayValue: '',
10+
value: '',
11+
name: 'task'
12+
};
13+
14+
// Function to submit the new reminder
15+
c.createReminder = function() {
16+
// Check if the form is valid before submitting
17+
if ($scope.reminderForm.$invalid) {
18+
return;
19+
}
20+
21+
// Set the task sys_id from the record picker into our submission object
22+
c.newReminder.task = c.taskField.value;
23+
c.data.newReminder = c.newReminder;
24+
25+
// Set an action for the server to identify the request
26+
c.data.action = 'create_reminder';
27+
28+
// Call the server script to insert the record
29+
c.server.update().then(function(response) {
30+
// Clear the action and the form model after successful submission
31+
c.data.action = undefined;
32+
c.newReminder = {};
33+
c.taskField.displayValue = '';
34+
c.taskField.value = '';
35+
36+
// Refresh the reminder list by reloading server data
37+
c.server.get().then(function(response) {
38+
c.data = response.data;
39+
});
40+
});
41+
};
42+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
(function() {
2+
3+
var currentUserId = gs.getUserID();
4+
data.reminders = [];
5+
6+
7+
if (input && input.action === 'create_reminder') {
8+
var newReminder = new GlideRecord('reminder');
9+
newReminder.initialize();
10+
newReminder.setValue('user', currentUserId);
11+
newReminder.setValue('task', input.newReminder.task);
12+
newReminder.setValue('subject', input.newReminder.subject);
13+
newReminder.setValue('notes', input.newReminder.notes);
14+
newReminder.setValue('remind_me', input.newReminder.remind_me);
15+
newReminder.setValue('field', input.newReminder.field);
16+
newReminder.setValue('using', input.newReminder.using);
17+
newReminder.insert();
18+
}
19+
20+
21+
var reminderGR = new GlideRecord('reminder');
22+
reminderGR.addQuery('user', currentUserId);
23+
reminderGR.orderByDesc('sys_created_on'); // Show newest first
24+
reminderGR.query();
25+
26+
while (reminderGR.next()) {
27+
var reminderObj = {};
28+
reminderObj.sys_id = reminderGR.getUniqueValue();
29+
reminderObj.subject = reminderGR.getValue('subject');
30+
reminderObj.notes = reminderGR.getValue('notes');
31+
reminderObj.remind_me = reminderGR.getValue('remind_me');
32+
reminderObj.field_display = reminderGR.getDisplayValue('field'); // Get user-friendly display value
33+
reminderObj.using = reminderGR.getValue('using');
34+
reminderObj.task_display = reminderGR.getDisplayValue('task'); // Get task number/display value
35+
data.reminders.push(reminderObj);
36+
}
37+
38+
})();

0 commit comments

Comments
 (0)