fix: collection auth headers active tab update bug and type fix (#3899)
This commit is contained in:
@@ -66,19 +66,18 @@
|
||||
<script setup lang="ts">
|
||||
import { watch, ref } from "vue"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { HoppCollection } from "@hoppscotch/data"
|
||||
import { HoppCollection, HoppRESTAuth, HoppRESTHeaders } from "@hoppscotch/data"
|
||||
import { RESTOptionTabs } from "../http/RequestOptions.vue"
|
||||
import { TeamCollection } from "~/helpers/teams/TeamCollection"
|
||||
import { clone } from "lodash-es"
|
||||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
type EditingProperties = {
|
||||
collection: HoppCollection | TeamCollection | null
|
||||
collection: Partial<HoppCollection> | null
|
||||
isRootCollection: boolean
|
||||
path: string
|
||||
inheritedProperties: HoppInheritedProperty | undefined
|
||||
inheritedProperties?: HoppInheritedProperty
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -95,21 +94,23 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "set-collection-properties", newCollection: any): void
|
||||
(
|
||||
e: "set-collection-properties",
|
||||
newCollection: Omit<EditingProperties, "inheritedProperties">
|
||||
): void
|
||||
(e: "hide-modal"): void
|
||||
}>()
|
||||
|
||||
const editableCollection = ref({
|
||||
body: {
|
||||
contentType: null,
|
||||
body: null,
|
||||
},
|
||||
const editableCollection = ref<{
|
||||
headers: HoppRESTHeaders
|
||||
auth: HoppRESTAuth
|
||||
}>({
|
||||
headers: [],
|
||||
auth: {
|
||||
authType: "inherit",
|
||||
authActive: false,
|
||||
},
|
||||
}) as any
|
||||
})
|
||||
|
||||
const selectedOptionTab = ref("headers")
|
||||
|
||||
@@ -122,17 +123,13 @@ watch(
|
||||
(show) => {
|
||||
if (show && props.editingProperties?.collection) {
|
||||
editableCollection.value.auth = clone(
|
||||
props.editingProperties.collection.auth
|
||||
props.editingProperties.collection.auth as HoppRESTAuth
|
||||
)
|
||||
editableCollection.value.headers = clone(
|
||||
props.editingProperties.collection.headers
|
||||
props.editingProperties.collection.headers as HoppRESTHeaders
|
||||
)
|
||||
} else {
|
||||
editableCollection.value = {
|
||||
body: {
|
||||
contentType: null,
|
||||
body: null,
|
||||
},
|
||||
headers: [],
|
||||
auth: {
|
||||
authType: "inherit",
|
||||
@@ -146,7 +143,6 @@ watch(
|
||||
const saveEditedCollection = () => {
|
||||
if (!props.editingProperties) return
|
||||
const finalCollection = clone(editableCollection.value)
|
||||
delete finalCollection.body
|
||||
const collection = {
|
||||
path: props.editingProperties.path,
|
||||
collection: {
|
||||
@@ -155,7 +151,7 @@ const saveEditedCollection = () => {
|
||||
},
|
||||
isRootCollection: props.editingProperties.isRootCollection,
|
||||
}
|
||||
emit("set-collection-properties", collection)
|
||||
emit("set-collection-properties", collection as EditingProperties)
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
|
||||
@@ -292,7 +292,7 @@ const editingRequestIndex = ref<number | null>(null)
|
||||
const editingRequestID = ref<string | null>(null)
|
||||
|
||||
const editingProperties = ref<{
|
||||
collection: Omit<HoppCollection, "v"> | TeamCollection | null
|
||||
collection: Partial<HoppCollection> | null
|
||||
isRootCollection: boolean
|
||||
path: string
|
||||
inheritedProperties?: HoppInheritedProperty
|
||||
@@ -739,7 +739,7 @@ const onAddRequest = (requestName: string) => {
|
||||
saveContext: {
|
||||
originLocation: "team-collection",
|
||||
requestID: createRequestInCollection.id,
|
||||
collectionID: createRequestInCollection.collection.id,
|
||||
collectionID: path,
|
||||
teamID: createRequestInCollection.collection.team.id,
|
||||
},
|
||||
inheritedProperties: {
|
||||
@@ -2021,7 +2021,7 @@ const editProperties = (payload: {
|
||||
{
|
||||
parentID: "",
|
||||
parentName: "",
|
||||
inheritedHeaders: [],
|
||||
inheritedHeader: {},
|
||||
},
|
||||
],
|
||||
} as HoppInheritedProperty
|
||||
@@ -2039,7 +2039,7 @@ const editProperties = (payload: {
|
||||
}
|
||||
|
||||
editingProperties.value = {
|
||||
collection,
|
||||
collection: collection as Partial<HoppCollection>,
|
||||
isRootCollection: isAlreadyInRoot(collectionIndex),
|
||||
path: collectionIndex,
|
||||
inheritedProperties,
|
||||
@@ -2083,7 +2083,7 @@ const editProperties = (payload: {
|
||||
}
|
||||
|
||||
editingProperties.value = {
|
||||
collection: coll,
|
||||
collection: coll as unknown as Partial<HoppCollection>,
|
||||
isRootCollection: isAlreadyInRoot(collectionIndex),
|
||||
path: collectionIndex,
|
||||
inheritedProperties,
|
||||
@@ -2094,11 +2094,12 @@ const editProperties = (payload: {
|
||||
}
|
||||
|
||||
const setCollectionProperties = (newCollection: {
|
||||
collection: HoppCollection
|
||||
path: string
|
||||
collection: Partial<HoppCollection> | null
|
||||
isRootCollection: boolean
|
||||
path: string
|
||||
}) => {
|
||||
const { collection, path, isRootCollection } = newCollection
|
||||
if (!collection) return
|
||||
|
||||
if (collectionsType.value.type === "my-collections") {
|
||||
if (isRootCollection) {
|
||||
@@ -2148,8 +2149,7 @@ const setCollectionProperties = (newCollection: {
|
||||
auth,
|
||||
headers,
|
||||
},
|
||||
"rest",
|
||||
"team"
|
||||
"rest"
|
||||
)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
@@ -307,6 +307,7 @@ import { useColorMode } from "@composables/theming"
|
||||
import { computed, reactive, ref, watch } from "vue"
|
||||
import { isEqual, cloneDeep } from "lodash-es"
|
||||
import {
|
||||
HoppRESTAuth,
|
||||
HoppRESTHeader,
|
||||
HoppRESTRequest,
|
||||
parseRawKeyValueEntriesE,
|
||||
@@ -364,7 +365,12 @@ const deletionToast = ref<{ goAway: (delay: number) => void } | null>(null)
|
||||
|
||||
// v-model integration with props and emit
|
||||
const props = defineProps<{
|
||||
modelValue: HoppRESTRequest
|
||||
modelValue:
|
||||
| HoppRESTRequest
|
||||
| {
|
||||
headers: HoppRESTHeader[]
|
||||
auth: HoppRESTAuth
|
||||
}
|
||||
isCollectionProperty?: boolean
|
||||
inheritedProperties?: HoppInheritedProperty
|
||||
envs?: AggregateEnvironment[]
|
||||
|
||||
@@ -109,7 +109,6 @@ export function updateSaveContextForAffectedRequests(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check the new folder path is close to the save context folder path or not
|
||||
* @param folderPathCurrent The path saved as the inherited path in the inherited properties
|
||||
@@ -123,120 +122,109 @@ function folderPathCloseToSaveContext(
|
||||
saveContextPath: string
|
||||
) {
|
||||
if (!folderPathCurrent) return newFolderPath
|
||||
|
||||
const folderPathCurrentArray = folderPathCurrent.split("/")
|
||||
const newFolderPathArray = newFolderPath.split("/")
|
||||
|
||||
const saveContextFolderPathArray = saveContextPath.split("/")
|
||||
|
||||
let folderPathCurrentMatch = 0
|
||||
const folderPathCurrentMatch = folderPathCurrentArray.filter(
|
||||
(folder, i) => folder === saveContextFolderPathArray[i]
|
||||
).length
|
||||
|
||||
for (let i = 0; i < folderPathCurrentArray.length; i++) {
|
||||
if (folderPathCurrentArray[i] === saveContextFolderPathArray[i]) {
|
||||
folderPathCurrentMatch++
|
||||
const newFolderPathMatch = newFolderPathArray.filter(
|
||||
(folder, i) => folder === saveContextFolderPathArray[i]
|
||||
).length
|
||||
|
||||
return folderPathCurrentMatch > newFolderPathMatch
|
||||
? folderPathCurrent
|
||||
: newFolderPath
|
||||
}
|
||||
|
||||
function removeDuplicatesAndKeepLast(arr: HoppInheritedProperty["headers"]) {
|
||||
const keyMap: { [key: string]: number[] } = {} // Map to store array of indices for each key
|
||||
|
||||
// Populate keyMap with the indices of each key
|
||||
arr.forEach((item, index) => {
|
||||
const key = item.inheritedHeader.key
|
||||
if (!(key in keyMap)) {
|
||||
keyMap[key] = []
|
||||
}
|
||||
keyMap[key].push(index)
|
||||
})
|
||||
|
||||
// Create a new array containing only the last occurrence of each key
|
||||
const result = []
|
||||
for (const key in keyMap) {
|
||||
if (Object.prototype.hasOwnProperty.call(keyMap, key)) {
|
||||
const lastIndex = keyMap[key][keyMap[key].length - 1]
|
||||
result.push(arr[lastIndex])
|
||||
}
|
||||
}
|
||||
|
||||
let newFolderPathMatch = 0
|
||||
|
||||
for (let i = 0; i < newFolderPathArray.length; i++) {
|
||||
if (newFolderPathArray[i] === saveContextFolderPathArray[i]) {
|
||||
newFolderPathMatch++
|
||||
}
|
||||
}
|
||||
|
||||
if (folderPathCurrentMatch > newFolderPathMatch) {
|
||||
return folderPathCurrent
|
||||
}
|
||||
return newFolderPath
|
||||
// Sort the result array based on the parentID
|
||||
result.sort((a, b) => a.parentID.localeCompare(b.parentID))
|
||||
return result
|
||||
}
|
||||
|
||||
export function updateInheritedPropertiesForAffectedRequests(
|
||||
path: string,
|
||||
inheritedProperties: HoppInheritedProperty,
|
||||
type: "rest" | "graphql",
|
||||
workspace: "personal" | "team" = "personal"
|
||||
type: "rest" | "graphql"
|
||||
) {
|
||||
const tabService =
|
||||
type === "rest" ? getService(RESTTabService) : getService(GQLTabService)
|
||||
|
||||
let tabs
|
||||
if (workspace === "personal") {
|
||||
tabs = tabService.getTabsRefTo((tab) => {
|
||||
return (
|
||||
tab.document.saveContext?.originLocation === "user-collection" &&
|
||||
tab.document.saveContext.folderPath.startsWith(path)
|
||||
)
|
||||
})
|
||||
} else {
|
||||
tabs = tabService.getTabsRefTo((tab) => {
|
||||
return (
|
||||
tab.document.saveContext?.originLocation === "team-collection" &&
|
||||
tab.document.saveContext.collectionID?.startsWith(path)
|
||||
)
|
||||
})
|
||||
}
|
||||
const effectedTabs = tabService.getTabsRefTo((tab) => {
|
||||
const saveContext = tab.document.saveContext
|
||||
|
||||
const tabsEffectedByAuth = tabs.filter((tab) => {
|
||||
if (workspace === "personal") {
|
||||
return (
|
||||
tab.value.document.saveContext?.originLocation === "user-collection" &&
|
||||
tab.value.document.saveContext.folderPath.startsWith(path) &&
|
||||
path ===
|
||||
folderPathCloseToSaveContext(
|
||||
tab.value.document.inheritedProperties?.auth.parentID,
|
||||
path,
|
||||
tab.value.document.saveContext.folderPath
|
||||
)
|
||||
)
|
||||
}
|
||||
const saveContextPath =
|
||||
saveContext?.originLocation === "team-collection"
|
||||
? saveContext.collectionID
|
||||
: saveContext?.folderPath
|
||||
|
||||
return (
|
||||
tab.value.document.saveContext?.originLocation === "team-collection" &&
|
||||
tab.value.document.saveContext.collectionID?.startsWith(path) &&
|
||||
path ===
|
||||
folderPathCloseToSaveContext(
|
||||
tab.value.document.inheritedProperties?.auth.parentID,
|
||||
path,
|
||||
tab.value.document.saveContext.collectionID
|
||||
)
|
||||
)
|
||||
return saveContextPath?.startsWith(path) ?? false
|
||||
})
|
||||
|
||||
const tabsEffectedByHeaders = tabs.filter((tab) => {
|
||||
return (
|
||||
tab.value.document.inheritedProperties &&
|
||||
tab.value.document.inheritedProperties.headers.some(
|
||||
effectedTabs.map((tab) => {
|
||||
const inheritedParentID =
|
||||
tab.value.document.inheritedProperties?.auth.parentID
|
||||
|
||||
const contextPath =
|
||||
tab.value.document.saveContext?.originLocation === "team-collection"
|
||||
? tab.value.document.saveContext.collectionID
|
||||
: tab.value.document.saveContext?.folderPath
|
||||
|
||||
const effectedPath = folderPathCloseToSaveContext(
|
||||
inheritedParentID,
|
||||
path,
|
||||
contextPath ?? ""
|
||||
)
|
||||
|
||||
if (effectedPath === path) {
|
||||
if (tab.value.document.inheritedProperties) {
|
||||
tab.value.document.inheritedProperties.auth = inheritedProperties.auth
|
||||
}
|
||||
}
|
||||
|
||||
if (tab.value.document.inheritedProperties?.headers) {
|
||||
// filter out the headers with the parentID not as the path
|
||||
const headers = tab.value.document.inheritedProperties.headers.filter(
|
||||
(header) => header.parentID !== path
|
||||
)
|
||||
|
||||
// filter out the headers with the parentID as the path in the inheritedProperties
|
||||
const inheritedHeaders = inheritedProperties.headers.filter(
|
||||
(header) => header.parentID === path
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
for (const tab of tabsEffectedByAuth) {
|
||||
tab.value.document.inheritedProperties = inheritedProperties
|
||||
}
|
||||
// merge the headers with the parentID as the path
|
||||
const mergedHeaders = removeDuplicatesAndKeepLast([
|
||||
...new Set([...inheritedHeaders, ...headers]),
|
||||
])
|
||||
|
||||
for (const tab of tabsEffectedByHeaders) {
|
||||
const headers = tab.value.document.inheritedProperties?.headers.map(
|
||||
(header) => {
|
||||
if (header.parentID === path) {
|
||||
return {
|
||||
...header,
|
||||
inheritedHeader: inheritedProperties.headers.find(
|
||||
(inheritedHeader) =>
|
||||
inheritedHeader.inheritedHeader?.key ===
|
||||
header.inheritedHeader?.key
|
||||
)?.inheritedHeader,
|
||||
}
|
||||
}
|
||||
return header
|
||||
}
|
||||
)
|
||||
|
||||
tab.value.document.inheritedProperties = {
|
||||
...tab.value.document.inheritedProperties,
|
||||
headers,
|
||||
tab.value.document.inheritedProperties.headers = mergedHeaders
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function resetSaveContextForAffectedRequests(folderPath: string) {
|
||||
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
HoppRESTParam,
|
||||
parseRawKeyValueEntriesE,
|
||||
parseTemplateStringE,
|
||||
HoppRESTAuth,
|
||||
HoppRESTHeaders,
|
||||
} from "@hoppscotch/data"
|
||||
import { arrayFlatMap, arraySort } from "../functional/array"
|
||||
import { toFormData } from "../functional/formData"
|
||||
@@ -44,7 +46,12 @@ export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
||||
*/
|
||||
export const getComputedAuthHeaders = (
|
||||
envVars: Environment["variables"],
|
||||
req?: HoppRESTRequest,
|
||||
req?:
|
||||
| HoppRESTRequest
|
||||
| {
|
||||
auth: HoppRESTAuth
|
||||
headers: HoppRESTHeaders
|
||||
},
|
||||
auth?: HoppRESTRequest["auth"],
|
||||
parse = true
|
||||
) => {
|
||||
@@ -108,7 +115,12 @@ export const getComputedAuthHeaders = (
|
||||
* @returns The list of headers
|
||||
*/
|
||||
export const getComputedBodyHeaders = (
|
||||
req: HoppRESTRequest
|
||||
req:
|
||||
| HoppRESTRequest
|
||||
| {
|
||||
auth: HoppRESTAuth
|
||||
headers: HoppRESTHeaders
|
||||
}
|
||||
): HoppRESTHeader[] => {
|
||||
// If a content-type is already defined, that will override this
|
||||
if (
|
||||
@@ -118,8 +130,10 @@ export const getComputedBodyHeaders = (
|
||||
)
|
||||
return []
|
||||
|
||||
if (!("body" in req)) return []
|
||||
|
||||
// Body should have a non-null content-type
|
||||
if (req.body.contentType === null) return []
|
||||
if (!req.body || req.body.contentType === null) return []
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -143,7 +157,12 @@ export type ComputedHeader = {
|
||||
* @returns The headers that are generated along with the source of that header
|
||||
*/
|
||||
export const getComputedHeaders = (
|
||||
req: HoppRESTRequest,
|
||||
req:
|
||||
| HoppRESTRequest
|
||||
| {
|
||||
auth: HoppRESTAuth
|
||||
headers: HoppRESTHeaders
|
||||
},
|
||||
envVars: Environment["variables"],
|
||||
parse = true
|
||||
): ComputedHeader[] => {
|
||||
|
||||
Reference in New Issue
Block a user