Skip to content

[WIP] Browser, Workfiles: Activity tab in the side panels - #2147

Draft
BigRoy wants to merge 18 commits into
developfrom
enhancement/browser-workfiles-activity-tab
Draft

BigRoy wants to merge 18 commits into
developfrom
enhancement/browser-workfiles-activity-tab

Conversation

@BigRoy

@BigRoy BigRoy commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Warning

WIP - prototype to get a sense of how viable this is in production. Not ready for review of the details, feedback on the approach is welcome.

Changelog Description

Add an Activity tab to the Browser inspector and to the Workfiles side panel, to give access to comments and other activity without cluttering the tools or making them wider.

  • Browser: the inspector keeps the path and thumbnail, the space below switches between Details (the content it had) and Activity of the selected versions.
  • Workfiles: the side panel gets the same two tabs. Activity shows the selected task, or the folder until a task is selected.

Browser inspector, Details and Activity tab:

Browser inspector

Workfiles side panel, Details and Activity tab at 280px, and Activity at the default 190px:

Workfiles side panel

Rendered offscreen from the real widgets with sample data.

Additional info

Part of a stack:

  1. UI: Activity feed styling and activity stream component #2145 UI: Activity feed styling and activity stream component, targets develop, includes the avatars of UI: Show user avatars in the activity stream #2146 which is merged into it
  2. [WIP] Browser, Workfiles: Activity tab in the side panels #2147 Browser, Workfiles: Activity tab in the side panels (WIP), targets UI: Activity feed styling and activity stream component #2145 (this PR)
  3. [WIP] Scene Inventory: Version history panel #2148 Scene Inventory: Version history panel (WIP), targets [WIP] Browser, Workfiles: Activity tab in the side panels #2147
  • Nothing is fetched until the Activity tab is shown, and the feed is fetched in the background.
  • The feed has the latest 50 activities made on the entity, mentions of it and activity of related entities (e.g. versions published from a task).
  • In the Browser, activity is not shown for a selection of more than 20 versions.
  • In the Browser, a label above the feed names the product and version the activity is of, or the count of selected versions. A selected product group shows the activity of its featured version.
  • User avatars come from the UserAvatarCache that the views of the Browser, Workfiles and Launcher already use. It downloads into the image cache on disk, which is shared by all AYON tools and processes of the user, so an avatar is downloaded once per machine.
  • ayon_api.get_activities(limit=...) crashes in released ayon_api versions, fixed in Fix 'get_activities' crashing when 'limit' is passed ayon-python-api#365. The limit argument is not used here so it works with the ayon_api of current launchers.

New pieces:

  • AYTabBar: tab strip for side panels.
  • ActivitiesModel (backend, tools/common_models): fetches the feed and returns serializable ActivityItems (to_data() / from_data()). It has no ayon_core.ui or Qt import.
  • ActivityWidget(controller): the stream with background loading. It only talks to the controller of the tool, through the ActivityController interface: get_activity_items, get_project_status_items, get_user_items and get_version_thumbnail_path. It converts the items to the UI models, and creates a UserAvatarCache unless one is passed (the Browser inspector shares the cache of the table).
  • A refresh keeps the displayed feed until the new one arrives, so the rows of the stream are reused and the scroll position is kept.

Backend / frontend separation

The Browser and Workfiles tools keep the frontend behind a controller, so it can run over IPC at some point. Done in this PR:

  • ActivityWidget requests the feed through the controller of each tool, the model is owned by the backend controller.

  • ActivitiesModel returns its own serializable items, converted to the UI models in the frontend.

  • Entity ids are list[str] | set[str].

  • Version thumbnails go through the controller with project name, version id and thumbnail id as arguments. The feed has no download code of its own: the Browser uses its existing thumbnail loader, Workfiles the shared ThumbnailsModel.

  • Project statuses and users come from the ProjectsModel / UsersModel of the controllers.

  • Everything of the activity in the Workfiles side panel goes through its controller.

  • Version thumbnails are downloaded by the backend for both tools, through the shared ThumbnailsModel into the thumbnails cache on local storage (ayon_core.pipeline.thumbnails). That cache is shared by all AYON tools and processes of the user, so a thumbnail is downloaded once per machine. The Browser no longer downloads thumbnails in its frontend, its table, cards and inspector ask the controller too.

  • The Browser queries project users once: the table takes the names from the UsersModel that also serves the feed.

Still open:

  • The Browser keeps a second copy of a thumbnail in the UI ImageCache, which its thumbnail widgets use to show an image by key without waiting. It is filled from the path the controller returns, not by a download.
  • User avatars do not go through the controller: UserAvatarCache downloads them in the frontend, the same as it does for the views of Workfiles and Launcher on develop. The avatars cache on local storage and get_user_avatar_path of the controllers, which an earlier state of this PR had, are removed to not have a second way to download and store the same images.
  • Each view creates its own UserAvatarCache (the Browser inspector shares the one of the table). Only the rendered pixmaps are per instance, the downloaded images are shared.
  • Statuses are requested from a worker thread, so the events of ProjectsModel are emitted from that thread. In Workfiles that happens on every load of the feed.
  • The review desktop still downloads thumbnails and avatars with its own data manager, it does not use these caches.

