Fixes#1359
The SidebarSlideOutPanel was checking '(min-width: 640px)' while the rest of
the dashboard uses the project-wide useIsMobile() at 768px. At viewports
between 640-767px the slide-out rendered the desktop side-attached overlay
while the surrounding layout had already collapsed to mobile, leaving the
panel positioned against a sidebar that was no longer there.
Aligning to the shared hook fixes the layout choice at every viewport size.
useIsMobile's 768px threshold is unchanged; only this call site adapts.
CitationPanelContent uses a single instance across different citations
(RightPanel.tsx:251 renders without a key), so when the user clicks a
new citation while the panel is open, the prior expanded state leaks
into the new citation. The reset effect had an empty dependency array,
so it only fired on mount.
Add chunkId to the effect deps so the expanded state resets each time
the citation changes.
Fixes#1368
Previously, was duplicated in 4 places with 3 subtly different fallback behaviors:
1. inline-citation.tsx: returned on error
2. markdown-text.tsx: returned on error
3. assistant-message.tsx: returned on error
4. citation.tsx: returned on error
Created canonical in that:
- Returns
- Strips prefix from hostname
- Returns on invalid URL (safest contract)
Updated all 4 call sites:
- inline-citation.tsx: (preserves original fallback)
- markdown-text.tsx: (preserves original fallback)
- assistant-message.tsx: (drop-in, both return )
- citation.tsx: (drop-in, both return )
Co-authored-by: guangyang1206 <guangyang1206@users.noreply.github.com>
Fixes#1370
Object.values() produces order-dependent cache keys because the order of values depends on the order of keys in the object. This causes the same logical query to produce different cache keys when the parameter object has keys in different orders.
Added stableEntries() helper that:
1. Filters out undefined values
2. Sorts entries by key name
3. Returns flat array of [key, value] pairs
This ensures cache key identity is stable regardless of parameter object key order.
Co-authored-by: guangyang1206 <guangyang1206@users.noreply.github.com>
This commit modifies various metadata and canonical URLs in the SurfSense application to ensure consistency by using "https://www.surfsense.com" instead of "https://surfsense.com". Changes were made in layout files, blog posts, and SEO components to reflect this update.
Per #1373, the registered save chord is Mod+Shift+S (not Mod+S, which
collides with the browser's Save-Page-As). The JSDoc on PlateEditorProps.onSave
still claims Mod+S, which is misleading for downstream consumers of the
component. Update the JSDoc to match the actual chord and call out why.
Targeting dev per maintainer request.
Closes#1371. Retarget of #1385 onto dev per maintainer request.
surfsense_web/lib/query-client/client.ts configures a global
MutationCache.onError that shows an error toast for every failed
mutation unless meta.suppressGlobalErrorToast is set. The opt-out
hook existed in the consumer but had zero producers — every mutation
atom that already had its own onError: toast.error(...) was
double-toasting on failure.
Add meta: { suppressGlobalErrorToast: true } to the 30 mutations
across 9 atom files that own their own error toast:
- atoms/prompts/prompts-mutation.atoms.ts (4)
- atoms/invites/invites-mutation.atoms.ts (4)
- atoms/chat-comments/comments-mutation.atoms.ts (4)
- atoms/new-llm-config/new-llm-config-mutation.atoms.ts (4)
- atoms/members/members-mutation.atoms.ts (3)
- atoms/roles/roles-mutation.atoms.ts (3)
- atoms/image-gen-config/image-gen-config-mutation.atoms.ts (3)
- atoms/vision-llm-config/vision-llm-config-mutation.atoms.ts (3)
- atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms.ts (2)
Atoms intentionally left alone (no local onError, rely on global):
auth, user, search-spaces, logs, documents, connectors.
Local validation (against dev): pnpm biome check on the 9 touched
files is clean; tsc --noEmit shows no new errors in the touched files
(pre-existing errors elsewhere unrelated).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Slot MCPTrustedTools in mcp-service-config (gated on connector.id > 0) so
any connected MCP-backed connector exposes a revoke surface for
approve_always grants.
- Add new mcp-trusted-tools.tsx (audit + revoke list) and
connectorsApiService.untrustMCPTool() that backs it.
- Drop the redundant row-level Disconnect from ConnectorAccountsListView:
Manage now leads to the edit view whose own Disconnect is the single
source of truth. Remove the now-dead onDisconnect prop, confirm-flow
state, and handleDisconnectFromList hook callback + return entry.
The 'Always Allow' button is now driven entirely by the server-supplied
allowed_decisions palette. The card no longer peeks at
context.mcp_connector_id to decide whether to render the button, and no
longer fires a separate trust-tool HTTP call on click - one
{type: 'approve_always'} dispatch is enough; the agent middleware
handles the in-memory promotion and (for MCP tools) the database save
via its trusted_tool_saver callback.
Drops the dead trustMCPTool / untrustMCPTool service helpers - they had
no remaining callers after this rework. The backing HTTP routes are
kept on the server as a programmatic surface.