[PR #3859] [MERGED] refactor(workspaces): provider additions for collections under personal workspace #4559

Closed
opened 2026-03-17 02:05:02 +03:00 by kerem · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/hoppscotch/hoppscotch/pull/3859
Author: @jamesgeorge007
Created: 2/26/2024
Status: Merged
Merged: 5/22/2024
Merged by: @AndrewBastin

Base: refactor/workspacesHead: refactor/workspaces-collection-provider-additions


📝 Commits (10+)

  • 175ab50 refactor: port import/export functionality
  • cfc726d refactor: port collection move/reorder
  • c2e4ea5 refactor: provider method definitions for collection reorder/move
  • a797a04 refactor: unify markup
  • 7542d23 refactor: integrate provider API methods for collection move/reorder
  • 84078e0 fix: associate requests under tabs while reordering collections
  • 8e44639 refactor: view based implementation for search in personal workspace
  • 726a816 refactor: add new tree adapter corresponding to search
  • 7c17c22 refactor: integrate REST search collection adapter
  • a4754db fix: update save context for affected requests with collection move/reorder

📊 Changes

40 files changed (+8207 additions, -1263 deletions)

View changed files

📝 packages/hoppscotch-common/src/components/app/Header.vue (+5 -9)
📝 packages/hoppscotch-common/src/components/collections/ImportExport.vue (+83 -33)
📝 packages/hoppscotch-common/src/components/collections/SaveRequest.vue (+8 -21)
📝 packages/hoppscotch-common/src/components/collections/graphql/ImportExport.vue (+3 -3)
📝 packages/hoppscotch-common/src/components/environments/ImportExport.vue (+3 -3)
📝 packages/hoppscotch-common/src/components/http/Request.vue (+27 -19)
📝 packages/hoppscotch-common/src/components/http/RequestTab.vue (+31 -5)
📝 packages/hoppscotch-common/src/components/new-collections/index.vue (+9 -30)
📝 packages/hoppscotch-common/src/components/new-collections/rest/Collection.vue (+213 -6)
📝 packages/hoppscotch-common/src/components/new-collections/rest/Request.vue (+145 -2)
📝 packages/hoppscotch-common/src/components/new-collections/rest/index.vue (+1341 -347)
📝 packages/hoppscotch-common/src/components/workspace/Current.vue (+4 -2)
📝 packages/hoppscotch-common/src/components/workspace/PersonalWorkspaceSelector.vue (+5 -4)
📝 packages/hoppscotch-common/src/components/workspace/TestWorkspaceSelector.vue (+5 -4)
packages/hoppscotch-common/src/helpers/adapters/WorkspaceRESTCollectionSearchTreeAdapter.ts (+92 -0)
📝 packages/hoppscotch-common/src/helpers/adapters/WorkspaceRESTCollectionTreeAdapter.ts (+23 -18)
📝 packages/hoppscotch-common/src/helpers/collection/collection.ts (+200 -162)
📝 packages/hoppscotch-common/src/helpers/collection/request.ts (+57 -10)
📝 packages/hoppscotch-common/src/helpers/import-export/export/index.ts (+17 -18)
packages/hoppscotch-common/src/helpers/import-export/export/myCollections.ts (+0 -5)

...and 20 more files

📄 Description

Description

This PR ports the existing implementation for import/export, move/reorder, and search corresponding to collections under personal workspace to the provider-based new architecture. It also adds support for searching collections at any depth.

We're also moving to a new inert handle-based approach (proposed by @AndrewBastin). Previously, reactive handles were sent around everywhere with the provider methods expecting the same. This resulted in issues with the reactivity behavior mostly with the issued handle updates not getting reflected in the issued handles since the reference was coming up differently and the value getting automatically unwrapped at places. In the new approach, while obtaining a handle it's just a plain object and the underlying reactive value can be accessed later in time.

const requestHandleResult = workspaceService.getRequestHandle(activeWorkspaceHandle, requestID)

if (E.isLeft(requestHandleResult)) {
  // Error handling
}

const requestHandleRef = requestHandleResult.right.get()

Personal workspaces have dynamic path-based IDs (0/0, 2/1/0, etc) based on the position (levels are separated by /, single digit represents root collections) of a resource (collection/request) in the tree. Previously to keep the association between requests open under tabs and the ones from the tree, every time the resultant IDs were computed manually after the action. Say, a request at a deeply nested collection is moved to a different location, each tab has information about the ID path of the request being open from the tree, and necessary updates are made to the above information based on the action computed from the source and destination IDs.

With the new handle-based system, since handles are reactive references to a resource, we keep a list of issued handles (obtained while creating/selecting a request,). Each tab keeps a request handle reference under tab.document.saveContext, and whenever an action requiring updates to the IDs happens, the corresponding handle is found from the compiled list of issued handles and the respective ID (collectionID, requestID) is updated accordingly. The updates are streamed to the tabs via the reactive behavior. The same approach is used for toggling the dirty state associated with requests when any parent-level collection is deleted or if the request itself is deleted.

Closes HFE-437.

Changes

  • Adds the following methods under the personal workspace provider corresponding to the abovementioned features.

    // Views
    getRESTSearchResultsView(
      workspaceHandle: HandleRef<Workspace>,
      searchQuery: Ref<string>
    ): Promise<E.Either<never, HandleRef<RESTSearchResultsView>>>
    getRESTCollectionJSONView(
      workspaceHandle: HandleRef<Workspace>
    ): Promise<E.Either<never, HandleRef<RESTCollectionJSONView>>>
    
    importRESTCollections(
      workspaceHandle: HandleRef<Workspace>,
      collections: HoppCollection[]
    ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
    exportRESTCollections(
      workspaceHandle: HandleRef<Workspace>,
      collections: HoppCollection[]
    ): Promise<E.Either<unknown, void>>
    exportRESTCollection(
      collectionHandle: HandleRef<WorkspaceCollection>,
      collection: HoppCollection
    ): Promise<E.Either<unknown, void>>
    
    reorderRESTCollection(
      collectionHandle: HandleRef<WorkspaceCollection>,
      destinationCollectionID: string | null
    ): Promise<E.Either<unknown, void>>
    moveRESTCollection(
      collectionHandle: HandleRef<WorkspaceCollection>,
      destinationCollectionID: string | null
    ): Promise<E.Either<unknown, void>>
    reorderRESTRequest(
      requestHandle: HandleRef<WorkspaceRequest>,
      destinationCollectionID: string,
      destinationRequestID: string | null
    ): Promise<E.Either<unknown, void>>
    moveRESTRequest(
      requestHandle: HandleRef<WorkspaceRequest>,
      destinationCollectionID: string
    ): Promise<E.Either<unknown, void>>
    
  • Migrate to the new inert handle-based approach.

  • Move to handle based updates to keep the association between requests from the collection tree and the ones open under tabs.

  • Additions to the NewCollectionsRest component accounting for the ported features mentioned above. The business logic associated with updates to the store for each action resides in the provider definition for each workspace invoked from the component level via the new workspace service implementation.

  • Move the markup and associated logic wrt showing the active workspace and search from the parent level NewCollections component to `NewCollectionsRest.

  • Port the collection/request move/reorder logic (markup, events, handlers, etc) into the NewCollectionsRestCollection and NewCollectionsRestRequest components.

  • Introduce a new tree adapter to render the tree with search results. This was required since the existing adapter for rendering the default collection tree operates based on the supplied workspace handle. While, for search, is to be based on the initial data provided to be filtered based on.

  • The getChildren method to be implemented by the tree adapter now takes an additional argument signifying the type of the incoming node (collection/request). This acts as a safeguard to prevent errors with operations specific to a collection node.

  • Remove collectionID from information persisted under the REST tab saveContext since requestID accounts for it.

  • initializeDownloadCollection helper under ~/packages/hoppscotch-common/src/helpers/import-export/export is given an agnosic name initializeDownloadFile since it gets consumed in different contexts. The definition is updated to point to the platform definition to ensure the underlying platform defines the behavior.

  • New helper functions under ~/packages/hoppscotch-common/src/services/new-workspace/helpers.ts to abstract common logic consumed in the provider method definitions.

  • Formalise a system for creating a persistable handle reference that can be loaded back again - Persist request handles at runtime, write only the unique IDs (provider, workspace & request IDs) required to restore the handle to localStorage. Load the request handle back via the IDs at runtime.

  • Introduce writable handles to signify updates to other handle references when an action is performed. For instance, a request from the collection tree is deleted and at the same time the handle issued is updated thereby the request handle persisted under tab saveContext is aware of the update (handle type is set to invalid) and toggles the dirty state in this case.

  • Adds a test suite for the PersonalWorkspaceProviderService with associated mocks and helpers.

Checks

  • My pull request adheres to the code style of this project
  • All the tests have passed

Note to reviewers

Switching to a team workspace will result in exceptions at the moment and can be ignored. This PR includes changes specific to the personal workspace. The existing provider definition for teams test.workspace.ts is meant as a placeholder to be removed once the teams-side implementation is brought in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/hoppscotch/hoppscotch/pull/3859 **Author:** [@jamesgeorge007](https://github.com/jamesgeorge007) **Created:** 2/26/2024 **Status:** ✅ Merged **Merged:** 5/22/2024 **Merged by:** [@AndrewBastin](https://github.com/AndrewBastin) **Base:** `refactor/workspaces` ← **Head:** `refactor/workspaces-collection-provider-additions` --- ### 📝 Commits (10+) - [`175ab50`](https://github.com/hoppscotch/hoppscotch/commit/175ab509068756b77d8f38818b15480ef3f9fc96) refactor: port import/export functionality - [`cfc726d`](https://github.com/hoppscotch/hoppscotch/commit/cfc726d000a67bdcd09e2f1d1fb09a006b347a5d) refactor: port collection move/reorder - [`c2e4ea5`](https://github.com/hoppscotch/hoppscotch/commit/c2e4ea5ffc221476b38939270064001a84f0f835) refactor: provider method definitions for collection reorder/move - [`a797a04`](https://github.com/hoppscotch/hoppscotch/commit/a797a04c96fe9cc0d5a78ba006d7b1b0889ad3bb) refactor: unify markup - [`7542d23`](https://github.com/hoppscotch/hoppscotch/commit/7542d23b3917b13f11baeaeb9a55276541ad5e71) refactor: integrate provider API methods for collection move/reorder - [`84078e0`](https://github.com/hoppscotch/hoppscotch/commit/84078e08df7e5d6743143f43186a2f9cb94749d9) fix: associate requests under tabs while reordering collections - [`8e44639`](https://github.com/hoppscotch/hoppscotch/commit/8e44639fec8aa5df468fc712519f475467e14686) refactor: view based implementation for search in personal workspace - [`726a816`](https://github.com/hoppscotch/hoppscotch/commit/726a816954d8006f6ace68df6eae38ad2c953f61) refactor: add new tree adapter corresponding to search - [`7c17c22`](https://github.com/hoppscotch/hoppscotch/commit/7c17c229811938d09bd1f499632c8d4812561085) refactor: integrate REST search collection adapter - [`a4754db`](https://github.com/hoppscotch/hoppscotch/commit/a4754dbc2083734bc06f6501423b7d142f0553bf) fix: update save context for affected requests with collection move/reorder ### 📊 Changes **40 files changed** (+8207 additions, -1263 deletions) <details> <summary>View changed files</summary> 📝 `packages/hoppscotch-common/src/components/app/Header.vue` (+5 -9) 📝 `packages/hoppscotch-common/src/components/collections/ImportExport.vue` (+83 -33) 📝 `packages/hoppscotch-common/src/components/collections/SaveRequest.vue` (+8 -21) 📝 `packages/hoppscotch-common/src/components/collections/graphql/ImportExport.vue` (+3 -3) 📝 `packages/hoppscotch-common/src/components/environments/ImportExport.vue` (+3 -3) 📝 `packages/hoppscotch-common/src/components/http/Request.vue` (+27 -19) 📝 `packages/hoppscotch-common/src/components/http/RequestTab.vue` (+31 -5) 📝 `packages/hoppscotch-common/src/components/new-collections/index.vue` (+9 -30) 📝 `packages/hoppscotch-common/src/components/new-collections/rest/Collection.vue` (+213 -6) 📝 `packages/hoppscotch-common/src/components/new-collections/rest/Request.vue` (+145 -2) 📝 `packages/hoppscotch-common/src/components/new-collections/rest/index.vue` (+1341 -347) 📝 `packages/hoppscotch-common/src/components/workspace/Current.vue` (+4 -2) 📝 `packages/hoppscotch-common/src/components/workspace/PersonalWorkspaceSelector.vue` (+5 -4) 📝 `packages/hoppscotch-common/src/components/workspace/TestWorkspaceSelector.vue` (+5 -4) ➕ `packages/hoppscotch-common/src/helpers/adapters/WorkspaceRESTCollectionSearchTreeAdapter.ts` (+92 -0) 📝 `packages/hoppscotch-common/src/helpers/adapters/WorkspaceRESTCollectionTreeAdapter.ts` (+23 -18) 📝 `packages/hoppscotch-common/src/helpers/collection/collection.ts` (+200 -162) 📝 `packages/hoppscotch-common/src/helpers/collection/request.ts` (+57 -10) 📝 `packages/hoppscotch-common/src/helpers/import-export/export/index.ts` (+17 -18) ➖ `packages/hoppscotch-common/src/helpers/import-export/export/myCollections.ts` (+0 -5) _...and 20 more files_ </details> ### 📄 Description ### Description This PR ports the existing implementation for import/export, move/reorder, and search corresponding to collections under personal workspace to the provider-based new architecture. It also adds support for searching collections at any depth. We're also moving to a new inert handle-based approach (proposed by @AndrewBastin). Previously, reactive handles were sent around everywhere with the provider methods expecting the same. This resulted in issues with the reactivity behavior mostly with the issued handle updates not getting reflected in the issued handles since the reference was coming up differently and the value getting automatically unwrapped at places. In the new approach, while obtaining a handle it's just a plain object and the underlying reactive value can be accessed later in time. ```ts const requestHandleResult = workspaceService.getRequestHandle(activeWorkspaceHandle, requestID) if (E.isLeft(requestHandleResult)) { // Error handling } const requestHandleRef = requestHandleResult.right.get() ``` Personal workspaces have dynamic path-based IDs (`0/0`, `2/1/0`, etc) based on the position (levels are separated by `/`, single digit represents root collections) of a resource (collection/request) in the tree. Previously to keep the association between requests open under tabs and the ones from the tree, every time the resultant IDs were computed manually after the action. Say, a request at a deeply nested collection is moved to a different location, each tab has information about the ID path of the request being open from the tree, and necessary updates are made to the above information based on the action computed from the source and destination IDs. With the new handle-based system, since handles are reactive references to a resource, we keep a list of issued handles (obtained while creating/selecting a request,). Each tab keeps a request handle reference under `tab.document.saveContext`, and whenever an action requiring updates to the IDs happens, the corresponding handle is found from the compiled list of issued handles and the respective ID (`collectionID`, `requestID`) is updated accordingly. The updates are streamed to the tabs via the reactive behavior. The same approach is used for toggling the dirty state associated with requests when any parent-level collection is deleted or if the request itself is deleted. Closes HFE-437. ### Changes - Adds the following methods under the personal workspace provider corresponding to the abovementioned features. ```js // Views getRESTSearchResultsView( workspaceHandle: HandleRef<Workspace>, searchQuery: Ref<string> ): Promise<E.Either<never, HandleRef<RESTSearchResultsView>>> getRESTCollectionJSONView( workspaceHandle: HandleRef<Workspace> ): Promise<E.Either<never, HandleRef<RESTCollectionJSONView>>> importRESTCollections( workspaceHandle: HandleRef<Workspace>, collections: HoppCollection[] ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> exportRESTCollections( workspaceHandle: HandleRef<Workspace>, collections: HoppCollection[] ): Promise<E.Either<unknown, void>> exportRESTCollection( collectionHandle: HandleRef<WorkspaceCollection>, collection: HoppCollection ): Promise<E.Either<unknown, void>> reorderRESTCollection( collectionHandle: HandleRef<WorkspaceCollection>, destinationCollectionID: string | null ): Promise<E.Either<unknown, void>> moveRESTCollection( collectionHandle: HandleRef<WorkspaceCollection>, destinationCollectionID: string | null ): Promise<E.Either<unknown, void>> reorderRESTRequest( requestHandle: HandleRef<WorkspaceRequest>, destinationCollectionID: string, destinationRequestID: string | null ): Promise<E.Either<unknown, void>> moveRESTRequest( requestHandle: HandleRef<WorkspaceRequest>, destinationCollectionID: string ): Promise<E.Either<unknown, void>> ``` - Migrate to the new inert handle-based approach. - Move to handle based updates to keep the association between requests from the collection tree and the ones open under tabs. - Additions to the `NewCollectionsRest` component accounting for the ported features mentioned above. The business logic associated with updates to the store for each action resides in the provider definition for each workspace invoked from the component level via the new workspace service implementation. - Move the markup and associated logic wrt showing the active workspace and search from the parent level `NewCollections` component to `NewCollectionsRest. - Port the collection/request move/reorder logic (markup, events, handlers, etc) into the `NewCollectionsRestCollection` and `NewCollectionsRestRequest` components. - Introduce a new tree adapter to render the tree with search results. This was required since the existing adapter for rendering the default collection tree operates based on the supplied workspace handle. While, for search, is to be based on the initial data provided to be filtered based on. - The `getChildren` method to be implemented by the tree adapter now takes an additional argument signifying the type of the incoming node (`collection/request`). This acts as a safeguard to prevent errors with operations specific to a collection node. - Remove `collectionID` from information persisted under the REST tab `saveContext` since `requestID` accounts for it. - `initializeDownloadCollection` helper under `~/packages/hoppscotch-common/src/helpers/import-export/export` is given an agnosic name `initializeDownloadFile` since it gets consumed in different contexts. The definition is updated to point to the platform definition to ensure the underlying platform defines the behavior. - New helper functions under [~/packages/hoppscotch-common/src/services/new-workspace/helpers.ts](https://github.com/hoppscotch/hoppscotch/pull/3859/files#diff-07a17c74fac49fdb88e9c9a0fae916a48aaecd8366f4eeeeabb258263d5abd67) to abstract common logic consumed in the provider method definitions. - Formalise a system for creating a persistable handle reference that can be loaded back again - Persist request handles at runtime, write only the unique IDs (provider, workspace & request IDs) required to restore the handle to `localStorage`. Load the request handle back via the IDs at runtime. - Introduce writable handles to signify updates to other handle references when an action is performed. For instance, a request from the collection tree is deleted and at the same time the handle issued is updated thereby the request handle persisted under tab `saveContext` is aware of the update (handle type is set to `invalid`) and toggles the dirty state in this case. - Adds a test suite for the `PersonalWorkspaceProviderService` with associated mocks and helpers. ### Checks - [x] My pull request adheres to the code style of this project - [x] All the tests have passed ### Note to reviewers Switching to a team workspace will result in exceptions at the moment and can be ignored. This PR includes changes specific to the personal workspace. The existing provider definition for teams `test.workspace.ts` is meant as a placeholder to be removed once the teams-side implementation is brought in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
kerem 2026-03-17 02:05:02 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hoppscotch#4559
No description provided.