Multiple tabs with their own root components

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Multiple tabs with their own root components

Esteban A. Maringolo
Hi all,

I have a question that I cannot answer myself even though I have built
a handful of medium sized applications with Seaside. To some degree it
is embarrassing, but I need to ask just in case I've been missing
something trivial all these years.

I'm building a "public" web app, and I have some newer concerns I
didn't have before because most apps ran in private environments or
behind logins and were mostly complex UI or flows where Seaside shines
and no one cares (mostly) about URLs.

These days it is very common that you can open a link in a new tab to
view something, then close it, duplicate it or even the browser might
restart on that page. The problem is that with Seaside, as long as one
action continuation is triggered then as soon as you reload one of
these tabs it shows content from the last tab that had some
continuation activated.

My solution was to change all callbacks that do simple #show: actions
with the canonical url of the called page, to implement
#initialRequest: to handle the few cases where I need to provide a
stable url (for sharing and for Open Graph and friends) and to use
Cookie based session tracking.

This is similar to the method proposed years ago by Ramon on his blog
[1], but without meddling with the Render Loop. I guess that the
Seaside book website does something similar.

Is there any other way of achieving independent flow in each tab, each
with its own renderloop with a different root component? So basically
I can have different branches of "_k" when needed.

Maybe a Stateful framework such as Seaside is overkill for these
cases, in particular because it's heretical in many aspects, but I'm
still very productive with its component based development and it's
canvas way of building them.

Shall we start thinking what we need and want for Seaside 4.0? :-)

Regards,

[1] http://onsmalltalk.com/clean-urls-in-seaside

Esteban A. Maringolo
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Multiple tabs with their own root components

Karsten Kusche
Hi Esteban,

isn’t that what Seaside does automatically? You have an action continuation that handles your callbacks and then does a redirect to the render continuation. Then you can reload the render continuation again and again and everything should behave as expected. 

The only requirement for that to work is that you implement updateStates „the right way“.

At least that’s as far as the Seaside part of the game is concerned. If the underlying model can handle all that is another question. If only your components store all the state, it may work. But on the other hand you end up with the same instance of a WAComponent being used with 3 different tabs and then 3 different sets of instance variable values.

As an example you can use the simple Counter example, it should behave correctly, no matter how many tabs you spawn and what you do in each of these.

Kind Regards
Karsten


— 

Georg Heeg eK
Wallstraße 22
06366 Köthen

Tel.: 03496/214328
FAX: 03496/214712
Amtsgericht Dortmund HRA 12812


Am 11. August 2020 um 04:38:21, Esteban Maringolo ([hidden email]) schrieb:

Hi all,

I have a question that I cannot answer myself even though I have built
a handful of medium sized applications with Seaside. To some degree it
is embarrassing, but I need to ask just in case I've been missing
something trivial all these years.

I'm building a "public" web app, and I have some newer concerns I
didn't have before because most apps ran in private environments or
behind logins and were mostly complex UI or flows where Seaside shines
and no one cares (mostly) about URLs.

These days it is very common that you can open a link in a new tab to
view something, then close it, duplicate it or even the browser might
restart on that page. The problem is that with Seaside, as long as one
action continuation is triggered then as soon as you reload one of
these tabs it shows content from the last tab that had some
continuation activated.

My solution was to change all callbacks that do simple #show: actions
with the canonical url of the called page, to implement
#initialRequest: to handle the few cases where I need to provide a
stable url (for sharing and for Open Graph and friends) and to use
Cookie based session tracking.

This is similar to the method proposed years ago by Ramon on his blog
[1], but without meddling with the Render Loop. I guess that the
Seaside book website does something similar.

Is there any other way of achieving independent flow in each tab, each
with its own renderloop with a different root component? So basically
I can have different branches of "_k" when needed.

Maybe a Stateful framework such as Seaside is overkill for these
cases, in particular because it's heretical in many aspects, but I'm
still very productive with its component based development and it's
canvas way of building them.

Shall we start thinking what we need and want for Seaside 4.0? :-)

Regards,

[1] http://onsmalltalk.com/clean-urls-in-seaside

Esteban A. Maringolo
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Multiple tabs with their own root components

Esteban A. Maringolo
Hi Karsten,

> The only requirement for that to work is that you implement updateStates „the right way“.

The snapshots and the updateStates: (or the proper answering of
#states of objects to be backtracked) is what I always understood that
was needed.

I should double-check whether I'm doing it correctly (which I probably don't).

