Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(workspaces): provider additions for collections under personal workspace #3859

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
175ab50
refactor: port import/export functionality
jamesgeorge007 Feb 19, 2024
cfc726d
refactor: port collection move/reorder
jamesgeorge007 Feb 20, 2024
c2e4ea5
refactor: provider method definitions for collection reorder/move
jamesgeorge007 Feb 20, 2024
a797a04
refactor: unify markup
jamesgeorge007 Feb 20, 2024
7542d23
refactor: integrate provider API methods for collection move/reorder
jamesgeorge007 Feb 20, 2024
84078e0
fix: associate requests under tabs while reordering collections
jamesgeorge007 Feb 22, 2024
8e44639
refactor: view based implementation for search in personal workspace
jamesgeorge007 Feb 22, 2024
726a816
refactor: add new tree adapter corresponding to search
jamesgeorge007 Feb 22, 2024
7c17c22
refactor: integrate REST search collection adapter
jamesgeorge007 Feb 22, 2024
a4754db
fix: update save context for affected requests with collection move/r…
jamesgeorge007 Feb 23, 2024
9d92965
refactor: session based search results view implementation
jamesgeorge007 Feb 24, 2024
6f0f159
refactor: eliminate `collectionID` from tab `saveContext`
jamesgeorge007 Feb 24, 2024
6801805
refactor: eliminate `parentCollectionID` field from `RESTCollectionVi…
jamesgeorge007 Feb 24, 2024
93664ed
refactor: port collection tree empty states
jamesgeorge007 Feb 26, 2024
d2daf7d
fix: ensure the collection tree for search immediately reflects actio…
jamesgeorge007 Feb 26, 2024
19ca22f
feat: support search at n level depth
jamesgeorge007 Feb 26, 2024
98e761e
fix: duplicate collection in search results
jamesgeorge007 Feb 27, 2024
9cd404f
refactor: update provider method signatures
jamesgeorge007 Feb 27, 2024
fbb9d56
refactor: leverage helpers
jamesgeorge007 Feb 27, 2024
b0c12f9
refactor: remove unnecessary safeguards + cleanup
jamesgeorge007 Feb 27, 2024
845db07
fix: ensure tree nodes are not computed for requests
jamesgeorge007 Feb 27, 2024
c5e1e19
refactor: update provider method signatures + cleanup
jamesgeorge007 Feb 29, 2024
89aedb6
chore: keep existing implementation for save context resolution
jamesgeorge007 Feb 29, 2024
2bff8b2
refactor: view implementation to retrieve collections for exporting
jamesgeorge007 Feb 29, 2024
2cd801c
fix: prevent infinite spinner state while expanding tree nodes
jamesgeorge007 Feb 29, 2024
854ffa2
refactor: persist request handles under tab `saveContext`
jamesgeorge007 Apr 22, 2024
a104ebb
refactor: introduce writable handles to signify updates to handle ref…
jamesgeorge007 Apr 23, 2024
0d03cba
refactor: keep tab dirty status logic at the page level
jamesgeorge007 Apr 25, 2024
8bdee92
refactor: convey updates via handle mutation for update request action
jamesgeorge007 Apr 27, 2024
df1add3
fix: make writable handle operate on refs within the `createRESTReque…
jamesgeorge007 Apr 28, 2024
d83a1e2
fix: ensure request name updates reflect immediately on the tabs
jamesgeorge007 Apr 28, 2024
dc65d7d
refactor: signify updates via handle reference mutation post request …
jamesgeorge007 Apr 29, 2024
53b0d22
refactor: update data under request handles during tab save context r…
jamesgeorge007 Apr 30, 2024
95039cc
refactor: consider request handles with tab saveContext resolution fo…
jamesgeorge007 Apr 30, 2024
c3e59d3
refactor: move tab saveContext resolution associated with actions on …
jamesgeorge007 Apr 30, 2024
08a9024
refactor: persist only request handles under tab `saveContext` at run…
jamesgeorge007 May 1, 2024
48792d4
refactor: add save context resolution logic post request deletion
jamesgeorge007 May 1, 2024
fcea882
fix: make close all tabs action account for tabs with invalid request…
jamesgeorge007 May 1, 2024
4b49ecf
refactor: better tab dirty check
jamesgeorge007 May 1, 2024
5ec50b5
refactor: tab saveContext resolution post collection remove action
jamesgeorge007 May 1, 2024
c3a6384
refactor: move to handle based updates with request move action
jamesgeorge007 May 2, 2024
1efd7c2
refactor: handle updates post move request action
jamesgeorge007 May 3, 2024
bc976af
refactor: move to inert handles
jamesgeorge007 May 6, 2024
7a2276e
refactor: move more things to handles instead of handleref
AndrewBastin May 8, 2024
e878b9a
chore: resolve type errors
jamesgeorge007 May 9, 2024
f086a96
fix: affected request indices computation post request move
jamesgeorge007 May 9, 2024
e4d204b
fix: affected request indices computation post request reorder
jamesgeorge007 May 9, 2024
fd2d240
refactor: handle based updates post collection move
jamesgeorge007 May 9, 2024
256cede
refactor: handle based updates post collection reorder
jamesgeorge007 May 14, 2024
0c388f6
refactor: handle based updates for affected requests post request del…
jamesgeorge007 May 14, 2024
67fe78d
refactor: handle based updates for affected requests post collection …
jamesgeorge007 May 14, 2024
97167c0
refactor: update inherited properties for affected requests flow updates
jamesgeorge007 May 15, 2024
1bfe70d
fix: handle based updates post collection move to a sibling level col…
jamesgeorge007 May 16, 2024
199d9d1
test: add test suite for personal workspace provider service
jamesgeorge007 May 16, 2024
0a2efe1
fix: empty state primary action for root collections
jamesgeorge007 May 20, 2024
37531bd
fix: resolve edge cases about moving collections under its sibling
jamesgeorge007 May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 5 additions & 9 deletions packages/hoppscotch-common/src/components/app/Header.vue
Expand Up @@ -262,7 +262,6 @@ import IconSettings from "~icons/lucide/settings"
import IconUploadCloud from "~icons/lucide/upload-cloud"
import IconUser from "~icons/lucide/user"
import IconUserPlus from "~icons/lucide/user-plus"
import IconUsers from "~icons/lucide/users"
import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
import { deleteTeam as backendDeleteTeam } from "~/helpers/backend/mutations/Team"
Expand Down Expand Up @@ -331,12 +330,6 @@ const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)

const workspace = workspaceService.currentWorkspace

const workspaceName = computed(() =>
workspace.value.type === "personal"
? t("workspace.personal")
: workspace.value.teamName
)

const refetchTeams = () => {
teamListAdapter.fetchList()
}
Expand Down Expand Up @@ -374,8 +367,11 @@ watch(
const newWorkspaceService = useService(NewWorkspaceService)

const activeWorkspaceName = computed(() => {
if (newWorkspaceService.activeWorkspaceHandle.value?.value.type === "ok") {
return newWorkspaceService.activeWorkspaceHandle.value?.value.data.name
const activeWorkspaceHandleRef =
newWorkspaceService.activeWorkspaceHandle.value?.get()

if (activeWorkspaceHandleRef?.value.type === "ok") {
return activeWorkspaceHandleRef.value.data.name
}

return t("workspace.no_workspace")
Expand Down
Expand Up @@ -30,7 +30,7 @@ import { defineStep } from "~/composables/step-components"

import { useI18n } from "~/composables/i18n"
import { useToast } from "~/composables/toast"
import { appendRESTCollections, restCollections$ } from "~/newstore/collections"
import { restCollections$ } from "~/newstore/collections"
import MyCollectionImport from "~/components/importExport/ImportExportSteps/MyCollectionImport.vue"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"

Expand All @@ -48,13 +48,14 @@ import { getTeamCollectionJSON } from "~/helpers/backend/helpers"

import { platform } from "~/platform"

import { initializeDownloadCollection } from "~/helpers/import-export/export"
import { initializeDownloadFile } from "~/helpers/import-export/export"
import { gistExporter } from "~/helpers/import-export/export/gist"
import { myCollectionsExporter } from "~/helpers/import-export/export/myCollections"
import { teamCollectionsExporter } from "~/helpers/import-export/export/teamCollections"

import { GistSource } from "~/helpers/import-export/import/import-sources/GistSource"
import { ImporterOrExporter } from "~/components/importExport/types"
import { useService } from "dioc/vue"
import { NewWorkspaceService } from "~/services/new-workspace"

const t = useI18n()
const toast = useToast()
Expand Down Expand Up @@ -86,15 +87,45 @@ const currentUser = useReadonlyStream(

const myCollections = useReadonlyStream(restCollections$, [])

const workspaceService = useService(NewWorkspaceService)

const activeWorkspaceHandle = workspaceService.activeWorkspaceHandle

const showImportFailedError = () => {
toast.error(t("import.failed"))
}

const handleImportToStore = async (collections: HoppCollection[]) => {
const importResult =
props.collectionsType.type === "my-collections"
? await importToPersonalWorkspace(collections)
: await importToTeamsWorkspace(collections)
if (props.collectionsType.type === "my-collections") {
if (!activeWorkspaceHandle.value) {
return
}

const collectionHandleResult = await workspaceService.importRESTCollections(
activeWorkspaceHandle.value,
collections
)

if (E.isLeft(collectionHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return toast.error(t("import.failed"))
}

const resultHandle = collectionHandleResult.right

const requestHandleRef = resultHandle.get()

if (requestHandleRef.value.type === "invalid") {
// WORKSPACE_INVALIDATED
}

toast.success(t("state.file_imported"))
emit("hide-modal")

return
}

const importResult = await importToTeamsWorkspace(collections)

if (E.isRight(importResult)) {
toast.success(t("state.file_imported"))
Expand All @@ -104,13 +135,6 @@ const handleImportToStore = async (collections: HoppCollection[]) => {
}
}

const importToPersonalWorkspace = (collections: HoppCollection[]) => {
appendRESTCollections(collections)
return E.right({
success: true,
})
}

function translateToTeamCollectionFormat(x: HoppCollection) {
const folders: HoppCollection[] = (x.folders ?? []).map(
translateToTeamCollectionFormat
Expand Down Expand Up @@ -390,28 +414,34 @@ const HoppMyCollectionsExporter: ImporterOrExporter = {
applicableTo: ["personal-workspace"],
isLoading: isHoppMyCollectionExporterInProgress,
},
action: () => {
action: async () => {
if (!myCollections.value.length) {
return toast.error(t("error.no_collections_to_export"))
}

if (!activeWorkspaceHandle.value) {
return
}

isHoppMyCollectionExporterInProgress.value = true

const message = initializeDownloadCollection(
myCollectionsExporter(myCollections.value),
"Collections"
const result = await workspaceService.exportRESTCollections(
activeWorkspaceHandle.value,
myCollections.value
)

if (E.isRight(message)) {
toast.success(t(message.right))

platform.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
exporter: "json",
platform: "rest",
})
if (E.isLeft(result)) {
// INVALID_WORKSPACE_HANDLE
}

toast.success(t("state.download_started"))

platform.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
exporter: "json",
platform: "rest",
})

isHoppMyCollectionExporterInProgress.value = false
},
}
Expand Down Expand Up @@ -445,10 +475,7 @@ const HoppTeamCollectionsExporter: ImporterOrExporter = {
return toast.error(t("error.no_collections_to_export"))
}

initializeDownloadCollection(
exportCollectionsToJSON,
"team-collections"
)
initializeDownloadFile(exportCollectionsToJSON, "team-collections")

platform.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
Expand Down Expand Up @@ -487,7 +514,7 @@ const HoppGistCollectionsExporter: ImporterOrExporter = {
const collectionJSON = await getCollectionJSON()
const accessToken = currentUser.value?.accessToken

if (!accessToken) {
if (!accessToken || E.isLeft(collectionJSON)) {
toast.error(t("error.something_went_wrong"))
isHoppGistCollectionExporterInProgress.value = false
return
Expand Down Expand Up @@ -583,6 +610,7 @@ const selectedTeamID = computed(() => {
})

const getCollectionJSON = async () => {
// TODO: Implement `getRESTCollectionJSONView` for team workspace
if (
props.collectionsType.type === "team-collections" &&
props.collectionsType.selectedTeam?.id
Expand All @@ -593,11 +621,33 @@ const getCollectionJSON = async () => {

return E.isRight(res)
? E.right(res.right.exportCollectionsToJSON)
: E.left(res.left)
: E.left(res.left.error.toString())
}

if (props.collectionsType.type === "my-collections") {
return E.right(JSON.stringify(myCollections.value, null, 2))
if (!activeWorkspaceHandle.value) {
return E.left("INVALID_WORKSPACE_HANDLE")
}

const collectionJSONHandleResult =
await workspaceService.getRESTCollectionJSONView(
activeWorkspaceHandle.value
)

if (E.isLeft(collectionJSONHandleResult)) {
return E.left(collectionJSONHandleResult.left.error)
}

const collectionJSONHandle = collectionJSONHandleResult.right

const collectionJSONHandleRef = collectionJSONHandle.get()

if (collectionJSONHandleRef.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return E.left("WORKSPACE_INVALIDATED")
}

return E.right(collectionJSONHandleRef.value.data.content)
}

return E.left("INVALID_SELECTED_TEAM_OR_INVALID_COLLECTION_TYPE")
Expand Down
Expand Up @@ -244,11 +244,6 @@ const saveRequestAs = async () => {

const collectionHandle = collectionHandleResult.right

if (collectionHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}

const requestHandleResult = await workspaceService.createRESTRequest(
collectionHandle,
updatedRequest
Expand All @@ -261,23 +256,19 @@ const saveRequestAs = async () => {

const requestHandle = requestHandleResult.right

if (requestHandle.value.type === "invalid") {
const requestHandleRef = requestHandle.get()

if (requestHandleRef.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}

const { collectionID, providerID, requestID, workspaceID } =
requestHandle.value.data

RESTTabs.currentActiveTab.value.document = {
request: updatedRequest,
isDirty: false,
saveContext: {
originLocation: "workspace-user-collection",
workspaceID,
providerID,
collectionID,
requestID,
requestHandle,
},
}

Expand All @@ -298,7 +289,9 @@ const saveRequestAs = async () => {

const requestHandle = requestHandleResult.right

if (requestHandle.value.type === "invalid") {
const requestHandleRef = requestHandle.get()

if (requestHandleRef.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
Expand All @@ -313,18 +306,12 @@ const saveRequestAs = async () => {
return
}

const { collectionID, providerID, requestID, workspaceID } =
requestHandle.value.data

RESTTabs.currentActiveTab.value.document = {
request: updatedRequest,
isDirty: false,
saveContext: {
originLocation: "workspace-user-collection",
workspaceID,
providerID,
collectionID,
requestID,
requestHandle,
},
}

Expand Down
Expand Up @@ -21,7 +21,7 @@ import { GistSource } from "~/helpers/import-export/import/import-sources/GistSo

import IconFolderPlus from "~icons/lucide/folder-plus"
import IconUser from "~icons/lucide/user"
import { initializeDownloadCollection } from "~/helpers/import-export/export"
import { initializeDownloadFile } from "~/helpers/import-export/export"
import { useReadonlyStream } from "~/composables/stream"

import { platform } from "~/platform"
Expand Down Expand Up @@ -133,12 +133,12 @@ const GqlCollectionsHoppExporter: ImporterOrExporter = {
disabled: false,
applicableTo: ["personal-workspace", "team-workspace"],
},
action: () => {
action: async () => {
if (!gqlCollections.value.length) {
return toast.error(t("error.no_collections_to_export"))
}

const message = initializeDownloadCollection(
const message = await initializeDownloadFile(
gqlCollectionsExporter(gqlCollections.value),
"GQLCollections"
)
Expand Down
Expand Up @@ -37,7 +37,7 @@ import IconFolderPlus from "~icons/lucide/folder-plus"
import IconPostman from "~icons/hopp/postman"
import IconInsomnia from "~icons/hopp/insomnia"
import IconUser from "~icons/lucide/user"
import { initializeDownloadCollection } from "~/helpers/import-export/export"
import { initializeDownloadFile } from "~/helpers/import-export/export"
import { computed } from "vue"
import { useReadonlyStream } from "~/composables/stream"
import { environmentsExporter } from "~/helpers/import-export/export/environments"
Expand Down Expand Up @@ -235,12 +235,12 @@ const HoppEnvironmentsExport: ImporterOrExporter = {
disabled: false,
applicableTo: ["personal-workspace", "team-workspace"],
},
action: () => {
action: async () => {
if (!environmentJson.value.length) {
return toast.error(t("error.no_environments_to_export"))
}

const message = initializeDownloadCollection(
const message = await initializeDownloadFile(
environmentsExporter(environmentJson.value),
"Environments"
)
Expand Down