I want to keep track of the current "IDs" of various entities being edited in an app, and save them to the database.
This is simple if I just save a bunch of IDs using the current_user.sid as the row identifier, into a database. However, if the user opens the app in two different browser tabs, I need to keep track of the separate IDs in play in each browser tab. It's the same user using each tab so events occurring in one tab end up overwriting the IDs for the events occurring on the other tab because the current_user.sid is the same.
I need to be able to identify each browser tab, or the session in each browser tab.
How do I uniquely identify each tabbed session please? It's got to be possible, it seems like it should be a really simple thing to do. Like window.currentTabid or something like that, but I can't find anything anywhere.
Even getting the server session-id would do, as I believe these are unique per browser tab.
Hi @xl_MURDOCH_lx ,
You can set a browser_tab_id by setting a unique variable for it and saving it to the database. You can use the uuid.v4() function to create a random, unique string to assign to the browser_tab_id. So,
first create a new variable called browser_tab_id:
if(browser_tab_id.value===null){
browser_tab_id.setValue(uuid.v4())
}
else throw new Error("browser tab id already created")
In the success handler for this query, save everything to your database, including the current User and the browser_tab_id.
The only issue with this approach is that if a user refreshes their page, they'll get another browser_tab_id. Is this what you want or do you want just ONE browser_tab_id per user per tab, regardless of them hitting refresh on their open tabs?
Many thanks for this, I'll give it a go but I don't think it's going to work. I'd have to put this query / code on every page and every module in the app, which doesn't seem practical. Also, I'd like the ID to remain even if the browser is refreshed or the page changes. Is the server SessionID not exposable to code?
This would all be a lot easier if I could access the app's "Global" variables from a module, but because modules can be used across multiple apps they don't seem to be able to "see" the global variables.
@xl_MURDOCH_lx
Retool does not give you access to the session storage, unfortunately. However, I think I may have a solution for you using search params in your url.
Declare a variable in the global scope called browser_tab_id and set it initially to null:
So we start with no search params when we open a new tab. When this happens, we create a search param and add it to the url and then add this to the database. Nothing happens when we switch pages between apps cause this will not cause a page reload. On refresh, the search param will still exist, so the actual browser_tab_id will change, but it will not be added to the database because an error is thrown, so the success event does not happen. (this just avoids it being set to null, which would trigger the database action on the next refresh)
Hi! Thank you so much or getting involved in this. Again, this causes more problems than it solves as it involves pasting the same piece of code on every single page in the app. So, if anything changes and I need to adjust the code, I'm facing 100+ pages of code changes.
All I really want is a way of uniquely identifying tabs without having to copy and paste code to every page and module on the app.
Your solution works, of course, so thank you. It just feels a bit clumsy.
Unfortunately, this also seems to involve global variables, which are not readable from modules, as modules can be used in multiple apps (each of which have their own global variables).
Life would be a lot simpler if Retool could expose the SessionID.
Could Retool add the feature to prefix JS commands with the app name, and therefore allow explicit calls to app global variables?
I have an app called "nav" which is the main navigator for the overall tool I'm building. It would be ace to be able to refer to the global variables in that app by prefixing the code with the app name.
eg.
nav.str_ACCOUNT_ID.value
or
nav.global.str_ACCOUNT_ID.value
This would make the whole SessionID / TabID issue null and void, as the global variables are localised to the session / tab anyway.
@xl_MURDOCH_lx ,
You can place all your code (which is the the 3 queries and the variable) in the global scope, so you would just have to do it ONCE because all pages have access to it in a multi-page app. (are you using multi-page app?) I'm not sure why your modules need access to the global variables cause we are simply placing a search parameter on one page (I believe all other pages will have it if you add it to just one page). You are importing modules into your pages, correct? See the screenshot below. I have placed all my queries in the global scope, just once and all three pages have access to it. Note that page3 has the search params in its url even though i have not explicitly set them on page3 (only page1).
Yes, my app is multi-page, and modules are re-used across multiple pages.
My re-usable modules contain data tables and a side drawer, which are used in multiple places across the app.
When an item is selected in a module's table, or the "edit" button is clicked in the side-drawer, I need to write various IDs to the database, including the tab ID., so I can keep track of the "current state of affairs". As modules cannot read or write to the app's global variables, this makes life pretty difficult and impossible to use your solution to ID the tab, as the modules cannot "see" the global tab id.
The modules are all "search" screens, which search through the database for businesses, people, contracts, products etc... and are repeatedly used across the app either as main screens, or as "tabs" when looking at detailed views. When the user selects an item in the search results, I need to update the database to retain the IDs of the current selection.
I'm afraid your solution doesn't work, as it adds the tab_id to the url hash after the page has loaded so that page is unaware of the param, it is not sent to the page
Access to session variables, where there is a separate session per tab seems the only solution to me.
@xl_MURDOCH_lx ,
I agree that the best solution would be to have session ids, but until we can offer that, I THINK that this solution can be a viable, if cumbersome, workaround. Check out my simple app here which includes a basic module. Create a simple table in retool DB using the attached CSV file and use my app with the app module that are both attached below.
With this setup, I am able to capture when a new user opens the app in a tab. It only saves this to the database once, and will not save again when pages are changed or there is a refresh.
With regard to the modules not having access to global scope, you can pass the browser_tab_id down from the parent page into the module so that you can reference the current browser_tab_id when the user does certain actions from within the module. When a user switches pages or refreshes, the broswer_tab_id will remain the same, and get passed to those pages' modules.
Regarding your comment above, I am not sure what you mean by the params not being sent to the page. On page load, I have the app checking to see if there are url params...If not, a browser tab uuid is created and saved in the db and then the searchParams are added for subsequent page changes or refreshes. That is what we want, isn't it?
const existing = window.sessionStorage.getItem('tab_id');
if (!existing) {
const newId = uuid.v4();
window.sessionStorage.setItem('tab_id', newId);
utils.openUrl({ url: '/home' });
}
Someone suggested this as a possible solution but unfortunately "window" is sandboxed and I can't access the properties / methods. It would be brilliant if as well as "localStorage" we could access the "sessionStorage" object.
@xl_MURDOCH_lx,
I totally agree that it would be nice to have session storage. There has been a ticket that has been created to address this. Meanwhile, if you need help passing params from the parent to the module, let me know. You can read about how to do this here.