Skip to content

Sidebar & Workspaces: "Pin" is used for two different behaviors #6994

Open

Description

@jaseemts

Summary

  • "Pin" means two different things in the UI, and the overlap is confusing
  • On the Workspaces page, right-click → "Pin to Sidebar" controls whether a workspace appears in the sidebar at all (membership)
  • In the sidebar, right-click → "Pin" moves a workspace into the PINNED section at the top (placement)
  • Same word, two unrelated behaviors — unpinning from the Workspaces page removes the workspace from the sidebar entirely, not from the PINNED row

Proposal

  • Keep "Pin to Sidebar" / "Unpin from Sidebar" on the Workspaces page — it reads correctly as show/hide in sidebar
  • Rename the sidebar action to "Favorite" (or "Star"), with a FAVORITES section instead of PINNED, so membership and placement get distinct names

Environment
Superset 1.25.0, macOS (Darwin arm64)

Related

  • Let me pin an automation so its latest workspace stays in the sidebar #6172 — triage there confirmed pin state is workspace-scoped and machine-local (renderer-side pinnedAt, never synced), which is the same overloaded "pin" surface this issue describes. The automations-group direction discussed there would also reduce how often pinning is the only tool for sidebar visibility.

Activity

  1. github-actions commented on Aug 29, 2026

    @github-actions
    Contributor

    Summary

    This is a naming/UX report, not a crash: the word "Pin" is bound to two independent pieces of state in the workspace sidebar model, and the two actions live one click apart. On the Workspaces page, "Pin to Sidebar" / "Unpin from Sidebar" toggles membership (sidebarState.isHidden) — whether the workspace appears in the sidebar at all. In the sidebar, "Pin" / "Unpin" toggles placement (sidebarState.pinnedAt) — whether the row floats up into the PINNED section. Both use a pushpin icon, and the Workspaces page filter chip labeled "Pinned" actually filters on membership, not on the PINNED section. The reported behavior is accurate as described.

    Affected code

    Two independent fields on v2WorkspaceLocalState.sidebarState:

    • Membership — isHidden, written by ensureWorkspaceInSidebar / hideWorkspaceInSidebar at apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts:334 and :912.
    • Placement — pinnedAt, written by setWorkspacePinned at useDashboardSidebarState.ts:815, ordered by reorderPinnedWorkspaces at :854.

    Surfaces that say "pin":

    Surface Label Actually does
    v2-workspaces/components/V2WorkspaceContextMenu/V2WorkspaceContextMenu.tsx:157-174 "Pin to Sidebar" / "Unpin from Sidebar" (RiPushpinFill/RiPushpinLine) membership — calls addToSidebar/removeFromSidebar (:65, :81)
    DashboardSidebar/.../DashboardSidebarWorkspaceContextMenu.tsx:109-121 "Pin" / "Unpin" (LuPin/LuPinOff) placement — onTogglePin → setWorkspacePinned
    DashboardSidebarWorkspaceContextMenu.tsx:248-253 "Remove from Sidebar" membership — the same action as "Unpin from Sidebar", under a different name, in the same menu as "Unpin"
    DashboardSidebarPinnedSection.tsx:73, :110 "Pinned" section header, "Drop to pin" placement
    v2-workspaces/stores/v2WorkspacesFilterStore/v2WorkspacesFilterStore.ts:59-78 "Pinned" / "Unpinned" filter membership — matchesPinFilter reads workspace.isInSidebar (useAccessibleV2Workspaces.ts:191-199, derived at :687)

    Note the third row: the sidebar's own menu already names the membership action "Remove from Sidebar", so the app currently has two different labels for one behavior and one label for two behaviors.

    Root cause

    Nothing is functionally broken — the two states are correctly separate and the code's internal names are unambiguous (isHidden vs pinnedAt, removeFromSidebar vs setWorkspacePinned). The collision is entirely at the label layer, introduced by giving the membership action a pushpin metaphor it doesn't need.

    One real sharp edge amplifies the confusion: hiding clears the pin. tombstoneSidebarWorkspaceRecord at apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/sidebarMutations.ts:57-65 sets pinnedAt = null alongside isHidden = true (deliberately — the comment explains a resurrected workspace must not reappear pre-pinned). So a user who right-clicks a PINNED workspace on the Workspaces page and picks "Unpin from Sidebar" expecting it to drop out of the PINNED row instead loses both the pin and the sidebar row, and re-adding it puts it back in the project tree rather than in PINNED. That's the concrete data-loss-shaped consequence of the naming overlap.

    Reproduction

    1. Sidebar → right-click a workspace → Pin. It moves into PINNED.
    2. Go to the Workspaces page → right-click that same workspace → Unpin from Sidebar.
    3. Observed: the workspace disappears from the sidebar entirely (isHidden = true, pinnedAt = null), not just from PINNED.
    4. Right-click it again → Pin to Sidebar. It returns to its project group, no longer pinned.

    For a unit-level check, useDashboardSidebarState/sidebarMutations.test.ts already exercises tombstoneSidebarWorkspaceRecord; a bun:test case asserting pinnedAt === null after tombstoning a pinned row would pin down step 3's mechanism.

    Fix direction

    The rename is the whole fix; no state-model change is needed. Two options, and the choice is a product call:

    A — the issue's proposal. Keep "Pin to Sidebar" on the Workspaces page, rename the sidebar action to Favorite/Star and the section to FAVORITES. Worth knowing before picking this: Pages already has a favorites store (favoritePageIds in providers/CollectionsProvider/dashboardSidebarLocal/schema.ts:411, usePageFavorites) whose UI is labeled "Pin"/"Pinned" (pages/.../PageCard/PageCard.tsx:151-155, PagesView.tsx:67) — so this option swaps the two words relative to Pages unless Pages is renamed in the same pass. Marketing copy also leans on the pin metaphor for the sidebar section (marketing.roadmap.item.workspacePinningBulkActions: "Pin workspaces above your projects").

    B — smaller churn. Leave PINNED alone (it's the conventional "pinned tab" meaning: placement) and rename the Workspaces-page action to "Add to Sidebar" / "Remove from Sidebar", matching the sidebar menu's existing "Remove from Sidebar" entry and the code's own addToSidebar/removeFromSidebar names. Swap RiPushpin* for a non-pin icon (LuPlus/LuX) at V2WorkspaceContextMenu.tsx:162,169, and relabel the filter at v2WorkspacesFilterStore.ts:66-77 to "In sidebar" / "Not in sidebar" — that chip is arguably the most misleading string of the set today, since it sits on the same page as a PINNED section that means something else.

    Either way, packages/i18n/README.md §"Editing English copy under a stable ID" applies: IDs are stable, so changing the JSX text alone doesn't change what ships — locales/en/messages.po must be regenerated and all 16 locales updated, with bun run --cwd packages/i18n check gating it in CI. Affected IDs: dashboard.workspaces.contextMenu.pinToSidebar / .unpinFromSidebar, dashboard.v2Workspaces.pinFilter*, dashboard.workspaces.header.pinnedFilter, and (under option A) dashboard.sidebar.workspaceMenu.pin / .unpin, dashboard.sidebar.sectionPinned, dashboard.sidebar.pinnedSection.dropToPin, dashboard.sidebar.projectContent.dropToUnpin, dashboard.sidebar.sessionsSection.dropToUnpin.

  2. Kitenite commented on Aug 29, 2026

    @Kitenite
    Member

    Very true, I like the suggestion let me see if there's something else like show on sidebar instead of pin on the workspace view

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions