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.
Renames the SurfSense HITL extension decision-type from "always" to
"approve_always" so it sits in the same verb-first family as "approve",
"reject", and "edit". The Python constant is now SURFSENSE_DECISION_APPROVE_ALWAYS;
the wire value, the permission-domain decision_type, and the FE union members
all match (no wire/internal mismatch).
Both the multi_agent_chat permission middleware and the legacy new_chat one
accept the new wire value; the FE types.ts union is updated accordingly.
The "context.always" payload key is intentionally left untouched - it's the
patterns-to-promote field, semantically distinct from the decision type.
Fixes#1369 — log create/update/delete mutations did not invalidate
the query keys that useLogs actually subscribes to, causing UI staleness.
Replace narrow invalidations (list, summary) with prefix-level
invalidation (["logs"]) to cover withQueryParams, list, summary
and detail in one shot.
Removes duplicated LogLevel, LogStatus, Log, LogFilters and LogSummary
definitions from surfsense_web/hooks/use-logs.ts. These shapes already
live as Zod-derived types in contracts/types/log.types.ts, which is the
source of truth used by logs-api.service.ts and log-mutation.atoms.ts.
Adds LogLevel and LogStatus aliases for LogLevelEnum/LogStatusEnum in
log.types.ts so the existing public surface from use-logs is preserved
without per-hook re-exports. The hook re-exports the canonical names so
callers (app/dashboard/[search_space_id]/logs/(manage)/page.tsx) do not
need to change.
Closes#1372