From bc9ee7b4d9381684841c6c5d584bcf21b16d6432 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sun, 15 Mar 2026 18:36:45 -0400 Subject: [PATCH] feat(ui): add bulk actions hamburger menu to workspace Models page (#22484) Add hamburger menu with bulk actions (Enable All, Disable All, Show All, Hide All) to the workspace Models page filter bar, matching the functionality from the admin Settings Models page. --- src/lib/components/workspace/Models.svelte | 115 +++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/src/lib/components/workspace/Models.svelte b/src/lib/components/workspace/Models.svelte index 564955e80d..ed09db4219 100644 --- a/src/lib/components/workspace/Models.svelte +++ b/src/lib/components/workspace/Models.svelte @@ -29,6 +29,8 @@ import { capitalizeFirstLetter, copyToClipboard } from '$lib/utils'; import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte'; + import CheckCircle from '../icons/CheckCircle.svelte'; + import Minus from '../icons/Minus.svelte'; import ModelMenu from './Models/ModelMenu.svelte'; import ModelDeleteConfirmDialog from '../common/ConfirmDialog.svelte'; import Tooltip from '../common/Tooltip.svelte'; @@ -41,6 +43,9 @@ import XMark from '../icons/XMark.svelte'; import EyeSlash from '../icons/EyeSlash.svelte'; import Eye from '../icons/Eye.svelte'; + import { DropdownMenu } from 'bits-ui'; + import { flyAndScale } from '$lib/utils/transitions'; + import Dropdown from '$lib/components/common/Dropdown.svelte'; import ViewSelector from './common/ViewSelector.svelte'; import TagSelector from './common/TagSelector.svelte'; import Pagination from '../common/Pagination.svelte'; @@ -224,6 +229,50 @@ await updateUserSettings(localStorage.token, { ui: $settings }); }; + const enableAllHandler = async () => { + const modelsToEnable = (models ?? []).filter((m) => !(m.is_active ?? true)); + // Optimistic UI update + modelsToEnable.forEach((m) => (m.is_active = true)); + models = models; + // Sync with server + await Promise.all(modelsToEnable.map((model) => toggleModelById(localStorage.token, model.id))); + }; + + const disableAllHandler = async () => { + const modelsToDisable = (models ?? []).filter((m) => m.is_active ?? true); + // Optimistic UI update + modelsToDisable.forEach((m) => (m.is_active = false)); + models = models; + // Sync with server + await Promise.all( + modelsToDisable.map((model) => toggleModelById(localStorage.token, model.id)) + ); + }; + + const showAllHandler = async () => { + const modelsToShow = (models ?? []).filter((m) => m?.meta?.hidden === true); + // Optimistic UI update + modelsToShow.forEach((m) => { + m.meta = { ...m.meta, hidden: false }; + }); + models = models; + // Sync with server + await Promise.all(modelsToShow.map((model) => updateModelById(localStorage.token, model.id, model))); + toast.success($i18n.t('All models are now visible')); + }; + + const hideAllHandler = async () => { + const modelsToHide = (models ?? []).filter((m) => !(m?.meta?.hidden ?? false)); + // Optimistic UI update + modelsToHide.forEach((m) => { + m.meta = { ...m.meta, hidden: true }; + }); + models = models; + // Sync with server + await Promise.all(modelsToHide.map((model) => updateModelById(localStorage.token, model.id, model))); + toast.success($i18n.t('All models are now hidden')); + }; + onMount(async () => { viewOption = localStorage.workspaceViewOption ?? ''; page = 1; @@ -420,6 +469,7 @@ {/if} + @@ -453,6 +503,71 @@ /> {/if} + +
+ + + + + + +
+ + { + enableAllHandler(); + }} + > + +
{$i18n.t('Enable All')}
+
+ + { + disableAllHandler(); + }} + > + +
{$i18n.t('Disable All')}
+
+ +
+ + { + showAllHandler(); + }} + > + +
{$i18n.t('Show All')}
+
+ + { + hideAllHandler(); + }} + > + +
{$i18n.t('Hide All')}
+
+
+
+
{#if models !== null}