From ae531f588204288e6818ac0b5d2a49e253ac6fdb Mon Sep 17 00:00:00 2001 From: nivedin Date: Tue, 28 Nov 2023 22:34:10 +0530 Subject: [PATCH] chore: update properties UI flow --- .../src/components/collections/Collection.vue | 1 - .../components/collections/MyCollections.vue | 7 + .../src/components/collections/Properties.vue | 62 ++++-- .../collections/TeamCollections.vue | 7 + .../src/components/collections/index.vue | 181 +++++++++++++++++- 5 files changed, 235 insertions(+), 23 deletions(-) diff --git a/packages/hoppscotch-common/src/components/collections/Collection.vue b/packages/hoppscotch-common/src/components/collections/Collection.vue index b5bd7f139..f59202186 100644 --- a/packages/hoppscotch-common/src/components/collections/Collection.vue +++ b/packages/hoppscotch-common/src/components/collections/Collection.vue @@ -161,7 +161,6 @@ " /> | TeamCollection | null + isRootCollection: boolean + path: string + inheritedProperties: HoppInheritedProperty | null +} + const props = withDefaults( defineProps<{ show: boolean loadingState: boolean - collection: HoppCollection | TeamCollection + editingProperties: EditingProperties | null }>(), { show: false, loadingState: false, + editingProperties: null, } ) const emit = defineEmits<{ - (e: "submit", name: string): void + (e: "set-collection-properties", newCollection: any): void (e: "hide-modal"): void }>() const editableCollection = ref({ - ...props.collection, body: { contentType: null, body: null, }, headers: [], auth: { - authType: "none", + authType: "inherit", authActive: false, }, }) as any @@ -124,23 +135,44 @@ const changeOptionTab = (tab: RESTOptionTabs) => { watch( () => props.show, (show) => { - if (!show) { + if (show && props.editingProperties?.collection) { + editableCollection.value.auth = clone( + props.editingProperties.collection.auth + ) + editableCollection.value.headers = clone( + props.editingProperties.collection.headers + ) + } else { + editableCollection.value = { + body: { + contentType: null, + body: null, + }, + headers: [], + auth: { + authType: "inherit", + authActive: false, + }, + } } } ) const saveEditedCollection = () => { - console.log("new-coll", editableCollection.value) + if (!props.editingProperties) return + const finalCollection = clone(editableCollection.value) + delete finalCollection.body + const collection = { + path: props.editingProperties.path, + collection: { + ...props.editingProperties.collection, + ...finalCollection, + }, + isRootCollection: props.editingProperties.isRootCollection, + } + emit("set-collection-properties", collection) } -// const addNewCollection = () => { -// if (!editingName.value) { -// toast.error(t("collection.invalid_name")) -// return -// } - -// } - const hideModal = () => { emit("hide-modal") } diff --git a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue index ad09b7758..2d624545e 100644 --- a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue +++ b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue @@ -166,6 +166,13 @@ folder: node.data.data.data, }) " + @edit-properties=" + node.data.type === 'folders' && + emit('edit-properties', { + collectionIndex: node.id, + collection: node.data.data.data, + }) + " @export-data=" node.data.type === 'folders' && emit('export-data', node.data.data.data) diff --git a/packages/hoppscotch-common/src/components/collections/index.vue b/packages/hoppscotch-common/src/components/collections/index.vue index 356a09744..944d465be 100644 --- a/packages/hoppscotch-common/src/components/collections/index.vue +++ b/packages/hoppscotch-common/src/components/collections/index.vue @@ -155,7 +155,9 @@ /> @@ -226,6 +228,7 @@ import { getFoldersByPath, resolveSaveContextOnCollectionReorder, updateSaveContextForAffectedRequests, + updateInheritedPropertiesForAffectedRequests, resetTeamRequestsContext, } from "~/helpers/collection/collection" import { currentReorderingStatus$ } from "~/newstore/reordering" @@ -233,6 +236,7 @@ import { defineActionHandler, invokeAction } from "~/helpers/actions" import { WorkspaceService } from "~/services/workspace.service" import { useService } from "dioc/vue" import { RESTTabService } from "~/services/tab/rest" +import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" const t = useI18n() const toast = useToast() @@ -288,6 +292,17 @@ const editingRequestName = ref("") const editingRequestIndex = ref(null) const editingRequestID = ref(null) +const editingProperties = ref<{ + collection: HoppCollection | TeamCollection | null + isRootCollection: boolean + path: string + inheritedProperties?: HoppInheritedProperty +}>({ + collection: null, + isRootCollection: false, + path: "", +}) + const confirmModalTitle = ref(null) const filterTexts = ref("") @@ -597,6 +612,11 @@ const addNewRootCollection = (name: string) => { name, folders: [], requests: [], + headers: [], + auth: { + authType: "inherit", + authActive: false, + }, }) ) @@ -657,6 +677,8 @@ const onAddRequest = (requestName: string) => { if (!path) return const insertionIndex = saveRESTRequestAs(path, newRequest) + const { auth, headers, name } = cascaseParentCollectionForHeaderAuth(path) + tabs.createNewTab({ request: newRequest, isDirty: false, @@ -665,6 +687,12 @@ const onAddRequest = (requestName: string) => { folderPath: path, requestIndex: insertionIndex, }, + inheritedProperties: { + auth, + headers, + parentName: name, + parentId: path, + }, }) platform.analytics?.logEvent({ @@ -1286,6 +1314,63 @@ const selectPicked = (payload: Picked | null) => { emit("select", payload) } +const cascaseParentCollectionForHeaderAuth = ( + folderPath: string | undefined +) => { + let auth: HoppRESTRequest["auth"] = { + authType: "none", + authActive: false, + } + const headers: HoppRESTRequest["headers"] = [] + let name = "" + if (!folderPath) return { auth, headers, name: "" } + const path = folderPath.split("/").map((i) => parseInt(i)) + + // Check if the path is empty or invalid + if (!path || path.length === 0) { + console.error("Invalid path:", folderPath) + return { auth, headers, name: "" } + } + + // 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 = navigateToFolderWithIndexPath( + restCollectionStore.value.state, + [...path.slice(0, i + 1)] // Create a copy of the path array + ) + + // Check if parentFolder is undefined or null + if (!parentFolder) { + console.error("Parent folder not found for path:", path) + return { auth, headers, name: "" } + } + + const parentFolderAuth = parentFolder.auth + const parentFolderHeaders = parentFolder.headers + + // Check if authType is not 'inherit' + if (parentFolderAuth?.authType !== "inherit") { + auth = parentFolderAuth || auth + name = parentFolder.name + } + // Update headers, overwriting duplicates by key + if (parentFolderHeaders) { + const activeHeaders = parentFolderHeaders.filter((h) => h.active) + activeHeaders.forEach((header) => { + const index = headers.findIndex((h) => h.key === header.key) + if (index !== -1) { + // Replace the existing header with the same key + headers[index] = header + } else { + headers.push(header) + } + }) + } + } + + return { auth, headers, name } +} + /** * 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 @@ -1301,6 +1386,9 @@ const selectRequest = (selectedRequest: { // If there is a request with this save context, switch into it let possibleTab = null + const { auth, headers, name } = + cascaseParentCollectionForHeaderAuth(folderPath) + if (collectionsType.value.type === "team-collections") { possibleTab = tabs.getTabRefWithSaveContext({ originLocation: "team-collection", @@ -1336,6 +1424,12 @@ const selectRequest = (selectedRequest: { folderPath: folderPath!, requestIndex: parseInt(requestIndex), }, + inheritedProperties: { + parentId: folderPath || "", + parentName: name, + auth: auth, + headers, + }, }) } } @@ -1364,14 +1458,14 @@ const dropRequest = (payload: { if (!requestIndex || !destinationCollectionIndex) return + let possibleTab = null + if (collectionsType.value.type === "my-collections" && folderPath) { - moveRESTRequest( - folderPath, - pathToLastIndex(requestIndex), + const { auth, headers, name } = cascaseParentCollectionForHeaderAuth( destinationCollectionIndex ) - const possibleTab = tabs.getTabRefWithSaveContext({ + possibleTab = tabs.getTabRefWithSaveContext({ originLocation: "user-collection", folderPath, requestIndex: pathToLastIndex(requestIndex), @@ -1387,6 +1481,13 @@ const dropRequest = (payload: { destinationCollectionIndex ).length, } + + possibleTab.value.document.inheritedProperties = { + parentId: destinationCollectionIndex, + parentName: name, + auth, + headers, + } } // When it's drop it's basically getting deleted from last folder. reordering last folder accordingly @@ -1396,6 +1497,11 @@ const dropRequest = (payload: { folderPath, length: getRequestsByPath(myCollections.value, folderPath).length, }) + moveRESTRequest( + folderPath, + pathToLastIndex(requestIndex), + destinationCollectionIndex + ) toast.success(`${t("request.moved")}`) draggingToRoot.value = false @@ -1420,7 +1526,7 @@ const dropRequest = (payload: { 1 ) - const possibleTab = tabs.getTabRefWithSaveContext({ + possibleTab = tabs.getTabRefWithSaveContext({ originLocation: "team-collection", requestID: requestIndex, }) @@ -1550,6 +1656,22 @@ const dropCollection = (payload: { `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}` ) + const { auth, headers, name } = cascaseParentCollectionForHeaderAuth( + `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}` + ) + + const inheritedProperty = { + parentId: `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`, + parentName: name, + auth, + headers, + } + + updateInheritedPropertiesForAffectedRequests( + `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`, + inheritedProperty + ) + draggingToRoot.value = false toast.success(`${t("collection.moved")}`) } else if (hasTeamWriteAccess.value) { @@ -1912,13 +2034,58 @@ const editProperties = (payload: { }) => { const { collection, collectionIndex } = payload - console.log(collectionIndex, collection) + const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder - editingCollection.value = collection + let inheritedProperties = {} + + if (parentIndex) { + const { auth, headers, name } = + cascaseParentCollectionForHeaderAuth(parentIndex) + + inheritedProperties = { + parentId: parentIndex ?? "", + parentName: name, + auth, + headers, + } as HoppInheritedProperty + } + + editingProperties.value = { + collection, + isRootCollection: isAlreadyInRoot(collectionIndex), + path: collectionIndex, + inheritedProperties, + } displayModalEditProperties(true) } +const setCollectionProperties = (newCollection: { + collection: HoppCollection + path: string + isRootCollection: boolean +}) => { + const { collection, path, isRootCollection } = newCollection + if (isRootCollection) { + editRESTCollection(parseInt(path), collection) + } else { + editRESTFolder(path, collection) + } + + const { auth, headers, name } = cascaseParentCollectionForHeaderAuth(path) + + nextTick(() => { + updateInheritedPropertiesForAffectedRequests(path, { + parentId: path, + parentName: name, + auth, + headers, + }) + }) + + displayModalEditProperties(false) +} + const resolveConfirmModal = (title: string | null) => { if (title === `${t("confirm.remove_collection")}`) onRemoveCollection() else if (title === `${t("confirm.remove_request")}`) onRemoveRequest()