Skip to content

Commit 89992b8

Browse files
Portal widget - manage delegates (#2038)
* Create delegates.html * Create delegates.scss * Create delegates_client.css * Create delegates_server.js * Create README.md
1 parent ee96566 commit 89992b8

File tree

5 files changed

+271
-0
lines changed

5 files changed

+271
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# My Delegates - Portal Widget
2+
## Overview
3+
Simple Service Portal widget to create, edit, list, and delete OOB Delegate functionality in portal.
4+
5+
## Files included
6+
- HTML : widget HTML.
7+
- CSS : widget CSS.
8+
- Client Script : widget Client contriller.
9+
- Server Script : widget Server Script.
10+
11+
## How to use
12+
- Create a new Service Portal widget.
13+
- Copy paste the html, css, client and server scipts to respective fields
14+
- Save and add the widget to a portal page.
15+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<div class="panel panel-default">
2+
<div class="panel-heading">
3+
<h3 class="panel-title">Delegates</h3>
4+
</div>
5+
<div class="panel-body">
6+
<div ng-if="!c.data.delegates.length" class="alert alert-info text-center">
7+
You have no active delegates.
8+
</div>
9+
10+
<ul class="list-group" ng-if="c.data.delegates.length > 0">
11+
<li class="list-group-item delegate-item" ng-repeat="d in c.data.delegates">
12+
<h4>{{d.delegate_display}}</h4>
13+
<p class="text-muted">
14+
<strong>User:</strong> {{d.user_display}} <br/>
15+
<strong>Starts:</strong> {{d.starts_display || 'N/A'}} <br/>
16+
<strong>Ends:</strong> {{d.ends_display || 'N/A'}}
17+
</p>
18+
<p>
19+
<strong>Notifications:</strong>
20+
<span ng-if="d.approvals"> Approvals</span>
21+
<span ng-if="d.assignments"> Assignments</span>
22+
<span ng-if="d.notifications"> All</span>
23+
<span ng-if="d.invitations"> Invitations</span>
24+
</p>
25+
<div class="btn-row">
26+
<button class="btn btn-sm btn-default" ng-click="c.edit(d.sys_id)">
27+
<i class="fa fa-edit"></i> Edit
28+
</button>
29+
</div>
30+
</li>
31+
</ul>
32+
33+
<hr/>
34+
35+
<div class="delegate-form-container">
36+
<h4 ng-if="!c.editing">Create a New Delegate</h4>
37+
<h4 ng-if="c.editing">Edit Delegate</h4>
38+
39+
<form name="delegateForm" ng-submit="c.saveDelegate()">
40+
<!-- User is not editable: recorded as current user server-side -->
41+
42+
<div class="form-group">
43+
<label for="delegate">Delegate <span class="text-danger">*</span></label>
44+
<sn-record-picker field="c.delegateField" table="'sys_user'" display-field="'name'" value-field="'sys_id'" search-fields="'name,email'" page-size="10" placeholder="Search delegate..." required></sn-record-picker>
45+
</div>
46+
47+
<div class="row">
48+
<div class="col-md-6">
49+
<div class="form-group">
50+
<label>Starts</label>
51+
<input type="datetime-local" class="form-control" ng-model="c.form.starts_local" />
52+
</div>
53+
</div>
54+
<div class="col-md-6">
55+
<div class="form-group">
56+
<label>Ends</label>
57+
<input type="datetime-local" class="form-control" ng-model="c.form.ends_local" />
58+
</div>
59+
</div>
60+
</div>
61+
62+
<div class="checkboxes form-group">
63+
<label class="checkbox-inline"><input type="checkbox" ng-model="c.form.approvals"> Approvals</label>
64+
<label class="checkbox-inline"><input type="checkbox" ng-model="c.form.assignments"> Assignments</label>
65+
<label class="checkbox-inline"><input type="checkbox" ng-model="c.form.notifications"> All notifications</label>
66+
<label class="checkbox-inline"><input type="checkbox" ng-model="c.form.invitations"> Meeting invitations</label>
67+
</div>
68+
69+
<div class="form-group">
70+
<button type="submit" class="btn btn-primary" ng-disabled="delegateForm.$invalid">
71+
<i class="fa" ng-class="{'fa-plus-circle': !c.editing, 'fa-save': c.editing}"></i>
72+
{{c.editing ? 'Save' : 'Create'}}
73+
</button>
74+
<button type="button" class="btn btn-default" ng-click="c.resetForm()">New</button>
75+
<button type="button" class="btn btn-danger" ng-if="c.editing" ng-click="c.deleteDelegate()">
76+
<i class="fa fa-trash"></i> Delete
77+
</button>
78+
</div>
79+
</form>
80+
</div>
81+
</div>
82+
</div>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.delegate-item {
2+
border-left: 4px solid #5bc0de;
3+
margin-bottom: 10px;
4+
padding: 10px 15px;
5+
}
6+
.delegate-item h4 {
7+
margin-top: 0;
8+
font-weight: bold;
9+
color: #333;
10+
}
11+
.delegate-form-container {
12+
margin-top: 20px;
13+
padding-top: 15px;
14+
border-top: 1px solid #eee;
15+
}
16+
.btn-row { margin-top: 8px; }
17+
.form-group { margin-bottom: 15px; }
18+
.panel-heading + .panel-body { padding-top: 20px; }
19+
.checkboxes label { margin-right: 12px; }
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
function($scope) {
2+
var c = this;
3+
c.form = {};
4+
c.editing = false;
5+
c.delegateField = { displayValue: '', value: '', name: 'delegate' };
6+
7+
c.$onInit = function() {
8+
c.data = c.data || {};
9+
c.form = {
10+
approvals: false,
11+
assignments: false,
12+
notifications: false,
13+
invitations: false
14+
};
15+
};
16+
17+
function pad(n){ return n<10 ? '0'+n : n; }
18+
19+
function localToGlide(local) {
20+
if (!local) return '';
21+
var d = new Date(local);
22+
return d.getFullYear() + '-' + pad(d.getMonth()+1) + '-' + pad(d.getDate())
23+
+ ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
24+
}
25+
26+
c.saveDelegate = function() {
27+
c.form.delegate = c.delegateField.value;
28+
c.form.starts = localToGlide(c.form.starts_local);
29+
c.form.ends = localToGlide(c.form.ends_local);
30+
31+
c.data.action = 'save_delegate';
32+
c.data.record = angular.copy(c.form);
33+
34+
c.server.update().then(function() {
35+
c.data.action = undefined;
36+
c.resetForm();
37+
c.server.get().then(function(response) {
38+
c.data = response.data;
39+
});
40+
}, function() {
41+
alert('Failed to save delegate.');
42+
});
43+
};
44+
45+
c.edit = function(sys_id) {
46+
c.server.get().then(function(response) {
47+
c.data = response.data;
48+
var rec = c.data.delegates.find(function(x){ return x.sys_id === sys_id; }) || {};
49+
c.editing = true;
50+
c.form = {
51+
sys_id: rec.sys_id,
52+
approvals: !!rec.approvals,
53+
assignments: !!rec.assignments,
54+
notifications: !!rec.notifications,
55+
invitations: !!rec.invitations,
56+
starts_local: rec.starts_value ? new Date(rec.starts_value.replace(' ', 'T')) : null,
57+
ends_local: rec.ends_value ? new Date(rec.ends_value.replace(' ', 'T')) : null
58+
};
59+
c.delegateField.value = rec.delegate_sys_id || rec.delegate;
60+
c.delegateField.displayValue = rec.delegate_display;
61+
});
62+
};
63+
64+
c.deleteDelegate = function() {
65+
if (!c.form.sys_id) return;
66+
if (!confirm('Delete delegate record?')) return;
67+
c.data.action = 'delete_delegate';
68+
c.data.sys_id = c.form.sys_id;
69+
c.server.update().then(function() {
70+
c.data.action = undefined;
71+
c.resetForm();
72+
c.server.get().then(function(response) { c.data = response.data; });
73+
});
74+
};
75+
76+
c.resetForm = function() {
77+
c.editing = false;
78+
c.form = {
79+
approvals: false,
80+
assignments: false,
81+
notifications: false,
82+
invitations: false
83+
};
84+
c.delegateField = { displayValue: '', value: '', name: 'delegate' };
85+
};
86+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
(function() {
2+
data.delegates = [];
3+
var currentUser = gs.getUserID();
4+
5+
if (input && input.action === 'save_delegate' && input.record) {
6+
var rec = input.record;
7+
var gr;
8+
if (rec.sys_id) {
9+
gr = new GlideRecord('sys_user_delegate');
10+
if (!gr.get(rec.sys_id)) {
11+
gr.initialize();
12+
}
13+
} else {
14+
gr = new GlideRecord('sys_user_delegate');
15+
gr.initialize();
16+
}
17+
18+
gr.setValue('user', currentUser);
19+
20+
if (rec.delegate) gr.setValue('delegate', rec.delegate);
21+
if (rec.starts) gr.setValue('starts', rec.starts);
22+
if (rec.ends) gr.setValue('ends', rec.ends);
23+
24+
gr.setValue('approvals', rec.approvals ? 'true' : 'false');
25+
gr.setValue('assignments', rec.assignments ? 'true' : 'false');
26+
gr.setValue('notifications', rec.notifications ? 'true' : 'false');
27+
gr.setValue('invitations', rec.invitations ? 'true' : 'false');
28+
29+
var id = gr.update();
30+
data.saved_sys_id = id;
31+
}
32+
33+
if (input && input.action === 'delete_delegate' && input.sys_id) {
34+
var ddel = new GlideRecord('sys_user_delegate');
35+
if (ddel.get(input.sys_id)) {
36+
ddel.deleteRecord();
37+
data.deleted = true;
38+
} else {
39+
data.deleted = false;
40+
}
41+
}
42+
43+
44+
var grList = new GlideRecord('sys_user_delegate');
45+
grList.addQuery('user', currentUser);
46+
grList.orderByDesc('starts');
47+
grList.query();
48+
while (grList.next()) {
49+
var obj = {};
50+
obj.sys_id = grList.getUniqueValue();
51+
obj.user = grList.getValue('user');
52+
obj.delegate = grList.getValue('delegate');
53+
obj.user_display = grList.getDisplayValue('user');
54+
obj.delegate_display = grList.getDisplayValue('delegate');
55+
obj.starts_display = grList.getDisplayValue('starts');
56+
obj.ends_display = grList.getDisplayValue('ends');
57+
obj.starts_value = grList.getValue('starts');
58+
obj.ends_value = grList.getValue('ends');
59+
obj.approvals = grList.getValue('approvals') === 'true' || grList.getValue('approvals') === '1';
60+
obj.assignments = grList.getValue('assignments') === 'true' || grList.getValue('assignments') === '1';
61+
obj.notifications = grList.getValue('notifications') === 'true' || grList.getValue('notifications') === '1';
62+
obj.invitations = grList.getValue('invitations') === 'true' || grList.getValue('invitations') === '1';
63+
64+
obj.user_sys_id = obj.user;
65+
obj.delegate_sys_id = obj.delegate;
66+
67+
data.delegates.push(obj);
68+
}
69+
})();

0 commit comments

Comments
 (0)