1 2 Previous Next 17 Replies Latest reply on Dec 1, 2015 1:45 PM by Malcolm

    Truly portable layout widgets in a multi-user, multi-window environment?


      Not sure how easy it'll be to explain this, since it's pretty "out there". I think I'm on the verge of something really useful for us and possibly for others, though, so I'm going to give it a shot. I'm down to a "why doesn't this work?" sort of problem, and I'm not sure if I'm just breathing my own exhaust and missing something fairly obvious, or if there's a subtle issue with FM14 here.


      See the two attached files. They are essentially the same, except the "inty" file uses references from the main file (separation) while if you open the main file it's unseparated.


      Each file has the following tables:


      • products - just an example of a "parent" table, with just a simple name field for now
      • contacts - likewise
      • roles - a join table that accepts two foreign keys, "keyThis" and "keyThat". For simplicity, and to allow self-joins, in practice we'd script the creation of these records as pairs, with keyThis and keyThat "flipped" in the sister record. For the purposes of this demo, I've just left these as "one way"
      • attachments - an example of a commonly used "child" table, with just a simple name field for now
      • windows - (this is important) a table containing a record for each window "instance" of the user's "session" (in practice, we'd get a session key from a new session table on startup, but just to keep things simple, I'm declaring a variable on startup for now).


      Here's what I'd like to accomplish:


      Our solutions tend to have a lot of many-to-many relationships. For example, an attached file might be linked to 0:M contacts, 0:M activities, 0:M objectives, 0:M products, and so on. Other examples from our current base include custom attributes, activities, objectives and more. (For this demo, I'm talking about "parent" and "child" for clarity, but in reality a table often exists in both roles.)


      In the spirit of "selector-connector", I'd like to be able to have, say, a portal of attachments via the roles table on contacts, and be able to copy/paste that portal to products, activities, objectives, etc. without repointing everything. Selector-connector as defined now would allow us to do this, but only if we give up multiple windows, which we find useful for a variety of reasons, and which is kind of a key feature of our base solution and other development methods. (Not trying to reopen that debate here; we know we could give up multiple windows and get what we want. We're going to try everything we can to get the advantages of both, though.)


      Some moving parts:

      The window title would include a window "instance". For this demo, it's a certain number of BOM characters (char 65279, an invisible character with no width). The first window you open would be instance 1, and if you spawned a new window it'd be instance 2, etc. In our current solutions, we put the window instance in brackets at the end of the window title, but I like that the BOM character method doesn't mess with the readability of the window title.


      Each table would have an unstored calculated value that is the window instance (determined by the current window name) and the session key. On record load, a script would set the primary key of the main record into a field in the windows record for this instance and session.


      Here's what I'm seeing, and trying to understand:


      I've got the main, non-separated file set up as a proof of concept, and it works find in FMP13 and FMP14 (although there are plenty of refinements and continued testing to do, it's a decent "proof of concept".)


      The "inty" file, with separation, seems to work well in FM13.


      However, the inty file doesn't work right in FM14. OnRecordLoad, even though the unstored calc for windowInstance exists in the local (contacts, for instance) table, and a windows record exists for that same instance, FM can't "see" the windows record unless and until it creates one via relationship. Instead of setting the current key into the existing windows record, a new windows record is created, and the old windows record (with a different keyCurrent) ends up getting recognized, so I end up seeing attachments from this record and a previous record (or records) that I viewed in this window.


      Why I think this is worth the trouble

      Currently, our base solution includes a handful of these "applicable everywhere" types of supporting records: attachments, activities, related contacts, custom attributes and objectives. I actually have a lot of ideas for more of these, for example a "comments" table that would work somewhat like posts here on the forum, so I could, for instance, follow and comment on other users' comments regarding a specific project, contact, etc.


      We currently don't spread these around to all data elements even though they are applicable at least in theory to just about anything. The reason is that currently we end up with a flock of required TO's in each TOG, for each portal. Also, if we make improvements to one of these "applicable everywhere" tables/portals, we need to go around setting and re-pointing things on each layout. If we could copy/paste whole tabs/portals, we'd use these utilities in more places, update them more consistently, and generally get more out of them.


      I absolutely love the idea of selector-connector, for reducing TO proliferation and making these things more portable, but having to do away with multiple windows is a tough choice. Being able to spawn a new window (for example, if the phone rings and you want to record details of the phone call) without abandoning what you were working on, and just generally being able to look at two things side-by-side, is a feature that's been a strong selling point, and one that we've pushed hard with existing clients. Giving that up, while it may eventually prove to be an "either-or" proposition, is not something we'd take lightly, and frankly feels like a big step backwards.



      I know there are other considerations with this idea, such as keeping the number of windows records reasonably low (deleting old ones). I also know that there are other ways we could pursue our goals. I'd ask that we not debate the merits of multiple windows, whether repointing things on layouts is "really so hard" and things like that. I'm not closed to those discussions, but I'd like to focus on what's changed in FMP14 that makes this approach not work. I've spent quite a bit of time and effort trying to get this down to where I can see the moment that it breaks in FMP14 with separation, but I just don't understand what I'm seeing. I'd like to focus on understanding, and possibly working around, the one issue I've narrowed down here.


      I suspect that even with the demo files and the length of this post, I've not covered all the moving parts in enough detail, or defined the goal clearly enough. If you're willing to help me work through this, though, I'm more than willing to answer questions you may have.


      Chris Cain


        • 1. Re: Truly portable layout widgets in a multi-user, multi-window environment?

          You cannot share globals across file boundaries. The value of $$SES will always be calculated in the context of the data file. That calculation will never see the value of $$SES defined in the UI file.

          • 2. Re: Truly portable layout widgets in a multi-user, multi-window environment?

            The OFW in the interface runs OFW in the data file, which sets $$SES. This is not the issue. Look at the field values, you'll see it.


            Also: "in practice, we'd get a session key from a new session table [record, sic] on startup, but just to keep things simple, I'm declaring a variable on startup for now"

            • 3. Re: Truly portable layout widgets in a multi-user, multi-window environment?

              I am trying to see if I have anything to contribute.

              One thing I did (see attachment) is just to clean up the layouts, resize things, and modify the opener scripts so that it is easier for me to see whether I am looking at the interface file or data file.

              • 4. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                Thanks for taking a look, Bruce, and for the help with the demo files. (The originals are a bit of a mess, I'll admit.)


                Can you follow what I'm trying to do here, especially if you open it in 13? So close...


                Chris Cain


                • 5. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                  No actually, I can't. I have some kind of tiny inkling. But really - no, I don't know at all what you're trying to do.

                  • 6. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                    Darn. Let me keep trying. Aside from helping with my demo files, maybe you can help me clarify the explanation, too.


                    Note the attachments table TO and portal, as shown on both the contacts and products layouts. The attachments portal only appears once on the graph, but the portals are identical.


                    Currently, we have a number of these common relationships like attachments where, for instance, contacts can have attachments, products can have attachments, activities can have attachments, objectives can have attachments, projects can have attachments... the list goes on. Other examples are activities, custom attributes and assignees, but there are many more. Setting this up, as things are now, is even more tedious, inefficient and repetitive than the way I wrote this paragraph.


                    As evidenced by the "activities" in the examples, tables like this aren't always clearly "parent" or "child". They can be linked to multiple things, and to one another.


                    The goal here is similar to that of selector/connector: Create a relationship from all "data" tables to the windows table (instead of an "all globals" table), in which we'll set the primary key of the record shown in a particular window of the current user's session. From there, related to common interface TO's, like related attachments, activities, custom attributes and the like. Other possibilities include the "system" (single record for settings) table, virtual lists used for navigation, and more.


                    The way this works in 13, and the way it works in 14 without separation, would allow whole chunks of functionality on layouts (whole tabs, if you will) to be copied and pasted across any of the data layouts, without TO proliferation and without having to repoint every portal, portal filter, field, hide when, tooltip, conditional format...




                    You create a contacts layout. It includes a tab with a portal showing attachments. Anther tab shows related activities. Another shows objectives ("tasks"). There's a popover with a portal of reports relevant to this layout and the logged-in user (could be virtual list, I'll leave that to your imagination). There's a link in the header for "not chris cain? click here to log out" that references the account record of the current user to get the user's full name (not bypassing security here; it's just related info, not passwords). the "normal" way to do this involves TO's like (pardon my naming convention) CON_ATT, CON_ACT, CON_OBJ, CON_RPT, CON_ACC_current...


                    Now you determine that you need a Projects layout in the same solution. Projects have attachments, activities and objectives. They have relevant reports, and the logged in user is still the logged in user. Now I need PRJ_ATT, PRJ_ACT, CON_OBJ, CON_RPT, CON_ACC_current... Also, to copy/paste the elements from the contacts layout to the projects layout, I need to repoint everything: fields, portals, portal filters, hide whens, conditional format...


                    BUT, if I could get this method to work, both contacts and projects would be related to the window table, and the primary key of the current record in that window, which is the only thing (or at worst, one of only a few possible things) I need to get to the right attachments, activities, objectives and so forth. The TO's for those would be referenced from common "interface" TOGs. No more TO proliferation. No more endless repointing.


                    Could I do without this? Sure, have been so far. However, if I could do this through the windows table, as I've modeled here, I'd be much more likely to make things like attachments, activities and so forth "universal", adding them wherever they might be useful, rather than confronting a time sink, and potential excess TO's, every time I decide to link something up. I'd also be more likely to innovate with new common relationships, functions and "layout widgets" if I knew I could painlessly put them wherever they might be useful.


                    Unfortunately, if you try this in 14, going through the inty file (separation model), it stops working. The session/window key consistently calculates correctly, but the relationship built on that key inexplicably stops working.


                    Like selector/connector, this would cut the TO count considerably (I'd estimate by more than half), and it would also make layout objects much easier to copy and paste, into what would normally be incompatible contexts. Unlike selector/connector, though, this has the potential to work even if the user has multiple windows open, or even multiple windows looking at the same layout.


                    (Not in any way dissing selector/connector, btw. It's brilliant, and the single window limitation isn't one that would affect many people. It's just that it affects us, so I'm trying to find a way around it.)


                    There are a lot of pieces in flux and in question at this stage, and I'm a bit too close to the effort, so it's hard for me to back up and describe the "big picture". Let me try again to list the moving parts:


                    • TOGs are "data" TOGs ("normal" anchor-buoy, with the anchors being the layout contexts) or "interface" TOG's, representing common related data elements found on many layouts
                    • A "windows" table contains a record for each "window instance" of each user session. (Again, normally we create a session record and set the key into a global on startup, but right now I'm using $$SES just as a placeholder, which gets set in both files).
                    • Window instances are set when new windows are open. The instance is retrieved by parsing the current window name. (In this case, I'm setting a number of BOM characters corresponding to the instance number. In our current development, we put the number in brackets at the end of the window name, but it does clutter the title. Regardless, I've tried this with the window title being nothing but the window instance number, and it doesn't make a difference.)
                    • Data TOGs are linked to the windows table where the calculated session window key (unstored) found in each data table equals the current key that is set in the windows table, with creation allowed on the windows side.
                    • Interface TOGs are linked to the windows table where the set current key in the windows table equals the foreign key in the interface table to be shown as related data.
                    • OnRecordLoad, the primary key of the record being loaded is set into the windows record for this session and window instance. If the windows record doesn't exist, it's created then.


                    BruceRobertson, when I put this out here for some expert opinions, you were just the kind of genius I had in mind, and your name in particular is one of the names that ran through my head as the ideal people from whom I'd like input. I'm sorry to drag you through these long (and apparently, not very clear) explanations. The problem of not being able to describe this well to someone like you is just as real a problem as not being able to actually accomplish what I'm aiming for (at least not with FM14 and separation). If I still having given you a better "inkling", I'd be thrilled if we could have a little back-channel chat (you know my number) and maybe you could at least help me describe the challenge better.


                    Chris Cain


                    • 7. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                      I'm confused by your descriptions: both of them. I can't see what the current window has to do with the display of the data. What is the reason for wanting to differentiate the relationship based on the name of the window?


                      In your demo data, the attachments windows display different data for each record in contacts and products. You have script triggers running onRecordLoad to move the current record ID into the windows table, so the current record ID is the effective ID. The only effect of the window ID is to prevent the user from viewing attachment data in two different windows simultaneously. That can't be the breakthrough you're looking for.


                      I've modified BruceRobertson 's files by changing the relationship keys between window - contacts and window - products. This model allows you to have multiple windows open, each viewing their unique data set in attachments. It's done that by taking the window key away from the relationship so I presume that it completely misses the point that you're trying make.

                      • 8. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                        While I still think you've misunderstood the method I was trying to use, this approach has promise. I'm still wrapping my head around it, and the ramifications, but growing more optimistic as I do.


                        (I apologize in advance, but I'm going to keep referring to the connector table as "windows" even though it looks like that name is destined for the scrap heap. It's confusing, but I think changing the name mid-thread might be even worse.)


                        The selector/connector uses a global field in a globals only record to set the current key. This is great unless you need multiple windows. What I was attempting was to create a record for each spawned window in a user's session. (I thought I had it, with FM13 and with a single-file FM14 solution, but not FM14 separated. I still think there's some odd behavior change here.)


                        What you've changed it to is that you get a record in the windows table for every record that's been looked at by any user. If left unchecked, this would mean a record in the "windows" table for every record in every other table). With the method I was attempting, it'd be unlikely that a single session would result in more than a few records, and unused records could easily be cleaned up. I was already concerned that these "windows" records could pile up, so I didn't even consider creating a record for every record a user groups. Now that you present this, though, I'm questioning whether this might be just as, or even more, manageable.


                        The possible record proliferation may not be a deal killer, if there's a way to identify "old" records in the windows table and delete them, so we don't end up over time with an unwieldy large table smack in the middle of the solution.


                        Perhaps, we could still add the session key. (I've checked, it's definitely the use of the window name, not the session key, that broke in my example with the behavior change.) I realize that a record with a current key in it will work equally well for multiple users, but we wouldn't ever be able to delete an old record without the risk unlinking a record that another user was looking at.


                        Adding a session key would, unchecked, mean even more records, but if there were a session key we could delete all these temporary records on log out, and/or have a server-routine to identify records that are left over from old sessions (because the user crashed without running the onLastWindow script). I might (might) even consider deleting those "windows" records as I leave a record, so long as it's not being viewed in another window... but I'd have to think of a way to minimize the performance hit, of course.


                        ToddGeist, in an earlier thread, was originally skeptical about using a table of actual records rather than a one-record globals record (which is why I was, and am, hesitant to let this table get very many records). Todd, perhaps you could chime in?


                        Consider my mind blown. I think I'm going to have to mull this over for a bit, but mostly just because it's a big shift. So far, this sounds like a good approach. If you (or anyone else) can come up with any potential pitfalls, please chime in. Also, if you still can't see the benefit I'm trying to get here, let me know. As I've said, my difficulty describing this is a challenge in its own right.


                        Suffice it to say:




                        Chris Cain


                        • 9. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                          I see what you are getting at, I think. Abstracted layout objects built to work in your ecosystem of solutions in a multi window environment.

                          I am moving away from multiple windows in general. Most of what I do does not need them. Although this idea has merit for single window as well.


                          Managing a session ID for each window seems to be the way to go. Possibly using a repeating global variable. Deleting these records with PSOS sounds like a good idea. Deleting the transient records based on date may be a good idea as well.


                          In window_testing (single file) having a second window open and changing records changes the data in the first windows record. I am assuming that should not happen.


                          It is a lot to get your head around for sure. The idea is simple enough, but the nuts and bolts of getting it to work is tough.

                          • 10. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                            In the file I posted the Windows TO is simply a conduit. As you realise, it would need a record for every record in every table that connects to Roles. If it were ONLY a conduit, and didn't have any other purpose it could be removed because it would be functionally equivalent to this diagram.



                            • 11. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                              Good point, but roles is just one of the most common tables we'd relate to. Not every "common interface" element would go through roles. Think virtual lists, primary record photos, etc. Also, I realized after my explanation that "custom attributes" don't go through roles; they are directly related to the records for which they apply.


                              Chris Cain


                              • 12. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                                Right. So the windows TO would be the hub that provided a one to one

                                join between the "universals" on one side and the data on the other. I

                                just wanted to be clear that unless the windows TO has other

                                functionality it is a spare wheel.

                                • 13. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                                  Once again, you've challenged some assumptions and potentially some "relics" of past things I've tried. Got my gears churning again.


                                  I'll have to get a little further along to figure out if that table really does need to do anything else. I'll have to try out some different scenarios. Discarding the "spare wheel" is now an option on the table, though, and seems a likely one.


                                  I'm still (and this isn't entirely because of this latest thought) concerned about linking "everything to everything". I know this method could substantially reduce TO proliferation, but I'm wondering about cases where FM needs to "check" everything related.


                                  For example, in the data file (where admittedly, with separation, this model wouldn't be used), data changes prompt updates and propagations to everything related, based on the dependency tree, and my understanding is that the "everything to everything" approach can cause a performance hit.


                                  I've also had the impression (although this could be bad assumptions, too) that on FM Go, particularly, layouts from isolated TOGs loaded faster and performed better.


                                  Malcolm, as my new favorite muse ( ), do you have any thoughts on this? Does anyone else?


                                  Chris Cain


                                  • 14. Re: Truly portable layout widgets in a multi-user, multi-window environment?

                                    Wait. Just as I posted, I think I found the reason for the "spare wheel". Since not everything would go through Roles (some things are just direct 1:M relationships) I can't relate, for example, both contacts and products to both roles and, say, virtual lists. This would create multiple relationship paths, and require additional TO's.


                                    I say this in a confident tone, but I keep finding out I'm wrong, so...


                                    Chris Cain


                                    1 2 Previous Next