> At least that’s as far as the Seaside part of the game is concerned. If the underlying model can handle all that is another question.

Only the session is shared, and in this case everything is read only,
so no issues in this case.

I have another app where the application model can't handle different
tabs and I need to forbid opening a new tab, but that's another story
:-)

> If only your components store all the state, it may work.

The store the UI state, the model is at the "model" layer, but there
is no "Component-Model", just components and the domain models.

> But on the other hand you end up with the same instance of a WAComponent
> being used with 3 different tabs and then 3 different sets of instance variable values.

Is that how the snapshot works? I thought it made copies of the
objects, but not a swapping of the instVars of the registered ones.

Thanks!

Esteban A. Maringolo


On Tue, Aug 11, 2020 at 2:22 AM Karsten Kusche <[hidden email]> wrote:

>
> Hi Esteban,
>
> isn’t that what Seaside does automatically? You have an action continuation that handles your callbacks and then does a redirect to the render continuation. Then you can reload the render continuation again and again and everything should behave as expected.
>
> The only requirement for that to work is that you implement updateStates „the right way“.
>
> At least that’s as far as the Seaside part of the game is concerned. If the underlying model can handle all that is another question. If only your components store all the state, it may work. But on the other hand you end up with the same instance of a WAComponent being used with 3 different tabs and then 3 different sets of instance variable values.
>
> As an example you can use the simple Counter example, it should behave correctly, no matter how many tabs you spawn and what you do in each of these.
>
> Kind Regards
> Karsten
>
>
> —
>
> Georg Heeg eK
>
> Wallstraße 22
> 06366 Köthen
>
> Tel.: 03496/214328
> FAX: 03496/214712
> Amtsgericht Dortmund HRA 12812
>
>
>
> Am 11. August 2020 um 04:38:21, Esteban Maringolo ([hidden email]) schrieb:
>
> Hi all,
>
> I have a question that I cannot answer myself even though I have built
> a handful of medium sized applications with Seaside. To some degree it
> is embarrassing, but I need to ask just in case I've been missing
> something trivial all these years.
>
> I'm building a "public" web app, and I have some newer concerns I
> didn't have before because most apps ran in private environments or
> behind logins and were mostly complex UI or flows where Seaside shines
> and no one cares (mostly) about URLs.
>
> These days it is very common that you can open a link in a new tab to
> view something, then close it, duplicate it or even the browser might
> restart on that page. The problem is that with Seaside, as long as one
> action continuation is triggered then as soon as you reload one of
> these tabs it shows content from the last tab that had some
> continuation activated.
>
> My solution was to change all callbacks that do simple #show: actions
> with the canonical url of the called page, to implement
> #initialRequest: to handle the few cases where I need to provide a
> stable url (for sharing and for Open Graph and friends) and to use
> Cookie based session tracking.
>
> This is similar to the method proposed years ago by Ramon on his blog
> [1], but without meddling with the Render Loop. I guess that the
> Seaside book website does something similar.
>
> Is there any other way of achieving independent flow in each tab, each
> with its own renderloop with a different root component? So basically
> I can have different branches of "_k" when needed.
>
> Maybe a Stateful framework such as Seaside is overkill for these
> cases, in particular because it's heretical in many aspects, but I'm
> still very productive with its component based development and it's
> canvas way of building them.
>
> Shall we start thinking what we need and want for Seaside 4.0? :-)
>
> Regards,
>
> [1] http://onsmalltalk.com/clean-urls-in-seaside
>
> Esteban A. Maringolo
> _______________________________________________
> seaside mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Multiple tabs with their own root components

Karsten Kusche
Hi Esteban,


> But on the other hand you end up with the same instance of a WAComponent 
> being used with 3 different tabs and then 3 different sets of instance variable values. 

Is that how the snapshot works? I thought it made copies of the 
objects, but not a swapping of the instVars of the registered ones. 


Seaside does make copies, but upon restoring these copies are asked for their instance variables and put back in the original object.

At least that’s the default implementation of #snapshotCopy and #restoreFromSnapshot:


Kind Regards

Karsten





Thanks! 

Esteban A. Maringolo 


On Tue, Aug 11, 2020 at 2:22 AM Karsten Kusche <[hidden email]> wrote: 
> 
> Hi Esteban, 
> 
> isn’t that what Seaside does automatically? You have an action continuation that handles your callbacks and then does a redirect to the render continuation. Then you can reload the render continuation again and again and everything should behave as expected. 
> 
> The only requirement for that to work is that you implement updateStates „the right way“. 
> 
> At least that’s as far as the Seaside part of the game is concerned. If the underlying model can handle all that is another question. If only your components store all the state, it may work. But on the other hand you end up with the same instance of a WAComponent being used with 3 different tabs and then 3 different sets of instance variable values. 
> 
> As an example you can use the simple Counter example, it should behave correctly, no matter how many tabs you spawn and what you do in each of these. 
> 
> Kind Regards 
> Karsten 
> 
> 
> — 
> 
> Georg Heeg eK 
> 
> Wallstraße 22 
> 06366 Köthen 
> 
> Tel.: 03496/214328 
> FAX: 03496/214712 
> Amtsgericht Dortmund HRA 12812 
> 
> 
> 
> Am 11. August 2020 um 04:38:21, Esteban Maringolo ([hidden email]) schrieb: 
> 
> Hi all, 
> 
> I have a question that I cannot answer myself even though I have built 
> a handful of medium sized applications with Seaside. To some degree it 
> is embarrassing, but I need to ask just in case I've been missing 
> something trivial all these years. 
> 
> I'm building a "public" web app, and I have some newer concerns I 
> didn't have before because most apps ran in private environments or 
> behind logins and were mostly complex UI or flows where Seaside shines 
> and no one cares (mostly) about URLs. 
> 
> These days it is very common that you can open a link in a new tab to 
> view something, then close it, duplicate it or even the browser might 
> restart on that page. The problem is that with Seaside, as long as one 
> action continuation is triggered then as soon as you reload one of 
> these tabs it shows content from the last tab that had some 
> continuation activated. 
> 
> My solution was to change all callbacks that do simple #show: actions 
> with the canonical url of the called page, to implement 
> #initialRequest: to handle the few cases where I need to provide a 
> stable url (for sharing and for Open Graph and friends) and to use 
> Cookie based session tracking. 
> 
> This is similar to the method proposed years ago by Ramon on his blog 
> [1], but without meddling with the Render Loop. I guess that the 
> Seaside book website does something similar. 
> 
> Is there any other way of achieving independent flow in each tab, each 
> with its own renderloop with a different root component? So basically 
> I can have different branches of "_k" when needed. 
> 
> Maybe a Stateful framework such as Seaside is overkill for these 
> cases, in particular because it's heretical in many aspects, but I'm 
> still very productive with its component based development and it's 
> canvas way of building them. 
> 
> Shall we start thinking what we need and want for Seaside 4.0? :-) 
> 
> Regards, 
> 
> [1] http://onsmalltalk.com/clean-urls-in-seaside 
> 
> Esteban A. Maringolo 
> _______________________________________________ 
> seaside mailing list 
> [hidden email] 
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside 

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Multiple tabs with their own root components

Bob Nemec
In reply to this post by Esteban A. Maringolo
On the point...

    These days it is very common that you can open a link in a new tab to
    view something, then close it, duplicate it or even the browser might
    restart on that page.

...we have that issue with our in-house ERP system (about 650 users). 
Having users open an internal application link in a new tab is just wrong in Seaside.
To prevent that we check the history.length on the render for logged-in sessions.
We also have options to open the application for saved links that open a domain object.
That also had to to be checked for. To distinguish between browser tabs I use sessionStorage.

aSession validNewSession ifTrue: [
    html script: 'sessionStorage.setItem("validSession",1)'
    ...]

...if the session is not a special case, and for the next render, I use...

html script: ((JSStream on: '(history.length > 1) || (sessionStorage.getItem("validSession") == 1) ') 
then: (html jQuery ajax script: [:script | 
script << (html jQuery id: 'user application div') show;
<< (html jQuery id: 'invalid session message div') hide] )
else: (html jQuery ajax script: [:script | 
script << (html jQuery id: 'user application div') hide;
<< (html jQuery id: 'invalid session message div') show]))].


Users are able to open new tabs with logged in sessions. 
We provide that with a 'new session' anchor...

html popupAnchor
url: (self session requestContext request url printString, '&newSession');
with: [...]

...our WAApplication subclass handleFiltered: checks for newSession and sets up a new logged in session. 

handleNewSession: aRequestContext

| newSession oldSession companyOop | 

oldSession := self sessionForRequest: aRequestContext.
oldSession isNil ifTrue: [
^super handleFiltered: aRequestContext].
        ...copy stuff from old session to new session...
        ^self handle: aRequestContext registering: newSession.



I'm sure there are cleaner ways to do this (I'd like to see other techniques), but this works for us.

