refactor: compile data in handles

Introduce a handle for requests.
This commit is contained in:
jamesgeorge007
2024-02-07 11:36:33 +05:30
parent ab7df212c2
commit 89bcc58de6
10 changed files with 1616 additions and 666 deletions

View File

@@ -75,7 +75,7 @@ import {
import { useVModel } from "@vueuse/core" import { useVModel } from "@vueuse/core"
import { useService } from "dioc/vue" import { useService } from "dioc/vue"
import { clone } from "lodash-es" import { clone } from "lodash-es"
import { ref, watch } from "vue" import { ref, toRefs, watch } from "vue"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
import { PersistenceService } from "~/services/persistence" import { PersistenceService } from "~/services/persistence"
@@ -100,11 +100,15 @@ const props = withDefaults(
editingProperties: EditingProperties | null editingProperties: EditingProperties | null
source: "REST" | "GraphQL" source: "REST" | "GraphQL"
modelValue: string modelValue: string
// TODO: Purpose of this prop is to maintain backwards compatibility
// To be removed after porting all usages of this component
emitWithFullCollection: boolean
}>(), }>(),
{ {
show: false, show: false,
loadingState: false, loadingState: false,
editingProperties: null, editingProperties: null,
emitWithFullCollection: true,
} }
) )
@@ -178,15 +182,24 @@ watch(
const saveEditedCollection = () => { const saveEditedCollection = () => {
if (!props.editingProperties) return if (!props.editingProperties) return
const finalCollection = clone(editableCollection.value) const finalCollection = clone(editableCollection.value)
delete finalCollection.body
const { path } = toRefs(props.editingProperties)
const collection = { const collection = {
path: props.editingProperties.path, path: path.value,
collection: { collection: {
...props.editingProperties.collection, ...props.editingProperties.collection,
...finalCollection, ...finalCollection,
}, },
isRootCollection: props.editingProperties.isRootCollection, isRootCollection: props.editingProperties.isRootCollection,
} }
emit("set-collection-properties", collection as EditingProperties)
const data = props.emitWithFullCollection
? collection
: { ...finalCollection, collIndexPath: path.value }
emit("set-collection-properties", data as EditingProperties)
persistenceService.removeLocalConfig("unsaved_collection_properties") persistenceService.removeLocalConfig("unsaved_collection_properties")
} }

View File

@@ -245,7 +245,6 @@ import { UpdateRequestDocument } from "~/helpers/backend/graphql"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils" import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import { runRESTRequest$ } from "~/helpers/RequestRunner" import { runRESTRequest$ } from "~/helpers/RequestRunner"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { editRESTRequest } from "~/newstore/collections"
import IconChevronDown from "~icons/lucide/chevron-down" import IconChevronDown from "~icons/lucide/chevron-down"
import IconCode2 from "~icons/lucide/code-2" import IconCode2 from "~icons/lucide/code-2"
import IconFileCode from "~icons/lucide/file-code" import IconFileCode from "~icons/lucide/file-code"
@@ -265,9 +264,11 @@ import { HoppRESTDocument } from "~/helpers/rest/document"
import { RESTTabService } from "~/services/tab/rest" import { RESTTabService } from "~/services/tab/rest"
import { getMethodLabelColorClassOf } from "~/helpers/rest/labelColoring" import { getMethodLabelColorClassOf } from "~/helpers/rest/labelColoring"
import { WorkspaceService } from "~/services/workspace.service" import { WorkspaceService } from "~/services/workspace.service"
import { NewWorkspaceService } from "~/services/new-workspace"
const t = useI18n() const t = useI18n()
const interceptorService = useService(InterceptorService) const interceptorService = useService(InterceptorService)
const newWorkspaceService = useService(NewWorkspaceService)
const methods = [ const methods = [
"GET", "GET",
@@ -506,7 +507,7 @@ const cycleDownMethod = () => {
} }
} }
const saveRequest = () => { const saveRequest = async () => {
const saveCtx = tab.value.document.saveContext const saveCtx = tab.value.document.saveContext
if (!saveCtx) { if (!saveCtx) {
@@ -514,25 +515,72 @@ const saveRequest = () => {
return return
} }
if (saveCtx.originLocation === "user-collection") { if (saveCtx.originLocation === "user-collection") {
const req = tab.value.document.request const updatedRequest = tab.value.document.request
try { if (!newWorkspaceService.activeWorkspaceHandle.value) {
editRESTRequest(saveCtx.folderPath, saveCtx.requestIndex, req) return
tab.value.document.isDirty = false
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
platform: "rest",
createdNow: false,
workspaceType: "personal",
})
toast.success(`${t("request.saved")}`)
} catch (e) {
tab.value.document.saveContext = undefined
saveRequest()
} }
const collHandleResult = await newWorkspaceService.getCollectionHandle(
newWorkspaceService.activeWorkspaceHandle.value,
saveCtx.folderPath
)
if (E.isLeft(collHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return
}
const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}
const requestHandleResult = await newWorkspaceService.getRequestHandle(
collHandle,
`${saveCtx.folderPath}/${saveCtx.requestIndex.toString()}`
)
if (E.isLeft(requestHandleResult)) {
// INVALID_REQUEST_HANDLE
return
}
const requestHandle = requestHandleResult.right
if (requestHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_REQUEST_HANDLE
return
}
const updatedRequestResult = await newWorkspaceService.saveRESTRequest(
requestHandle,
updatedRequest
)
if (E.isLeft(updatedRequestResult)) {
// INVALID_REQUEST_HANDLE
return
}
const resultHandle = updatedRequestResult.right
if (resultHandle.value.type === "invalid") {
// REQUEST_INVALIDATED | REQUEST_PATH_NOT_FOUND
if (resultHandle.value.reason === "REQUEST_PATH_NOT_FOUND") {
// REQUEST_PATH_NOT_FOUND
tab.value.document.saveContext = undefined
await saveRequest()
}
return
}
tab.value.document.isDirty = false
toast.success(`${t("request.saved")}`)
} else if (saveCtx.originLocation === "team-collection") { } else if (saveCtx.originLocation === "team-collection") {
const req = tab.value.document.request const req = tab.value.document.request

View File

@@ -18,7 +18,7 @@
class="pointer-events-none flex min-w-0 flex-1 py-2 pr-2 transition group-hover:text-secondaryDark" class="pointer-events-none flex min-w-0 flex-1 py-2 pr-2 transition group-hover:text-secondaryDark"
> >
<span class="truncate"> <span class="truncate">
{{ collection.name }} {{ collectionView.collection.name }}
</span> </span>
</span> </span>
</div> </div>
@@ -28,22 +28,14 @@
:icon="IconFilePlus" :icon="IconFilePlus"
:title="t('request.new')" :title="t('request.new')"
class="hidden group-hover:inline-flex" class="hidden group-hover:inline-flex"
@click=" @click="addRequest"
emit('add-request', {
path: collection.collectionID,
})
"
/> />
<HoppButtonSecondary <HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:icon="IconFolderPlus" :icon="IconFolderPlus"
:title="t('folder.new')" :title="t('folder.new')"
class="hidden group-hover:inline-flex" class="hidden group-hover:inline-flex"
@click=" @click="addChildCollection"
emit('add-folder', {
path: collection.collectionID,
})
"
/> />
<span> <span>
<tippy <tippy
@@ -77,9 +69,7 @@
:shortcut="['R']" :shortcut="['R']"
@click=" @click="
() => { () => {
emit('add-request', { addRequest()
path: collection.collectionID,
})
hide() hide()
} }
" "
@@ -91,9 +81,7 @@
:shortcut="['N']" :shortcut="['N']"
@click=" @click="
() => { () => {
emit('add-folder', { addChildCollection()
path: collection.collectionID,
})
hide() hide()
} }
" "
@@ -105,7 +93,7 @@
:shortcut="['E']" :shortcut="['E']"
@click=" @click="
() => { () => {
emit('edit-collection') editCollection()
hide() hide()
} }
" "
@@ -128,9 +116,22 @@
:shortcut="['⌫']" :shortcut="['⌫']"
@click=" @click="
() => { () => {
emit('remove-collection', { removeCollection()
path: collection.collectionID, hide()
}) }
"
/>
<HoppSmartItem
ref="propertiesAction"
:icon="IconSettings2"
:label="t('action.properties')"
:shortcut="['P']"
@click="
() => {
emit(
'edit-collection-properties',
collectionView.collectionID
)
hide() hide()
} }
" "
@@ -158,36 +159,31 @@ import IconTrash2 from "~icons/lucide/trash-2"
import IconEdit from "~icons/lucide/edit" import IconEdit from "~icons/lucide/edit"
import IconFolder from "~icons/lucide/folder" import IconFolder from "~icons/lucide/folder"
import IconFolderOpen from "~icons/lucide/folder-open" import IconFolderOpen from "~icons/lucide/folder-open"
import IconSettings2 from "~icons/lucide/settings-2"
const t = useI18n() const t = useI18n()
const props = defineProps<{ const props = defineProps<{
collection: RESTCollectionViewCollection collectionView: RESTCollectionViewCollection
isOpen: boolean isOpen: boolean
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
(event: "toggle-children"): void (event: "toggle-children"): void
(event: "add-request", parentCollIndexPath: string): void
(event: "add-child-collection", parentCollIndexPath: string): void
( (
event: "add-request", event: "edit-root-collection",
payload: { payload: { collIndexPath: string; collectionName: string }
path: string
}
): void ): void
( (
event: "add-folder", event: "edit-child-collection",
payload: { payload: { collIndexPath: string; collectionName: string }
path: string
}
): void ): void
(event: "edit-collection"): void (event: "edit-collection-properties", collIndexPath: string): void
(event: "export-data"): void (event: "export-data"): void
( (event: "remove-root-collection", collIndexPath: string): void
event: "remove-collection", (event: "remove-child-collection", collIndexPath: string): void
payload: {
path: string
}
): void
}>() }>()
const tippyActions = ref<TippyComponent | null>(null) const tippyActions = ref<TippyComponent | null>(null)
@@ -201,4 +197,36 @@ const options = ref<TippyComponent | null>(null)
const collectionIcon = computed(() => { const collectionIcon = computed(() => {
return !props.isOpen ? IconFolder : IconFolderOpen return !props.isOpen ? IconFolder : IconFolderOpen
}) })
const addChildCollection = () => {
emit("add-child-collection", props.collectionView.collectionID)
}
const addRequest = () => {
emit("add-request", props.collectionView.collectionID)
}
const editCollection = () => {
const {
collectionID: collIndexPath,
collection: { name: collectionName },
} = props.collectionView
const data = {
collIndexPath,
collectionName,
}
collIndexPath.split("/").length > 1
? emit("edit-child-collection", data)
: emit("edit-root-collection", data)
}
const removeCollection = () => {
const { collectionID } = props.collectionView
collectionID.split("/").length > 1
? emit("remove-child-collection", collectionID)
: emit("remove-root-collection", collectionID)
}
</script> </script>

View File

@@ -6,7 +6,7 @@
> >
<div <div
class="pointer-events-auto flex min-w-0 flex-1 cursor-pointer items-center justify-center" class="pointer-events-auto flex min-w-0 flex-1 cursor-pointer items-center justify-center"
@click="selectRequest(request.requestID, request.request)" @click="selectRequest"
> >
<span <span
class="pointer-events-none flex w-16 items-center justify-center truncate px-2" class="pointer-events-none flex w-16 items-center justify-center truncate px-2"
@@ -14,14 +14,14 @@
:style="{ color: requestLabelColor }" :style="{ color: requestLabelColor }"
> >
<span class="truncate text-tiny font-semibold"> <span class="truncate text-tiny font-semibold">
{{ request.method }} {{ requestView.request.method }}
</span> </span>
</span> </span>
<span <span
class="pointer-events-none flex min-w-0 flex-1 items-center py-2 pr-2 transition group-hover:text-secondaryDark" class="pointer-events-none flex min-w-0 flex-1 items-center py-2 pr-2 transition group-hover:text-secondaryDark"
> >
<span class="truncate"> <span class="truncate">
{{ request.name }} {{ requestView.request.name }}
</span> </span>
<span <span
v-if="isActive" v-if="isActive"
@@ -45,7 +45,7 @@
:icon="IconRotateCCW" :icon="IconRotateCCW"
:title="t('action.restore')" :title="t('action.restore')"
class="hidden group-hover:inline-flex" class="hidden group-hover:inline-flex"
@click="selectRequest(request.requestID, request.request)" @click="selectRequest"
/> />
<span> <span>
<tippy <tippy
@@ -78,8 +78,8 @@
@click=" @click="
() => { () => {
emit('edit-request', { emit('edit-request', {
requestPath: request.requestID, requestIndexPath: requestView.requestID,
request: request.request, requestName: requestView.request.name,
}) })
hide() hide()
} }
@@ -92,10 +92,7 @@
:shortcut="['D']" :shortcut="['D']"
@click=" @click="
() => { () => {
emit('duplicate-request', { emit('duplicate-request', requestView.requestID)
requestPath: request.requestID,
request: request.request,
})
hide() hide()
} }
" "
@@ -132,37 +129,24 @@ import { RESTCollectionViewRequest } from "~/services/new-workspace/view"
import { computed, ref } from "vue" import { computed, ref } from "vue"
import { TippyComponent } from "vue-tippy" import { TippyComponent } from "vue-tippy"
import { getMethodLabelColorClassOf } from "~/helpers/rest/labelColoring" import { getMethodLabelColorClassOf } from "~/helpers/rest/labelColoring"
import { HoppRESTRequest } from "@hoppscotch/data"
const t = useI18n() const t = useI18n()
const props = defineProps<{ const props = defineProps<{
request: RESTCollectionViewRequest requestView: RESTCollectionViewRequest
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
( (event: "duplicate-request", requestIndexPath: string): void
event: "duplicate-request",
payload: {
requestPath: string
request: HoppRESTRequest
}
): void
( (
event: "edit-request", event: "edit-request",
payload: { payload: {
requestPath: string requestIndexPath: string
request: HoppRESTRequest requestName: string
} }
): void ): void
(event: "remove-request"): void (event: "remove-request"): void
( (event: "select-request", requestIndexPath: string): void
event: "select-request",
payload: {
requestPath: string
request: HoppRESTRequest
}
): void
}>() }>()
const tippyActions = ref<TippyComponent | null>(null) const tippyActions = ref<TippyComponent | null>(null)
@@ -172,12 +156,8 @@ const options = ref<TippyComponent | null>(null)
const isActive = ref(true) const isActive = ref(true)
const requestLabelColor = computed(() => const requestLabelColor = computed(() =>
getMethodLabelColorClassOf(props.request) getMethodLabelColorClassOf(props.requestView.request)
) )
const selectRequest = (requestPath: string, request: HoppRESTRequest) => const selectRequest = () => emit("select-request", props.requestView.requestID)
emit("select-request", {
requestPath,
request,
})
</script> </script>

View File

@@ -22,7 +22,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:icon="IconImport" :icon="IconImport"
:title="t('modal.import_export')" :title="t('modal.import_export')"
@click="onImportExportClick" @click="() => {}"
/> />
</span> </span>
</div> </div>
@@ -33,16 +33,20 @@
<!-- TODO: Implement --> <!-- TODO: Implement -->
<NewCollectionsRestCollection <NewCollectionsRestCollection
v-if="node.data.type === 'collection'" v-if="node.data.type === 'collection'"
:collection="node.data.value" :collection-view="node.data.value"
:is-open="isOpen" :is-open="isOpen"
@add-request="addRequest" @add-request="addRequest"
@add-folder="addFolder" @add-child-collection="addChildCollection"
@remove-collection="removeFolder" @edit-root-collection="editRootCollection"
@edit-collection-properties="editCollectionProperties"
@edit-child-collection="editChildCollection"
@remove-root-collection="removeRootCollection"
@remove-child-collection="removeChildCollection"
@toggle-children="toggleChildren" @toggle-children="toggleChildren"
/> />
<NewCollectionsRestRequest <NewCollectionsRestRequest
v-else-if="node.data.type === 'request'" v-else-if="node.data.type === 'request'"
:request="node.data.value" :request-view="node.data.value"
@duplicate-request="duplicateRequest" @duplicate-request="duplicateRequest"
@edit-request="editRequest" @edit-request="editRequest"
@remove-request="removeRequest(node.data.value.requestID)" @remove-request="removeRequest(node.data.value.requestID)"
@@ -72,10 +76,24 @@
@hide-modal="displayModalAddRequest(false)" @hide-modal="displayModalAddRequest(false)"
/> />
<CollectionsAddFolder <CollectionsAddFolder
:show="showModalAddFolder" :show="showModalAddChildColl"
:loading-state="modalLoadingState" :loading-state="modalLoadingState"
@add-folder="onAddFolder" @add-folder="onAddChildCollection"
@hide-modal="displayModalAddFolder(false)" @hide-modal="displayModalAddChildColl(false)"
/>
<CollectionsEdit
:show="showModalEditRootColl"
:editing-collection-name="editingRootCollName ?? ''"
:loading-state="modalLoadingState"
@hide-modal="displayModalEditCollection(false)"
@submit="onEditRootCollection"
/>
<CollectionsEditFolder
:show="showModalEditChildColl"
:editing-folder-name="editingChildCollName ?? ''"
:loading-state="modalLoadingState"
@submit="onEditChildCollection"
@hide-modal="displayModalEditChildCollection(false)"
/> />
<CollectionsEditRequest <CollectionsEditRequest
v-model="editingRequestName" v-model="editingRequestName"
@@ -92,6 +110,15 @@
@hide-modal="showConfirmModal = false" @hide-modal="showConfirmModal = false"
@resolve="resolveConfirmModal" @resolve="resolveConfirmModal"
/> />
<!-- TODO: Remove the `emitWithFullCollection` prop after porting all usages of the below component -->
<CollectionsProperties
:show="showModalEditProperties"
:editing-properties="editingProperties"
:emit-with-full-collection="false"
@hide-modal="displayModalEditProperties(false)"
@set-collection-properties="setCollectionProperties"
/>
</div> </div>
</template> </template>
@@ -112,18 +139,13 @@ import IconImport from "~icons/lucide/folder-down"
import IconHelpCircle from "~icons/lucide/help-circle" import IconHelpCircle from "~icons/lucide/help-circle"
import IconPlus from "~icons/lucide/plus" import IconPlus from "~icons/lucide/plus"
import { import {
resolveSaveContextOnCollectionReorder, cascadeParentCollectionForHeaderAuth,
getFoldersByPath, saveRESTRequestAs,
} from "~/helpers/collection/collection"
import {
navigateToFolderWithIndexPath,
restCollectionStore,
removeRESTFolder,
restCollections$,
} from "~/newstore/collections" } from "~/newstore/collections"
import { useReadonlyStream } from "~/composables/stream"
import { cloneDeep } from "lodash-es" import { cloneDeep } from "lodash-es"
import { HoppRESTRequest } from "@hoppscotch/data" import { HoppCollection, HoppRESTAuth, HoppRESTRequest } from "@hoppscotch/data"
import { TeamCollection } from "~/helpers/backend/graphql"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
const t = useI18n() const t = useI18n()
const toast = useToast() const toast = useToast()
@@ -150,27 +172,54 @@ const modalLoadingState = ref(false)
const showModalAdd = ref(false) const showModalAdd = ref(false)
const showModalAddRequest = ref(false) const showModalAddRequest = ref(false)
const showModalAddFolder = ref(false) const showModalAddChildColl = ref(false)
const showModalEditRootColl = ref(false)
const showModalEditChildColl = ref(false)
const showModalEditRequest = ref(false) const showModalEditRequest = ref(false)
const showModalEditProperties = ref(false)
const showConfirmModal = ref(false) const showConfirmModal = ref(false)
const editingFolderPath = ref<string | null>(null) const editingCollIndexPath = ref<string>("")
const editingRequest = ref<HoppRESTRequest | null>(null) const editingChildCollIndexPath = ref<string>("")
const editingRequestName = ref("") const editingRootCollName = ref<string>("")
const editingRequestIndex = ref<number | null>(null) const editingChildCollName = ref<string>("")
const editingRequestName = ref<string>("")
const editingRequestIndexPath = ref<string>("")
const editingProperties = ref<{
collection: Omit<HoppCollection, "v"> | TeamCollection | null
isRootCollection: boolean
path: string
inheritedProperties?: HoppInheritedProperty
}>({
collection: null,
isRootCollection: false,
path: "",
inheritedProperties: undefined,
})
const confirmModalTitle = ref<string | null>(null) const confirmModalTitle = ref<string | null>(null)
const myCollections = useReadonlyStream(restCollections$, [], "deep")
const displayModalAddRequest = (show: boolean) => { const displayModalAddRequest = (show: boolean) => {
showModalAddRequest.value = show showModalAddRequest.value = show
if (!show) resetSelectedData() if (!show) resetSelectedData()
} }
const displayModalAddFolder = (show: boolean) => { const displayModalAddChildColl = (show: boolean) => {
showModalAddFolder.value = show showModalAddChildColl.value = show
if (!show) resetSelectedData()
}
const displayModalEditCollection = (show: boolean) => {
showModalEditRootColl.value = show
if (!show) resetSelectedData()
}
const displayModalEditChildCollection = (show: boolean) => {
showModalEditChildColl.value = show
if (!show) resetSelectedData() if (!show) resetSelectedData()
} }
@@ -181,6 +230,12 @@ const displayModalEditRequest = (show: boolean) => {
if (!show) resetSelectedData() if (!show) resetSelectedData()
} }
const displayModalEditProperties = (show: boolean) => {
showModalEditProperties.value = show
if (!show) resetSelectedData()
}
const displayConfirmModal = (show: boolean) => { const displayConfirmModal = (show: boolean) => {
showConfirmModal.value = show showConfirmModal.value = show
@@ -210,19 +265,19 @@ const addNewRootCollection = async (name: string) => {
showModalAdd.value = false showModalAdd.value = false
} }
const addRequest = (payload: { path: string }) => { const removeRootCollection = (collPathIndex: string) => {
const { path } = payload editingCollIndexPath.value = collPathIndex
editingFolderPath.value = path
displayModalAddRequest(true) confirmModalTitle.value = `${t("confirm.remove_collection")}`
displayConfirmModal(true)
} }
const onAddRequest = async (requestName: string) => { const onRemoveRootCollection = async () => {
const path = editingFolderPath.value const collIndexPath = editingCollIndexPath.value
if (!path) return
const collHandleResult = await workspaceService.getCollectionHandle( const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle, props.workspaceHandle,
path collIndexPath
) )
if (E.isLeft(collHandleResult)) { if (E.isLeft(collHandleResult)) {
@@ -233,14 +288,54 @@ const onAddRequest = async (requestName: string) => {
const collHandle = collHandleResult.right const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") { if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}
const result = await workspaceService.removeRESTRootCollection(collHandle)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
if (result.right.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
toast.success(t("state.deleted"))
displayConfirmModal(false)
}
const addRequest = (requestPathIndex: string) => {
editingCollIndexPath.value = requestPathIndex
displayModalAddRequest(true)
}
const onAddRequest = async (requestName: string) => {
const parentCollIndexPath = editingCollIndexPath.value
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
parentCollIndexPath
)
if (E.isLeft(collHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return
}
const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return return
} }
const result = await workspaceService.createRESTRequest( const result = await workspaceService.createRESTRequest(
collHandle, collHandle,
requestName, requestName
path
) )
if (E.isLeft(result)) { if (E.isLeft(result)) {
@@ -256,20 +351,17 @@ const onAddRequest = async (requestName: string) => {
displayModalAddRequest(false) displayModalAddRequest(false)
} }
const addFolder = (payload: { path: string }) => { const addChildCollection = (parentCollIndexPath: string) => {
const { path } = payload editingCollIndexPath.value = parentCollIndexPath
editingFolderPath.value = path displayModalAddChildColl(true)
displayModalAddFolder(true)
} }
const onAddFolder = async (folderName: string) => { const onAddChildCollection = async (childCollName: string) => {
const path = editingFolderPath.value const parentCollIndexPath = editingCollIndexPath.value
if (!path) return
const collHandleResult = await workspaceService.getCollectionHandle( const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle, props.workspaceHandle,
path parentCollIndexPath
) )
if (E.isLeft(collHandleResult)) { if (E.isLeft(collHandleResult)) {
@@ -280,103 +372,224 @@ const onAddFolder = async (folderName: string) => {
const collHandle = collHandleResult.right const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") { if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return return
} }
const result = await workspaceService.createRESTChildCollection( const result = await workspaceService.createRESTChildCollection(
collHandle, collHandle,
folderName, childCollName
path
) )
if (E.isLeft(result)) { if (E.isLeft(result)) {
// INVALID_WORKSPACE_HANDLE // INVALID_COLLECTION_HANDLE
return return
} }
if (result.right.value.type === "invalid") { if (result.right.value.type === "invalid") {
// WORKSPACE_INVALIDATED // COLLECTION_INVALIDATED
return return
} }
displayModalAddFolder(false) displayModalAddChildColl(false)
} }
const removeFolder = (payload: { path: string }) => { const editRootCollection = (payload: {
const { path } = payload collIndexPath: string
editingFolderPath.value = path collectionName: string
}) => {
const { collIndexPath, collectionName } = payload
editingCollIndexPath.value = collIndexPath
editingRootCollName.value = collectionName
displayModalEditCollection(true)
}
const onEditRootCollection = async (newCollectionName: string) => {
const collID = editingCollIndexPath.value
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
collID
)
if (E.isLeft(collHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return
}
const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}
const result = await workspaceService.editRESTRootCollection(
collHandle,
newCollectionName
)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
if (result.right.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
displayModalEditCollection(false)
toast.success(t("collection.renamed"))
}
const editChildCollection = (payload: {
collIndexPath: string
collectionName: string
}) => {
const { collIndexPath, collectionName } = payload
editingChildCollIndexPath.value = collIndexPath
editingChildCollName.value = collectionName
displayModalEditChildCollection(true)
}
const onEditChildCollection = async (newCollectionName: string) => {
const collID = editingChildCollIndexPath.value
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
collID
)
if (E.isLeft(collHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return
}
const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}
const result = await workspaceService.editRESTChildCollection(
collHandle,
newCollectionName
)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
if (result.right.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
displayModalEditChildCollection(false)
toast.success(t("collection.renamed"))
}
const removeChildCollection = (parentCollIndexPath: string) => {
editingCollIndexPath.value = parentCollIndexPath
confirmModalTitle.value = `${t("confirm.remove_folder")}` confirmModalTitle.value = `${t("confirm.remove_folder")}`
displayConfirmModal(true) displayConfirmModal(true)
} }
const onRemoveFolder = () => { const onRemoveChildCollection = async () => {
const path = editingFolderPath.value const parentCollIndexPath = editingCollIndexPath.value
if (!path) return const parentCollHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
parentCollIndexPath
)
const folderToRemove = path if (E.isLeft(parentCollHandleResult)) {
? navigateToFolderWithIndexPath( // INVALID_WORKSPACE_HANDLE
restCollectionStore.value.state, return
path.split("/").map((i) => parseInt(i)) }
)
: undefined
removeRESTFolder(path, folderToRemove ? folderToRemove.id : undefined) const parentCollHandle = parentCollHandleResult.right
const parentFolder = path.split("/").slice(0, -1).join("/") // remove last folder to get parent folder if (parentCollHandle.value.type === "invalid") {
resolveSaveContextOnCollectionReorder({ // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
lastIndex: pathToLastIndex(path), return
newIndex: -1, }
folderPath: parentFolder,
length: getFoldersByPath(myCollections.value, parentFolder).length, const result =
}) await workspaceService.removeRESTChildCollection(parentCollHandle)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
if (result.right.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
toast.success(t("state.deleted")) toast.success(t("state.deleted"))
displayConfirmModal(false) displayConfirmModal(false)
} }
const removeRequest = (requestIndex: string) => { const removeRequest = (requestIndexPath: string) => {
const folderPath = requestIndex.slice(0, -2) const collIndexPath = requestIndexPath.split("/").slice(0, -1).join("/")
const requestID = requestIndex[requestIndex.length - 1]
editingFolderPath.value = folderPath editingCollIndexPath.value = collIndexPath
editingRequestIndex.value = parseInt(requestID) editingRequestIndexPath.value = requestIndexPath
confirmModalTitle.value = `${t("confirm.remove_request")}` confirmModalTitle.value = `${t("confirm.remove_request")}`
displayConfirmModal(true) displayConfirmModal(true)
} }
const onRemoveRequest = async () => { const onRemoveRequest = async () => {
const path = editingFolderPath.value const parentCollIndexPath = editingCollIndexPath.value
const requestIndex = editingRequestIndex.value const requestIndexPath = editingRequestIndexPath.value
if (path === null || requestIndex === null) return const parentCollHandleResult = await workspaceService.getCollectionHandle(
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle, props.workspaceHandle,
path parentCollIndexPath
) )
if (E.isLeft(collHandleResult)) { if (E.isLeft(parentCollHandleResult)) {
// INVALID_WORKSPACE_HANDLE // INVALID_WORKSPACE_HANDLE
return return
} }
const collHandle = collHandleResult.right const parentCollHandle = parentCollHandleResult.right
if (collHandle.value.type === "invalid") { if (parentCollHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return return
} }
const result = await workspaceService.removeRESTRequest( const requestHandleResult = await workspaceService.getRequestHandle(
collHandle, parentCollHandle,
path, requestIndexPath
requestIndex
) )
if (E.isLeft(requestHandleResult)) {
// INVALID_COLLECTION_HANDLE
return
}
const requestHandle = requestHandleResult.right
if (requestHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED | INVALID_REQUEST_HANDLE
return
}
const result = await workspaceService.removeRESTRequest(requestHandle)
if (E.isLeft(result)) { if (E.isLeft(result)) {
// INVALID_WORKSPACE_HANDLE // INVALID_WORKSPACE_HANDLE
return return
@@ -391,18 +604,12 @@ const onRemoveRequest = async () => {
displayConfirmModal(false) displayConfirmModal(false)
} }
const selectRequest = async (payload: { const selectRequest = async (requestIndexPath: string) => {
requestPath: string const collIndexPath = requestIndexPath.split("/").slice(0, -1).join("/")
request: HoppRESTRequest
}) => {
const { requestPath, request } = payload
const collPath = requestPath.slice(0, -2)
const requestIndex = requestPath[requestPath.length - 1]
const collHandleResult = await workspaceService.getCollectionHandle( const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle, props.workspaceHandle,
collPath collIndexPath
) )
if (E.isLeft(collHandleResult)) { if (E.isLeft(collHandleResult)) {
@@ -413,35 +620,64 @@ const selectRequest = async (payload: {
const collHandle = collHandleResult.right const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") { if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return return
} }
const result = await workspaceService.selectRESTRequest( const requestHandleResult = await workspaceService.getRequestHandle(
collHandle, collHandle,
collPath, requestIndexPath
requestIndex,
request
) )
if (E.isLeft(result)) { if (E.isLeft(requestHandleResult)) {
// INVALID_WORKSPACE_HANDLE // INVALID_COLLECTION_HANDLE
return return
} }
if (result.right.value.type === "invalid") { const requestHandle = requestHandleResult.right
// WORKSPACE_INVALIDATED
if (requestHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED | INVALID_REQUEST_HANDLE
return return
} }
const requestIndex = parseInt(requestIndexPath.split("/").slice(-1)[0])
const request = requestHandle.value.data.request as HoppRESTRequest
// If there is a request with this save context, switch into it
let possibleTab = null
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
collIndexPath,
"rest"
)
possibleTab = tabs.getTabRefWithSaveContext({
originLocation: "user-collection",
requestIndex,
folderPath: collIndexPath,
})
if (possibleTab) {
tabs.setActiveTab(possibleTab.value.id)
} else {
// If not, open the request in a new tab
tabs.createNewTab({
request: cloneDeep(request),
isDirty: false,
saveContext: {
originLocation: "user-collection",
folderPath: collIndexPath,
requestIndex,
},
inheritedProperties: {
auth,
headers,
},
})
}
} }
const duplicateRequest = async (payload: { const duplicateRequest = async (requestIndexPath: string) => {
requestPath: string const collPath = requestIndexPath.split("/").slice(0, -1).join("/")
request: HoppRESTRequest
}) => {
const { requestPath, request } = payload
const collPath = requestPath.slice(0, -2)
const collHandleResult = await workspaceService.getCollectionHandle( const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle, props.workspaceHandle,
@@ -456,95 +692,105 @@ const duplicateRequest = async (payload: {
const collHandle = collHandleResult.right const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") { if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return return
} }
const requestHandleResult = await workspaceService.getRequestHandle(
collHandle,
requestIndexPath
)
if (E.isLeft(requestHandleResult)) {
// INVALID_COLLECTION_HANDLE
return
}
const requestHandle = requestHandleResult.right
if (requestHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED | INVALID_REQUEST_HANDLE
return
}
const request = requestHandle.value.data.request as HoppRESTRequest
const newRequest = { const newRequest = {
...cloneDeep(request), ...cloneDeep(request),
name: `${request.name} - ${t("action.duplicate")}`, name: `${request.name} - ${t("action.duplicate")}`,
} }
const result = await workspaceService.duplicateRESTRequest( saveRESTRequestAs(collPath, newRequest)
collHandle,
collPath,
newRequest
)
if (E.isLeft(result)) {
// INVALID_WORKSPACE_HANDLE
return
}
if (result.right.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
toast.success(t("request.duplicated")) toast.success(t("request.duplicated"))
} }
const editRequest = (payload: { const editRequest = (payload: {
requestPath: string requestIndexPath: string
request: HoppRESTRequest requestName: string
}) => { }) => {
const { requestPath, request } = payload const { requestIndexPath, requestName } = payload
const collPath = requestPath.slice(0, -2)
const requestIndex = requestPath[requestPath.length - 1]
editingRequest.value = request const collPath = requestIndexPath.split("/").slice(0, -1).join("/")
editingRequestName.value = request.name ?? ""
editingFolderPath.value = collPath editingCollIndexPath.value = collPath
editingRequestIndex.value = parseInt(requestIndex) editingRequestIndexPath.value = requestIndexPath
editingRequestName.value = requestName
displayModalEditRequest(true) displayModalEditRequest(true)
} }
const onEditRequest = async (newReqName: string) => { const onEditRequest = async (newReqName: string) => {
const collPath = editingFolderPath.value const parentCollID = editingCollIndexPath.value
const requestIndex = editingRequestIndex.value const requestID = editingRequestIndexPath.value
const request = editingRequest.value
if (collPath === null || requestIndex === null || !request) { const parentCollHandleResult = await workspaceService.getCollectionHandle(
return
}
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle, props.workspaceHandle,
collPath parentCollID
) )
if (E.isLeft(collHandleResult)) { if (E.isLeft(parentCollHandleResult)) {
// INVALID_WORKSPACE_HANDLE // INVALID_WORKSPACE_HANDLE
return return
} }
const collHandle = collHandleResult.right const parentCollHandle = parentCollHandleResult.right
if (collHandle.value.type === "invalid") { if (parentCollHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return return
} }
const updatedRequest = { const requestHandleResult = await workspaceService.getRequestHandle(
...request, parentCollHandle,
name: newReqName || request.name, requestID
)
if (E.isLeft(requestHandleResult)) {
// INVALID_COLLECTION_HANDLE
return
}
const requestHandle = requestHandleResult.right
if (requestHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED | INVALID_REQUEST_HANDLE
return
} }
const result = await workspaceService.editRESTRequest( const result = await workspaceService.editRESTRequest(
collHandle, requestHandle,
collPath, newReqName
requestIndex,
updatedRequest
) )
if (E.isLeft(result)) { if (E.isLeft(result)) {
// INVALID_WORKSPACE_HANDLE // INVALID_REQUEST_HANDLE
return return
} }
if (result.right.value.type === "invalid") { if (result.right.value.type === "invalid") {
// WORKSPACE_INVALIDATED // REQUEST_INVALIDATED
return return
} }
@@ -552,17 +798,119 @@ const onEditRequest = async (newReqName: string) => {
toast.success(t("request.renamed")) toast.success(t("request.renamed"))
} }
function onImportExportClick() { const editCollectionProperties = async (collIndexPath: string) => {
// TODO: Implement const parentIndex = collIndexPath.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
let inheritedProperties = {
auth: {
parentID: "",
parentName: "",
inheritedAuth: {
authType: "inherit",
authActive: true,
},
},
headers: [
{
parentID: "",
parentName: "",
inheritedHeader: {},
},
],
} as HoppInheritedProperty
if (parentIndex) {
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
parentIndex,
"rest"
)
inheritedProperties = {
auth,
headers,
}
}
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
collIndexPath
)
if (E.isLeft(collHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return
}
const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}
const { collection } = collHandle.value.data
editingProperties.value = {
collection,
isRootCollection: isAlreadyInRoot(collIndexPath),
path: collIndexPath,
inheritedProperties,
}
displayModalEditProperties(true)
}
const setCollectionProperties = async (updatedCollectionProps: {
auth: HoppRESTAuth
headers: HoppCollection["headers"]
collIndexPath: string
}) => {
const { collIndexPath, auth, headers } = updatedCollectionProps
const collHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
collIndexPath
)
if (E.isLeft(collHandleResult)) {
// INVALID_WORKSPACE_HANDLE
return
}
const collHandle = collHandleResult.right
if (collHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
return
}
const result = await workspaceService.editRESTCollectionProperties(
collHandle,
{ auth, headers }
)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
if (result.right.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
toast.success(t("collection.properties_updated"))
displayModalEditProperties(false)
} }
const resolveConfirmModal = (title: string | null) => { const resolveConfirmModal = (title: string | null) => {
if (title === `${t("confirm.remove_collection")}`) { if (title === `${t("confirm.remove_collection")}`) {
// onRemoveCollection() onRemoveRootCollection()
} else if (title === `${t("confirm.remove_request")}`) { } else if (title === `${t("confirm.remove_request")}`) {
onRemoveRequest() onRemoveRequest()
} else if (title === `${t("confirm.remove_folder")}`) { } else if (title === `${t("confirm.remove_folder")}`) {
onRemoveFolder() onRemoveChildCollection()
} else { } else {
console.error( console.error(
`Confirm modal title ${title} is not handled by the component` `Confirm modal title ${title} is not handled by the component`
@@ -573,16 +921,25 @@ const resolveConfirmModal = (title: string | null) => {
} }
const resetSelectedData = () => { const resetSelectedData = () => {
editingFolderPath.value = null editingCollIndexPath.value = ""
} }
/** /**
* Used to get the index of the request from the path * @param path The path of the collection or request
* @param path The path of the request * @returns The index of the collection or request
* @returns The index of the request
*/ */
const pathToLastIndex = (path: string) => { const pathToIndex = (path: string) => {
const pathArr = path.split("/") const pathArr = path.split("/")
return parseInt(pathArr[pathArr.length - 1]) return pathArr
}
/**
* Checks if the collection is already in the root
* @param id - path of the collection
* @returns boolean - true if the collection is already in the root
*/
const isAlreadyInRoot = (id: string) => {
const indexPath = pathToIndex(id)
return indexPath.length === 1
} }
</script> </script>

View File

@@ -8,10 +8,10 @@ import {
shallowRef, shallowRef,
watch, watch,
} from "vue" } from "vue"
import { WorkspaceProvider } from "./provider" import { UpdatedCollectionProperties, WorkspaceProvider } from "./provider"
import { HandleRef } from "./handle" import { HandleRef } from "./handle"
import * as E from "fp-ts/Either" import * as E from "fp-ts/Either"
import { Workspace, WorkspaceCollection } from "./workspace" import { Workspace, WorkspaceCollection, WorkspaceRequest } from "./workspace"
import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view" import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view"
import { HoppRESTRequest } from "@hoppscotch/data" import { HoppRESTRequest } from "@hoppscotch/data"
@@ -138,6 +138,36 @@ export class NewWorkspaceService extends Service {
return E.right(result.right) return E.right(result.right)
} }
public async getRequestHandle(
parentCollHandle: HandleRef<WorkspaceCollection>,
requestID: string
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceRequest>
>
> {
if (parentCollHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.getRequestHandle(parentCollHandle, requestID)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async createRESTRootCollection( public async createRESTRootCollection(
workspaceHandle: HandleRef<Workspace>, workspaceHandle: HandleRef<Workspace>,
collectionName: string collectionName: string
@@ -173,8 +203,7 @@ export class NewWorkspaceService extends Service {
public async createRESTChildCollection( public async createRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>, parentCollHandle: HandleRef<WorkspaceCollection>,
collectionName: string, collectionName: string
path: string
): Promise< ): Promise<
E.Either< E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
@@ -195,8 +224,7 @@ export class NewWorkspaceService extends Service {
const result = await provider.createRESTChildCollection( const result = await provider.createRESTChildCollection(
parentCollHandle, parentCollHandle,
collectionName, collectionName
path
) )
if (E.isLeft(result)) { if (E.isLeft(result)) {
@@ -206,10 +234,166 @@ export class NewWorkspaceService extends Service {
return E.right(result.right) return E.right(result.right)
} }
public async editRESTRootCollection(
collHandle: HandleRef<WorkspaceCollection>,
newCollectionName: string
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (collHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
collHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.editRESTRootCollection(
collHandle,
newCollectionName
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async editRESTChildCollection(
collHandle: HandleRef<WorkspaceCollection>,
newCollectionName: string
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (collHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
collHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.editRESTChildCollection(
collHandle,
newCollectionName
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async editRESTCollectionProperties(
collHandle: HandleRef<WorkspaceCollection>,
updatedCollProps: UpdatedCollectionProperties
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (collHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
collHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.editRESTCollectionProperties(
collHandle,
updatedCollProps
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async removeRESTRootCollection(
collHandle: HandleRef<WorkspaceCollection>
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (collHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
collHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.removeRESTRootCollection(collHandle)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async removeRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (parentCollHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.removeRESTChildCollection(parentCollHandle)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async createRESTRequest( public async createRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>, parentCollHandle: HandleRef<WorkspaceCollection>,
requestName: string, requestName: string
path: string
): Promise< ): Promise<
E.Either< E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
@@ -230,8 +414,7 @@ export class NewWorkspaceService extends Service {
const result = await provider.createRESTRequest( const result = await provider.createRESTRequest(
parentCollHandle, parentCollHandle,
requestName, requestName
path
) )
if (E.isLeft(result)) { if (E.isLeft(result)) {
@@ -242,104 +425,26 @@ export class NewWorkspaceService extends Service {
} }
public async removeRESTRequest( public async removeRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>, requestHandle: HandleRef<WorkspaceRequest>
path: string,
requestIndex: number
): Promise< ): Promise<
E.Either< E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection> HandleRef<WorkspaceRequest>
> >
> { > {
if (parentCollHandle.value.type === "invalid") { if (requestHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
} }
const provider = this.registeredProviders.get( const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID requestHandle.value.data.providerID
) )
if (!provider) { if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" }) return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
} }
const result = await provider.removeRESTRequest( const result = await provider.removeRESTRequest(requestHandle)
parentCollHandle,
path,
requestIndex
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async selectRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>,
collPath: string,
requestIndex: string,
request: HoppRESTRequest
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (parentCollHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.selectRESTRequest(
parentCollHandle,
collPath,
requestIndex,
request
)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async duplicateRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>,
collPath: string,
request: HoppRESTRequest
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection>
>
> {
if (parentCollHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.duplicateRESTRequest(
parentCollHandle,
collPath,
request
)
if (E.isLeft(result)) { if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left }) return E.left({ type: "PROVIDER_ERROR", error: result.left })
@@ -349,34 +454,27 @@ export class NewWorkspaceService extends Service {
} }
public async editRESTRequest( public async editRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>, requestHandle: HandleRef<WorkspaceRequest>,
collPath: string, newRequestName: string
requestIndex: number,
request: HoppRESTRequest
): Promise< ): Promise<
E.Either< E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceCollection> HandleRef<WorkspaceRequest>
> >
> { > {
if (parentCollHandle.value.type === "invalid") { if (requestHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
} }
const provider = this.registeredProviders.get( const provider = this.registeredProviders.get(
parentCollHandle.value.data.providerID requestHandle.value.data.providerID
) )
if (!provider) { if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" }) return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
} }
const result = await provider.editRESTRequest( const result = await provider.editRESTRequest(requestHandle, newRequestName)
parentCollHandle,
collPath,
requestIndex,
request
)
if (E.isLeft(result)) { if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left }) return E.left({ type: "PROVIDER_ERROR", error: result.left })
@@ -385,6 +483,35 @@ export class NewWorkspaceService extends Service {
return E.right(result.right) return E.right(result.right)
} }
public async saveRESTRequest(
requestHandle: HandleRef<WorkspaceRequest>,
updatedRequest: HoppRESTRequest
): Promise<
E.Either<
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
HandleRef<WorkspaceRequest>
>
> {
if (requestHandle.value.type === "invalid") {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" })
}
const provider = this.registeredProviders.get(
requestHandle.value.data.providerID
)
if (!provider) {
return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" })
}
const result = await provider.saveRESTRequest(requestHandle, updatedRequest)
if (E.isLeft(result)) {
return E.left({ type: "PROVIDER_ERROR", error: result.left })
}
return E.right(result.right)
}
public async getRESTCollectionChildrenView( public async getRESTCollectionChildrenView(
collectionHandle: HandleRef<WorkspaceCollection> collectionHandle: HandleRef<WorkspaceCollection>

View File

@@ -1,9 +1,19 @@
import { Ref } from "vue" import { Ref } from "vue"
import * as E from "fp-ts/Either" import * as E from "fp-ts/Either"
import { HandleRef } from "./handle" import { HandleRef } from "./handle"
import { Workspace, WorkspaceCollection, WorkspaceDecor } from "./workspace" import {
Workspace,
WorkspaceCollection,
WorkspaceDecor,
WorkspaceRequest,
} from "./workspace"
import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view" import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view"
import { HoppRESTRequest } from "@hoppscotch/data" import { HoppRESTAuth, HoppRESTHeaders, HoppRESTRequest } from "@hoppscotch/data"
export type UpdatedCollectionProperties = {
auth: HoppRESTAuth
headers: HoppRESTHeaders
}
export interface WorkspaceProvider { export interface WorkspaceProvider {
providerID: string providerID: string
@@ -17,6 +27,10 @@ export interface WorkspaceProvider {
workspaceHandle: HandleRef<Workspace>, workspaceHandle: HandleRef<Workspace>,
collectionID: string collectionID: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
getRequestHandle(
parentCollHandle: HandleRef<WorkspaceCollection>,
requestID: string
): Promise<E.Either<unknown, HandleRef<WorkspaceRequest>>>
getRESTRootCollectionView( getRESTRootCollectionView(
workspaceHandle: HandleRef<Workspace> workspaceHandle: HandleRef<Workspace>
@@ -31,34 +45,39 @@ export interface WorkspaceProvider {
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
createRESTChildCollection( createRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>, parentCollHandle: HandleRef<WorkspaceCollection>,
collectionName: string, collectionName: string
path: string ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
editRESTRootCollection(
collHandle: HandleRef<WorkspaceCollection>,
newCollectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
editRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>,
newCollectionName: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
editRESTCollectionProperties(
parentCollHandle: HandleRef<WorkspaceCollection>,
updatedCollProps: UpdatedCollectionProperties
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
removeRESTRootCollection(
collHandle: HandleRef<WorkspaceCollection>
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
removeRESTChildCollection(
parentCollHandle: HandleRef<WorkspaceCollection>
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
createRESTRequest( createRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>, parentCollHandle: HandleRef<WorkspaceCollection>,
requestName: string, requestName: string
path: string
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> ): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
removeRESTRequest( removeRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>, requestHandle: HandleRef<WorkspaceRequest>
path: string, ): Promise<E.Either<unknown, HandleRef<WorkspaceRequest>>>
requestIndex: number
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
selectRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>,
collPath: string,
requestIndex: string,
request: HoppRESTRequest
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
duplicateRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>,
collPath: string,
request: HoppRESTRequest
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>>
editRESTRequest( editRESTRequest(
parentCollHandle: HandleRef<WorkspaceCollection>, requestHandle: HandleRef<WorkspaceRequest>,
collPath: string, newRequestName: string
requestIndex: number, ): Promise<E.Either<unknown, HandleRef<WorkspaceRequest>>>
request: HoppRESTRequest saveRESTRequest(
): Promise<E.Either<unknown, HandleRef<WorkspaceCollection>>> requestHandle: HandleRef<WorkspaceRequest>,
updatedRequest: HoppRESTRequest
): Promise<E.Either<unknown, HandleRef<WorkspaceRequest>>>
} }

View File

@@ -1,16 +1,16 @@
import { HoppRESTRequest } from "@hoppscotch/data" import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
import { Ref } from "vue" import { Ref } from "vue"
export type RESTCollectionViewCollection = { export type RESTCollectionViewCollection = {
collectionID: string collectionID: string
name: string
collection: HoppCollection
} }
export type RESTCollectionViewRequest = { export type RESTCollectionViewRequest = {
collectionID: string
requestID: string requestID: string
name: string
method: string
request: HoppRESTRequest request: HoppRESTRequest
} }

View File

@@ -1,3 +1,4 @@
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
import { Component } from "vue" import { Component } from "vue"
export type Workspace = { export type Workspace = {
@@ -5,8 +6,6 @@ export type Workspace = {
workspaceID: string workspaceID: string
name: string name: string
collectionsAreReadonly: boolean
} }
export type WorkspaceCollection = { export type WorkspaceCollection = {
@@ -14,7 +13,16 @@ export type WorkspaceCollection = {
workspaceID: string workspaceID: string
collectionID: string collectionID: string
name: string collection: HoppCollection | null
}
export type WorkspaceRequest = {
providerID: string
workspaceID: string
collectionID: string
requestID: string
request: HoppRESTRequest | null
} }
export type WorkspaceDecor = { export type WorkspaceDecor = {