diff --git a/packages/hoppscotch-common/src/components/collections/index.vue b/packages/hoppscotch-common/src/components/collections/index.vue index 39b4b74ad77..014f6d0ab91 100644 --- a/packages/hoppscotch-common/src/components/collections/index.vue +++ b/packages/hoppscotch-common/src/components/collections/index.vue @@ -24,7 +24,6 @@ autocomplete="off" class="flex w-full bg-transparent px-4 py-2 h-8" :placeholder="t('action.search')" - :disabled="collectionsType.type === 'team-collections'" /> ([]) +const teamsSearchResultsLoading = ref(false) + +type CollectionSearchNode = + | { + type: "request" + title: string + method: string + id: string + // parent collections + path: CollectionSearchNode[] + } + | { + type: "collection" + title: string + id: string + // parent collections + path: CollectionSearchNode[] + } + +export interface TeamCollection { + id: string + title: string + children: TeamCollection[] | null + requests: TeamRequest[] | null + data: string | null +} + +export interface TeamRequest { + id: string + collectionID: string + title: string + request: HoppRESTRequest +} + +const searchTeams = async (query: string) => { + const endpoint = import.meta.env.VITE_BACKEND_API_URL + + let searchResultsCollections: Record< + string, + TeamCollection & { parentID: string | null } + > = {} + + let searchResultsRequests: Record< + string, + { + id: string + collectionID: string + title: string + request: { + name: string + method: string + } + } + > = {} + + teamsSearchResultsLoading.value = true + + try { + const searchResponse = await axios.get( + `${endpoint}/team-collection/search/cltmcycid000cg7ate3wwvf6v/${query}`, + { + withCredentials: true, + } + ) + + if (searchResponse.status !== 200) { + console.error("Failed to search teams") + return + } + + const searchResults = searchResponse.data.data as CollectionSearchNode[] + + searchResults + .map((node) => { + const { existingCollections, existingRequests } = + convertToTeamCollection(node, {}, {}) + + return { + collections: existingCollections, + requests: existingRequests, + } + }) + .forEach(({ collections, requests }) => { + searchResultsCollections = { + ...searchResultsCollections, + ...collections, + } + searchResultsRequests = { ...searchResultsRequests, ...requests } + }) + + const collectionFetchingPromises = Object.values( + searchResultsCollections + ).map((col) => { + return getSingleCollection(col.id) + }) + + const requestFetchingPromises = Object.values(searchResultsRequests).map( + (req) => { + return getSingleRequest(req.id) + } + ) + + const collectionResponses = await Promise.all(collectionFetchingPromises) + const requestResponses = await Promise.all(requestFetchingPromises) + + requestResponses.map((res) => { + if (E.isLeft(res)) { + console.log("Error fetching request", res.left) + return + } + + const request = res.right.request + + if (!request) return + + searchResultsRequests[request.id] = { + id: request.id, + title: request.title, + request: JSON.parse(request.request) as TeamRequest["request"], + collectionID: request.collectionID, + } + }) + + collectionResponses.map((res) => { + if (E.isLeft(res)) { + console.log("Error fetching collection", res.left) + return + } + + const collection = res.right.collection + + if (!collection) return + + searchResultsCollections[collection.id].data = collection.data ?? null + }) + + const collectionTree = convertToTeamTree( + Object.values(searchResultsCollections), + Object.values(searchResultsRequests) + ) + + teamsSearchResults.value = collectionTree + + // teamsSearchResults.value = convertToTeamCollection(searchResults) + } catch (error) { + console.error(error) + } + + teamsSearchResultsLoading.value = false +} + +watch( + filterTexts, + (newFilterText) => { + console.log("filterTexts", newFilterText) + console.log("collectionsType", collectionsType.value.type) + if (collectionsType.value.type === "team-collections") { + console.log("searching teams") + searchTeams(newFilterText).then(() => { + console.group("Search Results") + console.log(teamsSearchResults.value) + console.groupEnd() + }) + } + }, + { + immediate: true, + } +) + +const getSingleCollection = (collectionID: string) => + runGQLQuery({ + query: GetSingleCollectionDocument, + variables: { + collectionID, + }, + }) + +const getSingleRequest = (requestID: string) => + runGQLQuery({ + query: GetSingleRequestDocument, + variables: { + requestID, + }, + }) + +function convertToTeamCollection( + node: CollectionSearchNode, + existingCollections: Record< + string, + TeamCollection & { parentID: string | null } + >, + existingRequests: Record< + string, + { + id: string + collectionID: string + title: string + request: { + name: string + method: string + } + } + > +) { + // for each node, it'll have the path array with only one element, that'll be the parent collection + + // const requests: { + // id: string + // collectionID: string + // title: string + // request: { + // name: string + // method: string + // } + // }[] = existingRequests ?? [] + + // debugger + // const collections: TeamCollection[] = existingCollections ?? [] + + if (node.type === "request") { + existingRequests[node.id] = { + id: node.id, + collectionID: node.path[0].id, + title: node.title, + request: { + name: node.title, + method: node.method, + }, + } + + if (node.path[0]) { + // add parent collections to the collections array recursively + convertToTeamCollection( + node.path[0], + existingCollections, + existingRequests + ) + } + } else { + existingCollections[node.id] = { + id: node.id, + title: node.title, + children: [], + requests: [], + data: null, + parentID: node.path[0]?.id, + } + + if (node.path[0]) { + // add parent collections to the collections array recursively + convertToTeamCollection( + node.path[0], + existingCollections, + existingRequests + ) + } + } + + return { + existingCollections, + existingRequests, + } +} + +function convertToTeamTree( + collections: (TeamCollection & { parentID: string | null })[], + requests: { + id: string + collectionID: string + title: string + request: { + name: string + method: string + } + }[] +) { + const collectionTree: TeamCollection[] = [] + + collections.forEach((collection) => { + const parentCollection = collection.parentID + ? collections.find((c) => c.id === collection.parentID) + : null + + if (parentCollection) { + parentCollection.children = parentCollection.children || [] + parentCollection.children.push(collection) + } else { + collectionTree.push(collection) + } + }) + + requests.forEach((request) => { + const parentCollection = collections.find( + (c) => c.id === request.collectionID + ) + + if (parentCollection) { + parentCollection.requests = parentCollection.requests || [] + parentCollection.requests.push({ + id: request.id, + collectionID: request.collectionID, + title: request.title, + request: { + name: request.title, + method: request.request.method, + }, + }) + } + }) + + return collectionTree +} + +window.searchTeams = searchTeams + watch( () => myTeams.value, (newTeams) => { @@ -365,6 +689,7 @@ const switchToMyCollections = () => { } const expandTeamCollection = (collectionID: string) => { + // TODO: use teamSearchResults to handle expanding search results teamCollectionAdapter.expandCollection(collectionID) } @@ -1312,9 +1637,46 @@ const onRemoveRequest = () => { // The request is picked in the save request as modal const selectPicked = (payload: Picked | null) => { + console.log("selectPicked", payload) emit("select", payload) } +const findParentAuthRecursively = (collectionID: string) => { + const defaultInheritedAuth: HoppInheritedProperty["auth"] = { + parentID: "", + parentName: "", + inheritedAuth: { + authType: "none", + authActive: true, + }, + } + + const defaultInheritedHeaders: HoppInheritedProperty["headers"] = [] + + const collection = Object.values(searchResultsCollections).find( + (col) => col.id === collectionID + ) + + if (!collection) + return { auth: defaultInheritedAuth, headers: defaultInheritedHeaders } + + const collectionAuth = + collection.data ?? (JSON.parse(collection.data) as HoppInheritedProperty) +} + +const cascadeParentCollectionForHeaderAuthForSearchResults = ( + collectionID: string, + collections: TeamCollection[], + requests: TeamRequest[] +) => { + const collection = Object.values(searchResultsCollections).find( + (col) => col.id === collectionID + ) + + if (!collection) + return { auth: defaultInheritedAuth, headers: defaultInheritedHeaders } +} + /** * This function is called when the user clicks on a request * @param selectedRequest The request that the user clicked on emited from the collection tree @@ -1329,7 +1691,11 @@ const selectRequest = (selectedRequest: { // If there is a request with this save context, switch into it let possibleTab = null - if (collectionsType.value.type === "team-collections") { + if ( + filterTexts.value.length > 0 && + collectionsType.value.type === "team-collections" + ) { + } else if (collectionsType.value.type === "team-collections") { const { auth, headers } = teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(folderPath)