Functionality:

  • Read-only: no posting, editing or deleting of comments.
  • Image attachments and annotations of comments are not shown.
  • No "load more" past the latest 50 activities. The backend does not report anymore that there are more than it returned, that has to come back for this.
  • Comments that mention the entity show as plain comments, without the "mentioned version on ..." header of the web frontend.
  • The selected tab is not remembered between sessions.
  • Decide on the reference types queried for a task and folder (origin, mention, relation).

Testing notes:

  1. Open the Browser from a host or the tray, select a version that has comments and click the Activity tab of the inspector.
  2. Select multiple versions, the feed shows the activity of all of them.
  3. Group the Browser by product and select a product group, the label above the feed names the featured version the activity is of.
  4. Open the Workfiles tool, select a task that has comments or published versions and click the Activity tab of the side panel.
  5. Select only a folder, the feed shows the activity of the folder.
  6. Resize the side panels narrower, the feed should stay readable.
  7. Run ./tools/manage.sh run pytest tests/client/ayon_core/tools -v

@BigRoy BigRoy added type: enhancement Improvement of existing functionality or minor addition ui labels Oct 5, 2026
@BigRoy BigRoy self-assigned this Oct 5, 2026
@BigRoy
BigRoy requested a review from iLLiCiTiT October 5, 2026 10:09
@ynbot ynbot added the size/M label Oct 5, 2026
@BigRoy
BigRoy requested a review from LiborBatek October 5, 2026 10:24
@BigRoy
BigRoy force-pushed the enhancement/browser-workfiles-activity-tab branch from c9c494b to 586808e Compare October 5, 2026 10:27
@BigRoy
BigRoy force-pushed the enhancement/activity-stream-avatars branch from 8984ead to d512079 Compare October 5, 2026 10:27
@BigRoy
BigRoy force-pushed the enhancement/browser-workfiles-activity-tab branch from 586808e to 60ff137 Compare October 5, 2026 10:55
@BigRoy
BigRoy force-pushed the enhancement/activity-stream-avatars branch from d512079 to 95f5631 Compare October 5, 2026 10:55
if not content.is_valid:
return ""
is_jpeg = content.content_type and "jpeg" in content.content_type
with tempfile.NamedTemporaryFile(

@iLLiCiTiT iLLiCiTiT Oct 5, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the thumbnail be stored using ImageCache logic? This just add another way how the thumbnail are downloaded, to a different place using different logic.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That function is gone (bf5310a), there is no separate download code for the feed anymore. The widget asks its controller, and each tool answers with the thumbnail loading it already has:

  • Browser: the existing _thumbnail_loader of _browser_thumbnails, so the same ImageCache entries as the table, the cards and the inspector (ab8618d).
  • Workfiles: ThumbnailsModel from common_models, the one the Loader controller uses, with a new get_thumbnail_path() for a known thumbnail id (62fad62, 03dc40c).

So no new way of downloading, but the two tools still store thumbnails in two different caches, as they did before this PR (UI ImageCache in the Browser, the pipeline thumbnails cache in the Loader and now Workfiles). In the Browser the method also lives on the Qt-side BrowserWidgetController, because its thumbnail loading is frontend code today. If you would rather have one cache behind a backend model for both, I would do that as a follow up, it is listed in the to-do of the description.

Comment thread client/ayon_core/tools/common_models/activities.py Outdated
Comment thread client/ayon_core/tools/common_models/activities.py Outdated
Comment thread client/ayon_core/tools/utils/activity_widget.py Outdated
Comment on lines +136 to +143
controller.register_event_callback(
"selection.folder.changed",
self._on_folder_selection_change,
)
controller.register_event_callback(
"selection.task.changed",
self._on_task_selection_change,
)

@iLLiCiTiT iLLiCiTiT Oct 5, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should not be needed. The context is changed with "selection.representation.changed" and "selection.workarea.changed", or no?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are needed for the activity, as far as I can tell from the selection model. Both of those events are only emitted when the selected file changes:

  • set_selected_workfile_path() returns early when the path is the same as before, so "selection.workarea.changed" is not emitted when you go from one task to another and no workfile is selected in either (path None -> None).
  • set_selected_representation_id() does the same for "selection.representation.changed".

The details of the side panel are about the selected file, so those two events are enough there. The activity is about the task (or the folder until a task is selected), and should update when the task changes even if the workarea is empty, which is the case where there is no file event. That is why it listens to "selection.folder.changed" and "selection.task.changed".

This is from reading models/selection.py, I have not confirmed it in the running tool yet.

@BigRoy
BigRoy force-pushed the enhancement/browser-workfiles-activity-tab branch from 175dc9f to 265a91b Compare October 5, 2026 14:04
Base automatically changed from enhancement/activity-stream-avatars to enhancement/activity-stream-component October 6, 2026 10:40
@BigRoy
BigRoy force-pushed the enhancement/browser-workfiles-activity-tab branch from 265a91b to d5ca2fd Compare October 7, 2026 16:13
BigRoy added 8 commits October 7, 2026 20:46
The Browser inspector and the Workfiles side panel get a
Details | Activity tab pair, so the activity of the selected versions
or task is available without making the tools wider. The feed is only
fetched while its tab is visible.
The widget creates a cache only when none is passed. The Browser
inspector uses the cache of the table, so avatars are not downloaded
and rendered twice.
'get_activity_items' returns backend items with 'to_data' and
'from_data' instead of the UI models, so activities can be passed
from a controller to the frontend. Entity ids are a list or a set,
which can be converted to json.

The feed of UI models is kept until the activity widget stops using it.
'get_thumbnail_paths' queries the entities to find their thumbnail ids.
That is not needed when the thumbnail id is known, e.g. for versions
of an activity feed.
The backend controller owns the activities model and exposes the
activity and user items. The widget controller forwards them with the
project statuses, and gets version thumbnails the way the table and
the inspector do, from separate project name, version id and
thumbnail id.
The controller owns the activities model and exposes the activity and
user items to the frontend. Version thumbnails are loaded by the
thumbnails model, as in the Loader. 'get_project_status_items' was
implemented already, it is now part of the frontend abstraction.
The widget takes the controller of the tool as a required argument and
does not create a model. 'ActivityController' describes the methods it
needs, so other tools can implement them.

Activity, status and user items of the controller are converted to the
models of the activity stream in the frontend. Thumbnails of published
versions are requested from the controller with their project name,
version id and thumbnail id.
BigRoy added 5 commits October 7, 2026 20:46
The model returned UI models, converted with a function of a module
that imports Qt, and cached project users and statuses on its own.
The activity widget gets those from the controller now, so the model
only fetches activity items and does not import the frontend.

Version thumbnails were downloaded by a function next to the model,
they are loaded by the controllers too.
The model does not import the frontend anymore, so it can be imported
from the package like the other common models.
The rows of the stream are reused on refresh, which needs the previous
feed to stay until the new one arrives. The loading message is shown
only for a different context.
Avatars are stored in a directory shared by all AYON processes of the
user, like thumbnails, so an avatar is downloaded once per machine.
A cached avatar is refreshed after a day and users without an avatar
are remembered. The users model exposes it for the controllers.
The Browser downloaded thumbnails and avatars in its frontend and the
activity feed added its own paths. All of them now ask the controller:
thumbnails come from the shared thumbnails model and its cache on
local storage, avatars from the avatars cache. The avatar cache of the
UI accepts a loader for that.

The Browser table takes user names from the users model as well, so
project users are queried once for the table and the activity feed.
@BigRoy
BigRoy force-pushed the enhancement/browser-workfiles-activity-tab branch from 10741fa to 9a0ea6a Compare October 7, 2026 18:46
Comment thread client/ayon_core/pipeline/avatars.py Outdated
@@ -0,0 +1,162 @@
"""Cache of user avatars on local storage.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this has "pipeline" usage. Probably makes sense only for tools ayon_core/tools/utils/avatars.py?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and looking at it again it should not exist at all. The file is removed in b575b91, together with get_user_avatar_path on the controllers and UsersModel, and the avatar_loader argument of UserAvatarCache.

With #2189 merged, develop already has UserAvatarCache downloading into the ImageCache, used by the views of the Browser, Workfiles and Launcher. This was a second way to download and store the same images, so the activity feed now uses UserAvatarCache like those views do. The Browser inspector still shares the cache instance of the table.

That does mean avatars are downloaded by the frontend and do not go through the controller, the same as in Workfiles and Launcher on develop. It is listed under "Still open" in the description.

@iLLiCiTiT

Copy link
Copy Markdown
Member

In browser we do show activities when selecting product group (only for product groups). The header label is then -, if we'd keep it we probably should show the product, or version for which the activities are shown.
image

BigRoy added 4 commits October 9, 2026 23:49
Avatars are downloaded by 'UserAvatarCache' into the image cache, the
same as in the views of the Browser, Workfiles and Launcher tools. The
avatars cache on local storage and 'get_user_avatar_path' of the
controllers are removed, they were a second way to download and store
the same images.
A selected group of a product shows the activity of its featured
version, while the path in the header of the inspector is empty for
it. A label above the feed has the product and version name, or the
count of selected versions.
@BigRoy

BigRoy commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

In browser we do show activities when selecting product group (only for product groups). The header label is then -

A product group row carries its featured version, so the inspector shows that version: thumbnail, details, representations and now also its activity. Only the path in the header is empty for it.

Kept it, and added a label above the feed that tells what the activity is of (dd89252):

  • the product and version name for a single version, e.g. modelMain v003, which for a product group is its featured version
  • N versions for a selection of more versions

The path label in the header is not changed, it is still - for a group as it is on develop.

Checked in an offscreen render of the inspector and with a test, not in the running tool yet.

Base automatically changed from enhancement/activity-stream-component to develop October 13, 2026 13:40

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M type: enhancement Improvement of existing functionality or minor addition ui

Projects

Status: Review In Progress

Development

Successfully merging this pull request may close these issues.

3 participants