I'd like to create a system that shows a popup when someone logs in my app on perspective. The purpose is to show a message of an update so the user can be aware of it, and then when he acknowledges it, the popup no longer appears when he logs in.
I don't know how I can run a script when someone logs in.
Any idea ?
On your primary view (or home page), right-click on the root → Configure Events → onStartup → Script.
You'll need to run a query to see if the user has already seen the notification and then open the popup, if required. Make it Modal.
You'll need to record the acknowledgement in the database to prevent subsequent popups for that notice.
Things to watch: if your user can bypass the home page by providing a direct URL you will have to use a different method. This might be to create the event on one of the Page Configuration views (left sidebar or banner) that are always present.
How is working the 'onStart' ? If the main page has already been opened by a user, and another one comes and logs in, will the script still run ? The 'log in' button is on the main page.
I was thinking to store the acknowledgement in a tag dataset at the beginning, then if the system is working I guess I'll store in the database
Yes, you are correct that there's a problem if the page is already open.
I presume then that the home page login button is running an onActionPerformed event with a Login action? If so, you could change this to a script, use the system.perspective.login - Ignition User Manual 8.1 - Ignition Documentation function and follow that with your "notification required" check and optional popup.
So I tried this, but my popup doesn't show up. I think that as the 'system.perspective.login' brings me to another page to log in and then takes me back to the page of my project, the script doesn't run after the line of the login (or maybe it runs but as I leave the page and then comeback, it's resetting it). I've put a line to put a text in a label just after the line of the login command, and when I come back to the page nothing changed for the label.
Hmmm! I know that if you were to run a login action followed by a script action on the button event that they run asynchronously and that can cause problems. That's why I suggested doing it in a script so that you'd be sure of the sequence.
Someone else may be able to see the problem.
Meanwhile, I suggest you post the event script here (as formatted code).
Instead of a script within the onStartup Event of a Page, you should place a change script on some piece of the user object within session properties - most likely username.
To track who has viewed this Popup over time, you will need to incorporate a database. I'll leave managing this data to you, but your change script will look something like this:
if currentValue and currentValue.value: # length check to avoid None
# check database
popup_already_viewed = system.db.runPrepQuery(...)
if not popup_already_viewed:
"""
The Session-level properties have no page context/thread,
so you will need to open this popup on every page
of the session.
"""
for session in system.perspective.getSessionInfo():
if session.id = self.props.id:
for pageId in session.pageIds:
system.perspective.openPopup("PopupId", "ViewName", modal=True, sessionId=self.props.id, pageId=pageId)
I've put this script in the Change Script of Username:
if currentValue and currentValue.value: # length check to avoid None
# check database
if currentValue == "AP" or currentValue.value == "AP":
popup_already_viewed = system.tag.read("[default]Test Popup").value
if not popup_already_viewed:
"""
The Session-level properties have no page context/thread,
so you will need to open this popup on every page
of the session.
"""
for session in system.perspective.getSessionInfo():
if session.id == self.props.id:
for pageId in session.pageIds:
system.perspective.openPopup("Test_Popup", "Popup/testPopup", modal=True, sessionId=self.props.id, pageId=pageId)
I just changed the test if the popup is already viewed by a boolean tag (temporarily until it's working).
You're nesting about six levels deep. It's time to de-nest. I got some good tips from the first part of Why you shouldn't nest your code.
This doesn't address why your code isn't working but it may help you to figure it out. Here's my attempt (but there are many here much better with Python):
if not currentValue or not currentValue.value: # length check to avoid None
return
# check database
if currentValue != "AP" and currentValue.value != "AP":
return
popup_already_viewed = system.tag.read("[default]Test Popup").value
if popup_already_viewed:
return
"""
The Session-level properties have no page context/thread,
so you will need to open this popup on every page
of the session.
"""
for session in system.perspective.getSessionInfo():
if session.id != self.props.id:
continue # Skip to next session.
for pageId in session.pageIds:
system.perspective.openPopup("Test_Popup", "Popup/testPopup",
modal=True, sessionId=self.props.id, pageId=pageId
)
Do your Gateway logs contain any errors logged due to this script?
Also, I forgot this route will not work for projects which REQUIRE authentication, as the username value will not "change", it will initialize as the user's name - bypassing the change script.
I tried out the script and it worked 100% as expected on a project which did not require authentication.
In the logs I have this error:
Error running property change script on session.props.auth.user.userName: Traceback (most recent call last): File "function:valueChanged", line 15, in valueChanged at com.inductiveautomation.perspective.gateway.model.PageModel.send(PageModel.java:384) at com.inductiveautomation.perspective.gateway.model.PageModel.send(PageModel.java:365) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.lambda$popupAction$21(PerspectiveScriptingFunctions.java:778) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:82) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.popupAction(PerspectiveScriptingFunctions.java:758) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.openPopup(PerspectiveScriptingFunctions.java:240) at jdk.internal.reflect.GeneratedMethodAccessor456.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) java.io.IOException: java.io.IOException: Channel is not set.
No idea of what's the problem... Any clue on what is this 'channel' ?
I don't understand, how can it works if you don't use the authentication ?
Some projects do not require authentication. When those sessions start, username is null. When a user logs in, the username changes to the user's username, thus invoking the change script.
For me to help with the scripting issue, I would need a screenshot which clearly shows me the line numbers of your script. It's also helpful if you display the script with whitespace so that we can rule out certain issues.
Curious. Is this being used in a project which does require authentication? I'm wondering if perhaps it is executing the script on login but perhaps the page it is targeting no longer exists as the session does the unauthenticated -> authenticated transition?
Is it the project property 'Required Client Roles' that you are talking about ? If it's the case it's empty in my project. You can access my project without be logged in, but some functionalities like buttons require you to be logged in to use them.
Also I noticed something, I don't know if it's useful or not, but I tried this by logging in on the main view every times, but in the logs of the gateway in the logs properties of the error, there is a different view for all messages:
After the login screen it's supposed to take me back to the main view so I don't know why the view in the log properties is changing.
If Authenticated is checked, it means that your project in essence requires that a user be logged in to access the project.
Are those Views all open in different tabs in your browser? Are they open in the Designer? The Channel is not set error has been seen in the past on mobile devices. Where is the session you're using? Are there other sessions in use with this same user?
I just tried with my designer closed and only one tab with the main view and still different views in the log properties.
I'm not using it on a mobile, it's only on computers.
Some sessions are opened on other computers but none with this user (I can't try to close all the sessions to see if it works as we are currently using the project).
Just a small nit pick, but this will always be true, so is doing nothing but adding unneeded overhead.
The first two checks can be combined into:
if currentValue and currentValue.value != "AP":
return
I would reduce the code to this:
Poorly thought out code
This text will be hidden
if all([currentValue,currentValue.value == "AP",system.tag.readBlocking(["[default]Test Popup"])[0].value]):
for index,sessions in enumerate(system.perspective.getSessionInfo()):
if sessions[index].id != self.props.id:
continue
for pID in sessions[index].pageIds:
system.perspective.openPopup("Test_Popup","Popup/testPopup",modal=True,sessionId=self.props.id,pageId=pID)
Note: That I enumerated the return from getSessionInfo() This is because the function returns a List and so will likely not have the properties which the original code expected.
EDIT: It helps if you understand what a function does when you use it. See below for corrected code. No need to enumerate, as this is a list of objects and you're not referencing into the list for any reason. Just use a standard for loop. K.I.S.S.