Injecting a Client-Side Script to the pa_dashboard Page

JosephW1
Tera Guru

Hello,

I am trying to meet the below requirements but have not had success. I will not go into discussing the use case here, as I'd like this question to stay focused on finding a creative measure that can be used to meet these apparently-not-possible requirements. I would appreciate if the contributors would do the same. Thank you.

Requirements
1. Script must execute on the pa_dashboard page; the front-end of dashboards, not the list/form view pa_dashboards page.
2. Script must always execute before any widget on said dashboard tab on dashboard tab load/change events
  2a. This means that the script must execute while the dashboard is initializing, before it begins rendering the widgets. Which means the script can't be contained in a widget such as a dynamic content block.(!)
3. Script must execute client-side and have access to the client and its variables, such as window.SNC.canvas and window.SNC.dashboards

Example: If loading a dashboard tab that only has one widget (a sys_report widget), said script would execute a "console.log("hello world");" to the client console's log before said report outputs its "runBeforeRender" console log statement.


What I've Tried:
1. UI Script - These are client side but don't load on the pa_dashboard page, unfortunately.
2. Client Script - These are client side but don't load on the pa_dashboard page, unfortunately.
3. UX Client Script - Not all too sure how these work, not finding much documentation. I do see OOTB instances of these being used by dashboards, though, so these may be injected somewhere in the dashboard initialization phase. Haven't managed to build a solution via these yet.
4. UX Client Script Include - Not sure how these work, not finding much documentation.

 

I understand that what I'm trying to do is unique, may not be possible, and is not documented. I would not be surprised if some are tempted to respond "This is not possible OOTB". Even I am tempted to do so. However, regardless, there still may be some obscure hook that can be used to inject this script I'm simply not aware of. I appreciate any effort to think critically and find a way to meet these requirements.

Thank you for your time and reading this question! I hope it will end up helping others who have the same requirements.

Kind Regards,
Joseph

4 REPLIES 4

Pedro Grilo1
Mega Sage

Hi!

 

 

As you mentioned, client scripts or UI scripts should not work as this is based in angular and I don't think we have access to any of the UI Page or directives in use.

Only thing I can think of is to create a UI Page (something like $new_pa_dashboards_overview) and replace the links with the new page.

On the code, add the iframe to the OOB $pa_dashboards_verview and put your code on the client script side. Not sure it will fit your needs but maybe worth giving it a try.

find_real_file.png

 

I hope it helps!

Pedro

Hi Pedro!

 

That's great, thanks for a creative solution. That goes against requirement #1, though, as I really want this to not modify the OOTB $pa_dashboard and $pa_dashboards_overview UI pages.

Thank you, good idea! If I can't find a less invasive method this might end up being the method I have to use.

 

Kind Regards,

Joseph

Markus Kraus
Kilo Sage

Result of my method:


find_real_file.png

Thought thats a interesting topic, so here's a full UI Page (that also supports reloading).
Basically the code of PLEASE_INJECT_THIS_FUNCTION is getting executed just like an UI Script.

The UI Page actually consists only of HTML:
Name: injected_pa_dashboards
HTML:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<html>
		<head>
			<script>
				function PLEASE_INJECT_THIS_FUNCTION() {
					console.log("runBeforeRender?????");
				}
			</script>
			<style>
				body, html {
					margin: 0; padding: 0; height: 100%; overflow: hidden;
				}

				#content {
					position: absolute; left: 0; right: 0; bottom: 0; top: 0px; 
				}
				
				#content iframe {
					width: 100%;
					height: 100%;
					border: none;
				}
			</style>
		</head>
		<body>
			<div id="content">
				<iframe src="$pa_dashboard.do" />
			</div>
			<script>
				var iframe = document.querySelector("#content > iframe");
				var x = iframe.contentWindow;
					x.addEventListener('DOMContentLoaded', function () {
					var script = x.document.createElement('script'); 
					script.type = 'text/javascript';
					script.innerHTML = '(' + PLEASE_INJECT_THIS_FUNCTION.toString() + ')()';
					x.document.head.appendChild(script);
				});
			</script>
		</body>
	</html>
</j:jelly>

Thought thats a interesting topic, so here's the full UI Page that also supports reloading (the previous solution only works when opened once, if you reload the window the code will not get injected again).
Basically the code of PLEASE_INJECT_THIS_FUNCTION is getting executed just like an UI Script.

The UI Page actually consists only of HTML:
Name: injected_pa_dashboards
HTML:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<html>
		<head>
			<script>
				function PLEASE_INJECT_THIS_FUNCTION() {
					console.log("runBeforeRender?????");
				}
			</script>
			<style>
				body, html {
					margin: 0; padding: 0; height: 100%; overflow: hidden;
				}

				#content {
					position: absolute; left: 0; right: 0; bottom: 0; top: 0px; 
				}
				
				#content iframe {
					width: 100%;
					height: 100%;
					border: none;
				}
			</style>
		</head>
		<body>
			<div id="content">
				<iframe src="$pa_dashboard.do" />
			</div>
			<script>
				var iframe = document.querySelector("#content > iframe");
				var x = iframe.contentWindow;
					x.addEventListener('DOMContentLoaded', function () {
					var script = x.document.createElement('script'); 
					script.type = 'text/javascript';
					script.innerHTML = '(' + PLEASE_INJECT_THIS_FUNCTION.toString() + ')()';
					x.document.head.appendChild(script);
				});
			</script>
		</body>
	</html>
</j:jelly>