The accompanying element-web PR with the config documentation should
explain what this is & why. Internally, this breaks the assumption
that call.roomId is the room that the call appears in for the user.
call.roomId may now be a 'virtual' room while the react SDK actually
displays it in a different room. React SDK always stores the calls
under the user-facing rooms, and provides a function to get the
user-facing room for a given call.
Note that this ditches all previously set width values, however this is probably acceptable for now. Trying to remain backwards compatible gets tricky on top of already tricky code, and the impact of Element forgetting widths is not as severe as forgetting which widgets were/are pinned.
Turns out that we were obliterating the entire store of widgets each time we loaded a widget, which is less than helpful. This commit fixes that.
This commit also improves the cleanup of the pinned event object to remove unpinned widgets, reducing accumulation over time.
Fixes https://github.com/vector-im/element-web/issues/15948
This is for https://github.com/vector-im/element-web/issues/15705https://github.com/matrix-org/matrix-react-sdk/pull/5459 was unable to track down all the instances of where the issue happens, so this commit tries to do a more complete job.
Specifically, this replaces the getRoomId() function given widgets cannot reliably be referenced by widget ID in this way, and the store has been updated to handle a more unique widget ID for the store (just in case).
Further sanity checking has also been added to ensure that we are at least returning a valid result.
This should also help https://github.com/vector-im/element-web/issues/15705 by either implicitly fixing the problem, causing chaos as described in the issue, or by forcing a crash to identify the problem more easily.
This should alleviate https://github.com/vector-im/element-web/issues/15705 from happening, though the cause is still unknown.
Requiring a room ID is safe for this because only room widgets can be pinned, and widget IDs are not globally unique which means from a logical standpoint the contract still makes sense here.
Fixes https://github.com/vector-im/element-web/issues/15745
This was surprisingly easy given the number of errors I remember last time, but here it is. This also includes an over-engineered VisibilityProvider with the intention that it'll get used in the future for things like Spaces and other X as Rooms stuff.
The security key naming/practice was misguided, so let's call it what it is (a settings key) and abstract away the complexity to a new store.
Fixes https://github.com/vector-im/element-web/issues/15820 while we're here.
The "remember my selection" option wasn't working because the `missing` set still included the approved permission. Solution: remove it from `missing`.
The customisation point is to allow forks to change which widgets get which additional capabilities dependent on their own rules.
Following https://github.com/matrix-org/matrix-react-sdk/pull/5385, it is now possible for a widget to request these capabilities without being a video conference or sticker picker. This commit actually enables this support for those kinds of widgets.
This commit also fixes an issue in the URL templating where some variables might get set to 'undefined' - this appears to be a scoping issue, so StopGapWidget now stores the definition alongside the superclass.
Fixes https://github.com/vector-im/element-web/issues/15001
TypeScript helpfully pointed me towards this dead code, which has been floating
around unused for a while. If we want to bring back ILAG in the future, we can
always revive it from history.
Prototype behaviour:
* If you can't create a room in the community, say so.
* The UX for this could probably be improved, but for now the intention is to not break muscle memory by hiding the create room option.
* If you can't change settings in the community, or can't invite people, don't show those respective options.
* Breaking muscle memory here is moderately okay.
Behaviour constraints:
* If you're not in the conference, use a grey button that does nothing.
* If you're in the conference, show a button:
* If you're able to modify widgets in the room, annotate it in the context of ending the call for everyone and remove the widget. Use a confirmation dialog.
* If you're not able to modify widgets in the room, hang up.
For this we know that persistent Jitsi widgets will mean that the user is in the call, so we use that to determine if they are actually participating.
This is a step towards https://github.com/vector-im/element-web/issues/13430
Since we've stored the invite, we can send the user to it once they reload the page or revisit Element. We currently only support one invite at a time, but this should be fine for most cases.
We only do this restoration if the next screen isn't set to avoid breaking the user out of an expected flow.
As an added touch, this also ensures that the email address is pre-filled on the registration page if needed, just in case the user refreshes before getting to the submit button.
As part of new device verification, we were waiting for "cross-signing ready"
which means _both_ the public keys are trusted by this device _and_ private keys
are available. There's no guarantee that the private keys will ever arrive, so
it's too strict to wait for this as a blocking flow. This relaxes things to wait
only for the current device to trust public keys.
Fixes https://github.com/vector-im/element-web/issues/14970
Ideally this would open up the group members panel, but that's exceedingly difficult. Instead, we switch to the general chat and rename the button to be a bit more helpful.
Fixes https://github.com/vector-im/element-web/issues/14848
When we're filtering the sticky room will be excluded from the filtered set, and thus won't even appear in the `getOrderedRoomsWithoutSticky()` result. Further, we will likely have to update the position ourselves to ensure the sticky room can be placed appropriately in the list.
Fixes https://github.com/vector-im/riot-web/issues/14798 (part 2)
This is in two parts itself: The `RoomSublist` needs to break its references to the `RoomListStore`, so it now clones the room arrays. The `Algorithm` is the other part, which is slightly more complicated.
It turns out that we weren't handling splicing as a change in the `ImportanceAlgorithm`, therefore the `Algorithm` wasn't really feeling like it needed to change anything. Further, the `Algorithm` was using the wrong reference to where it should be dumping rooms (`this.cachedRooms` is a getter which returns a different object depending on conditions), so having fixed that we need to ensure that the filtered and sticky maps are also updated when we remove a room. Because we send the new tag through a Timeline update, we'll end up updating the tag later on and don't need to update the filter and sticky collections.
The EchoTransaction was wrongly assuming that it knew better than the caller for when the success condition was met, so the echo marking has been left an exercise for the caller. In this case, we mark when we finally receive the sync with the updated rules.
We also have to cancel previous transactions otherwise if the user mashes buttons we could forever show the toast, and that would be bad.
The structure here might need some documentation and work, but overall the idea is that all calls pass through a CachedEcho instance, which are self-updating.
This reduces the update cost of rooms changing, and fixes a bug where when a sublist became filtered it would change the notification count of the sublist.
This does change the expected usage of the state store to ensuring that only one place updates the rooms on the list states, which is currently the room list store. Ideally the state store could listen to the room list store to update itself, however due to a complicated require() loop it is not possible.
In 9969b01c5f we stopped updating the sublist whenever we felt like it, which indirectly froze message previews for room tiles (badges, unread state, etc were unaffected because that is managed by a different store). To fix this, we simply have to listen for changes and perform an update.
We were taking 0.2ms to handle the registration of a timer per event during startup, even before the app is visible to the user. These timers would be short-circuited too, leading to a bunch of wasted time.
0.2ms isn't a lot of time, but multiplied by thousands of events at startup it's pretty significant.
On my account this reduces the full page spinner time from ~50 seconds to just over 20 seconds.
This means we're abusing the AsyncStoreWithClient to get access to a lifecycle, but overall that seems like a minor crime compared to the time spend abusing the store's state as a map.
With thousands of rooms shown, we can save on average 743ms per preview. The new preview time is 0.12ms on average.
Fixes https://github.com/vector-im/riot-web/issues/14694
Instead of spending 10-1000ms in a function iterating over a whole lot of room events, we can use our cached state from the Notification State Store.
This commit sets up a structure that could be applied to communities in the TagPanel too, as that could probably use a similar optimization.
This reduces the updateStatusIndicator() time to just 4ms on average.
Fixes https://github.com/vector-im/riot-web/issues/14475
Background: Sticky rooms are actually a pair of lies to the underlying algorithm as a combination of REMOVE_ROOM/NEW_ROOM calls so they don't get considered as needing to be sorted. When a room is added under the importance algorithm, it is expected that the category it is being added to will be re-sorted to account for the change, however we weren't doing that since we optimized the NewRoom path to be a splice operation.
Fixes https://github.com/vector-im/riot-web/issues/14091
Design needs work, however this is behind labs anyways. This re-implements the behaviour of the old room list.
The implementation ended up being a lot easier due to early confusion with what the TagOrderStore and TagPanel take care of. Turns out they don't deal with tags, but groups. As such, we don't need to do anything with filtering (though we keep some sanity checks in place for safety), and just have to wire up the CustomRoomTagPanel and CustomRoomTagStore.
We use `RoomListStore` as a singleton, and don't want the ugly `2` at the end of the actual store instance, so here we rename it to something half-decent.
Fixes https://github.com/vector-im/riot-web/issues/14442
Turns out that we are so good at moving a room that when it flows through as a TIMELINE update the algorithm no-ops and does nothing, so don't do that.
Fixes https://github.com/vector-im/riot-web/issues/14411
The act of setting/changing the algorithm was causing the update function to be marked, meaning we wouldn't trigger an update until something else happened later. To get around this, and still support internal functions spamming calls without multiple updates, we simply move the guts to an internalized function and make the public interface do a trigger.
For https://github.com/vector-im/riot-web/issues/14035
**This option is not recommended as it completely obliterates all chances of being able to support someone with a broken room list. It is intended for specific testing scenarios only.**
The room list does a hefty amount of work, so instead of blocking the event loop with a `/sync` request and a bunch of room updates (as we can get multiple per sync) we can instead run it over several smaller tasks. The smaller tasks help the event loop do other things between our tasks, ensuring we don't inadvertently block the UI from rendering too slowly.
On my account and machine, this cuts the time to render in half (~30ms, down from ~60ms) .
The core of this is in the MarkedExecution class, with the remainder of the commit ensuring that the right marks and triggers are in place to do the firing.
Because everything is async/await and run through the RoomListStore, we don't have to worry about self-fed updates in the algorithm classes. This also means we have to trigger pretty much all the time.
Changes to tag ordering / list sorting get hit through two paths, so we mark before we do a bulk update and otherwise assume the call is coming in from outside.
Known issues:
* Causes scroll jumps when the button gets added to DOM
* Resize handle is invisible when there's a show more button
TODO:
* Clean up comments
* Clean up useless code (all the padding stuff isn't needed)
For new rooms, we need to append to our list of known rooms. For tag changes, we need to be sure to update our cache when the tag can reasonably be assumed to have changed.
Fixes https://github.com/vector-im/riot-web/issues/14389
Fixes https://github.com/vector-im/riot-web/issues/14388
We were receiving a read receipt before a room object, leading to the algorithm to assume the room is archived (no membership), which was causing later index issues when the room tried to get moved from archived to untagged.
To prevent this, we just ignore nonsensical updates.
Previously we were creating a notification state whenever we needed one, which was leading to hundreds of listeners even on a small account. To ease the burden, and reduce the load of having to wake so many listeners, we now record a single listener for each tag ID and room combination.
This commit also introduces a number of utilities to make future notification work a bit of an easier transition, such as the `isX` and `hasX` getters on the new NotificationState abstract class. Similarly, "snapshots" have been added to reduce code duplication between different kinds of states checking for updates.
The ListNotificationState is now heavily tied into the store which offers it to help reuse the cache of room notification states.
Fixes https://github.com/vector-im/riot-web/issues/14370
This is more general maintenance than performance as the RoomList doesn't need to be generating layouts for the sublists, and it certainly doesn't need to be creating a bunch of extra ones.
The sublists are perfectly capable of getting their own layout instance and using it, and we are perfectly able to limit the number of these things we create through the session's lifespan.
In this demonstration, we remove the cutting line (as it collides with the tile in a weird spot) and instead replace the tile with a placeholder when the text is about to collide with the avatar in the tile. We use a `round()` for this because through some amazing coincidence the collision happens at 0.47, which is close enough to 0.5 for people not to notice.
Fixes https://github.com/vector-im/riot-web/issues/14378
Rooms transitioning between multiple states are often at risk of going missing due to the sticky room handling. We now protect that transition by bluntly ensuring the room can't go missing, and by always ensuring we have an updated reference to the room.
react-resizer appears to be okay at tracking state, but it often desyncs from reality. re-resizer is more maintained and more broadly used (160k downloads vs 110k), and appears to generally do a better job of tracking the cursor.
The new library has some oddities though, such as deltas, touch support (hence the polyfill), and calling handles "Enable".
For https://github.com/vector-im/riot-web/issues/14022
We don't need the fake clock anymore, but we do have to wait for async actions to complete before moving forward.
This also exposes a number of functions for the store to be puppetted with.
Fixes https://github.com/vector-im/riot-web/issues/14372
We read/use the options in multiple places, and those places were not in sync. Now when algorithms change and on initial load, both will come to the same conclusions about how to order & sort the rooms.
This fixes a case where a user accepts an invite, which causes a tag change, but the room stays stuck in the invites list. The tag change additionally gets swallowed when the user moves away, causing the room to get lost.
By moving it when we see it, potentially during a sticky room change itself (though extremely rare), we avoid having the room get lost in the wrong lists. A side effect of this is that accepting an invite puts it at the top of the tag it's going to (usually untagged), however this feels like the best option for the user.
A rare case of a tag change happening during a sticky room change is when a leave event comes in for the sticky room, but because it's come through as a tag change it can get swallowed. If it does get swallowed and the user clicks away, the tag change will happen when the room is re-introduced to the list (fake NewRoom event).
Plus a bunch of logging.
This fixes a case where switching rooms would cause the last room you were on to disappear due to an optimization where known NewRoom fires would be translated to tag change fires, which wouldn't re-add the room to the underlying tag algorithm.
By tracking the last sticky room, we can identify when we're about to do this and avoid it.
This commit also adds a check to ensure that we have the latest reference of a room stored as rooms changing from invite -> join change references.
This commit additionally updates the PossibleTagChange handling to be faster and smarter, leading to a more stable generation of the room list. We convert the update cause to a Timeline update in order to indicate it is a change within the same tag rather than having to jump tags. This also means that PossibleTagChange should no longer make it as far as the underlying algorithm.
New logging has also been added to aid debugging.
Fixes https://github.com/vector-im/riot-web/issues/14179
Disclaimer: this is all of the horrible because it's not meant to be here. Invites in general are likely to move out of the room list, which means this is temporary. Additionally, the communities rework will take care of this more correctly. For now, we support the absolute bare minimum to have them shown.
For example, if you only have 3/10 rooms required for the default then resize smaller, we should have a 'show more' button.
This works by changing the rendering to be slightly more efficient and only looping over what is seen (renderVisibleTiles(), using this.numTiles in place of tiles.length) and using a new setVisibleTilesWithin() function on the layout. Previously resizing the 3/10 case would be setting visibleTiles to ~8 instead of ~1 like it should (because the getter returns a default).
`setKnownRooms` is called to regenerate the room list, and if we don't take the sticky room out of the equation we end up with the room being duplicated. So, to make this easy, we simply remove the sticky room and handle it after the fact.
This small check just ensures that we aren't about to blindly accept that the calling code knows what it is doing. There are some unknown cases where NewRoom gets fired for rooms we already know about, so in those cases we just change it to a PossibleTagChange which is what the caller likely intended.
Many of the edge cases are unknown, though this can happen for an invite being accepted (for example). It's easier to handle it here instead of tracking down every single possibility and fixing it higher up.
When a new room is added there's a fairly good chance that the other events being dispatched will happen in the middle of (for example) the room list being re-sorted. This commit wraps the entire handleRoomUpdate() function for the underlying algorithms in a lock so that if we're unlucky enough to get an update while we're sorting (as the ImportanceAlgorithm splices out what it is sorting) we won't scream about invalid index errors.
We have to do a bit of a dance to return the sticky room to the list so we can remove it, if needed, and ensure that we generally swap the rooms out of the list.
This reverts earlier changes made to textForEvent as they are no longer needed.
This also implements an entire tree of textForEvent-like behaviour as the previews need to be different, which is easiest done with its own stack.
Smaller handle width, small shadow on the top of the show more button if there's more rooms to be shown. The resize handle also only shows when you're hovering in the area now.
The original design called for the shadow to show up only if the user is cutting a tile or dragging, however that is complicated implementation-wise. For speed and encouraging a dogfooding pattern we're going ahead with this behaviour instead.
For https://github.com/vector-im/riot-web/issues/14034
One of the largest issues with room switching was that we'd regenerate the entire list when the sticky room changes, which is obviously detrimental on larger accounts (and even some medium accounts). To work through this, we simply handle the NewRoom and RoomRemoved causes (used by the sticky room handling) as splices rather than in-place updates.
Overall this leads to a smoother experience as it means we're doing far less calculations and can even opt out of an update if it isn't required, such as a RoomRemoved cause being fired twice - the second one can result in an update not being required, saving render time.
This commit also includes a fix for handling update causes on the sticky room, as the room list loves to print errors when this happens. We don't need to handle any updates because once the sticky room changes it'll get re-added through NewRoom, causing the underlying algorithm to slot it in where needed, effectively handling all the missed updates.
When the user would click 'show more' they would be presented with a 'show less' button that occluded the last room.
Similarly, if they resized the list so that all their rooms would be shown and refreshed the page, they would find their last room covered by the button.
This changes the handling so that showAllClick() sets the height to numTiles + button padding, and adjusts the height calculations on render to deal with relative tiles.
This also removes the conditional padding of the resize handle, as we always occupy the 4px of space. It was leading to rooms getting trimmed slightly by the show N button.
This commit is a bit involved, as it factors the tag specific handling out of `/list-ordering` (and moves the `Algorithm` class one higher as a result), leaving it in the `Algorithm`. The algorithms for list ordering now only know how to handle a single tag, and this is managed by the `Algorithm` class - which is also no longer the base class for the list ordering. The list ordering algorithms now inherit from a generic `OrderingAlgorithm` base class which handles some rudimentary things.
Overall the logic hasn't changed much: the tag-specific stuff has been moved into the `Algorithm`, and the list ordering algorithms essentially just removed the iteration on tags. The `RoomListStore2` still shovels a bunch of information over to the `Algorithm`, which can lead to an awkward code flow however this commit is meant to keep the number of surfaces touched to a minimum.
The RoomListStore has also gained the ability to set per-list (tag) ordering and sorting, which is required for the new room list. The assumption that it defaults from the account-level settings is not reviewed by design, yet. This decision is deferred.
The 'sort by' radio buttons are blocked by https://github.com/matrix-org/matrix-react-sdk/pull/4731 as it contains the styles needed.
The 'unread rooms' checkbox is intentionally not hooked up. This is a more complicated refactoring that needs to be done.
The message preview checkbox works, though the previews remain hardcoded in this change. The primary intent of this change is to have a good enough context menu and the hover states.
The hover states are as described in the design.
This is to fix an issue where when using both the community filter panel and the search box it's an AND rather than further refining the results.
This makes the search box further refine the community filter panel results.
This all-new component handles breadcrumbs a bit more smoothly for the app by always listening to changes even if the component isn't present. This allows the breadcrumbs to remain up to date for when the user re-enables breadcrumbs.
The new behaviour is that we turn breadcrumbs on once the user has a room, and we don't turn it back off for them.
This also introduces a new animation which is more stable and not laggy, though instead of sliding the breadcrumbs pop. This might be undesirable - to be reviewed.
For https://github.com/vector-im/riot-web/issues/13635
This adds support for:
* Tag changes
* DM changes
* Marking our own rooms as read
* Our own membership changes
The remaining branch we didn't need was the alternate 'new room' branch, so it was removed.
This is not optimized - optimization is deferred.
Originally this was intended to be done only in the importance algorithm, however it is clear that all algorithms will need to deal with this. As such, it has been put into the base class to deal with as we may override it in the future.
This commit should be self-documenting enough to describe what is going on, though the major highlight is that the handling of the sticky room is done by lying to the underlying algorithm.
This has not been optimized for performance yet.
For https://github.com/vector-im/riot-web/issues/13635
For https://github.com/vector-im/riot-web/issues/13635
This is an incomplete implementation and is mostly dumped in this state for review purposes. The remainder of the features/bugs are expected to be in more bite-sized chunks.
This exposes the RoomListStore on the window for easy access to things like the new filter functions (used in debugging).
This also adds initial handling of "new rooms" to the client, though the support is poor.
Known bugs:
* [ ] Regenerates the entire room list when a new room is seen.
* [ ] Doesn't handle 2+ filters at the same time very well (see gif. will need a priority/ordering of some sort).
* [ ] Doesn't handle room order changes within a tag yet, despite the docs implying it does.
Sorting and ordering has now been split apart. The ImportanceAlgorithm also finally makes use of the sorting.
So far metrics look okay at 3ms for a simple account, though this could potentially get worse due to the multiple loops involved (one for tags, one for categories, one for ordering). We might be able to feed a whole list of rooms into the thing and have it regenerate the lists on demand.
This is the fruits of about 3 attempts to write code that works. None of those attempts are here, but how edition 4 could work is at least documented now.
This is to get around the problem of a slow dispatch loop. Instead of slowing the whole app down to deal with room lists, we'll just raise events to say we're ready.
Based upon the EventEmitter class.
This does a number of things (sorry):
* Estimates the type changes needed to the dispatcher (later to be replaced by https://github.com/matrix-org/matrix-react-sdk/pull/4593)
* Sets up the stack for a whole new room list store, and later components for usage.
* Create a proxy class to ensure the app still functions as expected when the various stores are enabled/disabled
* Demonstrates a possible structure for algorithms
If you clicked on the header button whilst the right panel was
showing a room member, it would NPE because there was no
refireParams.member. It fires the same phase with no refireParams to
toggle the panel visibility (apparently), so detect that case.
Fixes https://github.com/vector-im/riot-web/issues/13571
Wait for our user to become verified and cross-signing to be ready
before declaring that we're finsihed, otherwise we could end up
prompting the user to verify again if we just wait for the verification
itself to complete.
Fixes part of https://github.com/vector-im/riot-web/issues/13464