The search tree adapter was typed `Ref<HoppCollection[]>` but the teams
provider forces a `Ref<TeamCollection[]>` into it via a double-cast
(`as unknown as Ref<HoppCollection[]>` in teams.workspace.ts:1472).
`HoppCollection` uses `folders` while `TeamCollection` uses `children`.
Root-level rendering worked because both types expose a top-level
`requests`, but expanding a nested team search hit would throw
`TypeError: Cannot read properties of undefined (reading 'map')` on
`item.folders.map`.
Normalize access inside the adapter via a union-safe shape that reads
either `folders` or `children`, and replace the personal-only
`navigateToFolderWithIndexPath` walk with a local walker using the same
accessor. Personal-workspace behavior is unchanged; team-workspace
expansion now walks the nested tree correctly.
WritableComputedRef setter only fires on .value assignment, not on
nested property mutation. Replace .value.data.requestID = ... with
full .value = { ...value, data: { ...data, ... } } to guarantee
reactive propagation through the writable computed layer.
Use IconUsers for team workspace items and IconCheck for the active
workspace indicator, matching the pattern in PersonalWorkspaceSelector.
Remove debug comment.
A null collection from the GQL query is an unexpected server response,
not a network error. Reclassify to graphql_error for accurate error
categorization.
- Wrap raw "error.something_went_wrong" string with t() in
ImportExport.vue environment export action
- Return status: "loaded" with empty data instead of "loading" for
unresolvable nodes in search tree adapter to avoid perpetual
loading spinners
Extract a safeJSONParse helper that logs and returns a fallback on
failure. Apply it to all remaining unguarded JSON.parse sites:
- Collection data parsing in _getCollectionChildren/_getRootCollections
- Request data parsing in _getCollectionChildRequests (uses flatMap to
skip unparseable requests instead of pushing null)
- Environment variables in create/duplicate/import (defaults to [])
- Environment variables in update paths (preserves existing variables
on parse failure instead of wiping to [])
- Environments view computed
- Subscription handlers (replaces earlier manual try/catch blocks)
- Remove window.testData global leak
- Replace useTimestamp live 3s polling timer with static ref
- Change implements Partial<WorkspaceProvider> to full interface
implementation with explicit throw stubs for unimplemented methods
- Remove eager TestWorkspaceProviderService instantiation from index.ts
so it's tree-shaken out of production builds
- Wrap JSON.parse in subscription handlers (request added/updated,
environment created/updated) with try/catch — a malformed server
payload would crash the handler and kill the entire subscription
stream for the session
- Clear collections and requests arrays before setting up new
subscriptions in selectWorkspace to prevent race conditions where
subscription events push into stale previous-workspace state during
the initial fetch await
getChildren threw an unhandled exception when the workspace handle was
invalid — the tree component doesn't wrap calls in try/catch, so this
propagated into Vue's render cycle. Return an empty loaded result
instead, matching the error recovery pattern used elsewhere in the
adapter.
- Reset this.subscriptions to [] after unsubscribing in selectWorkspace
to prevent unbounded array growth on workspace switches
- Narrow importRESTEnvironments filter to check E.isRight in addition
to promise fulfillment — prevents false success when all GQL calls
return E.Left
getRESTCollectionChildrenView accessed collectionHandleRef.value.data
after await boundaries — the computed ref re-evaluates on each access
and could return { type: "invalid" } if a subscription deleted the
collection during the in-flight API request, causing a TypeError on
.data access. Capture collectionID and workspaceID before the async
gap and use the stable values in .then() callbacks.
- Add type predicate to PromiseSettledResult filter in
importRESTEnvironments so TypeScript narrows to
PromiseFulfilledResult (fixes .value access on union type)
- Replace ref mutation inside computed in getRESTEnvironmentsView
with a separate computed ref — avoids Vue readonly warning and
potential infinite update loops
Handle refs from getRESTCollectionHandle/getRESTEnvironmentHandle are
lazy-computed — writing to .value is a no-op that triggers Vue readonly
warnings. The computed already auto-invalidates when the backing store
changes, so manual invalidation and name synchronization blocks are
unnecessary. Removes dead code in:
- updateRESTCollection (post-rename handle mutation)
- removeRESTCollection (post-delete handle invalidation)
- updateRESTEnvironment (post-rename handle mutation)
- removeRESTEnvironment (post-delete handle invalidation)
- platform.io doesn't exist on PlatformDef — all other callsites use
platform.kernelIO.saveFileWithDialog
- fetchAllTeams referenced runGQLQuery and GetMyTeamsDocument without
importing them, causing a build failure
- Add type: "request" to both createNewTab calls in new-collections/rest
component — required by HoppTabDocument discriminated union
- Replace non-existent HoppRESTDocument with correct types:
HoppRequestDocument in Request.vue, HoppTabDocument in helpers/tab,
remove duplicate broken import in TabHead.vue
- Tab restoration now always preserves the tab with its request data;
handle rehydration is best-effort — failed resolution no longer drops
the entire tab
- Replace delete updatedRequest.id with destructuring to avoid mutating
the caller's parameter object
- loadTabsFromPersistedState became async but callers were not updated,
causing a race where the persistence watcher could overwrite tabs with
an empty/partial array before handle resolution completes
- Replace lodash merge() with shallow spread in personal updateRESTRequest
to avoid element-by-element array merging that preserves deleted entries
- makeCollectionTree: always add each collection's own ID to the parent
set so requests on leaf collections are not silently dropped during export
- getRESTEnvironmentsView: create the environments ref once outside the
computed and update .value inside, preventing stale ref on re-evaluation
- RequestTab.vue: restore isEqualHoppRESTRequest from @hoppscotch/data
instead of lodash isEqual to preserve empty-entry filtering semantics
- removeRESTCollection and the collection-removed subscription now walk
the parent chain to remove all descendant collections and their
requests from local state (backend cascade-deletes but subscription
only fires for the top-level ID)
- RequestTab.vue sets isDirty=true when the request handle is absent
or invalid, preventing silent loss of edits
- parent?.id returns undefined for root collections; normalize to null
so sibling filter matches correctly
- sort filtered siblings with sortByOrder() before .at(-1) to ensure
generated fractional index follows the actual last sibling's order
Wrap unknown exceptions in generator catch blocks into proper
GQLError<string> objects with network_error type. Replace raw
error string in environment deletion toast with translated message.
Guard against null collection in pagination generator instead of
using non-null assertion. Wrap raw i18n key with t() in collections
ImportExport toast.
Break out of pagination generators on Left results in
_getCollectionChildRequests and _getRootCollections to prevent
infinite retry loops. Remove unused imports and variables from
TeamsWorkspaceSelector.