feat: support import collections between workspaces (#4377)
Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,9 @@
|
|||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"choose_file": "Choose a file",
|
"choose_file": "Choose a file",
|
||||||
|
"choose_workspace": "Choose a workspace",
|
||||||
|
"choose_collection": "Choose a collection",
|
||||||
|
"select_workspace": "Select a workspace",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"clear_all": "Clear all",
|
"clear_all": "Clear all",
|
||||||
"clear_history": "Clear all History",
|
"clear_history": "Clear all History",
|
||||||
@@ -460,6 +463,8 @@
|
|||||||
"from_json_description": "Import from Hoppscotch collection file",
|
"from_json_description": "Import from Hoppscotch collection file",
|
||||||
"from_my_collections": "Import from Personal Collections",
|
"from_my_collections": "Import from Personal Collections",
|
||||||
"from_my_collections_description": "Import from Personal Collections file",
|
"from_my_collections_description": "Import from Personal Collections file",
|
||||||
|
"from_all_collections": "Import from Another Workspace",
|
||||||
|
"from_all_collections_description": "Import any collection from Another Workspace to the current workspace",
|
||||||
"from_openapi": "Import from OpenAPI",
|
"from_openapi": "Import from OpenAPI",
|
||||||
"from_openapi_description": "Import from OpenAPI specification file (YML/JSON)",
|
"from_openapi_description": "Import from OpenAPI specification file (YML/JSON)",
|
||||||
"from_postman": "Import from Postman",
|
"from_postman": "Import from Postman",
|
||||||
@@ -947,7 +952,9 @@
|
|||||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||||
"unsubscribed_success": "Successfully unsubscribed from topic: {topic}",
|
"unsubscribed_success": "Successfully unsubscribed from topic: {topic}",
|
||||||
"waiting_send_request": "Waiting to send request"
|
"waiting_send_request": "Waiting to send request",
|
||||||
|
"loading_workspaces": "Loading workspaces",
|
||||||
|
"loading_collections_in_workspace": "Loading collections in workspace"
|
||||||
},
|
},
|
||||||
"support": {
|
"support": {
|
||||||
"changelog": "Read more about latest releases",
|
"changelog": "Read more about latest releases",
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ declare module 'vue' {
|
|||||||
ImportExportBase: typeof import('./components/importExport/Base.vue')['default']
|
ImportExportBase: typeof import('./components/importExport/Base.vue')['default']
|
||||||
ImportExportImportExportList: typeof import('./components/importExport/ImportExportList.vue')['default']
|
ImportExportImportExportList: typeof import('./components/importExport/ImportExportList.vue')['default']
|
||||||
ImportExportImportExportSourcesList: typeof import('./components/importExport/ImportExportSourcesList.vue')['default']
|
ImportExportImportExportSourcesList: typeof import('./components/importExport/ImportExportSourcesList.vue')['default']
|
||||||
|
ImportExportImportExportStepsAllCollectionImport: typeof import('./components/importExport/ImportExportSteps/AllCollectionImport.vue')['default']
|
||||||
ImportExportImportExportStepsFileImport: typeof import('./components/importExport/ImportExportSteps/FileImport.vue')['default']
|
ImportExportImportExportStepsFileImport: typeof import('./components/importExport/ImportExportSteps/FileImport.vue')['default']
|
||||||
ImportExportImportExportStepsMyCollectionImport: typeof import('./components/importExport/ImportExportSteps/MyCollectionImport.vue')['default']
|
ImportExportImportExportStepsMyCollectionImport: typeof import('./components/importExport/ImportExportSteps/MyCollectionImport.vue')['default']
|
||||||
ImportExportImportExportStepsUrlImport: typeof import('./components/importExport/ImportExportSteps/UrlImport.vue')['default']
|
ImportExportImportExportStepsUrlImport: typeof import('./components/importExport/ImportExportSteps/UrlImport.vue')['default']
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
|
|
||||||
import { defineStep } from "~/composables/step-components"
|
import { defineStep } from "~/composables/step-components"
|
||||||
|
|
||||||
import MyCollectionImport from "~/components/importExport/ImportExportSteps/MyCollectionImport.vue"
|
import AllCollectionImport from "~/components/importExport/ImportExportSteps/AllCollectionImport.vue"
|
||||||
import { useI18n } from "~/composables/i18n"
|
import { useI18n } from "~/composables/i18n"
|
||||||
import { useToast } from "~/composables/toast"
|
import { useToast } from "~/composables/toast"
|
||||||
import { appendRESTCollections, restCollections$ } from "~/newstore/collections"
|
import { appendRESTCollections, restCollections$ } from "~/newstore/collections"
|
||||||
@@ -61,7 +61,7 @@ const isPostmanImporterInProgress = ref(false)
|
|||||||
const isInsomniaImporterInProgress = ref(false)
|
const isInsomniaImporterInProgress = ref(false)
|
||||||
const isOpenAPIImporterInProgress = ref(false)
|
const isOpenAPIImporterInProgress = ref(false)
|
||||||
const isRESTImporterInProgress = ref(false)
|
const isRESTImporterInProgress = ref(false)
|
||||||
const isPersonalCollectionImporterInProgress = ref(false)
|
const isAllCollectionImporterInProgress = ref(false)
|
||||||
const isHarImporterInProgress = ref(false)
|
const isHarImporterInProgress = ref(false)
|
||||||
const isGistImporterInProgress = ref(false)
|
const isGistImporterInProgress = ref(false)
|
||||||
|
|
||||||
@@ -209,19 +209,19 @@ const HoppRESTImporter: ImporterOrExporter = {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
const HoppMyCollectionImporter: ImporterOrExporter = {
|
const HoppAllCollectionImporter: ImporterOrExporter = {
|
||||||
metadata: {
|
metadata: {
|
||||||
id: "hopp_my_collection",
|
id: "hopp_all_collection",
|
||||||
name: "import.from_my_collections",
|
name: "import.from_all_collections",
|
||||||
title: "import.from_my_collections_description",
|
title: "import.from_all_collections_description",
|
||||||
icon: IconUser,
|
icon: IconUser,
|
||||||
disabled: false,
|
disabled: !currentUser.value,
|
||||||
applicableTo: ["team-workspace"],
|
applicableTo: ["personal-workspace", "team-workspace"],
|
||||||
},
|
},
|
||||||
component: defineStep("my_collection_import", MyCollectionImport, () => ({
|
component: defineStep("all_collection_import", AllCollectionImport, () => ({
|
||||||
loading: isPersonalCollectionImporterInProgress.value,
|
loading: isAllCollectionImporterInProgress.value,
|
||||||
async onImportFromMyCollection(content) {
|
async onImportCollection(content) {
|
||||||
isPersonalCollectionImporterInProgress.value = true
|
isAllCollectionImporterInProgress.value = true
|
||||||
|
|
||||||
await handleImportToStore([content])
|
await handleImportToStore([content])
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ const HoppMyCollectionImporter: ImporterOrExporter = {
|
|||||||
platform: "rest",
|
platform: "rest",
|
||||||
})
|
})
|
||||||
|
|
||||||
isPersonalCollectionImporterInProgress.value = false
|
isAllCollectionImporterInProgress.value = false
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
@@ -351,7 +351,7 @@ const HoppInsomniaImporter: ImporterOrExporter = {
|
|||||||
name: "import.from_insomnia",
|
name: "import.from_insomnia",
|
||||||
title: "import.from_insomnia_description",
|
title: "import.from_insomnia_description",
|
||||||
icon: IconInsomnia,
|
icon: IconInsomnia,
|
||||||
disabled: true,
|
disabled: false,
|
||||||
applicableTo: ["personal-workspace", "team-workspace", "url-import"],
|
applicableTo: ["personal-workspace", "team-workspace", "url-import"],
|
||||||
},
|
},
|
||||||
component: FileSource({
|
component: FileSource({
|
||||||
@@ -387,7 +387,7 @@ const HoppGistImporter: ImporterOrExporter = {
|
|||||||
name: "import.from_gist",
|
name: "import.from_gist",
|
||||||
title: "import.from_gist_description",
|
title: "import.from_gist_description",
|
||||||
icon: IconGithub,
|
icon: IconGithub,
|
||||||
disabled: true,
|
disabled: false,
|
||||||
applicableTo: ["personal-workspace", "team-workspace", "url-import"],
|
applicableTo: ["personal-workspace", "team-workspace", "url-import"],
|
||||||
},
|
},
|
||||||
component: GistSource({
|
component: GistSource({
|
||||||
@@ -596,7 +596,7 @@ const HARImporter: ImporterOrExporter = {
|
|||||||
const importerModules = computed(() => {
|
const importerModules = computed(() => {
|
||||||
const enabledImporters = [
|
const enabledImporters = [
|
||||||
HoppRESTImporter,
|
HoppRESTImporter,
|
||||||
HoppMyCollectionImporter,
|
HoppAllCollectionImporter,
|
||||||
HoppOpenAPIImporter,
|
HoppOpenAPIImporter,
|
||||||
HoppPostmanImporter,
|
HoppPostmanImporter,
|
||||||
HoppInsomniaImporter,
|
HoppInsomniaImporter,
|
||||||
@@ -607,6 +607,10 @@ const importerModules = computed(() => {
|
|||||||
const isTeams = props.collectionsType.type === "team-collections"
|
const isTeams = props.collectionsType.type === "team-collections"
|
||||||
|
|
||||||
return enabledImporters.filter((importer) => {
|
return enabledImporters.filter((importer) => {
|
||||||
|
if (importer.metadata.disabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return isTeams
|
return isTeams
|
||||||
? importer.metadata.applicableTo.includes("team-workspace")
|
? importer.metadata.applicableTo.includes("team-workspace")
|
||||||
: importer.metadata.applicableTo.includes("personal-workspace")
|
: importer.metadata.applicableTo.includes("personal-workspace")
|
||||||
|
|||||||
@@ -1,18 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<HoppSmartExpand v-if="showExpand">
|
<div class="flex flex-col space-y-2">
|
||||||
<template #body>
|
|
||||||
<HoppSmartItem
|
|
||||||
v-for="importer in importers"
|
|
||||||
:key="importer.id"
|
|
||||||
:icon="importer.icon"
|
|
||||||
:label="t(`${importer.name}`)"
|
|
||||||
@click="emit('importer-selected', importer.id)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</HoppSmartExpand>
|
|
||||||
|
|
||||||
<div v-else class="flex flex-col space-y-2">
|
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
v-for="importer in importers"
|
v-for="importer in importers"
|
||||||
:key="importer.id"
|
:key="importer.id"
|
||||||
@@ -59,7 +47,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from "@composables/i18n"
|
import { useI18n } from "@composables/i18n"
|
||||||
import { Component, computed } from "vue"
|
import { Component } from "vue"
|
||||||
|
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
|
||||||
@@ -73,7 +61,7 @@ type ImportExportEntryMeta = {
|
|||||||
isVisible?: boolean
|
isVisible?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
defineProps<{
|
||||||
importers: ImportExportEntryMeta[]
|
importers: ImportExportEntryMeta[]
|
||||||
exporters: ImportExportEntryMeta[]
|
exporters: ImportExportEntryMeta[]
|
||||||
}>()
|
}>()
|
||||||
@@ -82,6 +70,4 @@ const emit = defineEmits<{
|
|||||||
(e: "importer-selected", importerID: string): void
|
(e: "importer-selected", importerID: string): void
|
||||||
(e: "exporter-selected", exporterID: string): void
|
(e: "exporter-selected", exporterID: string): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const showExpand = computed(() => props.importers.length >= 4)
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,366 @@
|
|||||||
|
<template>
|
||||||
|
<div class="select-wrapper flex flex-col gap-2">
|
||||||
|
<div>
|
||||||
|
<p class="flex items-center">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center justify-center flex-shrink-0 mr-4 border-4 rounded-full border-primary text-dividerDark"
|
||||||
|
>
|
||||||
|
<icon-lucide-check-circle class="svg-icons" />
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ t(`action.choose_workspace`) }}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<div class="pl-10">
|
||||||
|
<div v-if="isLoadingTeams" class="flex gap-1 mt-2">
|
||||||
|
<HoppSmartSpinner />
|
||||||
|
|
||||||
|
{{ t("state.loading_workspaces") }}
|
||||||
|
</div>
|
||||||
|
<select
|
||||||
|
v-else
|
||||||
|
v-model="selectedWorkspaceID"
|
||||||
|
autocomplete="off"
|
||||||
|
class="select mt-2"
|
||||||
|
autofocus
|
||||||
|
>
|
||||||
|
<option :key="undefined" :value="undefined" disabled selected>
|
||||||
|
{{ t("action.select_workspace") }}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="workspace in workspaces"
|
||||||
|
:key="`workspace-${workspace.id}`"
|
||||||
|
:value="workspace.id"
|
||||||
|
class="bg-primary"
|
||||||
|
>
|
||||||
|
{{ workspace.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="showSelectCollections">
|
||||||
|
<p class="flex items-center">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center justify-center flex-shrink-0 mr-4 border-4 rounded-full border-primary text-dividerDark"
|
||||||
|
>
|
||||||
|
<icon-lucide-check-circle class="svg-icons" />
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ t(`action.choose_collection`) }}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<div class="pl-10">
|
||||||
|
<div v-if="isGettingWorkspaceRootCollections" class="flex gap-1 mt-2">
|
||||||
|
<HoppSmartSpinner />
|
||||||
|
|
||||||
|
{{ t("state.loading_collections_in_workspace") }}
|
||||||
|
</div>
|
||||||
|
<select
|
||||||
|
v-else
|
||||||
|
v-model="selectedCollectionID"
|
||||||
|
autocomplete="off"
|
||||||
|
class="select mt-2"
|
||||||
|
autofocus
|
||||||
|
>
|
||||||
|
<option :key="undefined" :value="undefined" disabled selected>
|
||||||
|
{{ t("collection.select") }}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="collection in selectableCollections"
|
||||||
|
:key="collection.id"
|
||||||
|
:value="collection.id"
|
||||||
|
class="bg-primary"
|
||||||
|
>
|
||||||
|
{{ collection.title }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-4">
|
||||||
|
<HoppButtonPrimary
|
||||||
|
class="w-full"
|
||||||
|
:label="t('import.title')"
|
||||||
|
:loading="loading"
|
||||||
|
:disabled="!hasSelectedCollectionID || loading"
|
||||||
|
@click="getCollectionDetailsAndImport"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
GQLHeader,
|
||||||
|
HoppCollection,
|
||||||
|
HoppGQLAuth,
|
||||||
|
HoppGQLRequest,
|
||||||
|
HoppRESTAuth,
|
||||||
|
HoppRESTHeader,
|
||||||
|
HoppRESTRequest,
|
||||||
|
makeCollection,
|
||||||
|
} from "@hoppscotch/data"
|
||||||
|
import { useService } from "dioc/vue"
|
||||||
|
import { computed, ref, watch } from "vue"
|
||||||
|
import { useI18n } from "~/composables/i18n"
|
||||||
|
import { useReadonlyStream } from "~/composables/stream"
|
||||||
|
import { runGQLQuery } from "~/helpers/backend/GQLClient"
|
||||||
|
import { RootCollectionsOfTeamDocument } from "~/helpers/backend/graphql"
|
||||||
|
import { TEAMS_BACKEND_PAGE_SIZE } from "~/helpers/teams/TeamCollectionAdapter"
|
||||||
|
import { getRESTCollection, restCollections$ } from "~/newstore/collections"
|
||||||
|
import { WorkspaceService } from "~/services/workspace.service"
|
||||||
|
import * as E from "fp-ts/Either"
|
||||||
|
import {
|
||||||
|
getCollectionChildCollections,
|
||||||
|
getSingleCollection,
|
||||||
|
} from "~/helpers/teams/TeamCollection"
|
||||||
|
import { getCollectionChildRequests } from "~/helpers/teams/TeamRequest"
|
||||||
|
import { useToast } from "~/composables/toast"
|
||||||
|
|
||||||
|
const workspaceService = useService(WorkspaceService)
|
||||||
|
const teamListAdapter = workspaceService.acquireTeamListAdapter(null)
|
||||||
|
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
|
||||||
|
const isLoadingTeams = useReadonlyStream(teamListAdapter.loading$, false)
|
||||||
|
|
||||||
|
const t = useI18n()
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
loading: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const selectedCollectionID = ref<string | undefined>(undefined)
|
||||||
|
|
||||||
|
const hasSelectedCollectionID = computed(() => {
|
||||||
|
return selectedCollectionID.value !== undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const personalCollections = useReadonlyStream(restCollections$, [])
|
||||||
|
|
||||||
|
const selectedWorkspaceID = ref<string | undefined>(undefined)
|
||||||
|
|
||||||
|
const isGettingWorkspaceRootCollections = ref(false)
|
||||||
|
|
||||||
|
const selectableCollections = ref<
|
||||||
|
{
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
data?: string | null
|
||||||
|
}[]
|
||||||
|
>([])
|
||||||
|
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
|
watch(
|
||||||
|
selectedWorkspaceID,
|
||||||
|
async () => {
|
||||||
|
// reset the selected collection when the workspace changes
|
||||||
|
selectedCollectionID.value = undefined
|
||||||
|
|
||||||
|
if (!selectedWorkspaceID.value) {
|
||||||
|
// do some cleanup on the previous workspace selection
|
||||||
|
selectableCollections.value = []
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedWorkspaceID.value === "personal") {
|
||||||
|
selectableCollections.value = personalCollections.value.map(
|
||||||
|
(collection, collectionIndex) => ({
|
||||||
|
id: `${collectionIndex}`, // because we don't have an ID for personal collections
|
||||||
|
title: collection.name,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isGettingWorkspaceRootCollections.value = true
|
||||||
|
|
||||||
|
const res = await getWorkspaceRootCollections(selectedWorkspaceID.value)
|
||||||
|
|
||||||
|
if (E.isLeft(res)) {
|
||||||
|
console.error(res.left)
|
||||||
|
isGettingWorkspaceRootCollections.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selectableCollections.value = res.right
|
||||||
|
|
||||||
|
isGettingWorkspaceRootCollections.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "importCollection", content: HoppCollection): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const showSelectCollections = computed(() => {
|
||||||
|
return !!selectedWorkspaceID.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const workspaces = computed(() => {
|
||||||
|
const allWorkspaces = [
|
||||||
|
{
|
||||||
|
id: "personal",
|
||||||
|
name: t("workspace.personal"),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
myTeams.value?.forEach((team) => {
|
||||||
|
allWorkspaces.push({
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return allWorkspaces
|
||||||
|
})
|
||||||
|
|
||||||
|
const getWorkspaceRootCollections = async (workspaceID: string) => {
|
||||||
|
const totalCollections: {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
data?: string | null
|
||||||
|
}[] = []
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const result = await runGQLQuery({
|
||||||
|
query: RootCollectionsOfTeamDocument,
|
||||||
|
variables: {
|
||||||
|
teamID: workspaceID,
|
||||||
|
cursor:
|
||||||
|
totalCollections.length > 0
|
||||||
|
? totalCollections[totalCollections.length - 1].id
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (E.isLeft(result)) {
|
||||||
|
return E.left(result.left)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCollections.push(...result.right.rootCollectionsOfTeam)
|
||||||
|
|
||||||
|
if (result.right.rootCollectionsOfTeam.length < TEAMS_BACKEND_PAGE_SIZE) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return E.right(totalCollections)
|
||||||
|
}
|
||||||
|
|
||||||
|
const convertToInheritedProperties = (
|
||||||
|
data?: string | null
|
||||||
|
): {
|
||||||
|
auth: HoppRESTAuth | HoppGQLAuth
|
||||||
|
headers: Array<HoppRESTHeader | GQLHeader>
|
||||||
|
} => {
|
||||||
|
const collectionLevelAuthAndHeaders = data
|
||||||
|
? (JSON.parse(data) as {
|
||||||
|
auth: HoppRESTAuth | HoppGQLAuth
|
||||||
|
headers: Array<HoppRESTHeader | GQLHeader>
|
||||||
|
})
|
||||||
|
: null
|
||||||
|
|
||||||
|
const headers = collectionLevelAuthAndHeaders?.headers ?? []
|
||||||
|
|
||||||
|
const auth = collectionLevelAuthAndHeaders?.auth ?? {
|
||||||
|
authType: "none",
|
||||||
|
authActive: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
auth,
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTeamCollection = async (
|
||||||
|
collectionID: string
|
||||||
|
): Promise<E.Either<any, HoppCollection>> => {
|
||||||
|
const rootCollectionRes = await getSingleCollection(collectionID)
|
||||||
|
|
||||||
|
if (E.isLeft(rootCollectionRes)) {
|
||||||
|
return E.left(rootCollectionRes.left)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootCollection = rootCollectionRes.right.collection
|
||||||
|
|
||||||
|
if (!rootCollection) {
|
||||||
|
return E.left("ROOT_COLLECTION_NOT_FOUND")
|
||||||
|
}
|
||||||
|
|
||||||
|
const childRequests = await getCollectionChildRequests(collectionID)
|
||||||
|
|
||||||
|
if (E.isLeft(childRequests)) {
|
||||||
|
return E.left(childRequests.left)
|
||||||
|
}
|
||||||
|
|
||||||
|
const childCollectionsRes = await getCollectionChildCollections(collectionID)
|
||||||
|
|
||||||
|
if (E.isLeft(childCollectionsRes)) {
|
||||||
|
return E.left(childCollectionsRes.left)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!childCollectionsRes.right.collection) {
|
||||||
|
return E.left("CHILD_COLLECTIONS_NOT_FOUND")
|
||||||
|
}
|
||||||
|
|
||||||
|
const childCollectionExpandedPromises =
|
||||||
|
childCollectionsRes.right.collection.children.map((col) =>
|
||||||
|
getTeamCollection(col.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
const childCollectionPromiseRes = await Promise.all(
|
||||||
|
childCollectionExpandedPromises
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasAnyError = childCollectionPromiseRes.some((res) => E.isLeft(res))
|
||||||
|
|
||||||
|
if (hasAnyError) {
|
||||||
|
return E.left("CHILD_COLLECTIONS_NOT_FOUND")
|
||||||
|
}
|
||||||
|
|
||||||
|
const unwrappedChildCollections = childCollectionPromiseRes.map(
|
||||||
|
(res) => (res as E.Right<HoppCollection>).right
|
||||||
|
)
|
||||||
|
|
||||||
|
const collectionInHoppFormat: HoppCollection = makeCollection({
|
||||||
|
name: rootCollection.title,
|
||||||
|
...convertToInheritedProperties(rootCollection.data),
|
||||||
|
folders: unwrappedChildCollections,
|
||||||
|
requests: childRequests.right.requestsInCollection.map((req) => {
|
||||||
|
return JSON.parse(req.request) as HoppRESTRequest | HoppGQLRequest
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
return E.right(collectionInHoppFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCollectionDetailsAndImport = async () => {
|
||||||
|
if (!selectedCollectionID.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let collectionToImport: HoppCollection
|
||||||
|
|
||||||
|
if (selectedWorkspaceID.value === "personal") {
|
||||||
|
collectionToImport = getRESTCollection(parseInt(selectedCollectionID.value))
|
||||||
|
} else {
|
||||||
|
const res = await getTeamCollection(selectedCollectionID.value)
|
||||||
|
|
||||||
|
if (E.isLeft(res)) {
|
||||||
|
toast.error(t("import.failed"))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionToImport = res.right
|
||||||
|
}
|
||||||
|
|
||||||
|
emit("importCollection", collectionToImport)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
import { runGQLQuery } from "../backend/GQLClient"
|
||||||
|
import {
|
||||||
|
GetCollectionChildrenDocument,
|
||||||
|
GetSingleCollectionDocument,
|
||||||
|
} from "../backend/graphql"
|
||||||
import { TeamRequest } from "./TeamRequest"
|
import { TeamRequest } from "./TeamRequest"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,3 +15,19 @@ export interface TeamCollection {
|
|||||||
requests: TeamRequest[] | null
|
requests: TeamRequest[] | null
|
||||||
data: string | null
|
data: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getSingleCollection = (collectionID: string) =>
|
||||||
|
runGQLQuery({
|
||||||
|
query: GetSingleCollectionDocument,
|
||||||
|
variables: {
|
||||||
|
collectionID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getCollectionChildCollections = (collectionID: string) =>
|
||||||
|
runGQLQuery({
|
||||||
|
query: GetCollectionChildrenDocument,
|
||||||
|
variables: {
|
||||||
|
collectionID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
} from "~/helpers/backend/graphql"
|
} from "~/helpers/backend/graphql"
|
||||||
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
||||||
|
|
||||||
const TEAMS_BACKEND_PAGE_SIZE = 10
|
export const TEAMS_BACKEND_PAGE_SIZE = 10
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the parent of a collection and returns the REFERENCE (or null)
|
* Finds the parent of a collection and returns the REFERENCE (or null)
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||||
|
import { runGQLQuery } from "../backend/GQLClient"
|
||||||
|
import {
|
||||||
|
GetCollectionRequestsDocument,
|
||||||
|
GetSingleRequestDocument,
|
||||||
|
} from "../backend/graphql"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines how a Teams request is represented in TeamCollectionAdapter
|
* Defines how a Teams request is represented in TeamCollectionAdapter
|
||||||
@@ -9,3 +14,19 @@ export interface TeamRequest {
|
|||||||
title: string
|
title: string
|
||||||
request: HoppRESTRequest
|
request: HoppRESTRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getCollectionChildRequests = (collectionID: string) =>
|
||||||
|
runGQLQuery({
|
||||||
|
query: GetCollectionRequestsDocument,
|
||||||
|
variables: {
|
||||||
|
collectionID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getSingleRequest = (requestID: string) =>
|
||||||
|
runGQLQuery({
|
||||||
|
query: GetSingleRequestDocument,
|
||||||
|
variables: {
|
||||||
|
requestID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -8,19 +8,15 @@ import axios from "axios"
|
|||||||
import { Service } from "dioc"
|
import { Service } from "dioc"
|
||||||
import * as E from "fp-ts/Either"
|
import * as E from "fp-ts/Either"
|
||||||
import { Ref, ref } from "vue"
|
import { Ref, ref } from "vue"
|
||||||
|
import { getSingleCollection, TeamCollection } from "./TeamCollection"
|
||||||
import { runGQLQuery } from "../backend/GQLClient"
|
|
||||||
import {
|
|
||||||
GetCollectionChildrenDocument,
|
|
||||||
GetCollectionRequestsDocument,
|
|
||||||
GetSingleCollectionDocument,
|
|
||||||
GetSingleRequestDocument,
|
|
||||||
} from "../backend/graphql"
|
|
||||||
import { TeamCollection } from "./TeamCollection"
|
|
||||||
|
|
||||||
import { platform } from "~/platform"
|
import { platform } from "~/platform"
|
||||||
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
||||||
import { TeamRequest } from "./TeamRequest"
|
import {
|
||||||
|
getSingleRequest,
|
||||||
|
getCollectionChildRequests,
|
||||||
|
TeamRequest,
|
||||||
|
} from "./TeamRequest"
|
||||||
|
|
||||||
type CollectionSearchMeta = {
|
type CollectionSearchMeta = {
|
||||||
isSearchResult?: boolean
|
isSearchResult?: boolean
|
||||||
@@ -552,38 +548,6 @@ export class TeamSearchService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSingleCollection = (collectionID: string) =>
|
|
||||||
runGQLQuery({
|
|
||||||
query: GetSingleCollectionDocument,
|
|
||||||
variables: {
|
|
||||||
collectionID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const getSingleRequest = (requestID: string) =>
|
|
||||||
runGQLQuery({
|
|
||||||
query: GetSingleRequestDocument,
|
|
||||||
variables: {
|
|
||||||
requestID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const getCollectionChildCollections = (collectionID: string) =>
|
|
||||||
runGQLQuery({
|
|
||||||
query: GetCollectionChildrenDocument,
|
|
||||||
variables: {
|
|
||||||
collectionID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const getCollectionChildRequests = (collectionID: string) =>
|
|
||||||
runGQLQuery({
|
|
||||||
query: GetCollectionRequestsDocument,
|
|
||||||
variables: {
|
|
||||||
collectionID,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const formatTeamsSearchResultsForSpotlight = (
|
const formatTeamsSearchResultsForSpotlight = (
|
||||||
request: {
|
request: {
|
||||||
collectionID: string
|
collectionID: string
|
||||||
|
|||||||
Reference in New Issue
Block a user