Running Seaside 3.2 on GemStone 3.4.3 
Bob Nemec

On Monday, August 10, 2020, 10:38:18 p.m. EDT, Esteban Maringolo <[hidden email]> wrote:


Hi all,

I have a question that I cannot answer myself even though I have built
a handful of medium sized applications with Seaside. To some degree it
is embarrassing, but I need to ask just in case I've been missing
something trivial all these years.

I'm building a "public" web app, and I have some newer concerns I
didn't have before because most apps ran in private environments or
behind logins and were mostly complex UI or flows where Seaside shines
and no one cares (mostly) about URLs.

These days it is very common that you can open a link in a new tab to
view something, then close it, duplicate it or even the browser might
restart on that page. The problem is that with Seaside, as long as one
action continuation is triggered then as soon as you reload one of
these tabs it shows content from the last tab that had some
continuation activated.

My solution was to change all callbacks that do simple #show: actions
with the canonical url of the called page, to implement
#initialRequest: to handle the few cases where I need to provide a
stable url (for sharing and for Open Graph and friends) and to use
Cookie based session tracking.

This is similar to the method proposed years ago by Ramon on his blog
[1], but without meddling with the Render Loop. I guess that the
Seaside book website does something similar.

Is there any other way of achieving independent flow in each tab, each
with its own renderloop with a different root component? So basically
I can have different branches of "_k" when needed.

Maybe a Stateful framework such as Seaside is overkill for these
cases, in particular because it's heretical in many aspects, but I'm
still very productive with its component based development and it's
canvas way of building them.

Shall we start thinking what we need and want for Seaside 4.0? :-)

Regards,


Esteban A. Maringolo
_______________________________________________
seaside mailing list

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Bob Nemec
Reply | Threaded
Open this post in threaded view
|

Re: Multiple tabs with their own root components

Esteban A. Maringolo
Hi Bob,

On Tue, Aug 11, 2020 at 12:09 PM Bob Nemec <[hidden email]> wrote:
>
> On the point...
>
>     These days it is very common that you can open a link in a new tab to
>     view something, then close it, duplicate it or even the browser might
>     restart on that page.

> ...we have that issue with our in-house ERP system (about 650 users).
> Having users open an internal application link in a new tab is just wrong in Seaside.

That will depend on how you architecture the application and the state
involved, of course you cannot start a workflow in one page, open a
link to another tab (or even duplicate the same tab) and have
different "timelines" on each tab.

Maybe in the past that was possible with the #isolate: decorator, but
that can't be done now.
For another app where I have similar restrictions as yours, I drive
most, if not all, of the interactions via AJAX, so there are no
"internal links", but that doesn't stop the user from duplicating the
tab or clicking the Back/Forward button with [Ctrl] pressed to
duplicate that.


> To prevent that we check the history.length on the render for logged-in sessions.
> We also have options to open the application for saved links that open a domain object.
> That also had to to be checked for. To distinguish between browser tabs I use sessionStorage.
>
> aSession validNewSession ifTrue: [
>     html script: 'sessionStorage.setItem("validSession",1)'
>     ...]
>
> ...if the session is not a special case, and for the next render, I use...

What would be a "special case"?

> html script: ((JSStream on: '(history.length > 1) || (sessionStorage.getItem("validSession") == 1) ')

Have you tried using the "duplicate tab" feature? Because that nasty
thing clones the sessionStorage.

> Users are able to open new tabs with logged in sessions.
> We provide that with a 'new session' anchor...

That might be a little overkill, unless the session is lightweight.
So far I've been building Seaside apps where there is a 1:1 relation
between the Seaside session
and some "app session" where all info about the user, the database
connection, etc. is managed.

In Gemstone I guess you save the DB connection part (which can take a
huge toll if you have that many hundreds of concurrent users).

> html popupAnchor
> url: (self session requestContext request url printString, '&newSession');
> with: [...]
>
> ...our WAApplication subclass handleFiltered: checks for newSession and sets up a new logged in session.
>
> handleNewSession: aRequestContext
>
> | newSession oldSession companyOop |
>
> oldSession := self sessionForRequest: aRequestContext.
> oldSession isNil ifTrue: [
> ^super handleFiltered: aRequestContext].
>         ...copy stuff from old session to new session...
>         ^self handle: aRequestContext registering: newSession.

This could certainly become some generic WARequestFilter, but what's
missing to make it of general use is being able to detect it without
using a &newSession parameter.

Regards!


Esteban A. Maringolo
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside