Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context menu items EPIC #21

Open
11 tasks
thomasgwatson opened this issue Oct 22, 2024 · 12 comments
Open
11 tasks

Context menu items EPIC #21

thomasgwatson opened this issue Oct 22, 2024 · 12 comments

Comments

@thomasgwatson
Copy link
Collaborator

thomasgwatson commented Oct 22, 2024

"ContextMenuWidgets": sections of the ContextMenu that display data and point to different views

Sources from the product spec as of 22OCT24:
These things can be:

  • Renamed from their default label (default label can be translated however => better for i18n)
  • reordered
  • added to and removed from the context menu (Are there any limits? There must be at least one? There must always be a
    'home' section?)
Naming

Section sounds like the container for these things in the html, as opposed to what they are. At a minimum, I'd prefer to refer to them as something more specific, like 'MenuSection'. If one searches 'section' in the repo, one gets lots of references to 'sections' in parts of the app that...

Will work with them being called ContextMenuWidget for now

Requirements

Each ContextMenuWidget must have:

  • a title/name
  • a type
  • variant (for 2nd phase)
  • an order (I need to look at dnd-kit to understand its implementation)
  • A way to define or connect to it's contents
  • Their contents are not 'type' constrained; they can include a chat, a custom link (This is currently not supported by customviews, so might have to be punted)

Categories of ContextMenuWidgets

  • single item (ungrouped): a direct link to a view. Similar to the prior Hylo menu items.
  • grouped view list: A list of views. Each view has some activity indicators
  • (?) grouped list, with platform additions: An ordered list that is editable but occasionally the platform appends something to
  • grouped content list: A list of content. Links directly to that content, so we have to figure out whether it also renders a view underneath the content. If its a chat, than yes that chat room... for posts: since all group content could plausibly go into the general chat, perhaps it is just that.
  • Special cases: Map view, members view (includes an action), calendar
Running lists of them:
  • member section (possibly several variants in the future) Basically a member list with an optional 'invite' button
  • "what's going on?/¿que pasa?" section
  • Chat section (for a list of chats) "What people are talking about"
  • Map widget (2nd phase?) "Near you"
  • Group list (list of groups) "Groups to join"
  • Group steward widget "Grow your group" (Only viewable by stewards for now)
  • Simple lists (content or views)
  • Events (link and shows events happening in the next few days)
  • Calendar (2nd)
  • About section (points to Purpose, Group Agreements, a Custom post)
  • Custom views
  • Is the HOME view its own section?
  • Legacy streams (projects, events, asks, offers, proposals, moderation actions)

Architecture

Goal: We have to have UI/UX that makes the common things a group wants (or expect from prior experience) easy to access.

A ContextMenuWidget could point to:

  • managed collection of things (can be ordered)
  • queried collection of things (can be sorted)
  • The above with special display or actions

Which things:

  • content (posts, all types, including new ones like group-activities)
  • groups
  • members
  • special views
  • tracks (in future)
  • custom views (many-to-many)

CustomViews (which point at: a collection of posts, a query/stream or an external link) cover some but not all of these needs...

Covering off on what we want to deliver in 1st phase:

Managed collections

  • Chats (managed collection)
  • About section (special display widget with optional collection)
  • Group steward widget (??? maybe a place to introduce actions?)

Queried collections

  • Member list (queried collection plus optional invite button)
  • Recent activity (queried collection)
  • Group list (queried list)
  • Events (queried collection with special display, if event is just about to happen)
  • Proposals (queried collection with special display, if event is just about to happen)

Others

  • what's happening (lots of behavior questions)
  • Home section (single option)
  • Simple lists (custom views)

So thinking about how to model all of this; some options
Option A: model ContextMenuWidget in db; hard-code what to do with common views, point at custom views
Option B: model ContextMenuWidget in db; create CommonView to model the legacy views, point at custom views

Leaning towards just doing Option A for now

UI/UX implementation

If we go crazy on multi layered dnd
https://www.reddit.com/r/reactjs/comments/16ogvr6/nested_sortable_lists_multiple_containers_with/

Only doing one layer of dnd (drag and drop) for phase one, for re-ordering widgets

Tracking 'recent activity'

What needs to be included? What data is available? What counts as 'recent' for the number counts?
Going to punt on figuring this part out until we have the rest of the context menu pieces in place

@tibetsprague
Copy link
Collaborator

Widget does give us more flexibility, since it looks like we may have one that displays the map. How about we call them ContextMenuWidget

@thomasgwatson
Copy link
Collaborator Author

thomasgwatson commented Oct 23, 2024

Database and backend summary

new table context_menu_widgets

  • id
  • name
  • group_id (each widget can only below to one group)
  • type (Need a solid list of options for this)
  • variant
  • order
  • contents_order (might be required for some use-cases, we need to clarify)
  • visibility (could just be a relationship to responsibilities)

