fix: resolve multiple UI issues and account for description field in syncing context (#4309)
* fix: collection properties header bulk update editor bug * chore: add migration step while resolving `headers` in the syncing context Resolve type errors. * fix: prevent inifinite loading state in add environments modal Toggle back the loading state if attempting to create an environment from a team workspace without specifying a name. * fix: tab change when clicking computed auth * fix: ensure tab change action works in GQL headers view `Go to Authorization tab` action. * chore: account for REST params while adding description fields Writing to store after pulling from the syncing context. --------- Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
<HttpHeaders
|
||||
v-model="editableCollection"
|
||||
:is-collection-property="true"
|
||||
@change-tab="changeOptionTab"
|
||||
/>
|
||||
<div
|
||||
class="bg-bannerInfo px-4 py-2 flex items-center sticky bottom-0"
|
||||
@@ -136,6 +137,7 @@ import { PersistenceService } from "~/services/persistence"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconHelpCircle from "~icons/lucide/help-circle"
|
||||
import { RESTOptionTabs } from "../http/RequestOptions.vue"
|
||||
|
||||
const persistenceService = useService(PersistenceService)
|
||||
const t = useI18n()
|
||||
@@ -268,6 +270,10 @@ const hideModal = () => {
|
||||
emit("hide-modal")
|
||||
}
|
||||
|
||||
const changeOptionTab = (e: RESTOptionTabs) => {
|
||||
activeTab.value = e
|
||||
}
|
||||
|
||||
const copyCollectionID = () => {
|
||||
copyToClipboard(props.editingProperties.path)
|
||||
copyIcon.value = IconCheck
|
||||
|
||||
@@ -354,7 +354,9 @@ const saveEnvironment = async () => {
|
||||
isLoading.value = true
|
||||
|
||||
if (!editingName.value) {
|
||||
isLoading.value = false
|
||||
toast.error(`${t("environment.invalid_name")}`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -127,19 +127,15 @@
|
||||
:icon="masking ? IconEye : IconEyeOff"
|
||||
@click="toggleMask()"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-else
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconArrowUpRight"
|
||||
:title="t('request.go_to_authorization_tab')"
|
||||
class="cursor-auto text-primary hover:text-primary"
|
||||
/>
|
||||
<div v-else class="aspect-square w-8"></div>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconArrowUpRight"
|
||||
:title="t('request.go_to_authorization_tab')"
|
||||
@click="changeTab"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@@ -235,6 +231,7 @@ import { useColorMode } from "@composables/theming"
|
||||
import { useToast } from "@composables/toast"
|
||||
import {
|
||||
GQLHeader,
|
||||
HoppGQLAuth,
|
||||
HoppGQLRequest,
|
||||
parseRawKeyValueEntriesE,
|
||||
rawKeyValueEntriesToString,
|
||||
@@ -267,6 +264,7 @@ import IconLock from "~icons/lucide/lock"
|
||||
import IconPlus from "~icons/lucide/plus"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconWrapText from "~icons/lucide/wrap-text"
|
||||
import { GQLOptionTabs } from "./RequestOptions.vue"
|
||||
|
||||
const colorMode = useColorMode()
|
||||
const t = useI18n()
|
||||
@@ -281,6 +279,7 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: HoppGQLRequest): void
|
||||
(e: "change-tab", value: GQLOptionTabs): void
|
||||
}>()
|
||||
|
||||
const request = useVModel(props, "modelValue", emit)
|
||||
@@ -645,7 +644,7 @@ const inheritedProperties = computed(() => {
|
||||
|
||||
const computedAuthHeader = getComputedAuthHeaders(
|
||||
request.value,
|
||||
props.inheritedProperties.auth.inheritedAuth
|
||||
props.inheritedProperties.auth.inheritedAuth as HoppGQLAuth
|
||||
)[0]
|
||||
|
||||
if (
|
||||
@@ -678,8 +677,5 @@ const mask = (header: any) => {
|
||||
return header.header.value
|
||||
}
|
||||
|
||||
// const changeTab = (tab: ComputedHeader["source"]) => {
|
||||
// if (tab === "auth") emit("change-tab", "authorization")
|
||||
// else emit("change-tab", "bodyParams")
|
||||
// }
|
||||
const changeTab = () => emit("change-tab", "authorization")
|
||||
</script>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<GraphqlHeaders
|
||||
v-model="request"
|
||||
:inherited-properties="inheritedProperties"
|
||||
@change-tab="changeOptionTab"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab :id="'authorization'" :label="`${t('tab.authorization')}`">
|
||||
@@ -261,6 +262,11 @@ const saveRequest = () => {
|
||||
const clearGQLQuery = () => {
|
||||
request.value.query = ""
|
||||
}
|
||||
|
||||
const changeOptionTab = (e: GQLOptionTabs) => {
|
||||
selectedOptionTab.value = e
|
||||
}
|
||||
|
||||
defineActionHandler("request.send-cancel", runQuery)
|
||||
defineActionHandler("request.save", saveRequest)
|
||||
defineActionHandler("request.save-as", () => {
|
||||
|
||||
@@ -49,8 +49,14 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="bulkMode" class="h-full relative w-full flex flex-col flex-1">
|
||||
<div ref="bulkEditor" class="absolute inset-0"></div>
|
||||
<div
|
||||
ref="bulkEditor"
|
||||
:class="{
|
||||
'absolute inset-0': !isCollectionProperty,
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<draggable
|
||||
|
||||
@@ -48,8 +48,11 @@ import {
|
||||
} from "@hoppscotch/common/newstore/collections"
|
||||
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||
import {
|
||||
GQLHeader,
|
||||
HoppCollection,
|
||||
HoppGQLRequest,
|
||||
HoppRESTHeaders,
|
||||
HoppRESTParam,
|
||||
HoppRESTRequest,
|
||||
} from "@hoppscotch/data"
|
||||
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
||||
@@ -100,12 +103,22 @@ type ExportedUserCollectionGQL = {
|
||||
data: string
|
||||
}
|
||||
|
||||
function addDescriptionField(
|
||||
candidate: HoppRESTHeaders | GQLHeader[] | HoppRESTParam[]
|
||||
) {
|
||||
return candidate.map((item) => ({
|
||||
...item,
|
||||
description: "description" in item ? item.description : "",
|
||||
}))
|
||||
}
|
||||
|
||||
function exportedCollectionToHoppCollection(
|
||||
collection: ExportedUserCollectionREST | ExportedUserCollectionGQL,
|
||||
collectionType: "REST" | "GQL"
|
||||
): HoppCollection {
|
||||
if (collectionType == "REST") {
|
||||
const restCollection = collection as ExportedUserCollectionREST
|
||||
|
||||
const data =
|
||||
restCollection.data && restCollection.data !== "null"
|
||||
? JSON.parse(restCollection.data)
|
||||
@@ -113,9 +126,10 @@ function exportedCollectionToHoppCollection(
|
||||
auth: { authType: "inherit", authActive: false },
|
||||
headers: [],
|
||||
}
|
||||
|
||||
return {
|
||||
id: restCollection.id,
|
||||
v: 2,
|
||||
v: 3,
|
||||
name: restCollection.name,
|
||||
folders: restCollection.folders.map((folder) =>
|
||||
exportedCollectionToHoppCollection(folder, collectionType)
|
||||
@@ -140,26 +154,31 @@ function exportedCollectionToHoppCollection(
|
||||
testScript,
|
||||
requestVariables,
|
||||
} = request
|
||||
|
||||
const resolvedParams = addDescriptionField(params)
|
||||
const resolvedHeaders = addDescriptionField(headers)
|
||||
|
||||
return {
|
||||
v,
|
||||
id,
|
||||
name,
|
||||
endpoint,
|
||||
method,
|
||||
params,
|
||||
requestVariables: requestVariables,
|
||||
params: resolvedParams,
|
||||
requestVariables,
|
||||
auth,
|
||||
headers,
|
||||
headers: resolvedHeaders,
|
||||
body,
|
||||
preRequestScript,
|
||||
testScript,
|
||||
}
|
||||
}),
|
||||
auth: data.auth,
|
||||
headers: data.headers,
|
||||
headers: addDescriptionField(data.headers),
|
||||
}
|
||||
} else {
|
||||
const gqlCollection = collection as ExportedUserCollectionGQL
|
||||
|
||||
const data =
|
||||
gqlCollection.data && gqlCollection.data !== "null"
|
||||
? JSON.parse(gqlCollection.data)
|
||||
@@ -170,25 +189,34 @@ function exportedCollectionToHoppCollection(
|
||||
|
||||
return {
|
||||
id: gqlCollection.id,
|
||||
v: 2,
|
||||
v: 3,
|
||||
name: gqlCollection.name,
|
||||
folders: gqlCollection.folders.map((folder) =>
|
||||
exportedCollectionToHoppCollection(folder, collectionType)
|
||||
),
|
||||
requests: gqlCollection.requests.map(
|
||||
({ v, auth, headers, name, id, query, url, variables }) => ({
|
||||
requests: gqlCollection.requests.map((request) => {
|
||||
const requestParsedResult = HoppGQLRequest.safeParse(request)
|
||||
if (requestParsedResult.type === "ok") {
|
||||
return requestParsedResult.value
|
||||
}
|
||||
|
||||
const { v, auth, headers, name, id, query, url, variables } = request
|
||||
|
||||
const resolvedHeaders = addDescriptionField(headers)
|
||||
|
||||
return {
|
||||
id,
|
||||
v,
|
||||
auth,
|
||||
headers,
|
||||
headers: resolvedHeaders,
|
||||
name,
|
||||
query,
|
||||
url,
|
||||
variables,
|
||||
})
|
||||
) as HoppGQLRequest[],
|
||||
}
|
||||
}),
|
||||
auth: data.auth,
|
||||
headers: data.headers,
|
||||
headers: addDescriptionField(data.headers),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,17 +377,17 @@ function setupUserCollectionCreatedSubscription() {
|
||||
name: res.right.userCollectionCreated.title,
|
||||
folders: [],
|
||||
requests: [],
|
||||
v: 2,
|
||||
v: 3,
|
||||
auth: data.auth,
|
||||
headers: data.headers,
|
||||
headers: addDescriptionField(data.headers),
|
||||
})
|
||||
: addRESTCollection({
|
||||
name: res.right.userCollectionCreated.title,
|
||||
folders: [],
|
||||
requests: [],
|
||||
v: 2,
|
||||
v: 3,
|
||||
auth: data.auth,
|
||||
headers: data?.headers,
|
||||
headers: addDescriptionField(data.headers),
|
||||
})
|
||||
|
||||
const localIndex = collectionStore.value.state.length - 1
|
||||
|
||||
Reference in New Issue
Block a user