fix: collection auth headers active tab update bug and type fix (#3899)

This commit is contained in:
Nivedin
2024-03-15 21:17:34 +05:30
committed by GitHub
parent 0e96665254
commit a14870f3f0
5 changed files with 131 additions and 122 deletions

View File

@@ -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 = () => {

View File

@@ -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)
}

View File

@@ -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[]

View File

@@ -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) {

View File

@@ -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[] => {