Change Application scope of instance using Script

Fazeel Ahmed
Tera Contributor

Here is the scenario, I have a widget that contains a button. When I click the button, it will change the application scope from global to Human Resource Core. I don't know how to do it through scripting. I tried to do it through user preference table where I set the sys id of HR Core Application in apps.current_app record, the scope only changes when I restart the session.   

1 ACCEPTED SOLUTION

-O-
Kilo Patron
Kilo Patron

Here's how one could do it - obviously adapting code SN already wrote:


create new Angular Provider record:

  • Type: Factory
  • Name: applicationScope
  • Client script:

 

function applicationScope ($rootScope, $http) {
	var fetchedInitialData = false;
	var initialized = false;

	var applicationData = {
		current: {},
		currentId: '',
		list: [],
		showInHeader: false,
	};

	$rootScope.$on('concourse.application.changed', concourseApplicationChanged);

	return {
		'applicationData': applicationData,
		'getApplicationList': getApplicationList,
		'hasFetchedData': hasFetchedData,
		'initialize': initialize,
		'updateCurrent': updateCurrent,
	};

	function concourseApplicationChanged (evt, current) {
		applicationData.current = current;
		applicationData.currentId = current.sysId;
	}

	function getApplicationList () {
		fetchedInitialData = true;
		return $http
			.get('/api/now/ui/concoursepicker/application?cache=' + new Date().getTime())
			.then(getApplicationListResponse);
	}

	function getApplicationListResponse (response) {
		if (response && response.data && response.data.result) {
			applicationData.list = response.data.result.list;

			if (response.data.result.current && response.data.result.current != applicationData.currentId) {
				var apps = response.data.result.list;
				var curr = response.data.result.current;

				for (var i = 0; i < apps.length; i++) {
					if (curr == apps[i].sysId) {
						applicationData.current = apps[i];
						applicationData.currentId = apps[i].sysId;
						break;
					}
				}

				triggerChangeEvent();
			}
		}
	}

	function hasFetchedData () {
		return fetchedInitialData;
	}

	function initialize (current) {
		if (initialized)
			return;
		initialized = true;
		applicationData.list = [current];
		applicationData.current = current;
		applicationData.currentId = current.sysId;
	}

	function triggerChangeEvent () {
		$rootScope.$broadcast('concourse.application.changed', applicationData.current);
	}

	function triggerRefreshFrameEvent () {
		$rootScope.$broadcast('concourse.application.refresh', {});
	}

	function updateCurrent () {
		var apps = applicationData.list;
		var curr = applicationData.currentId;

		for (var i = 0; i < apps.length; i++) {
			if (curr == apps[i].sysId) {
				applicationData.current = apps[i];
				break;
			}
		}

		$http
			.put('/api/now/ui/concoursepicker/application', { 'app_id': applicationData.currentId })
			.then(updateCurrentResponse);
	}

	function updateCurrentResponse (response) {
		if (response && response.data && response.data.result && response.data.result.app_id) {
			triggerRefreshFrameEvent();
			triggerChangeEvent();
		}
	}
}

 


create new Angular Provider record:

  • Type: Directive
  • Name: applicationScopePicker
  • Client script:

 

function applicationScopePicker (applicationScope, snCustomEvent) {
	"use strict";

	return {

		'controller': function ($scope) {
			$scope.app = applicationScope.applicationData;
			$scope.refreshApplicationPicker = refreshApplicationPicker;
			$scope.updateCurrent = updateCurrent;

			snCustomEvent.observe('glide:ui_notification.application_change', applicationChanged);
			snCustomEvent.observe('sn:change_application', changeApplication);
			snCustomEvent.observe('sn:refresh_application_picker', refreshApplicationPicker);

			if ($scope.current) {
				applicationScope.initialize($scope.current);
			}

			function applicationChanged () {
				applicationScope.getApplicationList();
			}

			function changeApplication (appId) {
				applicationScope.getApplicationList().then(getApplicationListResponder);
			}

			function getApplicationListResponder (appId) {
				return function getApplicationListResponse () {
					applicationScope.applicationData.currentId = appId;
					$scope.updateCurrent();
				};
			}

			function refreshApplicationPicker () {
				applicationScope.getApplicationList();
			}

			function updateCurrent () {
				applicationScope.updateCurrent();
			}
		},

		'link': function (scope, element) {
			element.on('mouseover', mouseOver);

			function mouseOver () {
				if (!applicationScope.hasFetchedData())
					applicationScope.getApplicationList();
			}
		},

		'replace': false,

		'restrict': 'E',

		'scope': {
			'current': '=',
			'hintText': '=',
			'titleText': '=',
		},

		'template': getTemplate(),
	};

	function getTemplate () {
		return '\n' +
			'<div class="applicationScopePicker">\n' +
			'	<div class="input-group">\n' +
			'		<span class="input-group-addon">\n' +
			'			<a class="icon-application-generic" data-name="current-application-picker" data-title-text="{{ titleText }}" data-toggle="tooltip" href="/sys_scope.do?sys_id={{ app.current.sysId }}" target="gsft_main">\n' +
			'				<span class="sr-only">{{ hintText }}</span>\n' +
			'			</a>\n' +
			'		</span>\n' +
			'		<select class="form-control" ng-change="updateCurrent()" ng-model="app.currentId" ng-options="a.sysId as a.name for a in app.list" title="{{ titleText }}"></select>\n' +
			'	</div>\n' +
			'</div>\n' +
			'';
	}
}
  • Related list [Required Providers]: add the previously created Factory - applicationScope

 