Each ContextMenuWidget can have many-to-many relationships to CustomViews

new table context_menu_widgets_custom_views (🥲)

  • context_menu_widget_id
  • custom_view_id
  • order

GraphQL

Will need to model a ContextMenuWidget in the graphQL schema.

CMWidgets are containers for

  • groups
  • users (members/moderators)
  • posts (with a comment, in case that is the relevant content)
  • tracks (future)
  • customViews (which are in turn can possibly be containers of things)

@tibetsprague
Copy link
Collaborator

i think we want to do this more like the current architecture for Widgets, which has a widgets table that has a name and type, and then a GroupsWidgets table that links the widget to the group and contains things like the order, customized name, and other settings. In fact, i wonder if we could just reuse/replace the current Widgets tables! May be more trouble than its worth but we are probably going to remove them because explore is going away. I guess what you are saying above is that maybe we dont need the Widgets table at all, we just use the type column to differentiate the widget types and then the UI handles all the display stuff including the default name for each widget type? That may work 🤔 Pondering whether there is value in the database knowing about all the widget types and names...

Similarly, do we need to track the common views in the database too, like Events, Projects, Map...? Because at least in the Views widget you will be tracking an order of the views, and maybe it makes sense to have just a an ordered list of view ids for this, and whether they are common or custom? Otherwise it will be an ordered list of some Custom Views by id and some common ones by name, which is a little weird, though ok.

@lorenjohnson
Copy link
Member

lorenjohnson commented Oct 25, 2024

i think we want to do this more like the current architecture for Widgets, which has a widgets table that has a name and type, and then a GroupsWidgets table that links the widget to the group and contains things like the order, customized name, and other settings. In fact, i wonder if we could just reuse/replace the current Widgets tables! May be more trouble than its worth but we are probably going to remove them because explore is going away. I guess what you are saying above is that maybe we dont need the Widgets table at all, we just use the type column to differentiate the widget types and then the UI handles all the display stuff including the default name for each widget type? That may work 🤔 Pondering whether there is value in the database knowing about all the widget types and names...

Similarly, do we need to track the common views in the database too, like Events, Projects, Map...? Because at least in the Views widget you will be tracking an order of the views, and maybe it makes sense to have just a an ordered list of view ids for this, and whether they are common or custom? Otherwise it will be an ordered list of some Custom Views by id and some common ones by name, which is a little weird, though ok.

I am not looking too carefully here so take what I say with a grain of salt... But I do think it is easier to maintain/manage/grok/develop generally if UI stuff is mostly handled in code with the absolute minimum coming from the database to shape what is displayed. So... generally the direction this is headed, if it is moving defaults and logic into components out of data this is great where possible, and obviously there is some customisation that is per member or group that is requiring the database storage so maybe I am likely not saying much.

@thomasgwatson
Copy link
Collaborator Author

thomasgwatson commented Oct 26, 2024

Ok, this is my current thinking. It is based on centering the interface (the graphQL schema type definitions), and focusing on ensuring we can smoothly model the ordering and grouping within the ContextMenu.

ContextWidget as graphQL model

We can model the groupings and views of the context menu with ContextWidgets

To map the nesting and order of the ContextWidgets in the menu, they need to have (GraphQL schema):

  • name/title: String
  • order: Int
  • parentId: ID (another ContextWidget or null)
  • groupId: ID
  • userId (future): ID
  • contextWidgets: [ContextWidget]

These are just what is needed to position the ContextWidgets.

Simple tree model

In this model, we can think of the group (the context in question) as a trunk of a tree. The group has a collection of ContextWidgets. Each of these views branch off that metaphorical trunk, in order. Each of these branches is rendered based on whether they terminate (there are no more child contextViews) or if they branch once more (they have child contextViews). For the purposes of our UX/UI needs, by convention, there will never be grandchild contextViews.

Views as leaves

Every one of these branches terminates in a leaf; for the purposes of our UX, these leaves are views. They represent a wide range of things:

  • a group
  • a user
  • a post
  • a customView
  • a view of groups (child/parent groups)
  • a view of x (posts of a specific type)
  • a track (future)

We can think of ContextWidgets being a wrapper to the views that exist on the platform, allowing these views to be manually ordered and grouped. This does not imply that all widgets will be orderable. Some are connected to queries that do their own ordering

To model the leaf part of the contextWidget in the graphQL schema, we must add other fields

  • type: String
  • icon: String
  • user: User
  • chat: Topic (?)
  • post: Post (need to figure out how to be able to focus on a comment)
  • CustomView: CustomView
  • group: Group
  • view: String
  • chat: Topic

Functionally, a ContextWidget can only have one of these child entities or a collection of ContextWidgets that in turn terminate into one of these entities

  • a user
  • a group
  • a chat room
  • a CustomView
  • a view (/map or /proposals etc)

The user, group, chatrooms and customView exist as entities in the DB. Each of those pass real values from the db that basically allow for a url or navigation action (recall that this must work for the mobile app as well) to be created. Click on the ContextWidget, and the main panel displays the result.

The view value here is synthetic (exists in the graphQL schema but not in the database), in the sense that it will be hardcoded in web/mobile/backend to point to a specific stream/query. No actual graphql query will be exposed via this interface.

Each one of these child entities will need to expose some sort of metric/number, that gives some sense of 'recent or unread activity'. Exactly what is somewhat underdeveloped from a product perspective.

Special rules

Some of these ContextWidgets will need to respond to specific rules. Like whichever one represents the 'home' view, will always be order 1. Or some view types must always be present. This needs to be fully fleshed out

Rendering

A ContextWidget will render different UI based on what it is;

If its a collection of other ContextWidgets, it will be a grouping. This grouping will in turn render the children elements in either a list or grid

Screenshot 2024-10-26 at 1 57 43 PM

If the contextWidget has no ContextWidget children, it will render the view referenced directly.

Screenshot 2024-10-26 at 2 01 19 PM

The ContextWidget rendering will also hard-code special UI/UX pieces to certain views:

Screenshot 2024-10-26 at 2 09 49 PM

Kitchen Sink/ 'All view'

This is a catch-all list of views; it means that no matter how stewards have composed the context menu, contents of the group can still be accessed. This is now easy to model/query; its just a request for all the collectionViews that are leaves, and rendering them in a grid. What about possible views that aren't included in the menu? Either these are covered by all the different views in the fabled "what's happening" grouping OR we create ContextWidgets for ALL of the different common views for a group, and leave them unordered (aka, order = null).

Screenshot 2024-10-26 at 2 12 26 PM

Extensibility

The group context is the main context, but this data model could easily allow us to model ordering and grouping in other context menus as well, such as the 'my home' context. It could also fairly easily be able to model ordering (and maybe grouping, depending on need) of items in the GLOBAL menu.

@tibetsprague
Copy link
Collaborator

This is cool, but feels a little too abstract maybe? I think the ContextMenuWidget version is easier for me to understand and reason about. For example, why would you need a ContextView for a single post or user? That seems like an unnecessary abstraction. And when would a context view contain a "query"? I think each widget is different enough that we should handle them differently. Unless you are thinking that someone may want to create a grid of subgroups, or a map of just the events? I suppose i could see that. We do need to think through the configuration UI and make sure this is not too complex for folks though. Have to balance flexibility with ease of setup/use. Also I think the name is too similar to CustomView. But lets talk it through so i can see what you are seeing!

@thomasgwatson
Copy link
Collaborator Author

thomasgwatson commented Oct 29, 2024

For example, why would you need a ContextView for a single post or user?

Its a way to model leaves consistently.

These are examples of users or single posts as leaves in the current designs

Screenshot 2024-10-29 at 10 49 57 AM
Screenshot 2024-10-29 at 10 51 03 AM
Screenshot 2024-10-29 at 10 54 34 AM

User stories:

  • As a steward, I want to have a menu item "READ THIS FIRST"
  • As a guru that charges access to my group, I want my profile and avatar in the menu

These are just simple examples to answer your question but they are not the basis for why I am suggesting ContextViews; this makes sense because of the overall requirements for the context menu.

I think each widget is different enough that we should handle them differently.

The idea of ContextWidgets is primarily about ordering them and grouping them. The differences between widgets can easily be modelled based on the ContextWidget proposal. The rendering (the actual Widget component) will be different; it will just be a lot easier to punch out those different units if we have a consistent interface across them.

Widgets have these things in common:

  • they need to be orderable
  • they need to be groupable
  • They point somewhere (they are themselves a leaf) or they contain a list of things that point somewhere

The more we can create a consistent, cross-platform abstraction for these concerns, the smoother the experience will feel to us and users. When you clarified that the contents of these widgets could themselves be 'promoted' to being a widget, it really pushed home the benefit for these having a consistent interface/data model.

We do need to think through the configuration UI and make sure this is not too complex for folks though. Have to balance flexibility with ease of setup/use.

Of course, one of the driving motivations behind ContextWidgets.

@thomasgwatson
Copy link
Collaborator Author

Changed name from ContextView to ContextWidget

@thomasgwatson
Copy link
Collaborator Author

So, periodically we will change something about a group's context menu based on some change in their content.

EG:
someone posts the first event to the group, now we show the events in the menu
someone posts something with a location, now we show the map in the menu
etc

I have considered two ways to track this, one that is content-centric and one that is group-centric:

Whenever someone creates/edits content to a group (or group relationship), there is a validation that runs each time for any group the content is posted to.
We run a cron job that does a variation of this validation

Option 1
only has to scan groups directly addressed by the content
but has to run on every post creation/edit or group relationship creation/edit (can probably skip chat posts, since those defacto need to be a different type of post to trigger one of these changes)

Option 2
Has to check every group that has the auto-view widget (aka What's happening), since that is where these views are placed (alternatively, if the group has removed this widget, we could send the stewards a message that a new view/widget has become active, if they want to add it manually to the menu)
Probably needs to store a cursor for each group, to ensure its not trying to check the rules for every piece of group content from the start of time
An advantage of this one is that is can be run after we port groups to the new context menu setup, and automatically get the groups menu parity

Any thoughts on the impacts of either choice? Given that the second option works as a migration as well, I'm inclined to do it. Otherwise Option 1 will likely need to be paired with some other migration function/method

@tibetsprague
Copy link
Collaborator

Ok so let me lay out my current thoughts, which honestly may align quite well with yours above, but im not quite sure yet. The context menu is basically a list containing two types of Widgets: 1) A single item (which I think we can just call a View) widget 2) A collection of views. There are several types of Views, which I think can probably all be contained by the Custom Views table, which maybe we rename to Views:

  • External Link - just a URL
  • A filtered query of posts - what we call a Stream Custom View right now
  • A curated set of posts, which can be automatically or manually sorted - currently called a Collection type of Custom Voew
  • A chat room - which is a named space (probably still connected to a Topic) for creating posts and the only place that chat posts appear. Currently this is a GroupTag row in the database, we are deciding whether to still use that with a column that indicates it is a chat room, or create a new table, or maybe just a new Custom View type?
  • The members view is a unique one that lists all the members in the group
  • The related groups view is a unique view that lists all related groups.
  • We could possibly have a view that is a link to a specific group (related or not related potentially). Not sure if we actually want/need this or not.
  • We could possibly have a view that is a link to a specific member of the group (unlikely)
  • We could possibly have a view that links to a specific post - like a pinned post
  • Future: An embedded iframe, like a Kumu map, or Miro board

A single view widget can either just be a link to that view, or can be displayed in different ways in the Context Menu, for example a map widget could be used for any filtered query set or curated set of posts. Similarly you could have a task list or mini calendar view connected to a query or curated set of posts. Another example is the members widget which is a unique

A collection widget displays a series of views either in a list, or a grid, with an order that could be manually set or potentially algorithmic (like the default Whats Happening that adds new views as you do things in the group).

So maybe we can pull this off with two database tables - GroupsViews, and GroupsWidgets. Each with a type column that the UI uses to decide how to display. The GroupsViews table would have types of: Link, PostQuery, PostCollection, Chat, Members, Groups, Group, Member, Post, Embed.

The GroupsWidgets table would have types of: SingleItem, ViewCollection, Map, Tasks, Members, Groups, Calendar...

How does that sound?

@tibetsprague
Copy link
Collaborator

i think this is very similar to what you describe above, though maybe a bit simpler?

@thomasgwatson
Copy link
Collaborator Author

Sorry I should have updated and explained that I've implemented ContextWidgets already, with mutations and graphql updates, and have a nice test set for them already.

So how I read this suggestion:

  • extending custom views to be just views (custom views are defacto GroupViews, or are you suggesting there to be a Views table as well? I think by the end of it you are just settling on it being GroupViews)
  • Redefining GroupWidgets
  • So at least two tables, and so two sets of models, two schemas, etc.

Generally, I don't find this compelling. If it was really compelling in some way, I'd consider abandoning the couple of days of implementation work on the ContextWidget setup. As far as I can infer, there aren't any behaviors or functionality that it offers over the ContextWidgets direction, and it creates more code and more changes to the db by needing two database tables to change/be created.

If you want to change something about custom views (maybe we should?) ContextWidgets will work with that easily, and they don't rely on it. I don't think the desire to change something with CustomViews needs to change how we handle the context menu.

From a UI perspective, this would imply that when a steward moves a view from being a child of a collection to being a widget, and/or back, we are creating and deleting GroupWidgets for this operation. For ContextWidgets, its just an update call, because its the same entity but just repositioned. This is easier to model in the optimistic updates that will be required in urql or redux. In short, we are juggling the relationships between two similar entities, instead of just modeling them as the one entity.

Additionally, I think we can extend ContextWidgets to model the navigation of the home context (here is belongs to a userId not a groupId) and even the global context, with the addition of a context 'column'.

Even if we are not offering customization of those things straight away, this simplifies the UI components we have to build; they can just expect a set of ContextWidgets and render them like any other, whether those data-structures are coming from the db or hardcoded behind a hook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants