feat: auth-headers in team collection

This commit is contained in:
nivedin
2023-12-07 22:47:50 +05:30
committed by Andrew Bastin
parent 574d800a12
commit 951cff9f30
13 changed files with 362 additions and 77 deletions

View File

@@ -74,7 +74,7 @@ import { Picked } from "~/helpers/types/HoppPicked"
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import {
cascaseParentCollectionForHeaderAuth,
cascadeParentCollectionForHeaderAuth,
editGraphqlRequest,
editRESTRequest,
saveGraphqlRequestAs,
@@ -240,7 +240,7 @@ const saveRequestAs = async () => {
},
}
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
`${picked.value.collectionIndex}`,
"rest"
)
@@ -277,7 +277,7 @@ const saveRequestAs = async () => {
},
}
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
picked.value.folderPath,
"rest"
)
@@ -315,7 +315,7 @@ const saveRequestAs = async () => {
},
}
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
picked.value.folderPath,
"rest"
)
@@ -409,7 +409,7 @@ const saveRequestAs = async () => {
workspaceType: "team",
})
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
picked.value.folderPath,
"graphql"
)
@@ -434,7 +434,7 @@ const saveRequestAs = async () => {
workspaceType: "team",
})
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
picked.value.folderPath,
"graphql"
)
@@ -459,7 +459,7 @@ const saveRequestAs = async () => {
workspaceType: "team",
})
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
`${picked.value.collectionIndex}`,
"graphql"
)

View File

@@ -252,6 +252,7 @@
selectRequest({
request: node.data.data.data.request,
requestIndex: node.data.data.data.id,
folderPath: getPath(node.id),
})
"
@share-request="
@@ -503,7 +504,7 @@ const emit = defineEmits<{
request: HoppRESTRequest
requestIndex: string
isActive: boolean
folderPath?: string | undefined
folderPath: string
}
): void
(
@@ -551,6 +552,12 @@ const emit = defineEmits<{
(event: "display-modal-import-export"): void
}>()
const getPath = (path: string) => {
const pathArray = path.split("/")
pathArray.pop()
return pathArray.join("/")
}
const teamCollectionsList = toRef(props, "teamCollectionList")
const hasNoTeamAccess = computed(
@@ -607,6 +614,7 @@ const isActiveRequest = (requestID: string) => {
const selectRequest = (data: {
request: HoppRESTRequest
requestIndex: string
folderPath: string | null
}) => {
const { request, requestIndex } = data
if (props.saveRequest) {
@@ -619,6 +627,7 @@ const selectRequest = (data: {
request: request,
requestIndex: requestIndex,
isActive: isActiveRequest(requestIndex),
folderPath: data.folderPath,
})
}
}

View File

@@ -161,7 +161,7 @@ import {
graphqlCollections$,
addGraphqlFolder,
saveGraphqlRequestAs,
cascaseParentCollectionForHeaderAuth,
cascadeParentCollectionForHeaderAuth,
editGraphqlCollection,
editGraphqlFolder,
moveGraphqlRequest,
@@ -343,7 +343,7 @@ const onAddRequest = ({
saveGraphqlRequestAs(path, newRequest)
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
path,
"graphql"
)
@@ -465,7 +465,7 @@ const selectRequest = ({
folderPath: folderPath,
requestIndex: requestIndex,
})
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
folderPath,
"graphql"
)
@@ -508,7 +508,7 @@ const dropRequest = ({
requestIndex: number
collectionIndex: number
}) => {
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
`${collectionIndex}`,
"graphql"
)
@@ -561,7 +561,7 @@ const editProperties = ({
let inheritedProperties = {}
if (parentIndex) {
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
parentIndex,
"graphql"
)
@@ -594,7 +594,7 @@ const setCollectionProperties = (newCollection: {
editGraphqlFolder(path, collection)
}
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
path,
"graphql"
)

View File

@@ -189,7 +189,7 @@ import {
moveRESTFolder,
navigateToFolderWithIndexPath,
restCollectionStore,
cascaseParentCollectionForHeaderAuth,
cascadeParentCollectionForHeaderAuth,
} from "~/newstore/collections"
import TeamCollectionAdapter from "~/helpers/teams/TeamCollectionAdapter"
import {
@@ -202,10 +202,10 @@ import { GQLError } from "~/helpers/backend/GQLClient"
import {
createNewRootCollection,
createChildCollection,
renameCollection,
deleteCollection,
moveRESTTeamCollection,
updateOrderRESTTeamCollection,
updateTeamCollection,
} from "~/helpers/backend/mutations/TeamCollection"
import {
updateTeamRequest,
@@ -674,12 +674,12 @@ const onAddRequest = (requestName: string) => {
name: requestName,
}
const path = editingFolderPath.value
if (!path) return
if (collectionsType.value.type === "my-collections") {
const path = editingFolderPath.value
if (!path) return
const insertionIndex = saveRESTRequestAs(path, newRequest)
const { auth, headers } = cascaseParentCollectionForHeaderAuth(path, "rest")
const { auth, headers } = cascadeParentCollectionForHeaderAuth(path, "rest")
tabs.createNewTab({
request: newRequest,
@@ -733,7 +733,8 @@ const onAddRequest = (requestName: string) => {
},
(result) => {
const { createRequestInCollection } = result
const { auth, headers } =
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(path)
tabs.createNewTab({
request: newRequest,
isDirty: false,
@@ -743,6 +744,10 @@ const onAddRequest = (requestName: string) => {
collectionID: createRequestInCollection.collection.id,
teamID: createRequestInCollection.collection.team.id,
},
inheritedProperties: {
auth,
headers,
},
})
modalLoadingState.value = false
@@ -857,7 +862,7 @@ const updateEditingCollection = (newName: string) => {
modalLoadingState.value = true
pipe(
renameCollection(editingCollection.value.id, newName),
updateTeamCollection(editingCollection.value.id, undefined, newName),
TE.match(
(err: GQLError<string>) => {
toast.error(`${getErrorMessage(err)}`)
@@ -906,7 +911,7 @@ const updateEditingFolder = (newName: string) => {
/* renameCollection can be used to rename both collections and folders
since folder is treated as collection in the BE. */
pipe(
renameCollection(editingFolder.value.id, newName),
updateTeamCollection(editingFolder.value.id, undefined, newName),
TE.match(
(err: GQLError<string>) => {
if (err.error === "team_coll/short_title") {
@@ -1320,21 +1325,18 @@ const selectPicked = (payload: Picked | null) => {
*/
const selectRequest = (selectedRequest: {
request: HoppRESTRequest
folderPath: string | undefined
folderPath: string
requestIndex: string
isActive: boolean
}) => {
const { request, folderPath, requestIndex } = selectedRequest
// If there is a request with this save context, switch into it
let possibleTab = null
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
folderPath,
"rest"
)
if (collectionsType.value.type === "team-collections") {
const { auth, headers } =
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(folderPath)
possibleTab = tabs.getTabRefWithSaveContext({
originLocation: "team-collection",
requestID: requestIndex,
@@ -1348,10 +1350,19 @@ const selectRequest = (selectedRequest: {
saveContext: {
originLocation: "team-collection",
requestID: requestIndex,
collectionID: folderPath,
},
inheritedProperties: {
auth,
headers,
},
})
}
} else {
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
folderPath,
"rest"
)
possibleTab = tabs.getTabRefWithSaveContext({
originLocation: "user-collection",
requestIndex: parseInt(requestIndex),
@@ -1399,12 +1410,12 @@ const dropRequest = (payload: {
}) => {
const { folderPath, requestIndex, destinationCollectionIndex } = payload
if (!requestIndex || !destinationCollectionIndex) return
if (!requestIndex || !destinationCollectionIndex || !folderPath) return
let possibleTab = null
if (collectionsType.value.type === "my-collections" && folderPath) {
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
if (collectionsType.value.type === "my-collections") {
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
destinationCollectionIndex,
"rest"
)
@@ -1467,6 +1478,10 @@ const dropRequest = (payload: {
requestMoveLoading.value.indexOf(requestIndex),
1
)
const { auth, headers } =
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(
destinationCollectionIndex
)
possibleTab = tabs.getTabRefWithSaveContext({
originLocation: "team-collection",
@@ -1478,6 +1493,10 @@ const dropRequest = (payload: {
originLocation: "team-collection",
requestID: requestIndex,
}
possibleTab.value.document.inheritedProperties = {
auth,
headers,
}
}
toast.success(`${t("request.moved")}`)
}
@@ -1598,7 +1617,7 @@ const dropCollection = (payload: {
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`
)
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
"rest"
)
@@ -1639,6 +1658,22 @@ const dropCollection = (payload: {
collectionMoveLoading.value.indexOf(collectionIndexDragged),
1
)
const { auth, headers } =
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(
destinationCollectionIndex
)
const inheritedProperty = {
auth,
headers,
}
updateInheritedPropertiesForAffectedRequests(
`${destinationCollectionIndex}`,
inheritedProperty,
"rest"
)
}
)
)()
@@ -1976,27 +2011,85 @@ const editProperties = (payload: {
}) => {
const { collection, collectionIndex } = payload
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
if (collectionsType.value.type === "my-collections") {
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
let inheritedProperties = {}
if (parentIndex) {
const { auth, headers } = cascaseParentCollectionForHeaderAuth(
parentIndex,
"rest"
)
inheritedProperties = {
auth,
headers,
let inheritedProperties = {
auth: {
parentID: "",
parentName: "",
inheritedAuth: {
authType: "none",
authActive: true,
},
},
headers: [
{
parentID: "",
parentName: "",
inheritedHeaders: [],
},
],
} as HoppInheritedProperty
}
editingProperties.value = {
collection,
isRootCollection: isAlreadyInRoot(collectionIndex),
path: collectionIndex,
inheritedProperties,
if (parentIndex) {
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
parentIndex,
"rest"
)
inheritedProperties = {
auth,
headers,
}
}
editingProperties.value = {
collection,
isRootCollection: isAlreadyInRoot(collectionIndex),
path: collectionIndex,
inheritedProperties,
}
} else if (hasTeamWriteAccess.value) {
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
const data = collection.data ? JSON.parse(collection.data) : null
let inheritedProperties = {}
let coll = {
id: collection.id,
name: collection.title,
auth: {
authType: "none",
authActive: true,
},
headers: [],
}
if (parentIndex) {
const { auth, headers } =
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(parentIndex)
inheritedProperties = {
auth,
headers,
}
}
if (data) {
coll = {
...coll,
auth: data.auth,
headers: data.headers,
}
}
editingProperties.value = {
collection: coll,
isRootCollection: isAlreadyInRoot(collectionIndex),
path: collectionIndex,
inheritedProperties,
}
}
displayModalEditProperties(true)
@@ -2008,25 +2101,57 @@ const setCollectionProperties = (newCollection: {
isRootCollection: boolean
}) => {
const { collection, path, isRootCollection } = newCollection
if (isRootCollection) {
editRESTCollection(parseInt(path), collection)
} else {
editRESTFolder(path, collection)
if (collectionsType.value.type === "my-collections") {
if (isRootCollection) {
editRESTCollection(parseInt(path), collection)
} else {
editRESTFolder(path, collection)
}
const { auth, headers } = cascadeParentCollectionForHeaderAuth(path, "rest")
nextTick(() => {
updateInheritedPropertiesForAffectedRequests(
path,
{
auth,
headers,
},
"rest"
)
})
} else if (hasTeamWriteAccess.value && collection.id) {
const data = {
auth: collection.auth,
headers: collection.headers,
}
pipe(
updateTeamCollection(collection.id, JSON.stringify(data), undefined),
TE.match(
(err: GQLError<string>) => {
toast.error(`${getErrorMessage(err)}`)
},
() => {
const { auth, headers } =
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(path)
nextTick(() => {
updateInheritedPropertiesForAffectedRequests(
path,
{
auth,
headers,
},
"rest",
"team"
)
})
}
)
)()
}
const { auth, headers } = cascaseParentCollectionForHeaderAuth(path, "rest")
nextTick(() => {
updateInheritedPropertiesForAffectedRequests(
path,
{
auth,
headers,
},
"rest"
)
})
displayModalEditProperties(false)
}

View File

@@ -0,0 +1,15 @@
mutation UpdateTeamCollection(
$collectionID: ID!
$newTitle: String
$data: String
) {
updateTeamCollection(
collectionID: $collectionID
newTitle: $newTitle
data: $data
) {
id
title
data
}
}

View File

@@ -3,6 +3,7 @@ query GetCollectionChildren($collectionID: ID!, $cursor: ID) {
children(cursor: $cursor) {
id
title
data
}
}
}

View File

@@ -2,5 +2,6 @@ query RootCollectionsOfTeam($teamID: ID!, $cursor: ID) {
rootCollectionsOfTeam(teamID: $teamID, cursor: $cursor) {
id
title
data
}
}

View File

@@ -2,6 +2,7 @@ subscription TeamCollectionUpdated($teamID: ID!) {
teamCollectionUpdated(teamID: $teamID) {
id
title
data
parent {
id
}

View File

@@ -21,6 +21,9 @@ import {
UpdateCollectionOrderDocument,
UpdateCollectionOrderMutation,
UpdateCollectionOrderMutationVariables,
UpdateTeamCollectionDocument,
UpdateTeamCollectionMutation,
UpdateTeamCollectionMutationVariables,
} from "../graphql"
type CreateNewRootCollectionError = "team_coll/short_title"
@@ -122,3 +125,18 @@ export const importJSONToTeam = (collectionJSON: string, teamID: string) =>
teamID,
}
)
export const updateTeamCollection = (
collectionID: string,
data?: string,
newTitle?: string
) =>
runMutation<
UpdateTeamCollectionMutation,
UpdateTeamCollectionMutationVariables,
""
>(UpdateTeamCollectionDocument, {
collectionID,
data,
newTitle,
})

View File

@@ -113,16 +113,29 @@ export function updateSaveContextForAffectedRequests(
export function updateInheritedPropertiesForAffectedRequests(
path: string,
inheritedProperties: HoppInheritedProperty,
type: "rest" | "graphql"
type: "rest" | "graphql",
workspace: "personal" | "team" = "personal"
) {
const tabService =
type === "rest" ? getService(RESTTabService) : getService(GQLTabService)
const tabs = tabService.getTabsRefTo((tab) => {
return (
tab.document.saveContext?.originLocation === "user-collection" &&
tab.document.saveContext.folderPath.startsWith(path)
)
})
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 tabsEffectedByAuth = tabs.filter((tab) => {
return (

View File

@@ -8,4 +8,5 @@ export interface TeamCollection {
title: string
children: TeamCollection[] | null
requests: TeamRequest[] | null
data: string | null
}

View File

@@ -1,6 +1,10 @@
import * as E from "fp-ts/Either"
import { BehaviorSubject, Subscription } from "rxjs"
import { translateToNewRequest } from "@hoppscotch/data"
import {
HoppRESTAuth,
HoppRESTHeader,
translateToNewRequest,
} from "@hoppscotch/data"
import { pull, remove } from "lodash-es"
import { Subscription as WSubscription } from "wonka"
import { runGQLQuery, runGQLSubscription } from "../backend/GQLClient"
@@ -21,6 +25,7 @@ import {
TeamRequestOrderUpdatedDocument,
TeamCollectionOrderUpdatedDocument,
} from "~/helpers/backend/graphql"
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
const TEAMS_BACKEND_PAGE_SIZE = 10
@@ -542,6 +547,7 @@ export default class NewTeamCollectionAdapter {
children: null,
requests: null,
title: title,
data: null,
},
parentID ?? null
)
@@ -693,6 +699,7 @@ export default class NewTeamCollectionAdapter {
children: null,
requests: null,
title: result.right.teamCollectionAdded.title,
data: null,
},
result.right.teamCollectionAdded.parent?.id ?? null
)
@@ -715,6 +722,7 @@ export default class NewTeamCollectionAdapter {
this.updateCollection({
id: result.right.teamCollectionUpdated.id,
title: result.right.teamCollectionUpdated.title,
data: result.right.teamCollectionUpdated.data,
})
})
@@ -931,6 +939,7 @@ export default class NewTeamCollectionAdapter {
<TeamCollection>{
id: el.id,
title: el.title,
data: el.data,
children: null,
requests: null,
}
@@ -1024,4 +1033,96 @@ export default class NewTeamCollectionAdapter {
)
}
}
public cascadeParentCollectionForHeaderAuth(folderPath: string) {
let auth: HoppInheritedProperty["auth"] = {
parentID: folderPath ?? "",
parentName: "",
inheritedAuth: {
authType: "none",
authActive: true,
},
}
const headers: HoppInheritedProperty["headers"] = []
if (!folderPath) return { auth, headers }
const path = folderPath.split("/")
// Check if the path is empty or invalid
if (!path || path.length === 0) {
console.error("Invalid path:", folderPath)
return { auth, headers }
}
// Loop through the path and get the last parent folder with authType other than 'inherit'
for (let i = 0; i < path.length; i++) {
const parentFolder = findCollInTree(this.collections$.value, path[i])
// Check if parentFolder is undefined or null
if (!parentFolder) {
console.error("Parent folder not found for path:", path)
return { auth, headers }
}
const data: {
auth?: HoppRESTAuth
headers?: HoppRESTHeader[]
} = parentFolder.data ? JSON.parse(parentFolder.data) : null
if (!data) return { auth, headers }
const parentFolderAuth = data.auth
const parentFolderHeaders = data.headers
const isRootCollection = path.length === 1
if (parentFolderAuth?.authType === "inherit" && isRootCollection) {
auth = {
parentID: parentFolder.id ?? folderPath,
parentName: parentFolder.title,
inheritedAuth: {
authType: "none",
authActive: true,
},
}
}
if (
parentFolderAuth?.authType !== "inherit" &&
parentFolderAuth?.authActive
) {
auth = {
parentID: parentFolder.id ?? folderPath,
parentName: parentFolder.title,
inheritedAuth: parentFolderAuth,
}
}
// Update headers, overwriting duplicates by key
if (parentFolderHeaders) {
const activeHeaders = parentFolderHeaders.filter((h) => h.active)
activeHeaders.forEach((header) => {
const index = headers.findIndex(
(h) => h.inheritedHeader?.key === header.key
)
const currentPath = [...path.slice(0, i + 1)].join("/")
if (index !== -1) {
// Replace the existing header with the same key
headers[index] = {
parentID: currentPath,
parentName: parentFolder.title,
inheritedHeader: header,
}
} else {
headers.push({
parentID: currentPath,
parentName: parentFolder.title,
inheritedHeader: header,
})
}
})
}
}
return { auth, headers }
}
}

View File

@@ -63,7 +63,7 @@ export function navigateToFolderWithIndexPath(
return target !== undefined ? target : null
}
export function cascaseParentCollectionForHeaderAuth(
export function cascadeParentCollectionForHeaderAuth(
folderPath: string | undefined,
type: "rest" | "graphql"
) {