create a new Widget record:

  • Body HTML template:

 

<div style="padding-top: 2.5em;">
	<application-scope-picker
		current="data.currentScope"
		hint-text="data.messages.hint"
		title-text="data.messages.title" />
</div>

 


  • Server script:

 

(function (data) {
	data.currentScope = getCurrentScope(gs.getCurrentApplicationId());
	data.messages = getMessages();

	function getCurrentApplicationDisplayValue (uniqueValue) {
		var gr = new GlideRecord('sys_scope');

		return gr.get(uniqueValue) ? gr.getDisplayValue() : uniqueValue;
	}

	function getCurrentScope (currentApplicationId) {
		return {
			'name': getCurrentApplicationDisplayValue(currentApplicationId),
			'sysId': currentApplicationId,
		};
	}

	function getMessages () {
		return {
			'hint': gs.getMessage('View current application under development'),
			'title': gs.getMessage('Show selected application'),
		};
	}
})(data);
  • Related list [Angular Providers]: add the previously created directive: applicationScopePicker

 


The result:

2023-02-14-1.png

2023-02-14-2.png

This literally does the exact same thing as the application picker in the main UI, so as soon as the select box is updated with a new option, the scope is changed for the current user.

View solution in original post

7 REPLIES 7

Shubham_Shinde
Giga Guru

Hello @Fazeel Ahmed ,

Maybe restarting the user session through script might help you out. Please find below mentioned thread regarding the same:
How can I refresh a user session via script 

If my answer has helped with your question, please mark it as correct and give it a thumbs up!

 

Regards,

Shubham

He suggest GlideSecurityManager but it's not working. do you have any idea why?

Community Alums
Not applicable

Hi @Fazeel Ahmed ,

Unfortunately, there is no way to change scope within a script.

 

-O-
Kilo Patron
Kilo Patron

Here's how one could do it - obviously adapting code SN already wrote:


create new Angular Provider record:

  • Type: Factory
  • Name: applicationScope
  • Client script:

 

function applicationScope ($rootScope, $http) {
	var fetchedInitialData = false;
	var initialized = false;

	var applicationData = {
		current: {},
		currentId: '',
		list: [],
		showInHeader: false,
	};

	$rootScope.$on('concourse.application.changed', concourseApplicationChanged);

	return {
		'applicationData': applicationData,
		'getApplicationList': getApplicationList,
		'hasFetchedData': hasFetchedData,
		'initialize': initialize,
		'updateCurrent': updateCurrent,
	};

	function concourseApplicationChanged (evt, current) {
		applicationData.current = current;
		applicationData.currentId = current.sysId;
	}

	function getApplicationList () {
		fetchedInitialData = true;
		return $http
			.get('/api/now/ui/concoursepicker/application?cache=' + new Date().getTime())
			.then(getApplicationListResponse);
	}

	function getApplicationListResponse (response) {
		if (response && response.data && response.data.result) {
			applicationData.list = response.data.result.list;

			if (response.data.result.current && response.data.result.current != applicationData.currentId) {
				var apps = response.data.result.list;
				var curr = response.data.result.current;

				for (var i = 0; i < apps.length; i++) {
					if (curr == apps[i].sysId) {
						applicationData.current = apps[i];
						applicationData.currentId = apps[i].sysId;
						break;
					}
				}

				triggerChangeEvent();
			}
		}
	}

	function hasFetchedData () {
		return fetchedInitialData;
	}

	function initialize (current) {
		if (initialized)
			return;
		initialized = true;
		applicationData.list = [current];
		applicationData.current = current;
		applicationData.currentId = current.sysId;
	}

	function triggerChangeEvent () {
		$rootScope.$broadcast('concourse.application.changed', applicationData.current);
	}

	function triggerRefreshFrameEvent () {
		$rootScope.$broadcast('concourse.application.refresh', {});
	}

	function updateCurrent () {
		var apps = applicationData.list;
		var curr = applicationData.currentId;

		for (var i = 0; i < apps.length; i++) {
			if (curr == apps[i].sysId) {
				applicationData.current = apps[i];
				break;
			}
		}

		$http
			.put('/api/now/ui/concoursepicker/application', { 'app_id': applicationData.currentId })
			.then(updateCurrentResponse);
	}

	function updateCurrentResponse (response) {
		if (response && response.data && response.data.result && response.data.result.app_id) {
			triggerRefreshFrameEvent();
			triggerChangeEvent();
		}
	}
}

 


create new Angular Provider record:

  • Type: Directive
  • Name: applicationScopePicker
  • Client script:

 

function applicationScopePicker (applicationScope, snCustomEvent) {
	"use strict";

	return {

		'controller': function ($scope) {
			$scope.app = applicationScope.applicationData;
			$scope.refreshApplicationPicker = refreshApplicationPicker;
			$scope.updateCurrent = updateCurrent;

			snCustomEvent.observe('glide:ui_notification.application_change', applicationChanged);
			snCustomEvent.observe('sn:change_application', changeApplication);
			snCustomEvent.observe('sn:refresh_application_picker', refreshApplicationPicker);

			if ($scope.current) {
				applicationScope.initialize($scope.current);
			}

			function applicationChanged () {
				applicationScope.getApplicationList();
			}

			function changeApplication (appId) {
				applicationScope.getApplicationList().then(getApplicationListResponder);
			}

			function getApplicationListResponder (appId) {
				return function getApplicationListResponse () {
					applicationScope.applicationData.currentId = appId;
					$scope.updateCurrent();
				};
			}

			function refreshApplicationPicker () {
				applicationScope.getApplicationList();
			}

			function updateCurrent () {
				applicationScope.updateCurrent();
			}
		},

		'link': function (scope, element) {
			element.on('mouseover', mouseOver);

			function mouseOver () {
				if (!applicationScope.hasFetchedData())
					applicationScope.getApplicationList();
			}
		},

		'replace': false,

		'restrict': 'E',

		'scope': {
			'current': '=',
			'hintText': '=',
			'titleText': '=',
		},

		'template': getTemplate(),
	};

	function getTemplate () {
		return '\n' +
			'<div class="applicationScopePicker">\n' +
			'	<div class="input-group">\n' +
			'		<span class="input-group-addon">\n' +
			'			<a class="icon-application-generic" data-name="current-application-picker" data-title-text="{{ titleText }}" data-toggle="tooltip" href="/sys_scope.do?sys_id={{ app.current.sysId }}" target="gsft_main">\n' +
			'				<span class="sr-only">{{ hintText }}</span>\n' +
			'			</a>\n' +
			'		</span>\n' +
			'		<select class="form-control" ng-change="updateCurrent()" ng-model="app.currentId" ng-options="a.sysId as a.name for a in app.list" title="{{ titleText }}"></select>\n' +
			'	</div>\n' +
			'</div>\n' +
			'';
	}
}
  • Related list [Required Providers]: add the previously created Factory - applicationScope

 


create a new Widget record:

  • Body HTML template:

 

<div style="padding-top: 2.5em;">
	<application-scope-picker
		current="data.currentScope"
		hint-text="data.messages.hint"
		title-text="data.messages.title" />
</div>

 


  • Server script:

 

(function (data) {
	data.currentScope = getCurrentScope(gs.getCurrentApplicationId());
	data.messages = getMessages();

	function getCurrentApplicationDisplayValue (uniqueValue) {
		var gr = new GlideRecord('sys_scope');

		return gr.get(uniqueValue) ? gr.getDisplayValue() : uniqueValue;
	}

	function getCurrentScope (currentApplicationId) {
		return {
			'name': getCurrentApplicationDisplayValue(currentApplicationId),
			'sysId': currentApplicationId,
		};
	}

	function getMessages () {
		return {
			'hint': gs.getMessage('View current application under development'),
			'title': gs.getMessage('Show selected application'),
		};
	}
})(data);
  • Related list [Angular Providers]: add the previously created directive: applicationScopePicker

 


The result:

2023-02-14-1.png

2023-02-14-2.png

This literally does the exact same thing as the application picker in the main UI, so as soon as the select box is updated with a new option, the scope is changed for the current user.