feat: collection variables (#5325)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
parent
ad974dbd5b
commit
2d2e65369f
77 changed files with 2696 additions and 773 deletions
|
|
@ -0,0 +1,102 @@
|
||||||
|
{
|
||||||
|
"id": "cmeicx49r00xylb1jxektmknk",
|
||||||
|
"_ref_id": "coll_meicx3z7_a1cb5e72-cd1b-414b-adc2-7d601ca0936d",
|
||||||
|
"v": 10,
|
||||||
|
"name": "coll-with-variables",
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"id": "cmeicy6fu00xzlb1jqmmqbjdm",
|
||||||
|
"_ref_id": "coll_meie14lh_818ea8a2-9839-4a1c-8cce-cc7565b5f594",
|
||||||
|
"v": 10,
|
||||||
|
"name": "folder-1",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "15",
|
||||||
|
"id": "cmeicyhnn00y1lb1j8d80g7ys",
|
||||||
|
"name": "request-1",
|
||||||
|
"method": "GET",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "collection-var-1",
|
||||||
|
"value": "<<collection-variable-1>>",
|
||||||
|
"active": true,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "collection-var-2",
|
||||||
|
"value": "<<collection-variable-2>>",
|
||||||
|
"active": true,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "folder-var-1",
|
||||||
|
"value": "<<folder-variable-1>>",
|
||||||
|
"active": true,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "folder-var-2",
|
||||||
|
"value": "<<folder-variable-2>>",
|
||||||
|
"active": true,
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"headers": [],
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "export {};\npw.test('Correctly inherits collection variables from the parent collection and folder', () =>\n{\n\n pw.expect([\n \"collection-var-1-initial-value\",\n \"collection-var-1-current-value\"\n ]).toInclude(pw.response.body.args[\"collection-var-1\"])\n\n pw.expect([\n \"collection-var-2-initial-value\",\n \"collection-var-2-current-value\"\n ]).toInclude(pw.response.body.args[\"collection-var-2\"])\n\n pw.expect([\n \"folder-variable-1-initial-value\",\n \"folder-variable-1-current-value\"\n ]).toInclude(pw.response.body.args[\"folder-var-1\"])\n\n pw.expect([\n \"folder-variable-2-initial-value\",\n \"folder-variable-2-current-value\"\n ]).toInclude(pw.response.body.args[\"folder-var-2\"])\n\n});",
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": [],
|
||||||
|
"responses": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": [],
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "folder-variable-1",
|
||||||
|
"secret": false,
|
||||||
|
"currentValue": "",
|
||||||
|
"initialValue": "folder-variable-1-initial-value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "folder-variable-2",
|
||||||
|
"secret": false,
|
||||||
|
"currentValue": "",
|
||||||
|
"initialValue": "folder-variable-2-initial-value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requests": [],
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": [],
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "collection-variable-1",
|
||||||
|
"secret": false,
|
||||||
|
"currentValue": "",
|
||||||
|
"initialValue": "collection-var-1-initial-value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "collection-variable-2",
|
||||||
|
"secret": false,
|
||||||
|
"currentValue": "",
|
||||||
|
"initialValue": "collection-var-2-initial-value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"v": 6,
|
"v": 6,
|
||||||
"id": "cm9wmuzj46s3imbs891pdamv4",
|
"id": "cm9wmuzj46s3imbs891pdamv4",
|
||||||
"name": "Multiple child collections with authorization & headers set at each level",
|
"name": "Multiple child collections with authorization, headers and variables set at each level",
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"v": 6,
|
"v": 6,
|
||||||
|
|
@ -688,5 +688,13 @@
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "collection-variable",
|
||||||
|
"currentValue": "collection-variable-value",
|
||||||
|
"initialValue": "collection-variable-value",
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
],
|
||||||
"_ref_id": "coll_m9wn4jl9_aa8a3bc2-a96f-4cac-86f3-2df4bb355cc8"
|
"_ref_id": "coll_m9wn4jl9_aa8a3bc2-a96f-4cac-86f3-2df4bb355cc8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,5 +86,6 @@
|
||||||
"authActive": true
|
"authActive": true
|
||||||
},
|
},
|
||||||
"headers": [],
|
"headers": [],
|
||||||
|
"variables": [],
|
||||||
"_ref_id": "coll_mbhuxoci_a8fc710e-04c1-489c-a183-7f16946a7225"
|
"_ref_id": "coll_mbhuxoci_a8fc710e-04c1-489c-a183-7f16946a7225"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,29 +11,29 @@ import {
|
||||||
WorkspaceEnvironment,
|
WorkspaceEnvironment,
|
||||||
} from "../../../utils/workspace-access";
|
} from "../../../utils/workspace-access";
|
||||||
|
|
||||||
export const WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: WorkspaceCollection[] =
|
export const WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK: WorkspaceCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
id: "clx1ldkzs005t10f8rp5u60q7",
|
id: "clx1ldkzs005t10f8rp5u60q7",
|
||||||
data: '{"auth":{"token":"BearerToken","authType":"bearer","authActive":true},"headers":[{"key":"X-Test-Header","value":"Set at root collection","active":true,"description":""}]}',
|
data: '{"auth":{"token":"BearerToken","authType":"bearer","authActive":true},"headers":[{"key":"X-Test-Header","value":"Set at root collection","active":true,"description":""}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "CollectionA",
|
title: "CollectionA",
|
||||||
parentID: null,
|
parentID: null,
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1ldkzs005v10f86b9wx4yc",
|
id: "clx1ldkzs005v10f86b9wx4yc",
|
||||||
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[]}',
|
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[],"variables":[]}',
|
||||||
title: "FolderA",
|
title: "FolderA",
|
||||||
parentID: "clx1ldkzs005t10f8rp5u60q7",
|
parentID: "clx1ldkzs005t10f8rp5u60q7",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1ldkzt005x10f8i0u5lzgj",
|
id: "clx1ldkzt005x10f8i0u5lzgj",
|
||||||
data: '{"auth":{"key":"key","addTo":"HEADERS","value":"test-key","authType":"api-key","authActive":true},"headers":[{"key":"X-Test-Header","value":"Overriden at FolderB","active":true}]}',
|
data: '{"auth":{"key":"key","addTo":"HEADERS","value":"test-key","authType":"api-key","authActive":true},"headers":[{"key":"X-Test-Header","value":"Overriden at FolderB","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "FolderB",
|
title: "FolderB",
|
||||||
parentID: "clx1ldkzs005v10f86b9wx4yc",
|
parentID: "clx1ldkzs005v10f86b9wx4yc",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1ldkzu005z10f880zx17bg",
|
id: "clx1ldkzu005z10f880zx17bg",
|
||||||
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[]}',
|
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[],"variables":[]}',
|
||||||
title: "FolderC",
|
title: "FolderC",
|
||||||
parentID: "clx1ldkzt005x10f8i0u5lzgj",
|
parentID: "clx1ldkzt005x10f8i0u5lzgj",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -85,7 +85,7 @@ export const WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Workspa
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] =
|
export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK: HoppCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
v: CollectionSchemaVersion,
|
v: CollectionSchemaVersion,
|
||||||
|
|
@ -142,6 +142,7 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppC
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -181,6 +182,14 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppC
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -211,6 +220,7 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppC
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -250,27 +260,35 @@ export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppC
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: WorkspaceCollection[] =
|
export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK: WorkspaceCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
id: "clx1f86hv000010f8szcfya0t",
|
id: "clx1f86hv000010f8szcfya0t",
|
||||||
data: '{"auth":{"authType":"basic","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value set at the root collection","active":true},{"key":"Inherited-Header","value":"Inherited header at all levels","active":true}]}',
|
data: '{"auth":{"authType":"basic","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value set at the root collection","active":true},{"key":"Inherited-Header","value":"Inherited header at all levels","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title:
|
title:
|
||||||
"Multiple child collections with authorization & headers set at each level",
|
"Multiple child collections with authorization, headers and variables set at each level",
|
||||||
parentID: null,
|
parentID: null,
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1fjgah000110f8a5bs68gd",
|
id: "clx1fjgah000110f8a5bs68gd",
|
||||||
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-1","active":true}]}',
|
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-1","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-1",
|
title: "folder-1",
|
||||||
parentID: "clx1f86hv000010f8szcfya0t",
|
parentID: "clx1f86hv000010f8szcfya0t",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1fjwmm000410f8l1gkkr1a",
|
id: "clx1fjwmm000410f8l1gkkr1a",
|
||||||
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-11","active":true}]}',
|
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-11","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-11",
|
title: "folder-11",
|
||||||
parentID: "clx1fjgah000110f8a5bs68gd",
|
parentID: "clx1fjgah000110f8a5bs68gd",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -287,7 +305,7 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1fjyxm000510f8pv90dt43",
|
id: "clx1fjyxm000510f8pv90dt43",
|
||||||
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-12","active":true},{"key":"key","value":"Set at folder-12","active":true}]}',
|
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-12","active":true},{"key":"key","value":"Set at folder-12","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-12",
|
title: "folder-12",
|
||||||
parentID: "clx1fjgah000110f8a5bs68gd",
|
parentID: "clx1fjgah000110f8a5bs68gd",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -304,7 +322,7 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1fk1cv000610f88kc3aupy",
|
id: "clx1fk1cv000610f88kc3aupy",
|
||||||
data: '{"auth":{"token":"test-token","authType":"bearer","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-13","active":true},{"key":"key","value":"Set at folder-13","active":true}]}',
|
data: '{"auth":{"token":"test-token","authType":"bearer","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-13","active":true},{"key":"key","value":"Set at folder-13","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-13",
|
title: "folder-13",
|
||||||
parentID: "clx1fjgah000110f8a5bs68gd",
|
parentID: "clx1fjgah000110f8a5bs68gd",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -333,13 +351,13 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1fjk9o000210f8j0573pls",
|
id: "clx1fjk9o000210f8j0573pls",
|
||||||
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-2","active":true}]}',
|
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-2","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-2",
|
title: "folder-2",
|
||||||
parentID: "clx1f86hv000010f8szcfya0t",
|
parentID: "clx1f86hv000010f8szcfya0t",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1fk516000710f87sfpw6bo",
|
id: "clx1fk516000710f87sfpw6bo",
|
||||||
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-21","active":true}]}',
|
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-21","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-21",
|
title: "folder-21",
|
||||||
parentID: "clx1fjk9o000210f8j0573pls",
|
parentID: "clx1fjk9o000210f8j0573pls",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -356,7 +374,7 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1fk72t000810f8gfwkpi5y",
|
id: "clx1fk72t000810f8gfwkpi5y",
|
||||||
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-22","active":true},{"key":"key","value":"Set at folder-22","active":true}]}',
|
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-22","active":true},{"key":"key","value":"Set at folder-22","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-22",
|
title: "folder-22",
|
||||||
parentID: "clx1fjk9o000210f8j0573pls",
|
parentID: "clx1fjk9o000210f8j0573pls",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -373,7 +391,7 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1fk95g000910f8bunhaoo8",
|
id: "clx1fk95g000910f8bunhaoo8",
|
||||||
data: '{"auth":{"token":"test-token","authType":"bearer","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-23","active":true},{"key":"key","value":"Set at folder-23","active":true}]}',
|
data: '{"auth":{"token":"test-token","authType":"bearer","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-23","active":true},{"key":"key","value":"Set at folder-23","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-23",
|
title: "folder-23",
|
||||||
parentID: "clx1fjk9o000210f8j0573pls",
|
parentID: "clx1fjk9o000210f8j0573pls",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -402,13 +420,13 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1fjmlq000310f86o4d3w2o",
|
id: "clx1fjmlq000310f86o4d3w2o",
|
||||||
data: '{"auth":{"key":"testuser","addTo":"HEADERS","value":"testpass","authType":"basic","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-3","active":true}]}',
|
data: '{"auth":{"key":"testuser","addTo":"HEADERS","value":"testpass","authType":"basic","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-3","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-3",
|
title: "folder-3",
|
||||||
parentID: "clx1f86hv000010f8szcfya0t",
|
parentID: "clx1f86hv000010f8szcfya0t",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
id: "clx1iwq0p003e10f8u8zg0p85",
|
id: "clx1iwq0p003e10f8u8zg0p85",
|
||||||
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-31","active":true}]}',
|
data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-31","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-31",
|
title: "folder-31",
|
||||||
parentID: "clx1fjmlq000310f86o4d3w2o",
|
parentID: "clx1fjmlq000310f86o4d3w2o",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -425,7 +443,7 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1izut7003m10f894ip59zg",
|
id: "clx1izut7003m10f894ip59zg",
|
||||||
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-32","active":true},{"key":"key","value":"Set at folder-32","active":true}]}',
|
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-32","active":true},{"key":"key","value":"Set at folder-32","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-32",
|
title: "folder-32",
|
||||||
parentID: "clx1fjmlq000310f86o4d3w2o",
|
parentID: "clx1fjmlq000310f86o4d3w2o",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -442,7 +460,7 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1j2ka9003q10f8cdbzpgpg",
|
id: "clx1j2ka9003q10f8cdbzpgpg",
|
||||||
data: '{"auth":{"token":"test-token","authType":"bearer","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-33","active":true},{"key":"key","value":"Set at folder-33","active":true}]}',
|
data: '{"auth":{"token":"test-token","authType":"bearer","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-33","active":true},{"key":"key","value":"Set at folder-33","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-33",
|
title: "folder-33",
|
||||||
parentID: "clx1fjmlq000310f86o4d3w2o",
|
parentID: "clx1fjmlq000310f86o4d3w2o",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -485,17 +503,17 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] =
|
export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1f86hv000010f8szcfya0t",
|
id: "clx1f86hv000010f8szcfya0t",
|
||||||
name: "Multiple child collections with authorization & headers set at each level",
|
name: "Multiple child collections with authorization, headers and variables set at each level",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fjgah000110f8a5bs68gd",
|
id: "clx1fjgah000110f8a5bs68gd",
|
||||||
name: "folder-1",
|
name: "folder-1",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fjwmm000410f8l1gkkr1a",
|
id: "clx1fjwmm000410f8l1gkkr1a",
|
||||||
name: "folder-11",
|
name: "folder-11",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -535,9 +553,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fjyxm000510f8pv90dt43",
|
id: "clx1fjyxm000510f8pv90dt43",
|
||||||
name: "folder-12",
|
name: "folder-12",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -593,9 +619,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fk1cv000610f88kc3aupy",
|
id: "clx1fk1cv000610f88kc3aupy",
|
||||||
name: "folder-13",
|
name: "folder-13",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -669,6 +703,14 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -705,14 +747,22 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fjk9o000210f8j0573pls",
|
id: "clx1fjk9o000210f8j0573pls",
|
||||||
name: "folder-2",
|
name: "folder-2",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fk516000710f87sfpw6bo",
|
id: "clx1fk516000710f87sfpw6bo",
|
||||||
name: "folder-21",
|
name: "folder-21",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -750,9 +800,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fk72t000810f8gfwkpi5y",
|
id: "clx1fk72t000810f8gfwkpi5y",
|
||||||
name: "folder-22",
|
name: "folder-22",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -808,9 +866,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fk95g000910f8bunhaoo8",
|
id: "clx1fk95g000910f8bunhaoo8",
|
||||||
name: "folder-23",
|
name: "folder-23",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -871,6 +937,14 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -913,14 +987,23 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1fjmlq000310f86o4d3w2o",
|
id: "clx1fjmlq000310f86o4d3w2o",
|
||||||
name: "folder-3",
|
name: "folder-3",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1iwq0p003e10f8u8zg0p85",
|
id: "clx1iwq0p003e10f8u8zg0p85",
|
||||||
name: "folder-31",
|
name: "folder-31",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -958,9 +1041,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1izut7003m10f894ip59zg",
|
id: "clx1izut7003m10f894ip59zg",
|
||||||
name: "folder-32",
|
name: "folder-32",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -1016,9 +1107,17 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
id: "clx1j2ka9003q10f8cdbzpgpg",
|
id: "clx1j2ka9003q10f8cdbzpgpg",
|
||||||
name: "folder-33",
|
name: "folder-33",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -1079,6 +1178,14 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -1134,6 +1241,14 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [
|
requests: [
|
||||||
|
|
@ -1179,16 +1294,24 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Collections with `data` field set to `null` at certain levels
|
// Collections with `data` field set to `null` at certain levels
|
||||||
export const WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK: WorkspaceCollection[] =
|
export const WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK: WorkspaceCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
id: "clx1kxvao005m10f8luqivrf1",
|
id: "clx1kxvao005m10f8luqivrf1",
|
||||||
data: null,
|
data: null,
|
||||||
title: "Collection with no authorization/headers set",
|
title: "Collection with no authorization/headers/variables set",
|
||||||
parentID: null,
|
parentID: null,
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
|
|
@ -1210,7 +1333,7 @@ export const WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1kym98005o10f8qg17t9o2",
|
id: "clx1kym98005o10f8qg17t9o2",
|
||||||
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Set at folder-2","active":true}]}',
|
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Set at folder-2","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-2",
|
title: "folder-2",
|
||||||
parentID: "clx1kxvao005m10f8luqivrf1",
|
parentID: "clx1kxvao005m10f8luqivrf1",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -1235,7 +1358,7 @@ export const WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "clx1l2eaz005s10f8loetbbeb",
|
id: "clx1l2eaz005s10f8loetbbeb",
|
||||||
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Set at folder-4","active":true}]}',
|
data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Set at folder-4","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}',
|
||||||
title: "folder-4",
|
title: "folder-4",
|
||||||
parentID: "clx1kxvao005m10f8luqivrf1",
|
parentID: "clx1kxvao005m10f8luqivrf1",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -1246,12 +1369,12 @@ export const WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK:
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK: HoppCollection[] =
|
export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK: HoppCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
v: CollectionSchemaVersion,
|
v: CollectionSchemaVersion,
|
||||||
id: "clx1kxvao005m10f8luqivrf1",
|
id: "clx1kxvao005m10f8luqivrf1",
|
||||||
name: "Collection with no authorization/headers set",
|
name: "Collection with no authorization/headers/variables set",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: CollectionSchemaVersion,
|
v: CollectionSchemaVersion,
|
||||||
|
|
@ -1284,6 +1407,7 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: CollectionSchemaVersion,
|
v: CollectionSchemaVersion,
|
||||||
|
|
@ -1323,6 +1447,14 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: CollectionSchemaVersion,
|
v: CollectionSchemaVersion,
|
||||||
|
|
@ -1335,6 +1467,7 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: CollectionSchemaVersion,
|
v: CollectionSchemaVersion,
|
||||||
|
|
@ -1354,6 +1487,14 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
variables: [
|
||||||
|
{
|
||||||
|
key: "collection-variable",
|
||||||
|
currentValue: "collection-variable-value",
|
||||||
|
initialValue: "collection-variable-value",
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
requests: [],
|
requests: [],
|
||||||
|
|
@ -1362,6 +1503,7 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,18 @@ import {
|
||||||
transformWorkspaceEnvironment,
|
transformWorkspaceEnvironment,
|
||||||
} from "../../utils/workspace-access";
|
} from "../../utils/workspace-access";
|
||||||
import {
|
import {
|
||||||
TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK,
|
TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK,
|
||||||
TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK,
|
TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK,
|
||||||
TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK,
|
TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK,
|
||||||
TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK,
|
TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK,
|
||||||
TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK,
|
TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK,
|
||||||
TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK,
|
TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK,
|
||||||
WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK,
|
WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK,
|
||||||
WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK,
|
WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK,
|
||||||
WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK,
|
WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK,
|
||||||
WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK,
|
WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK,
|
||||||
WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK,
|
WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK,
|
||||||
WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK,
|
WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK,
|
||||||
} from "./fixtures/workspace-access.mock";
|
} from "./fixtures/workspace-access.mock";
|
||||||
|
|
||||||
describe("workspace-access", () => {
|
describe("workspace-access", () => {
|
||||||
|
|
@ -24,15 +24,17 @@ describe("workspace-access", () => {
|
||||||
test("Successfully transforms collection data with deeply nested collections and authorization/headers set at each level to the `HoppCollection` format", () => {
|
test("Successfully transforms collection data with deeply nested collections and authorization/headers set at each level to the `HoppCollection` format", () => {
|
||||||
expect(
|
expect(
|
||||||
transformWorkspaceCollections(
|
transformWorkspaceCollections(
|
||||||
WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK
|
WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK
|
||||||
)
|
)
|
||||||
).toEqual(TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK);
|
).toEqual(
|
||||||
|
TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Successfully transforms collection data with multiple child collections and authorization/headers set at each level to the `HoppCollection` format", () => {
|
test("Successfully transforms collection data with multiple child collections and authorization/headers set at each level to the `HoppCollection` format", () => {
|
||||||
expect(
|
expect(
|
||||||
transformWorkspaceCollections(
|
transformWorkspaceCollections(
|
||||||
WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK
|
WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK
|
||||||
)
|
)
|
||||||
).toEqual(TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK);
|
).toEqual(TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK);
|
||||||
});
|
});
|
||||||
|
|
@ -40,10 +42,10 @@ describe("workspace-access", () => {
|
||||||
test("Adds the default value for `auth` & `header` fields while transforming collections without authorization/headers set at certain levels", () => {
|
test("Adds the default value for `auth` & `header` fields while transforming collections without authorization/headers set at certain levels", () => {
|
||||||
expect(
|
expect(
|
||||||
transformWorkspaceCollections(
|
transformWorkspaceCollections(
|
||||||
WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK
|
||||||
)
|
)
|
||||||
).toEqual(
|
).toEqual(
|
||||||
TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK
|
TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
import { Environment, HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
import {
|
||||||
|
Environment,
|
||||||
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
|
HoppRESTRequest,
|
||||||
|
} from "@hoppscotch/data";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { TestReport } from "../interfaces/response";
|
import { TestReport } from "../interfaces/response";
|
||||||
|
|
@ -37,5 +42,6 @@ export type ProcessRequestParams = {
|
||||||
envs: HoppEnvs;
|
envs: HoppEnvs;
|
||||||
path: string;
|
path: string;
|
||||||
delay: number;
|
delay: number;
|
||||||
legacySandbox: boolean;
|
legacySandbox?: boolean;
|
||||||
|
collectionVariables?: HoppCollectionVariable[];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -115,12 +115,18 @@ const processCollection = async (
|
||||||
for (const request of collection.requests) {
|
for (const request of collection.requests) {
|
||||||
const _request = preProcessRequest(request as HoppRESTRequest, collection);
|
const _request = preProcessRequest(request as HoppRESTRequest, collection);
|
||||||
const requestPath = `${path}/${_request.name}`;
|
const requestPath = `${path}/${_request.name}`;
|
||||||
|
|
||||||
|
const collectionVariables = collection.variables.filter(
|
||||||
|
(variable) => variable.key && variable.key.trim() !== ""
|
||||||
|
);
|
||||||
|
|
||||||
const processRequestParams: ProcessRequestParams = {
|
const processRequestParams: ProcessRequestParams = {
|
||||||
path: requestPath,
|
path: requestPath,
|
||||||
request: _request,
|
request: _request,
|
||||||
envs,
|
envs,
|
||||||
delay,
|
delay,
|
||||||
legacySandbox,
|
legacySandbox,
|
||||||
|
collectionVariables,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Request processing initiated message.
|
// Request processing initiated message.
|
||||||
|
|
@ -161,6 +167,20 @@ const processCollection = async (
|
||||||
updatedFolder.headers.push(...filteredHeaders);
|
updatedFolder.headers.push(...filteredHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updatedFolder.variables?.length) {
|
||||||
|
// Filter out variable entries present in the parent collection under the same name
|
||||||
|
// This ensures the folder variables take precedence over the collection variables
|
||||||
|
const filteredVariables = collection.variables.filter(
|
||||||
|
(collectionVariableEntries) => {
|
||||||
|
return !updatedFolder.variables.some(
|
||||||
|
(folderVariableEntries) =>
|
||||||
|
folderVariableEntries.key === collectionVariableEntries.key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
updatedFolder.variables.push(...filteredVariables);
|
||||||
|
}
|
||||||
|
|
||||||
await processCollection(
|
await processCollection(
|
||||||
updatedFolder,
|
updatedFolder,
|
||||||
`${path}/${updatedFolder.name}`,
|
`${path}/${updatedFolder.name}`,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
EnvironmentVariable,
|
EnvironmentVariable,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
HoppRESTParam,
|
HoppRESTParam,
|
||||||
HoppRESTRequestVariables,
|
HoppRESTRequestVariables,
|
||||||
|
|
@ -269,11 +270,13 @@ export const getResourceContents = async (
|
||||||
*
|
*
|
||||||
* @param {HoppRESTRequestVariables} requestVariables - Incoming request variables.
|
* @param {HoppRESTRequestVariables} requestVariables - Incoming request variables.
|
||||||
* @param {EnvironmentVariable[]} environmentVariables - Incoming environment variables.
|
* @param {EnvironmentVariable[]} environmentVariables - Incoming environment variables.
|
||||||
|
* @param {HoppCollectionVariable[]} collectionVariables - Optional collection variables to be included.
|
||||||
* @returns {EnvironmentVariable[]} The resolved list of variables that conforms to the shape of environment variables.
|
* @returns {EnvironmentVariable[]} The resolved list of variables that conforms to the shape of environment variables.
|
||||||
*/
|
*/
|
||||||
export const getResolvedVariables = (
|
export const getResolvedVariables = (
|
||||||
requestVariables: HoppRESTRequestVariables,
|
requestVariables: HoppRESTRequestVariables,
|
||||||
environmentVariables: EnvironmentVariable[]
|
environmentVariables: EnvironmentVariable[],
|
||||||
|
collectionVariables: HoppCollectionVariable[] = []
|
||||||
): EnvironmentVariable[] => {
|
): EnvironmentVariable[] => {
|
||||||
// Transforming request variables to the shape of environment variables
|
// Transforming request variables to the shape of environment variables
|
||||||
const activeRequestVariables = requestVariables
|
const activeRequestVariables = requestVariables
|
||||||
|
|
@ -287,11 +290,21 @@ export const getResolvedVariables = (
|
||||||
|
|
||||||
const requestVariableKeys = activeRequestVariables.map(({ key }) => key);
|
const requestVariableKeys = activeRequestVariables.map(({ key }) => key);
|
||||||
|
|
||||||
// Request variables have higher priority, hence filtering out environment variables with the same keys
|
// Request variables have higher priority, hence filtering out collection variables with the same keys
|
||||||
const filteredEnvironmentVariables = environmentVariables.filter(
|
const filteredCollectionVariables = collectionVariables.filter(
|
||||||
({ key }) => !requestVariableKeys.includes(key)
|
({ key }) => !requestVariableKeys.includes(key)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const collectionVariableKeys = filteredCollectionVariables.map(
|
||||||
|
({ key }) => key
|
||||||
|
);
|
||||||
|
|
||||||
|
// Filtering out environment variables that have keys present in request or collection variables
|
||||||
|
const filteredEnvironmentVariables = environmentVariables.filter(
|
||||||
|
({ key }) =>
|
||||||
|
![...requestVariableKeys, ...collectionVariableKeys].includes(key)
|
||||||
|
);
|
||||||
|
|
||||||
// Setting currentValue to initialValue for environment variables
|
// Setting currentValue to initialValue for environment variables
|
||||||
// because the exported file might not have the currentValue field
|
// because the exported file might not have the currentValue field
|
||||||
const processedEnvironmentVariables = filteredEnvironmentVariables.map(
|
const processedEnvironmentVariables = filteredEnvironmentVariables.map(
|
||||||
|
|
@ -304,5 +317,19 @@ export const getResolvedVariables = (
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return [...activeRequestVariables, ...processedEnvironmentVariables];
|
const processedCollectionVariables = filteredCollectionVariables.map(
|
||||||
|
({ key, initialValue, currentValue, secret }) => ({
|
||||||
|
key,
|
||||||
|
initialValue,
|
||||||
|
currentValue:
|
||||||
|
currentValue && currentValue !== "" ? currentValue : initialValue,
|
||||||
|
secret,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...activeRequestVariables,
|
||||||
|
...processedCollectionVariables,
|
||||||
|
...processedEnvironmentVariables,
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
parseTemplateString,
|
parseTemplateString,
|
||||||
parseTemplateStringE,
|
parseTemplateStringE,
|
||||||
generateJWTToken,
|
generateJWTToken,
|
||||||
|
HoppCollectionVariable,
|
||||||
} from "@hoppscotch/data";
|
} from "@hoppscotch/data";
|
||||||
import { runPreRequestScript } from "@hoppscotch/js-sandbox/node";
|
import { runPreRequestScript } from "@hoppscotch/js-sandbox/node";
|
||||||
import * as A from "fp-ts/Array";
|
import * as A from "fp-ts/Array";
|
||||||
|
|
@ -46,7 +47,8 @@ import { calculateHawkHeader } from "@hoppscotch/data";
|
||||||
export const preRequestScriptRunner = (
|
export const preRequestScriptRunner = (
|
||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
envs: HoppEnvs,
|
envs: HoppEnvs,
|
||||||
legacySandbox: boolean
|
legacySandbox: boolean,
|
||||||
|
collectionVariables?: HoppCollectionVariable[]
|
||||||
): TE.TaskEither<
|
): TE.TaskEither<
|
||||||
HoppCLIError,
|
HoppCLIError,
|
||||||
{ effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs }
|
{ effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs }
|
||||||
|
|
@ -67,7 +69,7 @@ export const preRequestScriptRunner = (
|
||||||
),
|
),
|
||||||
TE.chainW((env) =>
|
TE.chainW((env) =>
|
||||||
TE.tryCatch(
|
TE.tryCatch(
|
||||||
() => getEffectiveRESTRequest(request, env),
|
() => getEffectiveRESTRequest(request, env, collectionVariables),
|
||||||
(reason) => error({ code: "PRE_REQUEST_SCRIPT_ERROR", data: reason })
|
(reason) => error({ code: "PRE_REQUEST_SCRIPT_ERROR", data: reason })
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -93,7 +95,8 @@ export const preRequestScriptRunner = (
|
||||||
*/
|
*/
|
||||||
export async function getEffectiveRESTRequest(
|
export async function getEffectiveRESTRequest(
|
||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
environment: Environment
|
environment: Environment,
|
||||||
|
collectionVariables?: HoppCollectionVariable[]
|
||||||
): Promise<
|
): Promise<
|
||||||
E.Either<
|
E.Either<
|
||||||
HoppCLIError,
|
HoppCLIError,
|
||||||
|
|
@ -104,7 +107,8 @@ export async function getEffectiveRESTRequest(
|
||||||
|
|
||||||
const resolvedVariables = getResolvedVariables(
|
const resolvedVariables = getResolvedVariables(
|
||||||
request.requestVariables,
|
request.requestVariables,
|
||||||
envVariables
|
envVariables,
|
||||||
|
collectionVariables
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parsing final headers with applied ENVs.
|
// Parsing final headers with applied ENVs.
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,8 @@ export const processRequest =
|
||||||
params: ProcessRequestParams
|
params: ProcessRequestParams
|
||||||
): T.Task<{ envs: HoppEnvs; report: RequestReport }> =>
|
): T.Task<{ envs: HoppEnvs; report: RequestReport }> =>
|
||||||
async () => {
|
async () => {
|
||||||
const { envs, path, request, delay, legacySandbox } = params;
|
const { envs, path, request, delay, legacySandbox, collectionVariables } =
|
||||||
|
params;
|
||||||
|
|
||||||
// Initialising updatedEnvs with given parameter envs, will eventually get updated.
|
// Initialising updatedEnvs with given parameter envs, will eventually get updated.
|
||||||
const result = {
|
const result = {
|
||||||
|
|
@ -236,7 +237,8 @@ export const processRequest =
|
||||||
const preRequestRes = await preRequestScriptRunner(
|
const preRequestRes = await preRequestScriptRunner(
|
||||||
request,
|
request,
|
||||||
processedEnvs,
|
processedEnvs,
|
||||||
legacySandbox
|
legacySandbox,
|
||||||
|
collectionVariables
|
||||||
)();
|
)();
|
||||||
if (E.isLeft(preRequestRes)) {
|
if (E.isLeft(preRequestRes)) {
|
||||||
printPreRequestRunner.fail();
|
printPreRequestRunner.fail();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
Environment,
|
Environment,
|
||||||
EnvironmentSchemaVersion,
|
EnvironmentSchemaVersion,
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
HoppRESTHeaders,
|
HoppRESTHeaders,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
|
|
@ -173,12 +174,17 @@ export const transformWorkspaceCollections = (
|
||||||
return collections.map((collection) => {
|
return collections.map((collection) => {
|
||||||
const { id, title, data, requests, folders } = collection;
|
const { id, title, data, requests, folders } = collection;
|
||||||
|
|
||||||
const parsedData: { auth?: HoppRESTAuth; headers?: HoppRESTHeaders } = data
|
const parsedData: {
|
||||||
? JSON.parse(data)
|
auth?: HoppRESTAuth;
|
||||||
: {};
|
headers?: HoppRESTHeaders;
|
||||||
|
variables: HoppCollectionVariable[];
|
||||||
|
} = data ? JSON.parse(data) : {};
|
||||||
|
|
||||||
const { auth = { authType: "inherit", authActive: true }, headers = [] } =
|
const {
|
||||||
parsedData;
|
auth = { authType: "inherit", authActive: true },
|
||||||
|
headers = [],
|
||||||
|
variables = [],
|
||||||
|
} = parsedData;
|
||||||
|
|
||||||
const transformedAuth = transformAuth(auth);
|
const transformedAuth = transformAuth(auth);
|
||||||
|
|
||||||
|
|
@ -186,6 +192,10 @@ export const transformWorkspaceCollections = (
|
||||||
header.description ? header : { ...header, description: "" }
|
header.description ? header : { ...header, description: "" }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const filteredCollectionVariables = variables.filter(
|
||||||
|
(variable) => variable.key.trim() !== ""
|
||||||
|
);
|
||||||
|
|
||||||
// The response doesn't include a way to infer the schema version, so it's set to the latest version
|
// The response doesn't include a way to infer the schema version, so it's set to the latest version
|
||||||
// Any relevant migrations have to be accounted here
|
// Any relevant migrations have to be accounted here
|
||||||
// `ref_id` field isn't necessary being applicable only to personal workspace and asociates with syncing
|
// `ref_id` field isn't necessary being applicable only to personal workspace and asociates with syncing
|
||||||
|
|
@ -197,6 +207,7 @@ export const transformWorkspaceCollections = (
|
||||||
requests: transformWorkspaceRequests(requests),
|
requests: transformWorkspaceRequests(requests),
|
||||||
auth: transformedAuth,
|
auth: transformedAuth,
|
||||||
headers: transformedHeaders,
|
headers: transformedHeaders,
|
||||||
|
variables: filteredCollectionVariables,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -503,6 +503,11 @@ details[open] summary .indicator {
|
||||||
@apply hover:bg-amber-600;
|
@apply hover:bg-amber-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.collection-variable-highlight {
|
||||||
|
@apply bg-purple-500;
|
||||||
|
@apply hover:bg-purple-600;
|
||||||
|
}
|
||||||
|
|
||||||
&.environment-variable-highlight {
|
&.environment-variable-highlight {
|
||||||
@apply bg-green-500;
|
@apply bg-green-500;
|
||||||
@apply hover:bg-green-600;
|
@apply hover:bg-green-600;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Base shared styles for all tippy themes
|
// Base shared styles for all tippy themes
|
||||||
@mixin base-tippy-styles {
|
@mixin base-tippy-styles {
|
||||||
.cm-tooltip {
|
.cm-tooltip {
|
||||||
|
@apply z-[1000] #{!important};
|
||||||
.tippy-box {
|
.tippy-box {
|
||||||
@apply shadow-none #{!important};
|
@apply shadow-none #{!important};
|
||||||
@apply fixed;
|
@apply fixed;
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,7 @@
|
||||||
"empty_schema": "No schema found",
|
"empty_schema": "No schema found",
|
||||||
"endpoint": "Endpoint cannot be empty",
|
"endpoint": "Endpoint cannot be empty",
|
||||||
"environments": "Environments are empty",
|
"environments": "Environments are empty",
|
||||||
|
"collection_variables": "Collection variables are empty",
|
||||||
"folder": "Folder is empty",
|
"folder": "Folder is empty",
|
||||||
"headers": "This request does not have any headers",
|
"headers": "This request does not have any headers",
|
||||||
"history": "History is empty",
|
"history": "History is empty",
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ declare module 'vue' {
|
||||||
CollectionsRequest: typeof import('./components/collections/Request.vue')['default']
|
CollectionsRequest: typeof import('./components/collections/Request.vue')['default']
|
||||||
CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default']
|
CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default']
|
||||||
CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default']
|
CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default']
|
||||||
|
CollectionsVariables: typeof import('./components/collections/Variables.vue')['default']
|
||||||
ConsoleItem: typeof import('./components/console/Item.vue')['default']
|
ConsoleItem: typeof import('./components/console/Item.vue')['default']
|
||||||
ConsolePanel: typeof import('./components/console/Panel.vue')['default']
|
ConsolePanel: typeof import('./components/console/Panel.vue')['default']
|
||||||
ConsoleValue: typeof import('./components/console/Value.vue')['default']
|
ConsoleValue: typeof import('./components/console/Value.vue')['default']
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,9 @@
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!hasNoTeamAccess" class="flex">
|
<div class="flex">
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
:icon="IconFilePlus"
|
:icon="IconFilePlus"
|
||||||
:title="t('request.add')"
|
:title="t('request.add')"
|
||||||
|
|
@ -67,6 +68,7 @@
|
||||||
@click="emit('add-request')"
|
@click="emit('add-request')"
|
||||||
/>
|
/>
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
:icon="IconFolderPlus"
|
:icon="IconFolderPlus"
|
||||||
:title="t('folder.new')"
|
:title="t('folder.new')"
|
||||||
|
|
@ -109,6 +111,7 @@
|
||||||
@keyup.escape="hide()"
|
@keyup.escape="hide()"
|
||||||
>
|
>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
ref="requestAction"
|
ref="requestAction"
|
||||||
:icon="IconFilePlus"
|
:icon="IconFilePlus"
|
||||||
:label="t('request.new')"
|
:label="t('request.new')"
|
||||||
|
|
@ -121,6 +124,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
ref="folderAction"
|
ref="folderAction"
|
||||||
:icon="IconFolderPlus"
|
:icon="IconFolderPlus"
|
||||||
:label="t('folder.new')"
|
:label="t('folder.new')"
|
||||||
|
|
@ -145,6 +149,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
ref="edit"
|
ref="edit"
|
||||||
:icon="IconEdit"
|
:icon="IconEdit"
|
||||||
:label="t('action.edit')"
|
:label="t('action.edit')"
|
||||||
|
|
@ -157,6 +162,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
ref="duplicateAction"
|
ref="duplicateAction"
|
||||||
:icon="IconCopy"
|
:icon="IconCopy"
|
||||||
:label="t('action.duplicate')"
|
:label="t('action.duplicate')"
|
||||||
|
|
@ -170,6 +176,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
ref="exportAction"
|
ref="exportAction"
|
||||||
:icon="IconDownload"
|
:icon="IconDownload"
|
||||||
:label="t('export.title')"
|
:label="t('export.title')"
|
||||||
|
|
@ -182,18 +189,6 @@
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
|
||||||
ref="deleteAction"
|
|
||||||
:icon="IconTrash2"
|
|
||||||
:label="t('action.delete')"
|
|
||||||
:shortcut="['⌫']"
|
|
||||||
@click="
|
|
||||||
() => {
|
|
||||||
emit('remove-collection')
|
|
||||||
hide()
|
|
||||||
}
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
ref="propertiesAction"
|
ref="propertiesAction"
|
||||||
:icon="IconSettings2"
|
:icon="IconSettings2"
|
||||||
|
|
@ -206,6 +201,19 @@
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
<HoppSmartItem
|
||||||
|
v-if="!hasNoTeamAccess"
|
||||||
|
ref="deleteAction"
|
||||||
|
:icon="IconTrash2"
|
||||||
|
:label="t('action.delete')"
|
||||||
|
:shortcut="['⌫']"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
emit('remove-collection')
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</tippy>
|
</tippy>
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ function translateToTeamCollectionFormat(x: HoppCollection) {
|
||||||
const data = {
|
const data = {
|
||||||
auth: x.auth,
|
auth: x.auth,
|
||||||
headers: x.headers,
|
headers: x.headers,
|
||||||
|
variables: x.variables,
|
||||||
}
|
}
|
||||||
|
|
||||||
const obj = {
|
const obj = {
|
||||||
|
|
@ -419,7 +420,7 @@ const HoppInsomniaImporter: ImporterOrExporter = {
|
||||||
importSummary: currentImportSummary,
|
importSummary: currentImportSummary,
|
||||||
component: FileSource({
|
component: FileSource({
|
||||||
caption: "import.from_file",
|
caption: "import.from_file",
|
||||||
acceptedFileTypes: ".json",
|
acceptedFileTypes: ".json, .yaml, .yml, .har",
|
||||||
description: "import.from_insomnia_import_summary",
|
description: "import.from_insomnia_import_summary",
|
||||||
onImportFromFile: async (content) => {
|
onImportFromFile: async (content) => {
|
||||||
isInsomniaImporterInProgress.value = true
|
isInsomniaImporterInProgress.value = true
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
dialog
|
dialog
|
||||||
:title="t('collection.properties')"
|
:title="t('collection.properties')"
|
||||||
:full-width-body="true"
|
:full-width-body="true"
|
||||||
styles="sm:max-w-2xl"
|
styles="sm:max-w-3xl"
|
||||||
@close="hideModal"
|
@close="hideModal"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
|
|
@ -13,7 +13,11 @@
|
||||||
styles="sticky overflow-x-auto flex-shrink-0 bg-primary top-0 z-10 !-py-4"
|
styles="sticky overflow-x-auto flex-shrink-0 bg-primary top-0 z-10 !-py-4"
|
||||||
render-inactive-tabs
|
render-inactive-tabs
|
||||||
>
|
>
|
||||||
<HoppSmartTab id="headers" :label="`${t('tab.headers')}`">
|
<HoppSmartTab
|
||||||
|
v-if="hasTeamWriteAccess"
|
||||||
|
id="headers"
|
||||||
|
:label="`${t('tab.headers')}`"
|
||||||
|
>
|
||||||
<HttpHeaders
|
<HttpHeaders
|
||||||
v-model="editableCollection"
|
v-model="editableCollection"
|
||||||
:is-collection-property="true"
|
:is-collection-property="true"
|
||||||
|
|
@ -27,7 +31,11 @@
|
||||||
</div>
|
</div>
|
||||||
</HoppSmartTab>
|
</HoppSmartTab>
|
||||||
|
|
||||||
<HoppSmartTab id="authorization" :label="`${t('tab.authorization')}`">
|
<HoppSmartTab
|
||||||
|
v-if="hasTeamWriteAccess"
|
||||||
|
id="authorization"
|
||||||
|
:label="`${t('tab.authorization')}`"
|
||||||
|
>
|
||||||
<HttpAuthorization
|
<HttpAuthorization
|
||||||
v-model="editableCollection.auth"
|
v-model="editableCollection.auth"
|
||||||
:is-collection-property="true"
|
:is-collection-property="true"
|
||||||
|
|
@ -43,6 +51,19 @@
|
||||||
</div>
|
</div>
|
||||||
</HoppSmartTab>
|
</HoppSmartTab>
|
||||||
|
|
||||||
|
<!-- Collection variables is only available for REST collections for now -->
|
||||||
|
<HoppSmartTab
|
||||||
|
v-if="source === 'REST'"
|
||||||
|
id="variables"
|
||||||
|
:label="`${t('tab.variables')}`"
|
||||||
|
>
|
||||||
|
<CollectionsVariables
|
||||||
|
v-model="editableCollection.variables"
|
||||||
|
:inherited-properties="editingProperties.inheritedProperties"
|
||||||
|
:has-team-write-access="hasTeamWriteAccess"
|
||||||
|
/>
|
||||||
|
</HoppSmartTab>
|
||||||
|
|
||||||
<HoppSmartTab
|
<HoppSmartTab
|
||||||
v-if="showDetails"
|
v-if="showDetails"
|
||||||
:id="'details'"
|
:id="'details'"
|
||||||
|
|
@ -117,23 +138,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from "@composables/i18n"
|
|
||||||
import {
|
|
||||||
GQLHeader,
|
|
||||||
HoppCollection,
|
|
||||||
HoppGQLAuth,
|
|
||||||
HoppRESTAuth,
|
|
||||||
HoppRESTHeaders,
|
|
||||||
} from "@hoppscotch/data"
|
|
||||||
import { refAutoReset, useVModel } from "@vueuse/core"
|
|
||||||
import { useService } from "dioc/vue"
|
|
||||||
import { clone } from "lodash-es"
|
|
||||||
import { computed, ref, watch } from "vue"
|
import { computed, ref, watch } from "vue"
|
||||||
|
import { refAutoReset, useVModel } from "@vueuse/core"
|
||||||
|
import { clone } from "lodash-es"
|
||||||
|
import { useI18n } from "@composables/i18n"
|
||||||
import { useToast } from "~/composables/toast"
|
import { useToast } from "~/composables/toast"
|
||||||
|
|
||||||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
|
||||||
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
||||||
|
import { useService } from "dioc/vue"
|
||||||
|
|
||||||
|
import {
|
||||||
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
|
HoppRESTAuth,
|
||||||
|
HoppGQLAuth,
|
||||||
|
HoppRESTHeaders,
|
||||||
|
GQLHeader,
|
||||||
|
} from "@hoppscotch/data"
|
||||||
|
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||||
import { PersistenceService } from "~/services/persistence"
|
import { PersistenceService } from "~/services/persistence"
|
||||||
|
|
||||||
import IconCheck from "~icons/lucide/check"
|
import IconCheck from "~icons/lucide/check"
|
||||||
import IconCopy from "~icons/lucide/copy"
|
import IconCopy from "~icons/lucide/copy"
|
||||||
import IconHelpCircle from "~icons/lucide/help-circle"
|
import IconHelpCircle from "~icons/lucide/help-circle"
|
||||||
|
|
@ -141,6 +164,7 @@ import { RESTOptionTabs } from "../http/RequestOptions.vue"
|
||||||
|
|
||||||
const persistenceService = useService(PersistenceService)
|
const persistenceService = useService(PersistenceService)
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
export type EditingProperties = {
|
export type EditingProperties = {
|
||||||
collection: Partial<HoppCollection> | null
|
collection: Partial<HoppCollection> | null
|
||||||
|
|
@ -148,12 +172,9 @@ export type EditingProperties = {
|
||||||
path: string
|
path: string
|
||||||
inheritedProperties?: HoppInheritedProperty
|
inheritedProperties?: HoppInheritedProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
type HoppCollectionAuth = HoppRESTAuth | HoppGQLAuth
|
type HoppCollectionAuth = HoppRESTAuth | HoppGQLAuth
|
||||||
type HoppCollectionHeaders = HoppRESTHeaders | GQLHeader[]
|
type HoppCollectionHeaders = HoppRESTHeaders | GQLHeader[]
|
||||||
|
|
||||||
const toast = useToast()
|
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
show: boolean
|
show: boolean
|
||||||
|
|
@ -161,12 +182,14 @@ const props = withDefaults(
|
||||||
editingProperties: EditingProperties
|
editingProperties: EditingProperties
|
||||||
source: "REST" | "GraphQL"
|
source: "REST" | "GraphQL"
|
||||||
modelValue: string
|
modelValue: string
|
||||||
showDetails: boolean
|
showDetails?: boolean
|
||||||
|
hasTeamWriteAccess?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
show: false,
|
show: false,
|
||||||
loadingState: false,
|
loadingState: false,
|
||||||
showDetails: false,
|
showDetails: false,
|
||||||
|
hasTeamWriteAccess: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -182,104 +205,107 @@ const emit = defineEmits<{
|
||||||
const editableCollection = ref<{
|
const editableCollection = ref<{
|
||||||
headers: HoppCollectionHeaders
|
headers: HoppCollectionHeaders
|
||||||
auth: HoppCollectionAuth
|
auth: HoppCollectionAuth
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
}>({
|
}>({
|
||||||
headers: [],
|
headers: [],
|
||||||
auth: {
|
auth: { authType: "inherit", authActive: false },
|
||||||
authType: "inherit",
|
variables: [],
|
||||||
authActive: false,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(
|
const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(
|
||||||
IconCopy,
|
IconCopy,
|
||||||
1000
|
1000
|
||||||
)
|
)
|
||||||
|
const activeTab = useVModel(props, "modelValue", emit)
|
||||||
|
|
||||||
const activeTabIsDetails = computed(() => activeTab.value === "details")
|
const activeTabIsDetails = computed(() => activeTab.value === "details")
|
||||||
|
|
||||||
watch(
|
const persistUnsavedChanges = async (
|
||||||
editableCollection,
|
updated: typeof editableCollection.value
|
||||||
async (updatedEditableCollection) => {
|
) => {
|
||||||
if (props.show && props.editingProperties) {
|
if (!props.show) return
|
||||||
const unsavedCollectionProperties: EditingProperties = {
|
await persistenceService.setLocalConfig(
|
||||||
collection: updatedEditableCollection,
|
"unsaved_collection_properties",
|
||||||
isRootCollection: props.editingProperties.isRootCollection ?? false,
|
JSON.stringify({
|
||||||
path: props.editingProperties.path,
|
collection: updated,
|
||||||
inheritedProperties: props.editingProperties.inheritedProperties,
|
isRootCollection: props.editingProperties.isRootCollection ?? false,
|
||||||
}
|
path: props.editingProperties.path,
|
||||||
await persistenceService.setLocalConfig(
|
inheritedProperties: props.editingProperties.inheritedProperties,
|
||||||
"unsaved_collection_properties",
|
})
|
||||||
JSON.stringify(unsavedCollectionProperties)
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
},
|
const handleModalVisibility = async (show: boolean) => {
|
||||||
{
|
enforceTabAccessRules()
|
||||||
deep: true,
|
|
||||||
|
if (show && props.editingProperties.collection) {
|
||||||
|
loadEditableCollection()
|
||||||
|
} else {
|
||||||
|
resetEditableCollection()
|
||||||
|
await persistenceService.removeLocalConfig("unsaved_collection_properties")
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
const activeTab = useVModel(props, "modelValue", emit)
|
const enforceTabAccessRules = () => {
|
||||||
|
// `Details` tab doesn't exist for personal workspace, hence switching to the `Headers` tab
|
||||||
|
// The modal can appear empty while switching from a team workspace with `Details` as the active tab
|
||||||
|
if (activeTab.value === "details" && !props.showDetails)
|
||||||
|
activeTab.value = "headers"
|
||||||
|
// If the user doesn't have write access to the team, switch to `Variables` tab
|
||||||
|
// when the `Headers` or `Authorization` tab is active
|
||||||
|
if (
|
||||||
|
!props.hasTeamWriteAccess &&
|
||||||
|
["headers", "authorization"].includes(activeTab.value)
|
||||||
|
)
|
||||||
|
activeTab.value = "variables"
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
const loadEditableCollection = () => {
|
||||||
() => props.show,
|
editableCollection.value = {
|
||||||
async (show) => {
|
auth: clone(props.editingProperties.collection!.auth as HoppCollectionAuth),
|
||||||
// `Details` tab doesn't exist for personal workspace, hence switching to the `Headers` tab
|
headers: clone(
|
||||||
// The modal can appear empty while switching from a team workspace with `Details` as the active tab
|
props.editingProperties.collection!.headers as HoppCollectionHeaders
|
||||||
if (activeTab.value === "details" && !props.showDetails) {
|
),
|
||||||
activeTab.value = "headers"
|
variables: clone(props.editingProperties.collection!.variables || []),
|
||||||
}
|
|
||||||
|
|
||||||
if (show && props.editingProperties.collection) {
|
|
||||||
editableCollection.value.auth = clone(
|
|
||||||
props.editingProperties.collection.auth as HoppCollectionAuth
|
|
||||||
)
|
|
||||||
editableCollection.value.headers = clone(
|
|
||||||
props.editingProperties.collection.headers as HoppCollectionHeaders
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
editableCollection.value = {
|
|
||||||
headers: [],
|
|
||||||
auth: {
|
|
||||||
authType: "inherit",
|
|
||||||
authActive: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
await persistenceService.removeLocalConfig(
|
|
||||||
"unsaved_collection_properties"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
const resetEditableCollection = () => {
|
||||||
|
editableCollection.value = {
|
||||||
|
headers: [],
|
||||||
|
auth: { authType: "inherit", authActive: false },
|
||||||
|
variables: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const saveEditedCollection = async () => {
|
const saveEditedCollection = async () => {
|
||||||
if (!props.editingProperties) return
|
if (!props.editingProperties) return
|
||||||
const finalCollection = clone(editableCollection.value)
|
emit("set-collection-properties", {
|
||||||
const collection = {
|
|
||||||
path: props.editingProperties.path,
|
path: props.editingProperties.path,
|
||||||
collection: {
|
collection: {
|
||||||
...props.editingProperties.collection,
|
...props.editingProperties.collection,
|
||||||
...finalCollection,
|
...clone(editableCollection.value),
|
||||||
},
|
},
|
||||||
isRootCollection: props.editingProperties.isRootCollection,
|
isRootCollection: props.editingProperties.isRootCollection,
|
||||||
}
|
} as EditingProperties)
|
||||||
emit("set-collection-properties", collection as EditingProperties)
|
|
||||||
await persistenceService.removeLocalConfig("unsaved_collection_properties")
|
await persistenceService.removeLocalConfig("unsaved_collection_properties")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(editableCollection, persistUnsavedChanges, { deep: true })
|
||||||
|
watch(() => props.show, handleModalVisibility)
|
||||||
|
|
||||||
const hideModal = async () => {
|
const hideModal = async () => {
|
||||||
await persistenceService.removeLocalConfig("unsaved_collection_properties")
|
await persistenceService.removeLocalConfig("unsaved_collection_properties")
|
||||||
emit("hide-modal")
|
emit("hide-modal")
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeOptionTab = (e: RESTOptionTabs) => {
|
const changeOptionTab = (tab: RESTOptionTabs) => {
|
||||||
activeTab.value = e
|
activeTab.value = tab
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyCollectionID = () => {
|
const copyCollectionID = () => {
|
||||||
copyToClipboard(props.editingProperties.path)
|
copyToClipboard(props.editingProperties.path)
|
||||||
copyIcon.value = IconCheck
|
copyIcon.value = IconCheck
|
||||||
|
toast.success(t("state.copied_to_clipboard"))
|
||||||
toast.success(`${t("state.copied_to_clipboard")}`)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -128,18 +128,6 @@
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
|
||||||
ref="deleteAction"
|
|
||||||
:icon="IconTrash2"
|
|
||||||
:label="t('action.delete')"
|
|
||||||
:shortcut="['⌫']"
|
|
||||||
@click="
|
|
||||||
() => {
|
|
||||||
emit('remove-request')
|
|
||||||
hide()
|
|
||||||
}
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
ref="shareAction"
|
ref="shareAction"
|
||||||
:icon="IconShare2"
|
:icon="IconShare2"
|
||||||
|
|
@ -152,6 +140,18 @@
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
<HoppSmartItem
|
||||||
|
ref="deleteAction"
|
||||||
|
:icon="IconTrash2"
|
||||||
|
:label="t('action.delete')"
|
||||||
|
:shortcut="['⌫']"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
emit('remove-request')
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</tippy>
|
</tippy>
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ import {
|
||||||
} from "~/helpers/backend/mutations/TeamRequest"
|
} from "~/helpers/backend/mutations/TeamRequest"
|
||||||
import { Picked } from "~/helpers/types/HoppPicked"
|
import { Picked } from "~/helpers/types/HoppPicked"
|
||||||
import {
|
import {
|
||||||
cascadeParentCollectionForHeaderAuth,
|
cascadeParentCollectionForProperties,
|
||||||
editGraphqlRequest,
|
editGraphqlRequest,
|
||||||
editRESTRequest,
|
editRESTRequest,
|
||||||
saveGraphqlRequestAs,
|
saveGraphqlRequestAs,
|
||||||
|
|
@ -357,15 +357,11 @@ const saveRequestAs = async () => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
RESTTabs.currentActiveTab.value.document.inheritedProperties =
|
||||||
`${picked.value.collectionIndex}`,
|
cascadeParentCollectionForProperties(
|
||||||
"rest"
|
`${picked.value.collectionIndex}`,
|
||||||
)
|
"rest"
|
||||||
|
)
|
||||||
RESTTabs.currentActiveTab.value.document.inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
platform.analytics?.logEvent({
|
platform.analytics?.logEvent({
|
||||||
type: "HOPP_SAVE_REQUEST",
|
type: "HOPP_SAVE_REQUEST",
|
||||||
|
|
@ -395,15 +391,8 @@ const saveRequestAs = async () => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
RESTTabs.currentActiveTab.value.document.inheritedProperties =
|
||||||
picked.value.folderPath,
|
cascadeParentCollectionForProperties(picked.value.folderPath, "rest")
|
||||||
"rest"
|
|
||||||
)
|
|
||||||
|
|
||||||
RESTTabs.currentActiveTab.value.document.inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
platform.analytics?.logEvent({
|
platform.analytics?.logEvent({
|
||||||
type: "HOPP_SAVE_REQUEST",
|
type: "HOPP_SAVE_REQUEST",
|
||||||
|
|
@ -434,15 +423,8 @@ const saveRequestAs = async () => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
RESTTabs.currentActiveTab.value.document.inheritedProperties =
|
||||||
picked.value.folderPath,
|
cascadeParentCollectionForProperties(picked.value.folderPath, "rest")
|
||||||
"rest"
|
|
||||||
)
|
|
||||||
|
|
||||||
RESTTabs.currentActiveTab.value.document.inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
platform.analytics?.logEvent({
|
platform.analytics?.logEvent({
|
||||||
type: "HOPP_SAVE_REQUEST",
|
type: "HOPP_SAVE_REQUEST",
|
||||||
|
|
@ -538,15 +520,8 @@ const saveRequestAs = async () => {
|
||||||
workspaceType: "team",
|
workspaceType: "team",
|
||||||
})
|
})
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
GQLTabs.currentActiveTab.value.document.inheritedProperties =
|
||||||
picked.value.folderPath,
|
cascadeParentCollectionForProperties(picked.value.folderPath, "graphql")
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
GQLTabs.currentActiveTab.value.document.inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
requestSaved("GQL")
|
requestSaved("GQL")
|
||||||
} else if (picked.value.pickedType === "gql-my-folder") {
|
} else if (picked.value.pickedType === "gql-my-folder") {
|
||||||
|
|
@ -573,15 +548,8 @@ const saveRequestAs = async () => {
|
||||||
workspaceType: "team",
|
workspaceType: "team",
|
||||||
})
|
})
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
GQLTabs.currentActiveTab.value.document.inheritedProperties =
|
||||||
picked.value.folderPath,
|
cascadeParentCollectionForProperties(picked.value.folderPath, "graphql")
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
GQLTabs.currentActiveTab.value.document.inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
requestSaved("GQL")
|
requestSaved("GQL")
|
||||||
} else if (picked.value.pickedType === "gql-my-collection") {
|
} else if (picked.value.pickedType === "gql-my-collection") {
|
||||||
|
|
@ -608,15 +576,11 @@ const saveRequestAs = async () => {
|
||||||
workspaceType: "team",
|
workspaceType: "team",
|
||||||
})
|
})
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
GQLTabs.currentActiveTab.value.document.inheritedProperties =
|
||||||
`${picked.value.collectionIndex}`,
|
cascadeParentCollectionForProperties(
|
||||||
"graphql"
|
`${picked.value.collectionIndex}`,
|
||||||
)
|
"graphql"
|
||||||
|
)
|
||||||
GQLTabs.currentActiveTab.value.document.inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
requestSaved("GQL")
|
requestSaved("GQL")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,316 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col flex-1">
|
||||||
|
<div class="flex flex-1 justify-between items-center pl-4">
|
||||||
|
<span class="truncate font-semibold text-secondaryLight">{{
|
||||||
|
t("environment.variable_list")
|
||||||
|
}}</span>
|
||||||
|
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
to="https://docs.hoppscotch.io/documentation/features/environments"
|
||||||
|
blank
|
||||||
|
:title="t('app.wiki')"
|
||||||
|
:icon="IconHelpCircle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col border border-divider rounded">
|
||||||
|
<HoppSmartTabs v-model="selectedEnvOption" render-inactive-tabs>
|
||||||
|
<template #actions>
|
||||||
|
<div class="flex flex-1 items-center justify-between">
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-if="hasTeamWriteAccess"
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.clear_all')"
|
||||||
|
:icon="clearIcon"
|
||||||
|
@click="clearContent()"
|
||||||
|
/>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-if="hasTeamWriteAccess"
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:icon="IconPlus"
|
||||||
|
:title="t('add.new')"
|
||||||
|
@click="addEnvironmentVariable"
|
||||||
|
/>
|
||||||
|
<tippy
|
||||||
|
ref="options"
|
||||||
|
interactive
|
||||||
|
trigger="click"
|
||||||
|
theme="popover"
|
||||||
|
:on-shown="() => tippyActions!.focus()"
|
||||||
|
>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.more')"
|
||||||
|
:icon="IconMoreVertical"
|
||||||
|
/>
|
||||||
|
<template #content="{ hide }">
|
||||||
|
<div
|
||||||
|
ref="tippyActions"
|
||||||
|
class="flex flex-col focus:outline-none"
|
||||||
|
tabindex="0"
|
||||||
|
role="menu"
|
||||||
|
@keyup.escape="hide()"
|
||||||
|
>
|
||||||
|
<HoppSmartItem
|
||||||
|
v-if="hasTeamWriteAccess"
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:icon="IconCopyLeft"
|
||||||
|
:label="t('environment.replace_all_initial_with_current')"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
vars.forEach((v) => {
|
||||||
|
v.initialValue = v.currentValue
|
||||||
|
})
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<HoppSmartItem
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:icon="IconCopyRight"
|
||||||
|
:label="t('environment.replace_all_current_with_initial')"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
vars.forEach((v) => {
|
||||||
|
v.currentValue = v.initialValue
|
||||||
|
})
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</tippy>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<HoppSmartTab
|
||||||
|
v-for="tab in tabsData"
|
||||||
|
:id="tab.id"
|
||||||
|
:key="tab.id"
|
||||||
|
:label="tab.label"
|
||||||
|
>
|
||||||
|
<div class="divide-y divide-dividerLight">
|
||||||
|
<HoppSmartPlaceholder
|
||||||
|
v-if="tab.variables.length === 0"
|
||||||
|
:src="`/images/states/${colorMode.value}/blockchain.svg`"
|
||||||
|
:alt="tab.emptyStateLabel"
|
||||||
|
:text="tab.emptyStateLabel"
|
||||||
|
>
|
||||||
|
<template #body>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-if="hasTeamWriteAccess"
|
||||||
|
:label="`${t('add.new')}`"
|
||||||
|
filled
|
||||||
|
:icon="IconPlus"
|
||||||
|
@click="addEnvironmentVariable"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</HoppSmartPlaceholder>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<div
|
||||||
|
v-for="(env, index) in tab.variables"
|
||||||
|
:key="`${tab.id}-${index}`"
|
||||||
|
class="flex divide-x divide-dividerLight"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-model="env.key"
|
||||||
|
v-focus
|
||||||
|
class="flex flex-1 bg-transparent px-4 py-2 text-secondaryDark"
|
||||||
|
:placeholder="`${t('count.variable', {
|
||||||
|
count: index + 1,
|
||||||
|
})}`"
|
||||||
|
:name="'variable' + index"
|
||||||
|
:class="{
|
||||||
|
'opacity-25': !hasTeamWriteAccess,
|
||||||
|
}"
|
||||||
|
:disabled="!hasTeamWriteAccess"
|
||||||
|
/>
|
||||||
|
<div class="flex items-center flex-1">
|
||||||
|
<SmartEnvInput
|
||||||
|
v-model="env.initialValue"
|
||||||
|
:placeholder="`${t('count.initialValue', { count: index + 1 })}`"
|
||||||
|
:envs="liveEnvs"
|
||||||
|
:auto-complete-env="true"
|
||||||
|
:name="'initialValue' + index"
|
||||||
|
:secret="tab.isSecret"
|
||||||
|
:readonly="!hasTeamWriteAccess"
|
||||||
|
/>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('environment.replace_initial_with_current')"
|
||||||
|
:icon="IconCopyLeft"
|
||||||
|
:disabled="!hasTeamWriteAccess"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
env.initialValue = env.currentValue
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center flex-1">
|
||||||
|
<SmartEnvInput
|
||||||
|
v-model="env.currentValue"
|
||||||
|
:placeholder="`${t('count.currentValue', { count: index + 1 })}`"
|
||||||
|
:envs="liveEnvs"
|
||||||
|
:auto-complete-env="true"
|
||||||
|
:name="'currentValue' + index"
|
||||||
|
:secret="tab.isSecret"
|
||||||
|
/>
|
||||||
|
<HoppButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('environment.replace_current_with_initial')"
|
||||||
|
:icon="IconCopyRight"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
env.currentValue = env.initialValue
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="hasTeamWriteAccess" class="flex">
|
||||||
|
<HoppButtonSecondary
|
||||||
|
id="variable"
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.remove')"
|
||||||
|
:icon="IconTrash"
|
||||||
|
color="red"
|
||||||
|
@click="removeEnvironmentVariable(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</HoppSmartTab>
|
||||||
|
</HoppSmartTabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import IconDone from "~icons/lucide/check"
|
||||||
|
import IconHelpCircle from "~icons/lucide/help-circle"
|
||||||
|
import IconPlus from "~icons/lucide/plus"
|
||||||
|
import IconTrash from "~icons/lucide/trash"
|
||||||
|
import IconTrash2 from "~icons/lucide/trash-2"
|
||||||
|
import IconCopyRight from "~icons/lucide/clipboard-paste"
|
||||||
|
import IconCopyLeft from "~icons/lucide/clipboard-copy"
|
||||||
|
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||||
|
import { computed, ComputedRef, Ref, ref } from "vue"
|
||||||
|
import { useI18n } from "~/composables/i18n"
|
||||||
|
import { useToast } from "~/composables/toast"
|
||||||
|
import { useColorMode } from "~/composables/theming"
|
||||||
|
import { HoppCollectionVariable } from "@hoppscotch/data"
|
||||||
|
import { refAutoReset, useVModel } from "@vueuse/core"
|
||||||
|
import * as A from "fp-ts/Array"
|
||||||
|
import { pipe } from "fp-ts/function"
|
||||||
|
import { useReadonlyStream } from "~/composables/stream"
|
||||||
|
import {
|
||||||
|
AggregateEnvironment,
|
||||||
|
aggregateEnvsWithCurrentValue$,
|
||||||
|
} from "~/newstore/environments"
|
||||||
|
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||||
|
import { transformInheritedCollectionVariablesToAggregateEnv } from "~/helpers/utils/inheritedCollectionVarTransformer"
|
||||||
|
|
||||||
|
const t = useI18n()
|
||||||
|
const toast = useToast()
|
||||||
|
const colorMode = useColorMode()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: HoppCollectionVariable[]
|
||||||
|
inheritedProperties?: HoppInheritedProperty
|
||||||
|
hasTeamWriteAccess: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
type SelectedEnv = "variables" | "secret"
|
||||||
|
|
||||||
|
const selectedEnvOption = ref<SelectedEnv>("variables")
|
||||||
|
|
||||||
|
const tippyActions = ref<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
|
const vars = useVModel(props, "modelValue")
|
||||||
|
|
||||||
|
const secretVars = computed(() =>
|
||||||
|
pipe(
|
||||||
|
vars.value,
|
||||||
|
A.filter((e) => e.secret)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const nonSecretVars = computed(() =>
|
||||||
|
pipe(
|
||||||
|
vars.value,
|
||||||
|
A.filter((e) => !e.secret)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const tabsData: ComputedRef<
|
||||||
|
{
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
emptyStateLabel: string
|
||||||
|
isSecret: boolean
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
|
}[]
|
||||||
|
> = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: "variables",
|
||||||
|
label: t("environment.variables"),
|
||||||
|
emptyStateLabel: t("empty.collection_variables"),
|
||||||
|
isSecret: false,
|
||||||
|
variables: nonSecretVars.value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "secret",
|
||||||
|
label: t("environment.secrets"),
|
||||||
|
emptyStateLabel: t("empty.secret_environments"),
|
||||||
|
isSecret: true,
|
||||||
|
variables: secretVars.value,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
||||||
|
IconTrash2,
|
||||||
|
1000
|
||||||
|
)
|
||||||
|
|
||||||
|
const aggregateEnvs = useReadonlyStream(
|
||||||
|
aggregateEnvsWithCurrentValue$,
|
||||||
|
[]
|
||||||
|
) as Ref<AggregateEnvironment[]>
|
||||||
|
|
||||||
|
const liveEnvs = computed(() => {
|
||||||
|
const parentInheritedVariables =
|
||||||
|
transformInheritedCollectionVariablesToAggregateEnv(
|
||||||
|
props.inheritedProperties?.variables ?? []
|
||||||
|
)
|
||||||
|
return [...parentInheritedVariables, ...aggregateEnvs.value]
|
||||||
|
})
|
||||||
|
|
||||||
|
const addEnvironmentVariable = () => {
|
||||||
|
vars.value.push({
|
||||||
|
key: "",
|
||||||
|
currentValue: "",
|
||||||
|
initialValue: "",
|
||||||
|
secret: selectedEnvOption.value === "secret",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearContent = () => {
|
||||||
|
vars.value = vars.value.filter((e) =>
|
||||||
|
selectedEnvOption.value === "secret" ? !e.secret : e.secret
|
||||||
|
)
|
||||||
|
|
||||||
|
clearIcon.value = IconDone
|
||||||
|
toast.success(`${t("state.cleared")}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeEnvironmentVariable = (index: number) => {
|
||||||
|
vars.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -339,7 +339,7 @@ const isSelected = computed(
|
||||||
const collectionIcon = computed(() => {
|
const collectionIcon = computed(() => {
|
||||||
if (isSelected.value) return IconCheckCircle
|
if (isSelected.value) return IconCheckCircle
|
||||||
else if (!showChildren.value && !props.isFiltered) return IconFolder
|
else if (!showChildren.value && !props.isFiltered) return IconFolder
|
||||||
else if (!showChildren.value || props.isFiltered) return IconFolderOpen
|
else if (showChildren.value || props.isFiltered) return IconFolderOpen
|
||||||
return IconFolder
|
return IconFolder
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ import {
|
||||||
graphqlCollections$,
|
graphqlCollections$,
|
||||||
addGraphqlFolder,
|
addGraphqlFolder,
|
||||||
saveGraphqlRequestAs,
|
saveGraphqlRequestAs,
|
||||||
cascadeParentCollectionForHeaderAuth,
|
cascadeParentCollectionForProperties,
|
||||||
editGraphqlCollection,
|
editGraphqlCollection,
|
||||||
editGraphqlFolder,
|
editGraphqlFolder,
|
||||||
moveGraphqlRequest,
|
moveGraphqlRequest,
|
||||||
|
|
@ -402,11 +402,6 @@ const onAddRequest = ({ name, path }: { name: string; path: string }) => {
|
||||||
|
|
||||||
const insertionIndex = saveGraphqlRequestAs(path, newRequest)
|
const insertionIndex = saveGraphqlRequestAs(path, newRequest)
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
path,
|
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
tabs.createNewTab({
|
tabs.createNewTab({
|
||||||
saveContext: {
|
saveContext: {
|
||||||
originLocation: "user-collection",
|
originLocation: "user-collection",
|
||||||
|
|
@ -415,10 +410,7 @@ const onAddRequest = ({ name, path }: { name: string; path: string }) => {
|
||||||
},
|
},
|
||||||
request: newRequest,
|
request: newRequest,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
inheritedProperties: {
|
inheritedProperties: cascadeParentCollectionForProperties(path, "graphql"),
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
platform.analytics?.logEvent({
|
platform.analytics?.logEvent({
|
||||||
|
|
@ -524,10 +516,6 @@ const selectRequest = ({
|
||||||
folderPath: folderPath,
|
folderPath: folderPath,
|
||||||
requestIndex: requestIndex,
|
requestIndex: requestIndex,
|
||||||
})
|
})
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
folderPath,
|
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
// Switch to that request if that request is open
|
// Switch to that request if that request is open
|
||||||
if (possibleTab) {
|
if (possibleTab) {
|
||||||
tabs.setActiveTab(possibleTab.value.id)
|
tabs.setActiveTab(possibleTab.value.id)
|
||||||
|
|
@ -541,10 +529,10 @@ const selectRequest = ({
|
||||||
},
|
},
|
||||||
request: cloneDeep(request),
|
request: cloneDeep(request),
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
inheritedProperties: {
|
inheritedProperties: cascadeParentCollectionForProperties(
|
||||||
auth,
|
folderPath,
|
||||||
headers,
|
"graphql"
|
||||||
},
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -557,11 +545,6 @@ const dropRequest = ({
|
||||||
requestIndex: number
|
requestIndex: number
|
||||||
collectionIndex: number
|
collectionIndex: number
|
||||||
}) => {
|
}) => {
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
`${collectionIndex}`,
|
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
const possibleTab = tabs.getTabRefWithSaveContext({
|
const possibleTab = tabs.getTabRefWithSaveContext({
|
||||||
originLocation: "user-collection",
|
originLocation: "user-collection",
|
||||||
folderPath,
|
folderPath,
|
||||||
|
|
@ -576,10 +559,8 @@ const dropRequest = ({
|
||||||
.length,
|
.length,
|
||||||
}
|
}
|
||||||
|
|
||||||
possibleTab.value.document.inheritedProperties = {
|
possibleTab.value.document.inheritedProperties =
|
||||||
auth,
|
cascadeParentCollectionForProperties(`${collectionIndex}`, "graphql")
|
||||||
headers,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moveGraphqlRequest(folderPath, requestIndex, `${collectionIndex}`)
|
moveGraphqlRequest(folderPath, requestIndex, `${collectionIndex}`)
|
||||||
|
|
@ -610,15 +591,10 @@ const editProperties = ({
|
||||||
let inheritedProperties = undefined
|
let inheritedProperties = undefined
|
||||||
|
|
||||||
if (parentIndex) {
|
if (parentIndex) {
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
inheritedProperties = cascadeParentCollectionForProperties(
|
||||||
parentIndex,
|
parentIndex,
|
||||||
"graphql"
|
"graphql"
|
||||||
)
|
)
|
||||||
|
|
||||||
inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
editingProperties.value = {
|
editingProperties.value = {
|
||||||
|
|
@ -647,18 +623,10 @@ const setCollectionProperties = (newCollection: {
|
||||||
editGraphqlFolder(path, collection)
|
editGraphqlFolder(path, collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
path,
|
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
updateInheritedPropertiesForAffectedRequests(
|
updateInheritedPropertiesForAffectedRequests(
|
||||||
path,
|
path,
|
||||||
{
|
cascadeParentCollectionForProperties(path, "graphql"),
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
},
|
|
||||||
"graphql"
|
"graphql"
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,12 @@
|
||||||
v-model="collectionPropertiesModalActiveTab"
|
v-model="collectionPropertiesModalActiveTab"
|
||||||
:show="showModalEditProperties"
|
:show="showModalEditProperties"
|
||||||
:editing-properties="editingProperties"
|
:editing-properties="editingProperties"
|
||||||
:show-details="collectionsType.type === 'team-collections'"
|
:show-details="
|
||||||
|
collectionsType.type === 'team-collections' && hasTeamWriteAccess
|
||||||
|
"
|
||||||
|
:has-team-write-access="
|
||||||
|
collectionsType.type === 'team-collections' ? hasTeamWriteAccess : true
|
||||||
|
"
|
||||||
source="REST"
|
source="REST"
|
||||||
@hide-modal="displayModalEditProperties(false)"
|
@hide-modal="displayModalEditProperties(false)"
|
||||||
@set-collection-properties="setCollectionProperties"
|
@set-collection-properties="setCollectionProperties"
|
||||||
|
|
@ -225,8 +230,13 @@ import {
|
||||||
makeCollection,
|
makeCollection,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
import { useService } from "dioc/vue"
|
import { useService } from "dioc/vue"
|
||||||
|
|
||||||
import * as TE from "fp-ts/TaskEither"
|
import * as TE from "fp-ts/TaskEither"
|
||||||
import { pipe } from "fp-ts/function"
|
import { pipe } from "fp-ts/function"
|
||||||
|
import * as A from "fp-ts/Array"
|
||||||
|
import * as O from "fp-ts/Option"
|
||||||
|
import { flow } from "fp-ts/function"
|
||||||
|
|
||||||
import { cloneDeep, debounce, isEqual } from "lodash-es"
|
import { cloneDeep, debounce, isEqual } from "lodash-es"
|
||||||
import { PropType, computed, nextTick, onMounted, ref, watch } from "vue"
|
import { PropType, computed, nextTick, onMounted, ref, watch } from "vue"
|
||||||
import { useReadonlyStream } from "~/composables/stream"
|
import { useReadonlyStream } from "~/composables/stream"
|
||||||
|
|
@ -272,7 +282,7 @@ import { Picked } from "~/helpers/types/HoppPicked"
|
||||||
import {
|
import {
|
||||||
addRESTCollection,
|
addRESTCollection,
|
||||||
addRESTFolder,
|
addRESTFolder,
|
||||||
cascadeParentCollectionForHeaderAuth,
|
cascadeParentCollectionForProperties,
|
||||||
duplicateRESTCollection,
|
duplicateRESTCollection,
|
||||||
editRESTCollection,
|
editRESTCollection,
|
||||||
editRESTFolder,
|
editRESTFolder,
|
||||||
|
|
@ -301,6 +311,9 @@ import { RESTOptionTabs } from "../http/RequestOptions.vue"
|
||||||
import { Collection as NodeCollection } from "./MyCollections.vue"
|
import { Collection as NodeCollection } from "./MyCollections.vue"
|
||||||
import { EditingProperties } from "./Properties.vue"
|
import { EditingProperties } from "./Properties.vue"
|
||||||
import { CollectionRunnerData } from "../http/test/RunnerModal.vue"
|
import { CollectionRunnerData } from "../http/test/RunnerModal.vue"
|
||||||
|
import { HoppCollectionVariable } from "@hoppscotch/data"
|
||||||
|
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||||
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
|
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
@ -375,6 +388,10 @@ const draggingToRoot = ref(false)
|
||||||
const collectionMoveLoading = ref<string[]>([])
|
const collectionMoveLoading = ref<string[]>([])
|
||||||
const requestMoveLoading = ref<string[]>([])
|
const requestMoveLoading = ref<string[]>([])
|
||||||
|
|
||||||
|
//collection variables current value and secret value
|
||||||
|
const secretEnvironmentService = useService(SecretEnvironmentService)
|
||||||
|
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||||
|
|
||||||
// TeamList-Adapter
|
// TeamList-Adapter
|
||||||
const workspaceService = useService(WorkspaceService)
|
const workspaceService = useService(WorkspaceService)
|
||||||
const teamListAdapter = workspaceService.acquireTeamListAdapter(null)
|
const teamListAdapter = workspaceService.acquireTeamListAdapter(null)
|
||||||
|
|
@ -393,7 +410,7 @@ const teamLoadingCollections = useReadonlyStream(
|
||||||
const teamEnvironmentAdapter = new TeamEnvironmentAdapter(undefined)
|
const teamEnvironmentAdapter = new TeamEnvironmentAdapter(undefined)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
cascadeParentCollectionForHeaderAuthForSearchResults,
|
cascadeParentCollectionForPropertiesForSearchResults,
|
||||||
searchTeams,
|
searchTeams,
|
||||||
teamsSearchResults,
|
teamsSearchResults,
|
||||||
teamsSearchResultsLoading,
|
teamsSearchResultsLoading,
|
||||||
|
|
@ -774,6 +791,7 @@ const addNewRootCollection = (name: string) => {
|
||||||
authType: "none",
|
authType: "none",
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
|
variables: [],
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -834,8 +852,6 @@ const onAddRequest = (requestName: string) => {
|
||||||
if (collectionsType.value.type === "my-collections") {
|
if (collectionsType.value.type === "my-collections") {
|
||||||
const insertionIndex = saveRESTRequestAs(path, newRequest)
|
const insertionIndex = saveRESTRequestAs(path, newRequest)
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(path, "rest")
|
|
||||||
|
|
||||||
tabs.createNewTab({
|
tabs.createNewTab({
|
||||||
type: "request",
|
type: "request",
|
||||||
request: newRequest,
|
request: newRequest,
|
||||||
|
|
@ -845,10 +861,7 @@ const onAddRequest = (requestName: string) => {
|
||||||
folderPath: path,
|
folderPath: path,
|
||||||
requestIndex: insertionIndex,
|
requestIndex: insertionIndex,
|
||||||
},
|
},
|
||||||
inheritedProperties: {
|
inheritedProperties: cascadeParentCollectionForProperties(path, "rest"),
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
platform.analytics?.logEvent({
|
platform.analytics?.logEvent({
|
||||||
|
|
@ -889,8 +902,7 @@ const onAddRequest = (requestName: string) => {
|
||||||
},
|
},
|
||||||
(result) => {
|
(result) => {
|
||||||
const { createRequestInCollection } = result
|
const { createRequestInCollection } = result
|
||||||
const { auth, headers } =
|
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(path)
|
|
||||||
tabs.createNewTab({
|
tabs.createNewTab({
|
||||||
type: "request",
|
type: "request",
|
||||||
request: newRequest,
|
request: newRequest,
|
||||||
|
|
@ -901,10 +913,8 @@ const onAddRequest = (requestName: string) => {
|
||||||
collectionID: path,
|
collectionID: path,
|
||||||
teamID: createRequestInCollection.collection.team.id,
|
teamID: createRequestInCollection.collection.team.id,
|
||||||
},
|
},
|
||||||
inheritedProperties: {
|
inheritedProperties:
|
||||||
auth,
|
teamCollectionAdapter.cascadeParentCollectionForProperties(path),
|
||||||
headers,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
modalLoadingState.value = false
|
modalLoadingState.value = false
|
||||||
|
|
@ -1569,6 +1579,17 @@ const onRemoveCollection = () => {
|
||||||
|
|
||||||
toast.success(t("state.deleted"))
|
toast.success(t("state.deleted"))
|
||||||
displayConfirmModal(false)
|
displayConfirmModal(false)
|
||||||
|
|
||||||
|
// delete the secret collection variables
|
||||||
|
// and current collection variables value if the collection is removed
|
||||||
|
if (collectionToRemove) {
|
||||||
|
secretEnvironmentService.deleteSecretEnvironment(
|
||||||
|
collectionToRemove._ref_id ?? `${collectionIndex}`
|
||||||
|
)
|
||||||
|
currentEnvironmentValueService.deleteEnvironment(
|
||||||
|
collectionToRemove._ref_id ?? `${collectionIndex}`
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (hasTeamWriteAccess.value) {
|
} else if (hasTeamWriteAccess.value) {
|
||||||
const collectionID = editingCollectionID.value
|
const collectionID = editingCollectionID.value
|
||||||
|
|
||||||
|
|
@ -1584,6 +1605,13 @@ const onRemoveCollection = () => {
|
||||||
|
|
||||||
removeTeamCollectionOrFolder(collectionID).then(() => {
|
removeTeamCollectionOrFolder(collectionID).then(() => {
|
||||||
resetTeamRequestsContext()
|
resetTeamRequestsContext()
|
||||||
|
|
||||||
|
// delete the secret collection variables
|
||||||
|
// and current collection variables value if the collection is removed
|
||||||
|
if (collectionID) {
|
||||||
|
secretEnvironmentService.deleteSecretEnvironment(collectionID)
|
||||||
|
currentEnvironmentValueService.deleteEnvironment(collectionID)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1611,6 +1639,8 @@ const onRemoveFolder = () => {
|
||||||
emit("select", null)
|
emit("select", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const folderIndex = pathToLastIndex(folderPath)
|
||||||
|
|
||||||
const folderToRemove = folderPath
|
const folderToRemove = folderPath
|
||||||
? navigateToFolderWithIndexPath(
|
? navigateToFolderWithIndexPath(
|
||||||
restCollectionStore.value.state,
|
restCollectionStore.value.state,
|
||||||
|
|
@ -1630,6 +1660,17 @@ const onRemoveFolder = () => {
|
||||||
|
|
||||||
toast.success(t("state.deleted"))
|
toast.success(t("state.deleted"))
|
||||||
displayConfirmModal(false)
|
displayConfirmModal(false)
|
||||||
|
|
||||||
|
// delete the secret collection variables
|
||||||
|
// and current collection variables value if the collection is removed
|
||||||
|
if (folderToRemove) {
|
||||||
|
secretEnvironmentService.deleteSecretEnvironment(
|
||||||
|
folderToRemove.id ?? `${folderIndex}`
|
||||||
|
)
|
||||||
|
currentEnvironmentValueService.deleteEnvironment(
|
||||||
|
folderToRemove.id ?? `${folderIndex}`
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (hasTeamWriteAccess.value) {
|
} else if (hasTeamWriteAccess.value) {
|
||||||
const collectionID = editingCollectionID.value
|
const collectionID = editingCollectionID.value
|
||||||
|
|
||||||
|
|
@ -1645,6 +1686,13 @@ const onRemoveFolder = () => {
|
||||||
|
|
||||||
removeTeamCollectionOrFolder(collectionID).then(() => {
|
removeTeamCollectionOrFolder(collectionID).then(() => {
|
||||||
resetTeamRequestsContext()
|
resetTeamRequestsContext()
|
||||||
|
|
||||||
|
// delete the secret collection variables
|
||||||
|
// and current collection variables value if the collection is removed
|
||||||
|
if (collectionID) {
|
||||||
|
secretEnvironmentService.deleteSecretEnvironment(collectionID)
|
||||||
|
currentEnvironmentValueService.deleteEnvironment(collectionID)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1950,10 +1998,10 @@ const selectRequest = (selectedRequest: {
|
||||||
if (!collectionID) return
|
if (!collectionID) return
|
||||||
|
|
||||||
inheritedProperties =
|
inheritedProperties =
|
||||||
cascadeParentCollectionForHeaderAuthForSearchResults(collectionID)
|
cascadeParentCollectionForPropertiesForSearchResults(collectionID)
|
||||||
} else {
|
} else {
|
||||||
inheritedProperties =
|
inheritedProperties =
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(folderPath)
|
teamCollectionAdapter.cascadeParentCollectionForProperties(folderPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
const possibleTab = tabs.getTabRefWithSaveContext({
|
const possibleTab = tabs.getTabRefWithSaveContext({
|
||||||
|
|
@ -1978,10 +2026,6 @@ const selectRequest = (selectedRequest: {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
folderPath,
|
|
||||||
"rest"
|
|
||||||
)
|
|
||||||
possibleTab = tabs.getTabRefWithSaveContext({
|
possibleTab = tabs.getTabRefWithSaveContext({
|
||||||
originLocation: "user-collection",
|
originLocation: "user-collection",
|
||||||
requestIndex: parseInt(requestIndex),
|
requestIndex: parseInt(requestIndex),
|
||||||
|
|
@ -2000,10 +2044,10 @@ const selectRequest = (selectedRequest: {
|
||||||
folderPath: folderPath!,
|
folderPath: folderPath!,
|
||||||
requestIndex: parseInt(requestIndex),
|
requestIndex: parseInt(requestIndex),
|
||||||
},
|
},
|
||||||
inheritedProperties: {
|
inheritedProperties: cascadeParentCollectionForProperties(
|
||||||
auth,
|
folderPath,
|
||||||
headers,
|
"rest"
|
||||||
},
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2045,6 +2089,10 @@ const selectResponse = (payload: {
|
||||||
requestIndex: parseInt(requestIndex),
|
requestIndex: parseInt(requestIndex),
|
||||||
exampleID: responseID,
|
exampleID: responseID,
|
||||||
},
|
},
|
||||||
|
inheritedProperties: cascadeParentCollectionForProperties(
|
||||||
|
folderPath,
|
||||||
|
"rest"
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2070,6 +2118,10 @@ const selectResponse = (payload: {
|
||||||
collectionID: folderPath,
|
collectionID: folderPath,
|
||||||
exampleID: responseID,
|
exampleID: responseID,
|
||||||
},
|
},
|
||||||
|
inheritedProperties:
|
||||||
|
teamCollectionAdapter.cascadeParentCollectionForProperties(
|
||||||
|
folderPath
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2101,11 +2153,6 @@ const dropRequest = (payload: {
|
||||||
let possibleTab = null
|
let possibleTab = null
|
||||||
|
|
||||||
if (collectionsType.value.type === "my-collections") {
|
if (collectionsType.value.type === "my-collections") {
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
destinationCollectionIndex,
|
|
||||||
"rest"
|
|
||||||
)
|
|
||||||
|
|
||||||
possibleTab = tabs.getTabRefWithSaveContext({
|
possibleTab = tabs.getTabRefWithSaveContext({
|
||||||
originLocation: "user-collection",
|
originLocation: "user-collection",
|
||||||
folderPath,
|
folderPath,
|
||||||
|
|
@ -2123,10 +2170,8 @@ const dropRequest = (payload: {
|
||||||
).length,
|
).length,
|
||||||
}
|
}
|
||||||
|
|
||||||
possibleTab.value.document.inheritedProperties = {
|
possibleTab.value.document.inheritedProperties =
|
||||||
auth,
|
cascadeParentCollectionForProperties(destinationCollectionIndex, "rest")
|
||||||
headers,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When it's drop it's basically getting deleted from last folder. reordering last folder accordingly
|
// When it's drop it's basically getting deleted from last folder. reordering last folder accordingly
|
||||||
|
|
@ -2164,10 +2209,6 @@ const dropRequest = (payload: {
|
||||||
requestMoveLoading.value.indexOf(requestIndex),
|
requestMoveLoading.value.indexOf(requestIndex),
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
const { auth, headers } =
|
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(
|
|
||||||
destinationCollectionIndex
|
|
||||||
)
|
|
||||||
|
|
||||||
possibleTab = tabs.getTabRefWithSaveContext({
|
possibleTab = tabs.getTabRefWithSaveContext({
|
||||||
originLocation: "team-collection",
|
originLocation: "team-collection",
|
||||||
|
|
@ -2179,10 +2220,10 @@ const dropRequest = (payload: {
|
||||||
originLocation: "team-collection",
|
originLocation: "team-collection",
|
||||||
requestID: requestIndex,
|
requestID: requestIndex,
|
||||||
}
|
}
|
||||||
possibleTab.value.document.inheritedProperties = {
|
possibleTab.value.document.inheritedProperties =
|
||||||
auth,
|
teamCollectionAdapter.cascadeParentCollectionForProperties(
|
||||||
headers,
|
destinationCollectionIndex
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
toast.success(`${t("request.moved")}`)
|
toast.success(`${t("request.moved")}`)
|
||||||
}
|
}
|
||||||
|
|
@ -2303,16 +2344,11 @@ const dropCollection = (payload: {
|
||||||
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`
|
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`
|
||||||
)
|
)
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
const inheritedProperty = cascadeParentCollectionForProperties(
|
||||||
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
|
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
|
||||||
"rest"
|
"rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
const inheritedProperty = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
updateInheritedPropertiesForAffectedRequests(
|
updateInheritedPropertiesForAffectedRequests(
|
||||||
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
|
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
|
||||||
inheritedProperty,
|
inheritedProperty,
|
||||||
|
|
@ -2345,16 +2381,11 @@ const dropCollection = (payload: {
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
|
|
||||||
const { auth, headers } =
|
const inheritedProperty =
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(
|
teamCollectionAdapter.cascadeParentCollectionForProperties(
|
||||||
destinationCollectionIndex
|
destinationCollectionIndex
|
||||||
)
|
)
|
||||||
|
|
||||||
const inheritedProperty = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
|
|
||||||
updateInheritedPropertiesForAffectedRequests(
|
updateInheritedPropertiesForAffectedRequests(
|
||||||
`${destinationCollectionIndex}`,
|
`${destinationCollectionIndex}`,
|
||||||
inheritedProperty,
|
inheritedProperty,
|
||||||
|
|
@ -2696,16 +2727,43 @@ const shareRequest = ({ request }: { request: HoppRESTRequest }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get the current value of a variable
|
||||||
|
* It checks if the variable is a secret or not and returns the value accordingly.
|
||||||
|
* @param isSecret If the variable is a secret
|
||||||
|
* @param varIndex The index of the variable in the collection
|
||||||
|
* @param collectionID The ID of the collection
|
||||||
|
* @returns The current value of the variable, either from the secret environment or the current environment service
|
||||||
|
*/
|
||||||
|
const getCurrentValue = (
|
||||||
|
isSecret: boolean,
|
||||||
|
varIndex: number,
|
||||||
|
collectionID: string
|
||||||
|
) => {
|
||||||
|
if (isSecret) {
|
||||||
|
return secretEnvironmentService.getSecretEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
|
return currentEnvironmentValueService.getEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.currentValue
|
||||||
|
}
|
||||||
|
|
||||||
const editProperties = (payload: {
|
const editProperties = (payload: {
|
||||||
collectionIndex: string
|
collectionIndex: string
|
||||||
collection: HoppCollection | TeamCollection
|
collection: HoppCollection | TeamCollection
|
||||||
}) => {
|
}) => {
|
||||||
const { collection, collectionIndex } = payload
|
const { collection, collectionIndex } = payload
|
||||||
|
|
||||||
|
const collectionId = collection.id ?? collectionIndex.split("/").pop()
|
||||||
|
|
||||||
if (collectionsType.value.type === "my-collections") {
|
if (collectionsType.value.type === "my-collections") {
|
||||||
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
|
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
|
||||||
|
|
||||||
let inheritedProperties = {
|
let inheritedProperties: HoppInheritedProperty = {
|
||||||
auth: {
|
auth: {
|
||||||
parentID: "",
|
parentID: "",
|
||||||
parentName: "",
|
parentName: "",
|
||||||
|
|
@ -2714,34 +2772,42 @@ const editProperties = (payload: {
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
headers: [
|
headers: [],
|
||||||
{
|
variables: [],
|
||||||
parentID: "",
|
}
|
||||||
parentName: "",
|
|
||||||
inheritedHeader: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} as HoppInheritedProperty
|
|
||||||
|
|
||||||
if (parentIndex) {
|
if (parentIndex) {
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
inheritedProperties = cascadeParentCollectionForProperties(
|
||||||
parentIndex,
|
parentIndex,
|
||||||
"rest"
|
"rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
inheritedProperties = {
|
|
||||||
auth,
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const collectionVariables = pipe(
|
||||||
|
(collection as HoppCollection).variables ?? [],
|
||||||
|
A.mapWithIndex((index, e) => {
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
currentValue:
|
||||||
|
getCurrentValue(
|
||||||
|
e.secret,
|
||||||
|
index,
|
||||||
|
(collection as HoppCollection)._ref_id ?? collectionId!
|
||||||
|
) ?? e.currentValue,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
editingProperties.value = {
|
editingProperties.value = {
|
||||||
collection: collection as Partial<HoppCollection>,
|
collection: {
|
||||||
|
...collection,
|
||||||
|
variables: collectionVariables,
|
||||||
|
} as Partial<HoppCollection>,
|
||||||
isRootCollection: isAlreadyInRoot(collectionIndex),
|
isRootCollection: isAlreadyInRoot(collectionIndex),
|
||||||
path: collectionIndex,
|
path: collectionIndex,
|
||||||
inheritedProperties,
|
inheritedProperties,
|
||||||
}
|
}
|
||||||
} else if (hasTeamWriteAccess.value) {
|
} else {
|
||||||
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
|
const parentIndex = collectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
|
||||||
|
|
||||||
const data = (collection as TeamCollection).data
|
const data = (collection as TeamCollection).data
|
||||||
|
|
@ -2757,25 +2823,39 @@ const editProperties = (payload: {
|
||||||
authActive: true,
|
authActive: true,
|
||||||
} as HoppRESTAuth,
|
} as HoppRESTAuth,
|
||||||
headers: [] as HoppRESTHeaders,
|
headers: [] as HoppRESTHeaders,
|
||||||
|
variables: [] as HoppCollectionVariable[],
|
||||||
folders: null,
|
folders: null,
|
||||||
requests: null,
|
requests: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentIndex) {
|
if (parentIndex) {
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(parentIndex)
|
teamCollectionAdapter.cascadeParentCollectionForProperties(parentIndex)
|
||||||
|
|
||||||
inheritedProperties = {
|
inheritedProperties = {
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
|
variables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
|
const collectionVariables = pipe(
|
||||||
|
(data.variables ?? []) as HoppCollectionVariable[],
|
||||||
|
A.mapWithIndex((index, e) => {
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
currentValue:
|
||||||
|
getCurrentValue(e.secret, index, collectionId!) ?? e.currentValue,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
coll = {
|
coll = {
|
||||||
...coll,
|
...coll,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: data.headers as HoppRESTHeaders,
|
headers: data.headers as HoppRESTHeaders,
|
||||||
|
variables: collectionVariables as HoppCollectionVariable[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2803,6 +2883,65 @@ const setCollectionProperties = (newCollection: {
|
||||||
// Since path is being preserved, we extract the collectionId from path instead
|
// Since path is being preserved, we extract the collectionId from path instead
|
||||||
const collectionId = collection.id ?? path.split("/").pop()
|
const collectionId = collection.id ?? path.split("/").pop()
|
||||||
|
|
||||||
|
//setting current value and secret values to of collection variables
|
||||||
|
if (collection.variables) {
|
||||||
|
const filteredVariables = pipe(
|
||||||
|
collection.variables,
|
||||||
|
A.filterMap(
|
||||||
|
flow(
|
||||||
|
O.fromPredicate((e) => e.key !== ""),
|
||||||
|
O.map((e) => e)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const secretVariables = pipe(
|
||||||
|
filteredVariables,
|
||||||
|
A.filterMapWithIndex((i, e) =>
|
||||||
|
e.secret
|
||||||
|
? O.some({
|
||||||
|
key: e.key,
|
||||||
|
value: e.currentValue,
|
||||||
|
varIndex: i,
|
||||||
|
})
|
||||||
|
: O.none
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const nonSecretVariables = pipe(
|
||||||
|
filteredVariables,
|
||||||
|
A.filterMapWithIndex((i, e) =>
|
||||||
|
!e.secret
|
||||||
|
? O.some({
|
||||||
|
key: e.key,
|
||||||
|
currentValue: e.currentValue,
|
||||||
|
varIndex: i,
|
||||||
|
isSecret: e.secret ?? false,
|
||||||
|
})
|
||||||
|
: O.none
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
secretEnvironmentService.addSecretEnvironment(
|
||||||
|
collection._ref_id ?? collectionId!,
|
||||||
|
secretVariables
|
||||||
|
)
|
||||||
|
|
||||||
|
currentEnvironmentValueService.addEnvironment(
|
||||||
|
collection._ref_id ?? collectionId!,
|
||||||
|
nonSecretVariables
|
||||||
|
)
|
||||||
|
|
||||||
|
//set current value and secret values to empty string
|
||||||
|
collection.variables = pipe(
|
||||||
|
filteredVariables,
|
||||||
|
A.map((e) => ({
|
||||||
|
...e,
|
||||||
|
currentValue: "",
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (collectionsType.value.type === "my-collections") {
|
if (collectionsType.value.type === "my-collections") {
|
||||||
if (isRootCollection) {
|
if (isRootCollection) {
|
||||||
editRESTCollection(parseInt(path), collection)
|
editRESTCollection(parseInt(path), collection)
|
||||||
|
|
@ -2810,16 +2949,14 @@ const setCollectionProperties = (newCollection: {
|
||||||
editRESTFolder(path, collection)
|
editRESTFolder(path, collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(path, "rest")
|
const inheritedProperty = cascadeParentCollectionForProperties(path, "rest")
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
updateInheritedPropertiesForAffectedRequests(
|
updateInheritedPropertiesForAffectedRequests(
|
||||||
path,
|
path,
|
||||||
{
|
inheritedProperty,
|
||||||
auth,
|
"rest",
|
||||||
headers,
|
collection._ref_id ?? collectionId!
|
||||||
},
|
|
||||||
"rest"
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
toast.success(t("collection.properties_updated"))
|
toast.success(t("collection.properties_updated"))
|
||||||
|
|
@ -2827,6 +2964,7 @@ const setCollectionProperties = (newCollection: {
|
||||||
const data = {
|
const data = {
|
||||||
auth: collection.auth,
|
auth: collection.auth,
|
||||||
headers: collection.headers,
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
}
|
}
|
||||||
pipe(
|
pipe(
|
||||||
updateTeamCollection(collectionId, JSON.stringify(data), undefined),
|
updateTeamCollection(collectionId, JSON.stringify(data), undefined),
|
||||||
|
|
@ -2843,15 +2981,13 @@ const setCollectionProperties = (newCollection: {
|
||||||
//This is a hack to update the inherited properties of the requests if there an tab opened
|
//This is a hack to update the inherited properties of the requests if there an tab opened
|
||||||
// since it takes a little bit of time to update the collection tree
|
// since it takes a little bit of time to update the collection tree
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const { auth, headers } =
|
const inheritedProperty =
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(path)
|
teamCollectionAdapter.cascadeParentCollectionForProperties(path)
|
||||||
updateInheritedPropertiesForAffectedRequests(
|
updateInheritedPropertiesForAffectedRequests(
|
||||||
path,
|
path,
|
||||||
{
|
inheritedProperty,
|
||||||
auth,
|
"rest",
|
||||||
headers,
|
collectionId
|
||||||
},
|
|
||||||
"rest"
|
|
||||||
)
|
)
|
||||||
}, 200)
|
}, 200)
|
||||||
}
|
}
|
||||||
|
|
@ -2866,7 +3002,7 @@ const runCollectionHandler = (
|
||||||
) => {
|
) => {
|
||||||
if (payload.path && collectionsType.value.type === "team-collections") {
|
if (payload.path && collectionsType.value.type === "team-collections") {
|
||||||
const inheritedProperties =
|
const inheritedProperties =
|
||||||
teamCollectionAdapter.cascadeParentCollectionForHeaderAuth(payload.path)
|
teamCollectionAdapter.cascadeParentCollectionForProperties(payload.path)
|
||||||
|
|
||||||
if (inheritedProperties) {
|
if (inheritedProperties) {
|
||||||
collectionRunnerData.value = {
|
collectionRunnerData.value = {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import {
|
||||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||||
import { CreateTeamEnvironmentMutation } from "~/helpers/backend/graphql"
|
import { CreateTeamEnvironmentMutation } from "~/helpers/backend/graphql"
|
||||||
import { createTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
import { createTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||||
import { insomniaEnvImporter } from "~/helpers/import-export/import/insomniaEnv"
|
import { insomniaEnvImporter } from "~/helpers/import-export/import/insomnia/insomniaEnv"
|
||||||
import { postmanEnvImporter } from "~/helpers/import-export/import/postmanEnv"
|
import { postmanEnvImporter } from "~/helpers/import-export/import/postmanEnv"
|
||||||
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
|
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
<input
|
<input
|
||||||
v-model="env.key"
|
v-model="env.key"
|
||||||
v-focus
|
v-focus
|
||||||
class="flex flex-1 bg-transparent px-4 py-2"
|
class="flex flex-1 bg-transparent px-4 py-2 text-secondaryDark"
|
||||||
:placeholder="`${t('count.variable', {
|
:placeholder="`${t('count.variable', {
|
||||||
count: index + 1,
|
count: index + 1,
|
||||||
})}`"
|
})}`"
|
||||||
|
|
@ -150,6 +150,7 @@
|
||||||
:select-text-on-mount="
|
:select-text-on-mount="
|
||||||
env.key ? env.key === editingVariableName : false
|
env.key ? env.key === editingVariableName : false
|
||||||
"
|
"
|
||||||
|
:auto-complete-env="true"
|
||||||
/>
|
/>
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
|
@ -173,6 +174,7 @@
|
||||||
:select-text-on-mount="
|
:select-text-on-mount="
|
||||||
env.key ? env.key === editingVariableName : false
|
env.key ? env.key === editingVariableName : false
|
||||||
"
|
"
|
||||||
|
:auto-complete-env="true"
|
||||||
/>
|
/>
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@
|
||||||
<input
|
<input
|
||||||
v-model="env.key"
|
v-model="env.key"
|
||||||
v-focus
|
v-focus
|
||||||
class="flex flex-1 bg-transparent px-4 py-2"
|
class="flex flex-1 bg-transparent px-4 py-2 text-secondaryDark"
|
||||||
:placeholder="`${t('count.variable', {
|
:placeholder="`${t('count.variable', {
|
||||||
count: index + 1,
|
count: index + 1,
|
||||||
})}`"
|
})}`"
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@
|
||||||
</draggable>
|
</draggable>
|
||||||
|
|
||||||
<draggable
|
<draggable
|
||||||
v-model="inheritedProperties"
|
v-model="inheritedProperty"
|
||||||
item-key="id"
|
item-key="id"
|
||||||
animation="250"
|
animation="250"
|
||||||
handle=".draggable-handle"
|
handle=".draggable-handle"
|
||||||
|
|
@ -533,9 +533,7 @@ const getComputedAuthHeaders = async (
|
||||||
if (req && req.headers.find((h) => h.key.toLowerCase() === "authorization"))
|
if (req && req.headers.find((h) => h.key.toLowerCase() === "authorization"))
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if (!request) return []
|
if (!request || !request.auth || !request.auth.authActive) return []
|
||||||
|
|
||||||
if (!request.auth || !request.auth.authActive) return []
|
|
||||||
|
|
||||||
const headers: GQLHeader[] = []
|
const headers: GQLHeader[] = []
|
||||||
|
|
||||||
|
|
@ -627,75 +625,61 @@ const computedHeaders = computedAsync(async () =>
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
const inheritedProperties = computedAsync(async () => {
|
const inheritedProperty = ref<
|
||||||
if (!props.inheritedProperties?.auth || !props.inheritedProperties.headers)
|
{
|
||||||
return []
|
|
||||||
|
|
||||||
//filter out headers that are already in the request headers
|
|
||||||
|
|
||||||
const inheritedHeaders = props.inheritedProperties.headers.filter(
|
|
||||||
(header) =>
|
|
||||||
!request.value.headers.some(
|
|
||||||
(requestHeader) => requestHeader.key === header.inheritedHeader?.key
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
const headers = inheritedHeaders
|
|
||||||
.filter(
|
|
||||||
(header) =>
|
|
||||||
header.inheritedHeader !== null &&
|
|
||||||
header.inheritedHeader !== undefined &&
|
|
||||||
header.inheritedHeader.active
|
|
||||||
)
|
|
||||||
.map((header, index) => {
|
|
||||||
const { key, value, active, description } = header.inheritedHeader
|
|
||||||
|
|
||||||
return {
|
|
||||||
inheritedFrom: props.inheritedProperties?.headers[index].parentName,
|
|
||||||
source: "headers",
|
|
||||||
id: `header-${index}`,
|
|
||||||
header: {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
active,
|
|
||||||
description,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let auth = [] as {
|
|
||||||
inheritedFrom: string
|
inheritedFrom: string
|
||||||
source: "auth"
|
source: "auth" | "headers"
|
||||||
id: string
|
id: string
|
||||||
header: {
|
header: GQLHeader
|
||||||
key: string
|
|
||||||
value: string
|
|
||||||
active: boolean
|
|
||||||
}
|
|
||||||
}[]
|
}[]
|
||||||
|
>([])
|
||||||
|
|
||||||
const [computedAuthHeader] = await getComputedAuthHeaders(
|
watch(
|
||||||
request.value,
|
() => [props.inheritedProperties, request.value],
|
||||||
props.inheritedProperties.auth.inheritedAuth as HoppGQLAuth
|
async () => {
|
||||||
)
|
if (!props.inheritedProperties) return
|
||||||
|
|
||||||
if (
|
//filter out headers that are already in the request headers
|
||||||
computedAuthHeader &&
|
const inheritedHeaders = props.inheritedProperties.headers.filter(
|
||||||
request.value.auth.authType === "inherit" &&
|
(header) =>
|
||||||
request.value.auth.authActive
|
!request.value.headers.some(
|
||||||
) {
|
(requestHeader) =>
|
||||||
auth = [
|
requestHeader.key === header.inheritedHeader?.key &&
|
||||||
{
|
requestHeader.active
|
||||||
inheritedFrom: props.inheritedProperties?.auth.parentName,
|
)
|
||||||
source: "auth",
|
)
|
||||||
id: `header-auth`,
|
inheritedProperty.value = inheritedHeaders.map((header, index) => ({
|
||||||
header: computedAuthHeader,
|
inheritedFrom: props.inheritedProperties!.headers[index].parentName!,
|
||||||
},
|
source: "headers",
|
||||||
]
|
id: `header-${index}`,
|
||||||
}
|
header: header.inheritedHeader,
|
||||||
|
}))
|
||||||
|
|
||||||
return [...headers, ...auth]
|
if (
|
||||||
})
|
props.inheritedProperties.auth &&
|
||||||
|
request.value.auth.authType === "inherit" &&
|
||||||
|
request.value.auth.authActive &&
|
||||||
|
!request.value.headers.some(
|
||||||
|
(requestHeader) =>
|
||||||
|
requestHeader.key === "Authorization" && requestHeader.active
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const [computedAuthHeader] = await getComputedAuthHeaders(
|
||||||
|
request.value,
|
||||||
|
props.inheritedProperties.auth.inheritedAuth as HoppGQLAuth
|
||||||
|
)
|
||||||
|
if (computedAuthHeader) {
|
||||||
|
inheritedProperty.value.push({
|
||||||
|
inheritedFrom: props.inheritedProperties.auth.parentName,
|
||||||
|
source: "auth",
|
||||||
|
id: `header-auth`,
|
||||||
|
header: computedAuthHeader,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
const masking = ref(true)
|
const masking = ref(true)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@
|
||||||
</draggable>
|
</draggable>
|
||||||
|
|
||||||
<draggable
|
<draggable
|
||||||
v-model="inheritedProperties"
|
v-model="inheritedProperty"
|
||||||
item-key="id"
|
item-key="id"
|
||||||
animation="250"
|
animation="250"
|
||||||
handle=".draggable-handle"
|
handle=".draggable-handle"
|
||||||
|
|
@ -262,7 +262,7 @@ import { cloneDeep, isEqual } from "lodash-es"
|
||||||
import { reactive, Ref, ref, toRef, watch } from "vue"
|
import { reactive, Ref, ref, toRef, watch } from "vue"
|
||||||
import draggable from "vuedraggable-es"
|
import draggable from "vuedraggable-es"
|
||||||
|
|
||||||
import { computedAsync, useVModel } from "@vueuse/core"
|
import { useVModel } from "@vueuse/core"
|
||||||
import { useService } from "dioc/vue"
|
import { useService } from "dioc/vue"
|
||||||
import { useNestedSetting } from "~/composables/settings"
|
import { useNestedSetting } from "~/composables/settings"
|
||||||
import linter from "~/helpers/editor/linting/rawKeyValue"
|
import linter from "~/helpers/editor/linting/rawKeyValue"
|
||||||
|
|
@ -558,6 +558,15 @@ const computedHeaders: Ref<
|
||||||
}[]
|
}[]
|
||||||
> = ref([])
|
> = ref([])
|
||||||
|
|
||||||
|
const inheritedProperty = ref<
|
||||||
|
{
|
||||||
|
inheritedFrom: string
|
||||||
|
source: "auth" | "headers"
|
||||||
|
id: string
|
||||||
|
header: HoppRESTHeader
|
||||||
|
}[]
|
||||||
|
>([])
|
||||||
|
|
||||||
const currentSelectedEnvironment = getCurrentEnvironment()
|
const currentSelectedEnvironment = getCurrentEnvironment()
|
||||||
|
|
||||||
watch([props.modelValue, aggregateEnvs], async () => {
|
watch([props.modelValue, aggregateEnvs], async () => {
|
||||||
|
|
@ -583,77 +592,54 @@ watch([props.modelValue, aggregateEnvs], async () => {
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
const inheritedProperties = computedAsync(async () => {
|
watch(
|
||||||
if (!props.inheritedProperties?.auth || !props.inheritedProperties.headers)
|
() => [props.inheritedProperties, request.value],
|
||||||
return []
|
async () => {
|
||||||
|
if (!props.inheritedProperties) return
|
||||||
|
|
||||||
//filter out headers that are already in the request headers
|
//filter out headers that are already in the request headers
|
||||||
|
const inheritedHeaders = props.inheritedProperties.headers.filter(
|
||||||
const inheritedHeaders = props.inheritedProperties.headers.filter(
|
|
||||||
(header) =>
|
|
||||||
!request.value.headers.some(
|
|
||||||
(requestHeader) => requestHeader.key === header.inheritedHeader?.key
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
const headers = inheritedHeaders
|
|
||||||
.filter(
|
|
||||||
(header) =>
|
(header) =>
|
||||||
header.inheritedHeader !== null &&
|
!request.value.headers.some(
|
||||||
header.inheritedHeader !== undefined &&
|
(requestHeader) =>
|
||||||
header.inheritedHeader.active
|
requestHeader.key === header.inheritedHeader?.key &&
|
||||||
|
requestHeader.active
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.map((header, index) => {
|
inheritedProperty.value = inheritedHeaders.map((header, index) => ({
|
||||||
const { key, value, active, description } = header.inheritedHeader
|
inheritedFrom: props.inheritedProperties!.headers[index].parentName!,
|
||||||
|
source: "headers",
|
||||||
|
id: `header-${index}`,
|
||||||
|
header: header.inheritedHeader,
|
||||||
|
}))
|
||||||
|
|
||||||
return {
|
if (
|
||||||
inheritedFrom: props.inheritedProperties?.headers[index].parentName,
|
props.inheritedProperties.auth &&
|
||||||
source: "headers",
|
request.value.auth.authType === "inherit" &&
|
||||||
id: `header-${index}`,
|
request.value.auth.authActive &&
|
||||||
header: {
|
!request.value.headers.some(
|
||||||
key,
|
(requestHeader) =>
|
||||||
value,
|
requestHeader.key === "Authorization" && requestHeader.active
|
||||||
active,
|
)
|
||||||
description,
|
) {
|
||||||
},
|
const [computedAuthHeader] = await getComputedAuthHeaders(
|
||||||
|
aggregateEnvs.value,
|
||||||
|
request.value,
|
||||||
|
props.inheritedProperties.auth.inheritedAuth,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
if (computedAuthHeader) {
|
||||||
|
inheritedProperty.value.push({
|
||||||
|
inheritedFrom: props.inheritedProperties.auth.parentName,
|
||||||
|
source: "auth",
|
||||||
|
id: `header-auth`,
|
||||||
|
header: computedAuthHeader,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
let auth = [] as {
|
|
||||||
inheritedFrom: string
|
|
||||||
source: "auth"
|
|
||||||
id: string
|
|
||||||
header: {
|
|
||||||
key: string
|
|
||||||
value: string
|
|
||||||
active: boolean
|
|
||||||
}
|
}
|
||||||
}[]
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
const [computedAuthHeader] = await getComputedAuthHeaders(
|
)
|
||||||
aggregateEnvs.value,
|
|
||||||
request.value,
|
|
||||||
props.inheritedProperties.auth.inheritedAuth,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
computedAuthHeader &&
|
|
||||||
request.value.auth.authType === "inherit" &&
|
|
||||||
request.value.auth.authActive
|
|
||||||
) {
|
|
||||||
auth = [
|
|
||||||
{
|
|
||||||
inheritedFrom: props.inheritedProperties?.auth.parentName,
|
|
||||||
source: "auth",
|
|
||||||
id: `header-auth`,
|
|
||||||
header: computedAuthHeader,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return [...headers, ...auth]
|
|
||||||
})
|
|
||||||
|
|
||||||
const masking = ref(true)
|
const masking = ref(true)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
v-if="showDescription"
|
v-if="showDescription"
|
||||||
:value="description"
|
:value="description"
|
||||||
:placeholder="t('count.description')"
|
:placeholder="t('count.description')"
|
||||||
class="flex flex-1 px-4 bg-transparent"
|
class="flex flex-1 px-4 bg-transparent text-secondaryDark"
|
||||||
type="text"
|
type="text"
|
||||||
:class="{ 'opacity-50': !entityActive }"
|
:class="{ 'opacity-50': !entityActive }"
|
||||||
@update:value="emit('update:description', $event.target.value)"
|
@update:value="emit('update:description', $event.target.value)"
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,7 @@ const tryExampleResponse = () => {
|
||||||
params,
|
params,
|
||||||
requestVariables,
|
requestVariables,
|
||||||
},
|
},
|
||||||
|
inheritedProperties: tab.value.document.inheritedProperties,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ import {
|
||||||
} from "~/helpers/runner/adapter"
|
} from "~/helpers/runner/adapter"
|
||||||
import { getErrorMessage } from "~/helpers/runner/collection-tree"
|
import { getErrorMessage } from "~/helpers/runner/collection-tree"
|
||||||
import TeamCollectionAdapter from "~/helpers/teams/TeamCollectionAdapter"
|
import TeamCollectionAdapter from "~/helpers/teams/TeamCollectionAdapter"
|
||||||
|
import { transformInheritedCollectionVariablesToAggregateEnv } from "~/helpers/utils/inheritedCollectionVarTransformer"
|
||||||
import {
|
import {
|
||||||
getRESTCollectionByRefId,
|
getRESTCollectionByRefId,
|
||||||
getRESTCollectionInheritedProps,
|
getRESTCollectionInheritedProps,
|
||||||
|
|
@ -269,21 +270,28 @@ const runTests = async () => {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const parentVariables = transformInheritedCollectionVariablesToAggregateEnv(
|
||||||
|
tab.value.document.inheritedProperties?.variables ?? []
|
||||||
|
)
|
||||||
|
|
||||||
resolvedCollection = {
|
resolvedCollection = {
|
||||||
...collection.value,
|
...collection.value,
|
||||||
auth: requestAuth,
|
auth: requestAuth,
|
||||||
headers: requestHeaders as HoppRESTHeader[],
|
headers: requestHeaders as HoppRESTHeader[],
|
||||||
|
variables: parentVariables,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { auth, headers } = collectionInheritedProps ?? {
|
const { auth, headers, variables } = collectionInheritedProps ?? {
|
||||||
auth: { authActive: true, authType: "none" },
|
auth: { authActive: true, authType: "none" },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedCollection = {
|
resolvedCollection = {
|
||||||
...collection.value,
|
...collection.value,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
|
variables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ import { useService } from "dioc/vue"
|
||||||
import { RESTTabService } from "~/services/tab/rest"
|
import { RESTTabService } from "~/services/tab/rest"
|
||||||
import { syntaxTree } from "@codemirror/language"
|
import { syntaxTree } from "@codemirror/language"
|
||||||
import { uniqueID } from "~/helpers/utils/uniqueID"
|
import { uniqueID } from "~/helpers/utils/uniqueID"
|
||||||
|
import { transformInheritedCollectionVariablesToAggregateEnv } from "~/helpers/utils/inheritedCollectionVarTransformer"
|
||||||
|
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
|
||||||
|
|
@ -120,6 +121,7 @@ const props = withDefaults(
|
||||||
contextMenuEnabled?: boolean
|
contextMenuEnabled?: boolean
|
||||||
secret?: boolean
|
secret?: boolean
|
||||||
autoCompleteEnv?: boolean
|
autoCompleteEnv?: boolean
|
||||||
|
autoCompleteEnvSource?: AggregateEnvironment[] | null
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
modelValue: "",
|
modelValue: "",
|
||||||
|
|
@ -135,7 +137,8 @@ const props = withDefaults(
|
||||||
inspectionResults: undefined,
|
inspectionResults: undefined,
|
||||||
contextMenuEnabled: true,
|
contextMenuEnabled: true,
|
||||||
secret: false,
|
secret: false,
|
||||||
autoCompleteEnvSource: false,
|
autoCompleteEnv: false,
|
||||||
|
autoCompleteEnvSource: null,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -405,33 +408,21 @@ const envVars = computed(() => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestVariables =
|
const collectionVariables =
|
||||||
|
tabs.currentActiveTab.value.document.type === "request" ||
|
||||||
tabs.currentActiveTab.value.document.type === "example-response"
|
tabs.currentActiveTab.value.document.type === "example-response"
|
||||||
? tabs.currentActiveTab.value.document.response.originalRequest
|
? transformInheritedCollectionVariablesToAggregateEnv(
|
||||||
.requestVariables
|
tabs.currentActiveTab.value.document.inheritedProperties?.variables ??
|
||||||
: tabs.currentActiveTab.value.document.type === "request"
|
[],
|
||||||
? tabs.currentActiveTab.value.document.request.requestVariables
|
false
|
||||||
: []
|
)
|
||||||
|
: []
|
||||||
|
|
||||||
// Transform request variables to match the env format
|
return [...collectionVariables, ...aggregateEnvs.value]
|
||||||
return [
|
|
||||||
...requestVariables.map(({ active, key, value }) =>
|
|
||||||
active
|
|
||||||
? {
|
|
||||||
key,
|
|
||||||
currentValue: value,
|
|
||||||
initialValue: value,
|
|
||||||
sourceEnv: "RequestVariable",
|
|
||||||
secret: false,
|
|
||||||
}
|
|
||||||
: ({} as AggregateEnvironment)
|
|
||||||
),
|
|
||||||
...aggregateEnvs.value,
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function envAutoCompletion(context: CompletionContext) {
|
function envAutoCompletion(context: CompletionContext) {
|
||||||
const options = (envVars.value ?? [])
|
const options = (props.autoCompleteEnvSource ?? envVars.value ?? [])
|
||||||
.map((env) => ({
|
.map((env) => ({
|
||||||
label: env?.key ? `<<${env.key}>>` : "",
|
label: env?.key ? `<<${env.key}>>` : "",
|
||||||
info: env?.currentValue ?? "",
|
info: env?.currentValue ?? "",
|
||||||
|
|
@ -559,6 +550,7 @@ const getExtensions = (readonly: boolean): Extension => {
|
||||||
? autocompletion({
|
? autocompletion({
|
||||||
activateOnTyping: true,
|
activateOnTyping: true,
|
||||||
override: [envAutoCompletion],
|
override: [envAutoCompletion],
|
||||||
|
tooltipClass: () => "tooltip-autocomplete",
|
||||||
})
|
})
|
||||||
: [],
|
: [],
|
||||||
|
|
||||||
|
|
@ -694,6 +686,12 @@ watch(
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.tooltip-autocomplete {
|
||||||
|
@apply z-[1001] #{!important};
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.autocomplete-wrapper {
|
.autocomplete-wrapper {
|
||||||
@apply relative;
|
@apply relative;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
Environment,
|
Environment,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTHeaders,
|
HoppRESTHeaders,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
HoppRESTRequestVariable,
|
HoppRESTRequestVariable,
|
||||||
|
|
@ -58,6 +59,7 @@ import {
|
||||||
OutgoingSandboxPostRequestWorkerMessage,
|
OutgoingSandboxPostRequestWorkerMessage,
|
||||||
OutgoingSandboxPreRequestWorkerMessage,
|
OutgoingSandboxPreRequestWorkerMessage,
|
||||||
} from "./workers/sandbox.worker"
|
} from "./workers/sandbox.worker"
|
||||||
|
import { transformInheritedCollectionVariablesToAggregateEnv } from "./utils/inheritedCollectionVarTransformer"
|
||||||
|
|
||||||
const sandboxWorker = new Worker(
|
const sandboxWorker = new Worker(
|
||||||
new URL("./workers/sandbox.worker.ts", import.meta.url),
|
new URL("./workers/sandbox.worker.ts", import.meta.url),
|
||||||
|
|
@ -117,8 +119,10 @@ export const combineEnvVariables = (variables: {
|
||||||
temp?: Environment["variables"]
|
temp?: Environment["variables"]
|
||||||
}
|
}
|
||||||
requestVariables: Environment["variables"]
|
requestVariables: Environment["variables"]
|
||||||
|
collectionVariables: Environment["variables"]
|
||||||
}) => [
|
}) => [
|
||||||
...variables.requestVariables,
|
...variables.requestVariables,
|
||||||
|
...variables.collectionVariables,
|
||||||
...(variables.environments.temp ?? []),
|
...(variables.environments.temp ?? []),
|
||||||
...variables.environments.selected,
|
...variables.environments.selected,
|
||||||
...variables.environments.global,
|
...variables.environments.global,
|
||||||
|
|
@ -423,6 +427,16 @@ export function runRESTRequest$(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const collectionVariables =
|
||||||
|
transformInheritedCollectionVariablesToAggregateEnv(
|
||||||
|
tab.value.document.inheritedProperties?.variables || []
|
||||||
|
).map(({ key, initialValue, currentValue, secret }) => ({
|
||||||
|
key,
|
||||||
|
initialValue,
|
||||||
|
currentValue,
|
||||||
|
secret,
|
||||||
|
}))
|
||||||
|
|
||||||
const finalRequest = {
|
const finalRequest = {
|
||||||
...tab.value.document.request,
|
...tab.value.document.request,
|
||||||
auth: requestAuth ?? { authType: "none", authActive: false },
|
auth: requestAuth ?? { authType: "none", authActive: false },
|
||||||
|
|
@ -430,8 +444,9 @@ export function runRESTRequest$(
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalEnvs = {
|
const finalEnvs = {
|
||||||
requestVariables: finalRequestVariables as Environment["variables"],
|
|
||||||
environments: preRequestScriptResult.right.envs,
|
environments: preRequestScriptResult.right.envs,
|
||||||
|
requestVariables: finalRequestVariables as Environment["variables"],
|
||||||
|
collectionVariables,
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalEnvsWithNonEmptyValues = filterNonEmptyEnvironmentVariables(
|
const finalEnvsWithNonEmptyValues = filterNonEmptyEnvironmentVariables(
|
||||||
|
|
@ -569,7 +584,8 @@ function updateEnvsAfterTestScript(runResult: E.Right<SandboxTestResult>) {
|
||||||
|
|
||||||
export function runTestRunnerRequest(
|
export function runTestRunnerRequest(
|
||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
persistEnv = true
|
persistEnv = true,
|
||||||
|
inheritedVariables: HoppCollectionVariable[] = []
|
||||||
): Promise<
|
): Promise<
|
||||||
| E.Left<"script_fail">
|
| E.Left<"script_fail">
|
||||||
| E.Right<{
|
| E.Right<{
|
||||||
|
|
@ -609,6 +625,7 @@ export function runTestRunnerRequest(
|
||||||
temp: !persistEnv ? getTemporaryVariables() : [],
|
temp: !persistEnv ? getTemporaryVariables() : [],
|
||||||
},
|
},
|
||||||
requestVariables: finalRequestVariables,
|
requestVariables: finalRequestVariables,
|
||||||
|
collectionVariables: inheritedVariables,
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import {
|
import {
|
||||||
|
CollectionVariable,
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
HoppRESTHeaders,
|
HoppRESTHeaders,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
|
|
@ -30,7 +32,11 @@ type TeamCollectionJSON = {
|
||||||
data: string
|
data: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CollectionDataProps = { auth: HoppRESTAuth; headers: HoppRESTHeaders }
|
type CollectionDataProps = {
|
||||||
|
auth: HoppRESTAuth
|
||||||
|
headers: HoppRESTHeaders
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
|
}
|
||||||
|
|
||||||
export const BACKEND_PAGE_SIZE = 10
|
export const BACKEND_PAGE_SIZE = 10
|
||||||
|
|
||||||
|
|
@ -109,6 +115,7 @@ const parseCollectionData = (
|
||||||
const defaultDataProps: CollectionDataProps = {
|
const defaultDataProps: CollectionDataProps = {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|
@ -137,9 +144,15 @@ const parseCollectionData = (
|
||||||
defaultDataProps.headers
|
defaultDataProps.headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const variables = parseWithDefaultValue<CollectionDataProps["variables"]>(
|
||||||
|
z.array(CollectionVariable).safeParse(parsedData?.variables),
|
||||||
|
defaultDataProps.variables
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
|
variables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +160,7 @@ const parseCollectionData = (
|
||||||
const teamCollectionJSONToHoppRESTColl = (
|
const teamCollectionJSONToHoppRESTColl = (
|
||||||
coll: TeamCollectionJSON
|
coll: TeamCollectionJSON
|
||||||
): HoppCollection => {
|
): HoppCollection => {
|
||||||
const { auth, headers } = parseCollectionData(coll.data)
|
const { auth, headers, variables } = parseCollectionData(coll.data)
|
||||||
|
|
||||||
return makeCollection({
|
return makeCollection({
|
||||||
name: coll.name,
|
name: coll.name,
|
||||||
|
|
@ -155,6 +168,7 @@ const teamCollectionJSONToHoppRESTColl = (
|
||||||
requests: coll.requests,
|
requests: coll.requests,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
|
variables,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,9 +228,10 @@ export const teamCollToHoppRESTColl = (
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
const { auth, headers } = parseCollectionData(data)
|
const { auth, headers, variables } = parseCollectionData(data)
|
||||||
|
|
||||||
return makeCollection({
|
return makeCollection({
|
||||||
id: coll.id,
|
id: coll.id,
|
||||||
|
|
@ -225,6 +240,7 @@ export const teamCollToHoppRESTColl = (
|
||||||
requests: coll.requests?.map((x) => x.request) ?? [],
|
requests: coll.requests?.map((x) => x.request) ?? [],
|
||||||
auth: auth ?? { authType: "inherit", authActive: true },
|
auth: auth ?? { authType: "inherit", authActive: true },
|
||||||
headers: headers ?? [],
|
headers: headers ?? [],
|
||||||
|
variables: variables ?? [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,8 @@ function removeDuplicatesAndKeepLast(arr: HoppInheritedProperty["headers"]) {
|
||||||
export function updateInheritedPropertiesForAffectedRequests(
|
export function updateInheritedPropertiesForAffectedRequests(
|
||||||
path: string,
|
path: string,
|
||||||
inheritedProperties: HoppInheritedProperty,
|
inheritedProperties: HoppInheritedProperty,
|
||||||
type: "rest" | "graphql"
|
type: "rest" | "graphql",
|
||||||
|
collectionId?: string
|
||||||
) {
|
) {
|
||||||
const tabService =
|
const tabService =
|
||||||
type === "rest" ? getService(RESTTabService) : getService(GQLTabService)
|
type === "rest" ? getService(RESTTabService) : getService(GQLTabService)
|
||||||
|
|
@ -226,6 +227,22 @@ export function updateInheritedPropertiesForAffectedRequests(
|
||||||
|
|
||||||
tab.value.document.inheritedProperties.headers = mergedHeaders
|
tab.value.document.inheritedProperties.headers = mergedHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tab.value.document.inheritedProperties?.variables && collectionId) {
|
||||||
|
const tabInheritedVariables =
|
||||||
|
tab.value.document.inheritedProperties.variables.filter(
|
||||||
|
(variable) => variable.parentID !== collectionId
|
||||||
|
)
|
||||||
|
|
||||||
|
// filter out the variables with the parentID as the path in the inheritedProperties
|
||||||
|
const inheritedVariables = inheritedProperties.variables.filter(
|
||||||
|
(variable) => variable.parentID === collectionId
|
||||||
|
)
|
||||||
|
|
||||||
|
const finalVariables = [...inheritedVariables, ...tabInheritedVariables]
|
||||||
|
|
||||||
|
tab.value.document.inheritedProperties.variables = finalVariables
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import IconUser from "~icons/lucide/user?raw"
|
||||||
import IconUsers from "~icons/lucide/users?raw"
|
import IconUsers from "~icons/lucide/users?raw"
|
||||||
import IconGlobe from "~icons/lucide/globe?raw"
|
import IconGlobe from "~icons/lucide/globe?raw"
|
||||||
import IconVariable from "~icons/lucide/variable?raw"
|
import IconVariable from "~icons/lucide/variable?raw"
|
||||||
|
import IconLibrary from "~icons/lucide/library?raw"
|
||||||
import { isComment } from "./helpers"
|
import { isComment } from "./helpers"
|
||||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
|
|
||||||
|
|
@ -36,6 +37,7 @@ const HOPP_ENV_HIGHLIGHT =
|
||||||
"cursor-help transition rounded px-1 focus:outline-none mx-0.5 env-highlight"
|
"cursor-help transition rounded px-1 focus:outline-none mx-0.5 env-highlight"
|
||||||
|
|
||||||
const HOPP_REQUEST_VARIABLE_HIGHLIGHT = "request-variable-highlight"
|
const HOPP_REQUEST_VARIABLE_HIGHLIGHT = "request-variable-highlight"
|
||||||
|
const HOPP_COLLECTION_ENVIRONMENT_HIGHLIGHT = "collection-variable-highlight"
|
||||||
const HOPP_ENVIRONMENT_HIGHLIGHT = "environment-variable-highlight"
|
const HOPP_ENVIRONMENT_HIGHLIGHT = "environment-variable-highlight"
|
||||||
const HOPP_GLOBAL_ENVIRONMENT_HIGHLIGHT = "global-variable-highlight"
|
const HOPP_GLOBAL_ENVIRONMENT_HIGHLIGHT = "global-variable-highlight"
|
||||||
const HOPP_ENV_HIGHLIGHT_NOT_FOUND = "environment-not-found-highlight"
|
const HOPP_ENV_HIGHLIGHT_NOT_FOUND = "environment-not-found-highlight"
|
||||||
|
|
@ -138,10 +140,20 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||||
|
|
||||||
const isSecret = tooltipEnv?.secret === true
|
const isSecret = tooltipEnv?.secret === true
|
||||||
const hasSource = Boolean(tooltipEnv?.sourceEnv)
|
const hasSource = Boolean(tooltipEnv?.sourceEnv)
|
||||||
|
|
||||||
|
let tooltipSourceEnvID = "Global"
|
||||||
|
|
||||||
|
if (tooltipEnv?.sourceEnv === "Global") {
|
||||||
|
tooltipSourceEnvID = "Global"
|
||||||
|
} else {
|
||||||
|
tooltipSourceEnvID =
|
||||||
|
tooltipEnv?.sourceEnv === "CollectionVariable"
|
||||||
|
? tooltipEnv.sourceEnvID!
|
||||||
|
: currentSelectedEnvironment.id
|
||||||
|
}
|
||||||
|
|
||||||
const hasSecretStored = secretEnvironmentService.hasSecretValue(
|
const hasSecretStored = secretEnvironmentService.hasSecretValue(
|
||||||
tooltipEnv?.sourceEnv !== "Global"
|
tooltipSourceEnvID,
|
||||||
? currentSelectedEnvironment.id
|
|
||||||
: "Global",
|
|
||||||
tooltipEnv?.key ?? ""
|
tooltipEnv?.key ?? ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -198,7 +210,9 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||||
? IconVariable
|
? IconVariable
|
||||||
: selectedEnvType === "TEAM_ENV"
|
: selectedEnvType === "TEAM_ENV"
|
||||||
? IconUsers
|
? IconUsers
|
||||||
: IconUser
|
: tooltipEnv?.sourceEnv === "CollectionVariable"
|
||||||
|
? IconLibrary
|
||||||
|
: IconUser
|
||||||
}</span>`
|
}</span>`
|
||||||
|
|
||||||
const appendEditAction = (tooltip: HTMLElement) => {
|
const appendEditAction = (tooltip: HTMLElement) => {
|
||||||
|
|
@ -236,7 +250,9 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
editIcon.innerHTML = `<span class="inline-flex items-center justify-center my-1">${IconEdit}</span>`
|
editIcon.innerHTML = `<span class="inline-flex items-center justify-center my-1">${IconEdit}</span>`
|
||||||
tooltip.appendChild(editIcon)
|
if (tooltipEnv?.sourceEnv !== "CollectionVariable") {
|
||||||
|
tooltip.appendChild(editIcon)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -275,7 +291,7 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||||
const envContainer = document.createElement("div")
|
const envContainer = document.createElement("div")
|
||||||
tooltipContainer.appendChild(envContainer)
|
tooltipContainer.appendChild(envContainer)
|
||||||
envContainer.className =
|
envContainer.className =
|
||||||
"flex flex-col items-start space-y-1 flex-1 w-full mt-2"
|
"flex flex-col items-start space-y-1 flex-1 w-full mt-2 !z-[1002]"
|
||||||
|
|
||||||
const initialValueBlock = document.createElement("div")
|
const initialValueBlock = document.createElement("div")
|
||||||
initialValueBlock.className = "flex items-center space-x-2"
|
initialValueBlock.className = "flex items-center space-x-2"
|
||||||
|
|
@ -323,6 +339,8 @@ function checkEnv(env: string, aggregateEnvs: AggregateEnvironment[]) {
|
||||||
|
|
||||||
if (envSource === "RequestVariable")
|
if (envSource === "RequestVariable")
|
||||||
className = HOPP_REQUEST_VARIABLE_HIGHLIGHT
|
className = HOPP_REQUEST_VARIABLE_HIGHLIGHT
|
||||||
|
else if (envSource === "CollectionVariable")
|
||||||
|
className = HOPP_COLLECTION_ENVIRONMENT_HIGHLIGHT
|
||||||
else if (envSource === "Global") className = HOPP_GLOBAL_ENVIRONMENT_HIGHLIGHT
|
else if (envSource === "Global") className = HOPP_GLOBAL_ENVIRONMENT_HIGHLIGHT
|
||||||
else if (envSource !== undefined) className = HOPP_ENVIRONMENT_HIGHLIGHT
|
else if (envSource !== undefined) className = HOPP_ENVIRONMENT_HIGHLIGHT
|
||||||
|
|
||||||
|
|
@ -374,56 +392,18 @@ export class HoppEnvironmentPlugin {
|
||||||
private editorView: Ref<EditorView | undefined>
|
private editorView: Ref<EditorView | undefined>
|
||||||
) {
|
) {
|
||||||
const aggregateEnvs = getAggregateEnvsWithCurrentValue()
|
const aggregateEnvs = getAggregateEnvsWithCurrentValue()
|
||||||
const currentTab = restTabs.currentActiveTab.value
|
|
||||||
|
|
||||||
const currentTabRequest =
|
this.envs = [...aggregateEnvs]
|
||||||
currentTab.document.type === "example-response"
|
|
||||||
? currentTab.document.response.originalRequest
|
|
||||||
: currentTab.document.request
|
|
||||||
|
|
||||||
if (!currentTabRequest) return
|
this.editorView.value?.dispatch({
|
||||||
|
effects: this.compartment.reconfigure([
|
||||||
watch(
|
cursorTooltipField(this.envs),
|
||||||
currentTabRequest,
|
environmentHighlightStyle(this.envs),
|
||||||
(request) => {
|
]),
|
||||||
const requestVariables = request?.requestVariables
|
})
|
||||||
? request.requestVariables
|
|
||||||
: []
|
|
||||||
|
|
||||||
this.envs = [
|
|
||||||
...requestVariables.map(({ key, value }) => ({
|
|
||||||
key,
|
|
||||||
currentValue: value,
|
|
||||||
initialValue: value,
|
|
||||||
sourceEnv: "RequestVariable",
|
|
||||||
secret: false,
|
|
||||||
})),
|
|
||||||
...aggregateEnvs,
|
|
||||||
]
|
|
||||||
|
|
||||||
this.editorView.value?.dispatch({
|
|
||||||
effects: this.compartment.reconfigure([
|
|
||||||
cursorTooltipField(this.envs),
|
|
||||||
environmentHighlightStyle(this.envs),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{ immediate: true, deep: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
const requestVariables = currentTabRequest?.requestVariables ?? []
|
|
||||||
|
|
||||||
subscribeToStream(aggregateEnvsWithCurrentValue$, (envs) => {
|
subscribeToStream(aggregateEnvsWithCurrentValue$, (envs) => {
|
||||||
this.envs = [
|
this.envs = [...envs]
|
||||||
...requestVariables.map(({ key, value }) => ({
|
|
||||||
key,
|
|
||||||
currentValue: value,
|
|
||||||
initialValue: value,
|
|
||||||
sourceEnv: "RequestVariable",
|
|
||||||
secret: false,
|
|
||||||
})),
|
|
||||||
...envs,
|
|
||||||
]
|
|
||||||
|
|
||||||
this.editorView.value?.dispatch({
|
this.editorView.value?.dispatch({
|
||||||
effects: this.compartment.reconfigure([
|
effects: this.compartment.reconfigure([
|
||||||
|
|
|
||||||
|
|
@ -404,10 +404,10 @@ export const runGQLOperation = async (options: RunQueryOptions) => {
|
||||||
v: 9,
|
v: 9,
|
||||||
name: options.name || "Untitled Request",
|
name: options.name || "Untitled Request",
|
||||||
url: finalUrl,
|
url: finalUrl,
|
||||||
headers: request.headers,
|
headers: runHeaders,
|
||||||
query,
|
query,
|
||||||
variables,
|
variables,
|
||||||
auth: request.auth as HoppGQLAuth,
|
auth,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operationType === "subscription") {
|
if (operationType === "subscription") {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
export { hoppRESTImporter } from "./hopp"
|
export { hoppRESTImporter } from "./hopp"
|
||||||
export { hoppOpenAPIImporter } from "./openapi"
|
export { hoppOpenAPIImporter } from "./openapi"
|
||||||
export { hoppPostmanImporter } from "./postman"
|
export { hoppPostmanImporter } from "./postman"
|
||||||
export { hoppInsomniaImporter } from "./insomnia"
|
export { hoppInsomniaImporter } from "./insomnia/insomniaColl"
|
||||||
export { toTeamsImporter } from "./myCollections"
|
export { toTeamsImporter } from "./myCollections"
|
||||||
export { harImporter } from "./har"
|
export { harImporter } from "./har"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
HoppRESTParam,
|
HoppRESTParam,
|
||||||
|
|
@ -14,39 +15,33 @@ import {
|
||||||
import * as A from "fp-ts/Array"
|
import * as A from "fp-ts/Array"
|
||||||
import * as TE from "fp-ts/TaskEither"
|
import * as TE from "fp-ts/TaskEither"
|
||||||
import * as TO from "fp-ts/TaskOption"
|
import * as TO from "fp-ts/TaskOption"
|
||||||
|
import * as O from "fp-ts/Option"
|
||||||
import { pipe } from "fp-ts/function"
|
import { pipe } from "fp-ts/function"
|
||||||
import { ImportRequest, convert } from "insomnia-importers"
|
import { convert } from "insomnia-importers"
|
||||||
import { Header, Parameter } from "insomnia-importers/dist/src/entities"
|
|
||||||
|
|
||||||
import { IMPORTER_INVALID_FILE_FORMAT } from "."
|
import { IMPORTER_INVALID_FILE_FORMAT } from ".."
|
||||||
import { replaceInsomniaTemplating } from "./insomniaEnv"
|
import { replaceInsomniaTemplating } from "./insomniaEnv"
|
||||||
|
import { safeParseJSONOrYAML } from "~/helpers/functional/yaml"
|
||||||
|
import {
|
||||||
|
InsomniaDoc,
|
||||||
|
InsomniaDocV5,
|
||||||
|
InsomniaFolderResource,
|
||||||
|
InsomniaFolderV5,
|
||||||
|
InsomniaRequestResource,
|
||||||
|
InsomniaResource,
|
||||||
|
InsoReqAuth,
|
||||||
|
} from "./types"
|
||||||
|
|
||||||
// TODO: Insomnia allows custom prefixes for Bearer token auth, Hoppscotch doesn't. We just ignore the prefix for now
|
/**
|
||||||
|
* Used to check if the document is an Insomnia v5 document
|
||||||
type UnwrapPromise<T extends Promise<any>> =
|
* Insomnia v5 documents have a type field that starts with "collection.insomnia.rest/
|
||||||
T extends Promise<infer Y> ? Y : never
|
* @param data InsomniaDoc
|
||||||
|
* @returns true if the document is an Insomnia v5 document
|
||||||
type InsomniaDoc = UnwrapPromise<ReturnType<typeof convert>>
|
*/
|
||||||
type InsomniaResource = ImportRequest
|
const isV5InsomniaDoc = (data: InsomniaDoc) =>
|
||||||
|
data.type &&
|
||||||
// insomnia-importers v3.6.0 doesn't provide a type for path parameters and they have deprecated the library
|
typeof data.type === "string" &&
|
||||||
type InsomniaPathParameter = {
|
(data.type as string).startsWith("collection.insomnia.rest/5")
|
||||||
name: string
|
|
||||||
value: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type InsomniaFolderResource = ImportRequest & { _type: "request_group" }
|
|
||||||
type InsomniaRequestResource = Omit<ImportRequest, "headers" | "parameters"> & {
|
|
||||||
_type: "request"
|
|
||||||
} & {
|
|
||||||
pathParameters?: InsomniaPathParameter[]
|
|
||||||
} & {
|
|
||||||
headers: (Header & { description: string })[]
|
|
||||||
parameters: (Parameter & { description: string })[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseInsomniaDoc = (content: string) =>
|
|
||||||
TO.tryCatch(() => convert(content))
|
|
||||||
|
|
||||||
const replacePathVarTemplating = (expression: string) =>
|
const replacePathVarTemplating = (expression: string) =>
|
||||||
expression.replaceAll(/:([^/]+)/g, "<<$1>>")
|
expression.replaceAll(/:([^/]+)/g, "<<$1>>")
|
||||||
|
|
@ -84,24 +79,22 @@ const getRequestsIn = (
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
const getCollectionVariables = (
|
||||||
* The provided type by insomnia-importers, this type corrects it
|
environment: Record<string, string> | undefined,
|
||||||
*/
|
folderRes?: InsomniaFolderResource
|
||||||
type InsoReqAuth =
|
): HoppCollectionVariable[] => {
|
||||||
| { type: "basic"; disabled?: boolean; username?: string; password?: string }
|
const env =
|
||||||
| {
|
folderRes && folderRes.environment ? folderRes.environment : environment
|
||||||
type: "oauth2"
|
|
||||||
disabled?: boolean
|
if (!env) return []
|
||||||
accessTokenUrl?: string
|
|
||||||
authorizationUrl?: string
|
return Object.entries(env).map(([key, value]) => ({
|
||||||
clientId?: string
|
key: replaceVarTemplating(key),
|
||||||
scope?: string
|
currentValue: "", // set it as empty value since it is handled by currentValue service and we don't want it to sync with BE
|
||||||
}
|
initialValue: replaceVarTemplating(value),
|
||||||
| {
|
secret: false,
|
||||||
type: "bearer"
|
}))
|
||||||
disabled?: boolean
|
}
|
||||||
token?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const getHoppReqAuth = (req: InsomniaRequestResource): HoppRESTAuth => {
|
const getHoppReqAuth = (req: InsomniaRequestResource): HoppRESTAuth => {
|
||||||
if (!req.authentication) return { authType: "none", authActive: true }
|
if (!req.authentication) return { authType: "none", authActive: true }
|
||||||
|
|
@ -128,6 +121,9 @@ const getHoppReqAuth = (req: InsomniaRequestResource): HoppRESTAuth => {
|
||||||
token: "",
|
token: "",
|
||||||
isPKCE: false,
|
isPKCE: false,
|
||||||
tokenEndpoint: replaceVarTemplating(auth.accessTokenUrl ?? ""),
|
tokenEndpoint: replaceVarTemplating(auth.accessTokenUrl ?? ""),
|
||||||
|
authRequestParams: [],
|
||||||
|
refreshRequestParams: [],
|
||||||
|
tokenRequestParams: [],
|
||||||
},
|
},
|
||||||
addTo: "HEADERS",
|
addTo: "HEADERS",
|
||||||
}
|
}
|
||||||
|
|
@ -246,6 +242,7 @@ const getHoppFolder = (
|
||||||
requests: getRequestsIn(folderRes, resources).map(getHoppRequest),
|
requests: getRequestsIn(folderRes, resources).map(getHoppRequest),
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: getCollectionVariables(undefined, folderRes), // undefined is used to indicate no environment variables for v4 and below
|
||||||
})
|
})
|
||||||
|
|
||||||
const getHoppCollections = (docs: InsomniaDoc[]) => {
|
const getHoppCollections = (docs: InsomniaDoc[]) => {
|
||||||
|
|
@ -256,10 +253,112 @@ const getHoppCollections = (docs: InsomniaDoc[]) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hoppInsomniaImporter = (fileContents: string[]) =>
|
const getFolders = (collections: InsomniaDocV5["collection"]) => {
|
||||||
|
if (!collections) return []
|
||||||
|
return collections.filter(
|
||||||
|
(x): x is InsomniaFolderV5 => "children" in x && !("url" in x)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRequests = (
|
||||||
|
collections: InsomniaDocV5["collection"]
|
||||||
|
): InsomniaRequestResource[] => {
|
||||||
|
if (!collections) return []
|
||||||
|
return collections.filter((x): x is InsomniaRequestResource => "url" in x)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getParsedHoppFolder = (
|
||||||
|
name: string,
|
||||||
|
collection: InsomniaFolderV5
|
||||||
|
): HoppCollection => {
|
||||||
|
return makeCollection({
|
||||||
|
name: name ?? collection.name ?? "Untitled Collection",
|
||||||
|
folders: getFolders(collection.children ?? []).map((f) =>
|
||||||
|
getParsedHoppFolder(f.name, f)
|
||||||
|
),
|
||||||
|
requests: getRequests(collection.children ?? []).map(getParsedHoppRequest),
|
||||||
|
auth: { authType: "inherit", authActive: true },
|
||||||
|
headers: [],
|
||||||
|
variables: getCollectionVariables(collection.environment),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getParsedHoppRequest = (req: InsomniaRequestResource) => {
|
||||||
|
return makeRESTRequest({
|
||||||
|
name: req.name ?? "Untitled Request",
|
||||||
|
method: req.method?.toUpperCase() ?? "GET",
|
||||||
|
endpoint: replaceVarTemplating(req.url ?? "", true),
|
||||||
|
auth: getHoppReqAuth(req),
|
||||||
|
body: getHoppReqBody(req),
|
||||||
|
headers: getHoppReqHeaders(req),
|
||||||
|
params: getHoppReqParams(req),
|
||||||
|
|
||||||
|
preRequestScript: "",
|
||||||
|
testScript: "",
|
||||||
|
|
||||||
|
requestVariables: getHoppReqVariables(req),
|
||||||
|
|
||||||
|
//insomnia doesn't have saved response
|
||||||
|
responses: {},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getParsedHoppCollections = (docs: InsomniaDocV5[]): HoppCollection[] =>
|
||||||
|
docs.flatMap((doc) => {
|
||||||
|
if (doc && Array.isArray(doc.collection)) {
|
||||||
|
return makeCollection({
|
||||||
|
name: doc.name ?? "Untitled Collection",
|
||||||
|
folders: getFolders(doc.collection).map((f) =>
|
||||||
|
getParsedHoppFolder(f.name, f)
|
||||||
|
),
|
||||||
|
requests: getRequests(doc.collection).map((x) =>
|
||||||
|
getParsedHoppRequest(x)
|
||||||
|
),
|
||||||
|
auth: { authType: "inherit", authActive: true },
|
||||||
|
headers: [],
|
||||||
|
variables: getCollectionVariables(doc.environments?.data),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
const parseInsomniaDoc = (content: string) =>
|
||||||
pipe(
|
pipe(
|
||||||
fileContents,
|
TO.tryCatch(() => convert(content)),
|
||||||
A.traverse(TO.ApplicativeSeq)(parseInsomniaDoc),
|
TO.map((doc) => getHoppCollections([doc])),
|
||||||
TO.map(getHoppCollections),
|
|
||||||
TE.fromTaskOption(() => IMPORTER_INVALID_FILE_FORMAT)
|
TE.fromTaskOption(() => IMPORTER_INVALID_FILE_FORMAT)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const parseV5InsomniaDoc = (content: string) =>
|
||||||
|
pipe(
|
||||||
|
safeParseJSONOrYAML(content),
|
||||||
|
TO.fromOption,
|
||||||
|
TO.map((parsed) => parsed as InsomniaDocV5),
|
||||||
|
TO.map((doc) => getParsedHoppCollections([doc])),
|
||||||
|
TE.fromTaskOption(() => IMPORTER_INVALID_FILE_FORMAT)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insomina-importers v3.6.0 does supoort insomina v5
|
||||||
|
* (NOTE: Currently, insomnia-importers only supports v4 and below)
|
||||||
|
* https://github.com/Kong/insomnia/issues/8504
|
||||||
|
*/
|
||||||
|
export const hoppInsomniaImporter = (fileContents: string[]) => {
|
||||||
|
return pipe(
|
||||||
|
fileContents,
|
||||||
|
A.traverse(TE.ApplicativeSeq)((content) =>
|
||||||
|
pipe(
|
||||||
|
safeParseJSONOrYAML(content),
|
||||||
|
O.fold(
|
||||||
|
() => TE.left(IMPORTER_INVALID_FILE_FORMAT),
|
||||||
|
(parsed) =>
|
||||||
|
isV5InsomniaDoc(parsed as InsomniaDoc)
|
||||||
|
? parseV5InsomniaDoc(content)
|
||||||
|
: parseInsomniaDoc(content)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
TE.map(A.flatten)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import * as TE from "fp-ts/TaskEither"
|
import * as TE from "fp-ts/TaskEither"
|
||||||
import * as O from "fp-ts/Option"
|
import * as O from "fp-ts/Option"
|
||||||
|
|
||||||
import { IMPORTER_INVALID_FILE_FORMAT } from "."
|
import { IMPORTER_INVALID_FILE_FORMAT } from ".."
|
||||||
|
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import {
|
import {
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { ImportRequest, convert } from "insomnia-importers"
|
||||||
|
import { Header, Parameter } from "insomnia-importers/dist/src/entities"
|
||||||
|
|
||||||
|
type UnwrapPromise<T extends Promise<any>> =
|
||||||
|
T extends Promise<infer Y> ? Y : never
|
||||||
|
|
||||||
|
export type InsomniaDoc = UnwrapPromise<ReturnType<typeof convert>>
|
||||||
|
export type InsomniaResource = ImportRequest
|
||||||
|
|
||||||
|
// insomnia-importers v3.6.0 doesn't provide a type for path parameters and they have deprecated the library
|
||||||
|
export type InsomniaPathParameter = {
|
||||||
|
name: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaFolderResource = ImportRequest & { _type: "request_group" }
|
||||||
|
export type InsomniaRequestResource = Omit<
|
||||||
|
ImportRequest,
|
||||||
|
"headers" | "parameters"
|
||||||
|
> & {
|
||||||
|
_type: "request"
|
||||||
|
} & {
|
||||||
|
pathParameters?: InsomniaPathParameter[]
|
||||||
|
} & {
|
||||||
|
headers: (Header & { description: string })[]
|
||||||
|
parameters: (Parameter & { description: string })[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The provided type by insomnia-importers, this type corrects it
|
||||||
|
*/
|
||||||
|
export type InsoReqAuth =
|
||||||
|
| { type: "basic"; disabled?: boolean; username?: string; password?: string }
|
||||||
|
| {
|
||||||
|
type: "oauth2"
|
||||||
|
disabled?: boolean
|
||||||
|
accessTokenUrl?: string
|
||||||
|
authorizationUrl?: string
|
||||||
|
clientId?: string
|
||||||
|
scope?: string
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "bearer"
|
||||||
|
disabled?: boolean
|
||||||
|
token?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insomnia v5 document types
|
||||||
|
* These types are used to represent the structure of Insomnia v5 documents.
|
||||||
|
*/
|
||||||
|
export type InsomniaDocV5 = {
|
||||||
|
type: `collection.insomnia.rest/${string}`
|
||||||
|
name: string
|
||||||
|
meta: {
|
||||||
|
id: string
|
||||||
|
created: number
|
||||||
|
modified: number
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
collection: (
|
||||||
|
| InsomniaFolderV5
|
||||||
|
| InsomniaRequestResource
|
||||||
|
| InsomniaScriptOnlyV5
|
||||||
|
)[]
|
||||||
|
cookieJar?: InsomniaCookieJarV5
|
||||||
|
environments?: InsomniaEnvironmentV5
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaMetaV5 = {
|
||||||
|
id: string
|
||||||
|
created: number
|
||||||
|
modified: number
|
||||||
|
description?: string
|
||||||
|
sortKey?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaScriptOnlyV5 = {
|
||||||
|
name: string
|
||||||
|
meta: InsomniaMetaV5
|
||||||
|
scripts: {
|
||||||
|
afterResponse?: string
|
||||||
|
preRequest?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaFolderV5 = {
|
||||||
|
name: string
|
||||||
|
meta: InsomniaMetaV5
|
||||||
|
children?: (InsomniaFolderV5 | InsomniaRequestResource)[]
|
||||||
|
environment?: Record<string, string>
|
||||||
|
scripts?: {
|
||||||
|
afterResponse?: string
|
||||||
|
preRequest?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaKeyValueV5 = {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
value: string
|
||||||
|
description?: string
|
||||||
|
disabled?: boolean
|
||||||
|
type?: string
|
||||||
|
multiline?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaCookieJarV5 = {
|
||||||
|
name: string
|
||||||
|
meta: {
|
||||||
|
id: string
|
||||||
|
created: number
|
||||||
|
modified: number
|
||||||
|
}
|
||||||
|
cookies: {
|
||||||
|
key: string
|
||||||
|
value: string
|
||||||
|
domain: string
|
||||||
|
path: string
|
||||||
|
secure?: boolean
|
||||||
|
httpOnly?: boolean
|
||||||
|
hostOnly?: boolean
|
||||||
|
creation: string
|
||||||
|
lastAccessed: string
|
||||||
|
sameSite?: "lax" | "strict" | "none"
|
||||||
|
id: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InsomniaEnvironmentV5 = {
|
||||||
|
name: string
|
||||||
|
meta: {
|
||||||
|
id: string
|
||||||
|
created: number
|
||||||
|
modified: number
|
||||||
|
isPrivate?: boolean
|
||||||
|
}
|
||||||
|
data: Record<string, string>
|
||||||
|
subEnvironments?: {
|
||||||
|
name: string
|
||||||
|
meta: {
|
||||||
|
id: string
|
||||||
|
created: number
|
||||||
|
modified: number
|
||||||
|
isPrivate?: boolean
|
||||||
|
sortKey?: number
|
||||||
|
}
|
||||||
|
data: Record<string, string>
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
ValidContentTypes,
|
ValidContentTypes,
|
||||||
HoppRESTRequestResponses,
|
HoppRESTRequestResponses,
|
||||||
makeHoppRESTResponseOriginalRequest,
|
makeHoppRESTResponseOriginalRequest,
|
||||||
|
HoppCollectionVariable,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
import * as A from "fp-ts/Array"
|
import * as A from "fp-ts/Array"
|
||||||
import { flow, pipe } from "fp-ts/function"
|
import { flow, pipe } from "fp-ts/function"
|
||||||
|
|
@ -28,6 +29,7 @@ import {
|
||||||
RequestAuthDefinition,
|
RequestAuthDefinition,
|
||||||
Variable,
|
Variable,
|
||||||
VariableDefinition,
|
VariableDefinition,
|
||||||
|
VariableList,
|
||||||
} from "postman-collection"
|
} from "postman-collection"
|
||||||
import { stringArrayJoin } from "~/helpers/functional/array"
|
import { stringArrayJoin } from "~/helpers/functional/array"
|
||||||
import { PMRawLanguage } from "~/types/pm-coll-exts"
|
import { PMRawLanguage } from "~/types/pm-coll-exts"
|
||||||
|
|
@ -79,6 +81,32 @@ const parseDescription = (descField?: string | DescriptionDefinition) => {
|
||||||
return descField.content
|
return descField.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getHoppCollVariables = (
|
||||||
|
ig: ItemGroup<Item>
|
||||||
|
): HoppCollectionVariable[] => {
|
||||||
|
if (!("variables" in ig && ig.variables)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipe(
|
||||||
|
(ig.variables as VariableList).all(),
|
||||||
|
A.filter(
|
||||||
|
(variable) =>
|
||||||
|
variable.key !== undefined &&
|
||||||
|
variable.key !== null &&
|
||||||
|
variable.key.length > 0
|
||||||
|
),
|
||||||
|
A.map((variable) => {
|
||||||
|
return <HoppCollectionVariable>{
|
||||||
|
key: replacePMVarTemplating(variable.key ?? ""),
|
||||||
|
initialValue: replacePMVarTemplating(variable.value ?? ""),
|
||||||
|
currentValue: "",
|
||||||
|
secret: variable.type === "secret",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const getHoppReqHeaders = (
|
const getHoppReqHeaders = (
|
||||||
headers: Item["request"]["headers"] | null
|
headers: Item["request"]["headers"] | null
|
||||||
): HoppRESTHeader[] => {
|
): HoppRESTHeader[] => {
|
||||||
|
|
@ -288,6 +316,9 @@ const getHoppReqAuth = (
|
||||||
tokenEndpoint: accessTokenURL,
|
tokenEndpoint: accessTokenURL,
|
||||||
clientSecret: "",
|
clientSecret: "",
|
||||||
isPKCE: false,
|
isPKCE: false,
|
||||||
|
authRequestParams: [],
|
||||||
|
tokenRequestParams: [],
|
||||||
|
refreshRequestParams: [],
|
||||||
},
|
},
|
||||||
addTo: "HEADERS",
|
addTo: "HEADERS",
|
||||||
}
|
}
|
||||||
|
|
@ -457,6 +488,7 @@ const getHoppFolder = (ig: ItemGroup<Item>): HoppCollection =>
|
||||||
requests: pipe(ig.items.all(), A.filter(isPMItem), A.map(getHoppRequest)),
|
requests: pipe(ig.items.all(), A.filter(isPMItem), A.map(getHoppRequest)),
|
||||||
auth: getHoppReqAuth(ig.auth),
|
auth: getHoppReqAuth(ig.auth),
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: getHoppCollVariables(ig),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getHoppCollections = (collections: PMCollection[]) => {
|
export const getHoppCollections = (collections: PMCollection[]) => {
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,12 @@ export type HoppSavedExampleDocument = {
|
||||||
* (atleast as far as we can say)
|
* (atleast as far as we can say)
|
||||||
*/
|
*/
|
||||||
isDirty: boolean
|
isDirty: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The inherited properties from the parent collection
|
||||||
|
* (if any)
|
||||||
|
*/
|
||||||
|
inheritedProperties?: HoppInheritedProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import * as E from "fp-ts/Either"
|
import * as E from "fp-ts/Either"
|
||||||
import { BehaviorSubject, Subscription } from "rxjs"
|
import { BehaviorSubject, Subscription } from "rxjs"
|
||||||
import {
|
import {
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
translateToNewRequest,
|
translateToNewRequest,
|
||||||
|
|
@ -26,6 +27,9 @@ import {
|
||||||
TeamCollectionOrderUpdatedDocument,
|
TeamCollectionOrderUpdatedDocument,
|
||||||
} from "~/helpers/backend/graphql"
|
} from "~/helpers/backend/graphql"
|
||||||
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
||||||
|
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||||
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
|
import { getService } from "~/modules/dioc"
|
||||||
|
|
||||||
export const TEAMS_BACKEND_PAGE_SIZE = 10
|
export const TEAMS_BACKEND_PAGE_SIZE = 10
|
||||||
|
|
||||||
|
|
@ -1034,12 +1038,48 @@ export default class NewTeamCollectionAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getCurrentValue = (
|
||||||
|
env: HoppCollectionVariable,
|
||||||
|
varIndex: number,
|
||||||
|
collectionID: string
|
||||||
|
) => {
|
||||||
|
//collection variables current value and secret value
|
||||||
|
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||||
|
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||||
|
|
||||||
|
if (env && env.secret) {
|
||||||
|
return secretEnvironmentService.getSecretEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
|
return currentEnvironmentValueService.getEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.currentValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function populates the values of the variables with the current values or secrets.
|
||||||
|
* @param variables Variables to populate
|
||||||
|
* @returns Populated variables with current values or secrets
|
||||||
|
*/
|
||||||
|
private populateValues(
|
||||||
|
variables: HoppCollectionVariable[],
|
||||||
|
parentID: string
|
||||||
|
) {
|
||||||
|
return variables.map((v, index) => ({
|
||||||
|
...v,
|
||||||
|
currentValue: this.getCurrentValue(v, index, parentID) ?? v.currentValue,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to obtain the inherited auth and headers for a given folder path, used for both REST and GraphQL team collections
|
* Used to obtain the inherited auth and headers for a given folder path, used for both REST and GraphQL team collections
|
||||||
* @param folderPath the path of the folder to cascade the auth from
|
* @param folderPath the path of the folder to cascade the auth from
|
||||||
* @returns the inherited auth and headers for the given folder path
|
* @returns the inherited auth and headers for the given folder path
|
||||||
*/
|
*/
|
||||||
public cascadeParentCollectionForHeaderAuth(folderPath: string) {
|
public cascadeParentCollectionForProperties(folderPath: string) {
|
||||||
let auth: HoppInheritedProperty["auth"] = {
|
let auth: HoppInheritedProperty["auth"] = {
|
||||||
parentID: folderPath ?? "",
|
parentID: folderPath ?? "",
|
||||||
parentName: "",
|
parentName: "",
|
||||||
|
|
@ -1050,14 +1090,16 @@ export default class NewTeamCollectionAdapter {
|
||||||
}
|
}
|
||||||
const headers: HoppInheritedProperty["headers"] = []
|
const headers: HoppInheritedProperty["headers"] = []
|
||||||
|
|
||||||
if (!folderPath) return { auth, headers }
|
const variables: HoppInheritedProperty["variables"] = []
|
||||||
|
|
||||||
|
if (!folderPath) return { auth, headers, variables }
|
||||||
|
|
||||||
const path = folderPath.split("/")
|
const path = folderPath.split("/")
|
||||||
|
|
||||||
// Check if the path is empty or invalid
|
// Check if the path is empty or invalid
|
||||||
if (!path || path.length === 0) {
|
if (!path || path.length === 0) {
|
||||||
console.error("Invalid path:", folderPath)
|
console.error("Invalid path:", folderPath)
|
||||||
return { auth, headers }
|
return { auth, headers, variables }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through the path and get the last parent folder with authType other than 'inherit'
|
// Loop through the path and get the last parent folder with authType other than 'inherit'
|
||||||
|
|
@ -1067,17 +1109,19 @@ export default class NewTeamCollectionAdapter {
|
||||||
// Check if parentFolder is undefined or null
|
// Check if parentFolder is undefined or null
|
||||||
if (!parentFolder) {
|
if (!parentFolder) {
|
||||||
console.error("Parent folder not found for path:", path)
|
console.error("Parent folder not found for path:", path)
|
||||||
return { auth, headers }
|
return { auth, headers, variables }
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: {
|
const data: {
|
||||||
auth: HoppRESTAuth
|
auth: HoppRESTAuth
|
||||||
headers: HoppRESTHeader[]
|
headers: HoppRESTHeader[]
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
} = parentFolder.data
|
} = parentFolder.data
|
||||||
? JSON.parse(parentFolder.data)
|
? JSON.parse(parentFolder.data)
|
||||||
: {
|
: {
|
||||||
auth: null,
|
auth: null,
|
||||||
headers: null,
|
headers: null,
|
||||||
|
variables: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.auth) {
|
if (!data.auth) {
|
||||||
|
|
@ -1091,8 +1135,11 @@ export default class NewTeamCollectionAdapter {
|
||||||
|
|
||||||
if (!data.headers) data.headers = []
|
if (!data.headers) data.headers = []
|
||||||
|
|
||||||
|
if (!data.variables) data.variables = []
|
||||||
|
|
||||||
const parentFolderAuth = data.auth
|
const parentFolderAuth = data.auth
|
||||||
const parentFolderHeaders = data.headers
|
const parentFolderHeaders = data.headers
|
||||||
|
const parentFolderVariables = data.variables
|
||||||
|
|
||||||
if (
|
if (
|
||||||
parentFolderAuth?.authType === "inherit" &&
|
parentFolderAuth?.authType === "inherit" &&
|
||||||
|
|
@ -1137,8 +1184,22 @@ export default class NewTeamCollectionAdapter {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update variables, overwriting duplicates by key
|
||||||
|
if (parentFolderVariables) {
|
||||||
|
const currentPath = [...path.slice(0, i + 1)].join("/")
|
||||||
|
|
||||||
|
variables.push({
|
||||||
|
parentID: parentFolder.id ?? currentPath,
|
||||||
|
parentName: parentFolder.title,
|
||||||
|
inheritedVariables: this.populateValues(
|
||||||
|
parentFolderVariables,
|
||||||
|
parentFolder.id ?? currentPath
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { auth, headers }
|
return { auth, headers, variables }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
|
|
@ -337,7 +338,7 @@ export class TeamSearchService extends Service {
|
||||||
this.teamsSearchResultsLoading.value = false
|
this.teamsSearchResultsLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
cascadeParentCollectionForHeaderAuthForSearchResults = (
|
cascadeParentCollectionForPropertiesForSearchResults = (
|
||||||
collectionID: string
|
collectionID: string
|
||||||
): HoppInheritedProperty => {
|
): HoppInheritedProperty => {
|
||||||
const defaultInheritedAuth: HoppInheritedProperty["auth"] = {
|
const defaultInheritedAuth: HoppInheritedProperty["auth"] = {
|
||||||
|
|
@ -351,15 +352,23 @@ export class TeamSearchService extends Service {
|
||||||
|
|
||||||
const defaultInheritedHeaders: HoppInheritedProperty["headers"] = []
|
const defaultInheritedHeaders: HoppInheritedProperty["headers"] = []
|
||||||
|
|
||||||
|
const defaultInheritedVariables: HoppInheritedProperty["variables"] = []
|
||||||
|
|
||||||
const collection = Object.values(this.searchResultsCollections).find(
|
const collection = Object.values(this.searchResultsCollections).find(
|
||||||
(col) => col.id === collectionID
|
(col) => col.id === collectionID
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!collection)
|
if (!collection)
|
||||||
return { auth: defaultInheritedAuth, headers: defaultInheritedHeaders }
|
return {
|
||||||
|
auth: defaultInheritedAuth,
|
||||||
|
headers: defaultInheritedHeaders,
|
||||||
|
variables: defaultInheritedVariables,
|
||||||
|
}
|
||||||
|
|
||||||
const inheritedAuthData = this.findInheritableParentAuth(collectionID)
|
const inheritedAuthData = this.findInheritableParentAuth(collectionID)
|
||||||
const inheritedHeadersData = this.findInheritableParentHeaders(collectionID)
|
const inheritedHeadersData = this.findInheritableParentHeaders(collectionID)
|
||||||
|
const inheritedVariablesData =
|
||||||
|
this.findInheritableParentVariables(collectionID)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth: E.isRight(inheritedAuthData)
|
auth: E.isRight(inheritedAuthData)
|
||||||
|
|
@ -368,6 +377,9 @@ export class TeamSearchService extends Service {
|
||||||
headers: E.isRight(inheritedHeadersData)
|
headers: E.isRight(inheritedHeadersData)
|
||||||
? Object.values(inheritedHeadersData.right)
|
? Object.values(inheritedHeadersData.right)
|
||||||
: defaultInheritedHeaders,
|
: defaultInheritedHeaders,
|
||||||
|
variables: E.isRight(inheritedVariablesData)
|
||||||
|
? Object.values(inheritedVariablesData.right)
|
||||||
|
: defaultInheritedVariables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,6 +406,7 @@ export class TeamSearchService extends Service {
|
||||||
const parentInheritedData = JSON.parse(collection.data) as {
|
const parentInheritedData = JSON.parse(collection.data) as {
|
||||||
auth: HoppRESTAuth
|
auth: HoppRESTAuth
|
||||||
headers: HoppRESTHeader[]
|
headers: HoppRESTHeader[]
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const inheritedAuth = parentInheritedData.auth
|
const inheritedAuth = parentInheritedData.auth
|
||||||
|
|
@ -437,6 +450,7 @@ export class TeamSearchService extends Service {
|
||||||
const parentInheritedData = JSON.parse(collection.data) as {
|
const parentInheritedData = JSON.parse(collection.data) as {
|
||||||
auth: HoppRESTAuth
|
auth: HoppRESTAuth
|
||||||
headers: HoppRESTHeader[]
|
headers: HoppRESTHeader[]
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const inheritedHeaders = parentInheritedData.headers
|
const inheritedHeaders = parentInheritedData.headers
|
||||||
|
|
@ -464,6 +478,45 @@ export class TeamSearchService extends Service {
|
||||||
return E.right(existingHeaders)
|
return E.right(existingHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findInheritableParentVariables = (
|
||||||
|
collectionID: string,
|
||||||
|
existingVariables: HoppInheritedProperty["variables"] = []
|
||||||
|
): E.Either<string, HoppInheritedProperty["variables"]> => {
|
||||||
|
const collection = Object.values(this.searchResultsCollections).find(
|
||||||
|
(col) => col.id === collectionID
|
||||||
|
)
|
||||||
|
|
||||||
|
const vars = [...Object.values(existingVariables)]
|
||||||
|
|
||||||
|
if (!collection) {
|
||||||
|
return E.left("PARENT_NOT_FOUND" as const)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.data) {
|
||||||
|
const parentData = JSON.parse(collection.data) as {
|
||||||
|
auth: HoppRESTAuth
|
||||||
|
headers: HoppRESTHeader[]
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const variables = parentData.variables
|
||||||
|
|
||||||
|
if (variables) {
|
||||||
|
vars.push({
|
||||||
|
parentID: collection.id,
|
||||||
|
parentName: collection.title,
|
||||||
|
inheritedVariables: variables,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.parentID) {
|
||||||
|
return this.findInheritableParentVariables(collection.parentID, vars)
|
||||||
|
}
|
||||||
|
|
||||||
|
return E.right(vars)
|
||||||
|
}
|
||||||
|
|
||||||
expandCollection = async (collectionID: string) => {
|
expandCollection = async (collectionID: string) => {
|
||||||
if (this.expandingCollections.value.includes(collectionID)) return
|
if (this.expandingCollections.value.includes(collectionID)) return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
HoppGQLAuth,
|
HoppGQLAuth,
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
|
HoppCollectionVariable,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
|
|
||||||
export type HoppInheritedProperty = {
|
export type HoppInheritedProperty = {
|
||||||
|
|
@ -16,4 +17,9 @@ export type HoppInheritedProperty = {
|
||||||
parentName: string
|
parentName: string
|
||||||
inheritedHeader: HoppRESTHeader | GQLHeader
|
inheritedHeader: HoppRESTHeader | GQLHeader
|
||||||
}[]
|
}[]
|
||||||
|
variables: {
|
||||||
|
parentID: string
|
||||||
|
parentName: string
|
||||||
|
inheritedVariables: HoppCollectionVariable[]
|
||||||
|
}[]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { AggregateEnvironment } from "~/newstore/environments"
|
||||||
|
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
||||||
|
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||||
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
|
import { getService } from "~/modules/dioc"
|
||||||
|
import { HoppCollectionVariable } from "@hoppscotch/data"
|
||||||
|
|
||||||
|
const getCurrentValue = (
|
||||||
|
isSecret: boolean,
|
||||||
|
varIndex: number,
|
||||||
|
collectionID: string,
|
||||||
|
showSecret: boolean = false
|
||||||
|
) => {
|
||||||
|
//collection variables current value and secret value
|
||||||
|
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||||
|
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||||
|
|
||||||
|
if (isSecret && showSecret) {
|
||||||
|
return secretEnvironmentService.getSecretEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
|
return currentEnvironmentValueService.getEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.currentValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to transform inherited collection variables into an array of `AggregateEnvironment` objects.
|
||||||
|
* @param variables - The inherited collection variables to transform.
|
||||||
|
* @param showSecret - Whether to show secret values in the transformed variables.
|
||||||
|
* @returns An array of `AggregateEnvironment` objects representing the transformed collection variables.
|
||||||
|
*/
|
||||||
|
export const transformInheritedCollectionVariablesToAggregateEnv = (
|
||||||
|
variables: HoppInheritedProperty["variables"],
|
||||||
|
showSecret: boolean = true
|
||||||
|
): AggregateEnvironment[] => {
|
||||||
|
return variables.flatMap(({ parentID, inheritedVariables }) =>
|
||||||
|
inheritedVariables.map(
|
||||||
|
({ currentValue, initialValue, key, secret }, index) => ({
|
||||||
|
key,
|
||||||
|
currentValue:
|
||||||
|
getCurrentValue(secret, index, parentID, showSecret) ?? currentValue,
|
||||||
|
initialValue,
|
||||||
|
sourceEnv: "CollectionVariable",
|
||||||
|
secret,
|
||||||
|
sourceEnvID: parentID,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to populate current values in inherited collection variables.
|
||||||
|
* @param variables - The inherited collection variables to populate.
|
||||||
|
* @param parentID - The ID of the parent collection from which to inherit values.
|
||||||
|
* @returns - An array of `HoppCollectionVariable` objects with populated current values.
|
||||||
|
*/
|
||||||
|
export const populateValuesInInheritedCollectionVars = (
|
||||||
|
variables: HoppCollectionVariable[],
|
||||||
|
parentID?: string
|
||||||
|
): HoppCollectionVariable[] =>
|
||||||
|
parentID
|
||||||
|
? variables.map((variable, index) => ({
|
||||||
|
...variable,
|
||||||
|
currentValue:
|
||||||
|
getCurrentValue(variable.secret, index, parentID) ??
|
||||||
|
variable.currentValue,
|
||||||
|
}))
|
||||||
|
: []
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
generateUniqueRefId,
|
generateUniqueRefId,
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppGQLAuth,
|
HoppGQLAuth,
|
||||||
HoppGQLRequest,
|
HoppGQLRequest,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
|
|
@ -17,6 +18,8 @@ import { getService } from "~/modules/dioc"
|
||||||
import { getI18n } from "~/modules/i18n"
|
import { getI18n } from "~/modules/i18n"
|
||||||
import { RESTTabService } from "~/services/tab/rest"
|
import { RESTTabService } from "~/services/tab/rest"
|
||||||
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
||||||
|
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||||
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
|
|
||||||
const defaultRESTCollectionState = {
|
const defaultRESTCollectionState = {
|
||||||
state: [
|
state: [
|
||||||
|
|
@ -29,6 +32,7 @@ const defaultRESTCollectionState = {
|
||||||
authActive: false,
|
authActive: false,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +48,7 @@ const defaultGraphqlCollectionState = {
|
||||||
authActive: false,
|
authActive: false,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
@ -69,15 +74,56 @@ export function navigateToFolderWithIndexPath(
|
||||||
return target !== undefined ? target : null
|
return target !== undefined ? target : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getCurrentValue = (
|
||||||
|
env: HoppCollectionVariable,
|
||||||
|
varIndex: number,
|
||||||
|
collectionID: string,
|
||||||
|
showSecret: boolean
|
||||||
|
) => {
|
||||||
|
//collection variables current value and secret value
|
||||||
|
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||||
|
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||||
|
|
||||||
|
if (env && env.secret && showSecret) {
|
||||||
|
return secretEnvironmentService.getSecretEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
|
return currentEnvironmentValueService.getEnvironmentVariable(
|
||||||
|
collectionID,
|
||||||
|
varIndex
|
||||||
|
)?.currentValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function populates the values of the variables with the current values or secrets.
|
||||||
|
* @param variables Variables to populate
|
||||||
|
* @returns Populated variables with current values or secrets
|
||||||
|
*/
|
||||||
|
function populateValues(
|
||||||
|
variables: HoppCollectionVariable[],
|
||||||
|
parentID: string,
|
||||||
|
showSecret: boolean
|
||||||
|
) {
|
||||||
|
return variables.map((v, index) => ({
|
||||||
|
...v,
|
||||||
|
currentValue:
|
||||||
|
getCurrentValue(v, index, parentID, showSecret) ?? v.currentValue,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to obtain the inherited auth and headers for a given folder path, used for both REST and GraphQL personal collections
|
* Used to obtain the inherited auth and headers for a given folder path, used for both REST and GraphQL personal collections
|
||||||
* @param folderPath the path of the folder to cascade the auth from
|
* @param folderPath the path of the folder to cascade the auth from
|
||||||
* @param type the type of collection
|
* @param type the type of collection
|
||||||
|
* @param showSecret whether to show secret values in the collection variables
|
||||||
* @returns the inherited auth and headers for the given folder path
|
* @returns the inherited auth and headers for the given folder path
|
||||||
*/
|
*/
|
||||||
export function cascadeParentCollectionForHeaderAuth(
|
export function cascadeParentCollectionForProperties(
|
||||||
folderPath: string | undefined,
|
folderPath: string | undefined,
|
||||||
type: "rest" | "graphql"
|
type: "rest" | "graphql",
|
||||||
|
showSecret: boolean = false
|
||||||
) {
|
) {
|
||||||
const collectionStore =
|
const collectionStore =
|
||||||
type === "rest" ? restCollectionStore : graphqlCollectionStore
|
type === "rest" ? restCollectionStore : graphqlCollectionStore
|
||||||
|
|
@ -92,14 +138,16 @@ export function cascadeParentCollectionForHeaderAuth(
|
||||||
}
|
}
|
||||||
const headers: HoppInheritedProperty["headers"] = []
|
const headers: HoppInheritedProperty["headers"] = []
|
||||||
|
|
||||||
if (!folderPath) return { auth, headers }
|
const variables: HoppInheritedProperty["variables"] = []
|
||||||
|
|
||||||
|
if (!folderPath) return { auth, headers, variables }
|
||||||
|
|
||||||
const path = folderPath.split("/").map((i) => parseInt(i))
|
const path = folderPath.split("/").map((i) => parseInt(i))
|
||||||
|
|
||||||
// Check if the path is empty or invalid
|
// Check if the path is empty or invalid
|
||||||
if (!path || path.length === 0) {
|
if (!path || path.length === 0) {
|
||||||
console.error("Invalid path:", folderPath)
|
console.error("Invalid path:", folderPath)
|
||||||
return { auth, headers }
|
return { auth, headers, variables }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through the path and get the last parent folder with authType other than 'inherit'
|
// Loop through the path and get the last parent folder with authType other than 'inherit'
|
||||||
|
|
@ -112,7 +160,7 @@ export function cascadeParentCollectionForHeaderAuth(
|
||||||
// Check if parentFolder is undefined or null
|
// Check if parentFolder is undefined or null
|
||||||
if (!parentFolder) {
|
if (!parentFolder) {
|
||||||
console.error("Parent folder not found for path:", path)
|
console.error("Parent folder not found for path:", path)
|
||||||
return { auth, headers }
|
return { auth, headers, variables }
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentFolderAuth = parentFolder.auth as HoppRESTAuth | HoppGQLAuth
|
const parentFolderAuth = parentFolder.auth as HoppRESTAuth | HoppGQLAuth
|
||||||
|
|
@ -120,6 +168,9 @@ export function cascadeParentCollectionForHeaderAuth(
|
||||||
| HoppRESTHeaders
|
| HoppRESTHeaders
|
||||||
| GQLHeader[]
|
| GQLHeader[]
|
||||||
|
|
||||||
|
const parentFolderVariables =
|
||||||
|
parentFolder.variables as HoppCollectionVariable[]
|
||||||
|
|
||||||
// check if the parent folder has authType 'inherit' and if it is the root folder
|
// check if the parent folder has authType 'inherit' and if it is the root folder
|
||||||
if (
|
if (
|
||||||
parentFolderAuth?.authType === "inherit" &&
|
parentFolderAuth?.authType === "inherit" &&
|
||||||
|
|
@ -164,9 +215,23 @@ export function cascadeParentCollectionForHeaderAuth(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parentFolderVariables) {
|
||||||
|
const currentPath = [...path.slice(0, i + 1)].join("/")
|
||||||
|
|
||||||
|
variables.push({
|
||||||
|
parentID: parentFolder._ref_id ?? parentFolder.id ?? currentPath,
|
||||||
|
parentName: parentFolder.name,
|
||||||
|
inheritedVariables: populateValues(
|
||||||
|
parentFolderVariables,
|
||||||
|
parentFolder.id ?? currentPath,
|
||||||
|
showSecret
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { auth, headers }
|
return { auth, headers, variables }
|
||||||
}
|
}
|
||||||
|
|
||||||
function reorderItems(array: unknown[], from: number, to: number) {
|
function reorderItems(array: unknown[], from: number, to: number) {
|
||||||
|
|
@ -254,6 +319,7 @@ const restCollectionDispatchers = defineDispatchers({
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const newState = state
|
const newState = state
|
||||||
|
|
@ -879,6 +945,7 @@ const gqlCollectionDispatchers = defineDispatchers({
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
})
|
})
|
||||||
const newState = state
|
const newState = state
|
||||||
const indexPaths = path.split("/").map((x) => parseInt(x))
|
const indexPaths = path.split("/").map((x) => parseInt(x))
|
||||||
|
|
@ -1222,8 +1289,13 @@ function computeCollectionInheritedProps(
|
||||||
ref_id: string,
|
ref_id: string,
|
||||||
type: "my-collections" | "team-collections" = "my-collections",
|
type: "my-collections" | "team-collections" = "my-collections",
|
||||||
parentAuth: HoppRESTAuth | null = null,
|
parentAuth: HoppRESTAuth | null = null,
|
||||||
parentHeaders: HoppRESTHeaders | null = null
|
parentHeaders: HoppRESTHeaders | null = null,
|
||||||
): { auth: HoppRESTAuth; headers: HoppRESTHeaders } | null {
|
parentVariables: HoppCollectionVariable[] | null = null
|
||||||
|
): {
|
||||||
|
auth: HoppRESTAuth
|
||||||
|
headers: HoppRESTHeaders
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
|
} | null {
|
||||||
// Determine the inherited authentication and headers
|
// Determine the inherited authentication and headers
|
||||||
const inheritedAuth =
|
const inheritedAuth =
|
||||||
collection.auth?.authType === "inherit" && collection.auth.authActive
|
collection.auth?.authType === "inherit" && collection.auth.authActive
|
||||||
|
|
@ -1235,6 +1307,11 @@ function computeCollectionInheritedProps(
|
||||||
...collection.headers,
|
...collection.headers,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const inheritedVariables = [
|
||||||
|
...(parentVariables ?? []),
|
||||||
|
...collection.variables,
|
||||||
|
]
|
||||||
|
|
||||||
// Check if the current collection matches the target reference ID
|
// Check if the current collection matches the target reference ID
|
||||||
const isTargetCollection =
|
const isTargetCollection =
|
||||||
type === "my-collections"
|
type === "my-collections"
|
||||||
|
|
@ -1245,6 +1322,7 @@ function computeCollectionInheritedProps(
|
||||||
return {
|
return {
|
||||||
auth: inheritedAuth,
|
auth: inheritedAuth,
|
||||||
headers: inheritedHeaders,
|
headers: inheritedHeaders,
|
||||||
|
variables: inheritedVariables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1255,7 +1333,8 @@ function computeCollectionInheritedProps(
|
||||||
ref_id,
|
ref_id,
|
||||||
type,
|
type,
|
||||||
inheritedAuth,
|
inheritedAuth,
|
||||||
inheritedHeaders
|
inheritedHeaders,
|
||||||
|
inheritedVariables
|
||||||
)
|
)
|
||||||
if (result) return result // Return as soon as a match is found
|
if (result) return result // Return as soon as a match is found
|
||||||
}
|
}
|
||||||
|
|
@ -1267,7 +1346,11 @@ export function getRESTCollectionInheritedProps(
|
||||||
collectionID: string,
|
collectionID: string,
|
||||||
collections: HoppCollection[] = restCollectionStore.value.state,
|
collections: HoppCollection[] = restCollectionStore.value.state,
|
||||||
type: "my-collections" | "team-collections" = "my-collections"
|
type: "my-collections" | "team-collections" = "my-collections"
|
||||||
): { auth: HoppRESTAuth; headers: HoppRESTHeaders } | null {
|
): {
|
||||||
|
auth: HoppRESTAuth
|
||||||
|
headers: HoppRESTHeaders
|
||||||
|
variables: HoppCollectionVariable[]
|
||||||
|
} | null {
|
||||||
for (const collection of collections) {
|
for (const collection of collections) {
|
||||||
const result = computeCollectionInheritedProps(
|
const result = computeCollectionInheritedProps(
|
||||||
collection,
|
collection,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import DispatchingStore, {
|
||||||
} from "~/newstore/DispatchingStore"
|
} from "~/newstore/DispatchingStore"
|
||||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||||
|
import { RESTTabService } from "~/services/tab/rest"
|
||||||
|
|
||||||
export type SelectedEnvironmentIndex =
|
export type SelectedEnvironmentIndex =
|
||||||
| { type: "NO_ENV_SELECTED" }
|
| { type: "NO_ENV_SELECTED" }
|
||||||
|
|
@ -49,9 +50,6 @@ const defaultEnvironmentsState = {
|
||||||
} as SelectedEnvironmentIndex,
|
} as SelectedEnvironmentIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
const secretEnvironmentService = getService(SecretEnvironmentService)
|
|
||||||
const currentEnvironmentValueService = getService(CurrentValueService)
|
|
||||||
|
|
||||||
type EnvironmentStore = typeof defaultEnvironmentsState
|
type EnvironmentStore = typeof defaultEnvironmentsState
|
||||||
|
|
||||||
const dispatchers = defineDispatchers({
|
const dispatchers = defineDispatchers({
|
||||||
|
|
@ -423,6 +421,7 @@ export type AggregateEnvironment = {
|
||||||
currentValue: string
|
currentValue: string
|
||||||
secret: boolean
|
secret: boolean
|
||||||
sourceEnv: string
|
sourceEnv: string
|
||||||
|
sourceEnvID?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -431,13 +430,27 @@ export type AggregateEnvironment = {
|
||||||
* NOTE: The source environment attribute will be "Global" for Global Env as source.
|
* NOTE: The source environment attribute will be "Global" for Global Env as source.
|
||||||
* The priority of the variables is as follows:
|
* The priority of the variables is as follows:
|
||||||
* 1. Pre-defined variables
|
* 1. Pre-defined variables
|
||||||
* 2. Selected Environment Variables
|
* 2. Request Variables (from the current request)
|
||||||
* 3. Global Environment Variables
|
* 3. Selected Environment Variables
|
||||||
|
* 4. Global Environment Variables
|
||||||
*/
|
*/
|
||||||
export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
||||||
[currentEnvironment$, globalEnv$]
|
[currentEnvironment$, globalEnv$]
|
||||||
).pipe(
|
).pipe(
|
||||||
map(([selectedEnv, globalEnv]) => {
|
map(([selectedEnv, globalEnv]) => {
|
||||||
|
const restTabs = getService(RESTTabService)
|
||||||
|
|
||||||
|
const currentTab = restTabs.currentActiveTab.value
|
||||||
|
|
||||||
|
const currentTabRequest =
|
||||||
|
currentTab.document.type === "example-response"
|
||||||
|
? currentTab.document.response.originalRequest
|
||||||
|
: currentTab.document.request
|
||||||
|
|
||||||
|
const requestVariables = currentTabRequest?.requestVariables
|
||||||
|
? currentTabRequest.requestVariables
|
||||||
|
: []
|
||||||
|
|
||||||
const effectiveAggregateEnvs: AggregateEnvironment[] = []
|
const effectiveAggregateEnvs: AggregateEnvironment[] = []
|
||||||
|
|
||||||
// Ensure pre-defined variables are prioritised over other environment variables with the same name
|
// Ensure pre-defined variables are prioritised over other environment variables with the same name
|
||||||
|
|
@ -453,6 +466,18 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
||||||
|
|
||||||
const aggregateEnvKeys = effectiveAggregateEnvs.map(({ key }) => key)
|
const aggregateEnvKeys = effectiveAggregateEnvs.map(({ key }) => key)
|
||||||
|
|
||||||
|
requestVariables.forEach(({ key, value, active }) => {
|
||||||
|
if (!aggregateEnvKeys.includes(key) && active) {
|
||||||
|
effectiveAggregateEnvs.push({
|
||||||
|
key,
|
||||||
|
currentValue: value,
|
||||||
|
initialValue: value,
|
||||||
|
secret: false,
|
||||||
|
sourceEnv: "RequestVariable",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
selectedEnv?.variables.forEach((variable) => {
|
selectedEnv?.variables.forEach((variable) => {
|
||||||
const { key, secret } = variable
|
const { key, secret } = variable
|
||||||
const currentValue =
|
const currentValue =
|
||||||
|
|
@ -495,8 +520,47 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
||||||
)
|
)
|
||||||
|
|
||||||
export function getAggregateEnvs() {
|
export function getAggregateEnvs() {
|
||||||
|
const restTabs = getService(RESTTabService)
|
||||||
|
|
||||||
const currentEnv = getCurrentEnvironment()
|
const currentEnv = getCurrentEnvironment()
|
||||||
|
const currentTab = restTabs.currentActiveTab.value
|
||||||
|
|
||||||
|
const currentTabRequest =
|
||||||
|
currentTab.document.type === "example-response"
|
||||||
|
? currentTab.document.response.originalRequest
|
||||||
|
: currentTab.document.request
|
||||||
|
|
||||||
|
const requestVariables = currentTabRequest?.requestVariables
|
||||||
|
? currentTabRequest.requestVariables
|
||||||
|
: []
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
...HOPP_SUPPORTED_PREDEFINED_VARIABLES.map(({ key, getValue }) => {
|
||||||
|
return <AggregateEnvironment>{
|
||||||
|
key,
|
||||||
|
currentValue: getValue(),
|
||||||
|
initialValue: getValue(),
|
||||||
|
secret: false,
|
||||||
|
sourceEnv: currentEnv.name,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
...requestVariables
|
||||||
|
.map(({ key, value, active }) => {
|
||||||
|
if (active) {
|
||||||
|
return <AggregateEnvironment>{
|
||||||
|
key,
|
||||||
|
currentValue: value,
|
||||||
|
initialValue: value,
|
||||||
|
sourceEnv: "RequestVariable",
|
||||||
|
secret: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
})
|
||||||
|
.filter((v): v is AggregateEnvironment => v !== undefined),
|
||||||
|
|
||||||
...currentEnv.variables.map((x) => {
|
...currentEnv.variables.map((x) => {
|
||||||
let currentValue = ""
|
let currentValue = ""
|
||||||
if (!x.secret) {
|
if (!x.secret) {
|
||||||
|
|
@ -528,9 +592,49 @@ export function getAggregateEnvs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAggregateEnvsWithCurrentValue() {
|
export function getAggregateEnvsWithCurrentValue() {
|
||||||
|
const restTabs = getService(RESTTabService)
|
||||||
|
|
||||||
|
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||||
|
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||||
|
|
||||||
const currentEnv = getCurrentEnvironment()
|
const currentEnv = getCurrentEnvironment()
|
||||||
|
const currentTab = restTabs.currentActiveTab.value
|
||||||
|
|
||||||
|
const currentTabRequest =
|
||||||
|
currentTab.document.type === "example-response"
|
||||||
|
? currentTab.document.response.originalRequest
|
||||||
|
: currentTab.document.request
|
||||||
|
|
||||||
|
const requestVariables = currentTabRequest?.requestVariables
|
||||||
|
? currentTabRequest.requestVariables
|
||||||
|
: []
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
...HOPP_SUPPORTED_PREDEFINED_VARIABLES.map(({ key, getValue }) => {
|
||||||
|
return <AggregateEnvironment>{
|
||||||
|
key,
|
||||||
|
currentValue: getValue(),
|
||||||
|
initialValue: getValue(),
|
||||||
|
secret: false,
|
||||||
|
sourceEnv: currentEnv.name,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
...requestVariables
|
||||||
|
.map(({ key, value, active }) => {
|
||||||
|
if (active) {
|
||||||
|
return <AggregateEnvironment>{
|
||||||
|
key,
|
||||||
|
currentValue: value,
|
||||||
|
initialValue: value,
|
||||||
|
sourceEnv: "RequestVariable",
|
||||||
|
secret: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
.filter((v): v is AggregateEnvironment => v !== undefined),
|
||||||
|
|
||||||
...currentEnv.variables.map((x, index) => {
|
...currentEnv.variables.map((x, index) => {
|
||||||
let currentValue = x.currentValue
|
let currentValue = x.currentValue
|
||||||
if (x.secret) {
|
if (x.secret) {
|
||||||
|
|
@ -581,6 +685,22 @@ export const aggregateEnvsWithCurrentValue$: Observable<
|
||||||
AggregateEnvironment[]
|
AggregateEnvironment[]
|
||||||
> = combineLatest([currentEnvironment$, globalEnv$]).pipe(
|
> = combineLatest([currentEnvironment$, globalEnv$]).pipe(
|
||||||
map(([selectedEnv, globalEnv]) => {
|
map(([selectedEnv, globalEnv]) => {
|
||||||
|
const restTabs = getService(RESTTabService)
|
||||||
|
|
||||||
|
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||||
|
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||||
|
|
||||||
|
const currentTab = restTabs.currentActiveTab.value
|
||||||
|
|
||||||
|
const currentTabRequest =
|
||||||
|
currentTab.document.type === "example-response"
|
||||||
|
? currentTab.document.response.originalRequest
|
||||||
|
: currentTab.document.request
|
||||||
|
|
||||||
|
const requestVariables = currentTabRequest?.requestVariables
|
||||||
|
? currentTabRequest.requestVariables
|
||||||
|
: []
|
||||||
|
|
||||||
const results: AggregateEnvironment[] = []
|
const results: AggregateEnvironment[] = []
|
||||||
|
|
||||||
// Ensure pre-defined variables are prioritised over other environment variables with the same name
|
// Ensure pre-defined variables are prioritised over other environment variables with the same name
|
||||||
|
|
@ -594,6 +714,18 @@ export const aggregateEnvsWithCurrentValue$: Observable<
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
requestVariables.map(({ key, value, active }) => {
|
||||||
|
if (active) {
|
||||||
|
results.push({
|
||||||
|
key,
|
||||||
|
currentValue: value,
|
||||||
|
initialValue: value,
|
||||||
|
secret: false,
|
||||||
|
sourceEnv: "RequestVariable",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
selectedEnv?.variables.map((x, index) => {
|
selectedEnv?.variables.map((x, index) => {
|
||||||
let currentValue = x.currentValue
|
let currentValue = x.currentValue
|
||||||
if (x.secret) {
|
if (x.secret) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { Service } from "dioc"
|
import { Container, Service } from "dioc"
|
||||||
import { cloneDeep } from "lodash-es"
|
import { cloneDeep } from "lodash-es"
|
||||||
|
import { nextTick } from "vue"
|
||||||
|
import { watch } from "vue"
|
||||||
import { reactive, computed } from "vue"
|
import { reactive, computed } from "vue"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -21,6 +23,12 @@ export type Variable = {
|
||||||
export class CurrentValueService extends Service {
|
export class CurrentValueService extends Service {
|
||||||
public static readonly ID = "CURRENT_VALUE_SERVICE"
|
public static readonly ID = "CURRENT_VALUE_SERVICE"
|
||||||
|
|
||||||
|
constructor(c: Container) {
|
||||||
|
super(c)
|
||||||
|
// Initialize the secret environments map
|
||||||
|
this.watchCurrentEnvironments()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of current value of environments.
|
* Map of current value of environments.
|
||||||
* The key is the ID of the environment.
|
* The key is the ID of the environment.
|
||||||
|
|
@ -159,4 +167,26 @@ export class CurrentValueService extends Service {
|
||||||
})
|
})
|
||||||
return environments
|
return environments
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches the current environments for changes.
|
||||||
|
* If a secret variable is removed or has an empty key, it will be deleted.
|
||||||
|
*/
|
||||||
|
protected watchCurrentEnvironments() {
|
||||||
|
watch(
|
||||||
|
() => this.environments,
|
||||||
|
() => {
|
||||||
|
nextTick(() => {
|
||||||
|
this.environments.forEach((vars, id) => {
|
||||||
|
const filteredVars = vars.filter((v) => v.key !== "")
|
||||||
|
|
||||||
|
if (filteredVars.length === 0) {
|
||||||
|
this.environments.delete(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,14 @@ describe("RequestInspectorService", () => {
|
||||||
const req = ref({
|
const req = ref({
|
||||||
...getDefaultRESTRequest(),
|
...getDefaultRESTRequest(),
|
||||||
endpoint: "http://example.com/api/data",
|
endpoint: "http://example.com/api/data",
|
||||||
headers: [{ key: "Cookie", value: "some-cookie", active: true }],
|
headers: [
|
||||||
|
{
|
||||||
|
key: "Cookie",
|
||||||
|
value: "some-cookie",
|
||||||
|
active: true,
|
||||||
|
description: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = requestInspector.getInspections(req)
|
const result = requestInspector.getInspections(req)
|
||||||
|
|
@ -83,7 +90,14 @@ describe("RequestInspectorService", () => {
|
||||||
const req = ref({
|
const req = ref({
|
||||||
...getDefaultRESTRequest(),
|
...getDefaultRESTRequest(),
|
||||||
endpoint: "http://example.com/api/data",
|
endpoint: "http://example.com/api/data",
|
||||||
headers: [{ key: "Cookie", value: "some-cookie", active: true }],
|
headers: [
|
||||||
|
{
|
||||||
|
key: "Cookie",
|
||||||
|
value: "some-cookie",
|
||||||
|
active: true,
|
||||||
|
description: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = requestInspector.getInspections(req)
|
const result = requestInspector.getInspections(req)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { useStreamStatic } from "~/composables/stream"
|
||||||
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||||
import { RESTTabService } from "~/services/tab/rest"
|
import { RESTTabService } from "~/services/tab/rest"
|
||||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||||
|
import { transformInheritedCollectionVariablesToAggregateEnv } from "~/helpers/utils/inheritedCollectionVarTransformer"
|
||||||
|
|
||||||
const HOPP_ENVIRONMENT_REGEX = /(<<[a-zA-Z0-9-_]+>>)/g
|
const HOPP_ENVIRONMENT_REGEX = /(<<[a-zA-Z0-9-_]+>>)/g
|
||||||
|
|
||||||
|
|
@ -76,16 +77,17 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||||
|
|
||||||
const currentTab = this.restTabs.currentActiveTab.value
|
const currentTab = this.restTabs.currentActiveTab.value
|
||||||
|
|
||||||
const currentTabRequest =
|
const collectionVariables =
|
||||||
currentTab.document.type === "request"
|
currentTab.document.type === "request" ||
|
||||||
? currentTab.document.request
|
currentTab.document.type === "example-response"
|
||||||
: currentTab.document.type === "example-response"
|
? transformInheritedCollectionVariablesToAggregateEnv(
|
||||||
? currentTab.document.response.originalRequest
|
currentTab.document.inheritedProperties?.variables ?? []
|
||||||
: null
|
)
|
||||||
|
: []
|
||||||
|
|
||||||
const environmentVariables = [
|
const environmentVariables = [
|
||||||
...(currentTabRequest?.requestVariables ?? []),
|
|
||||||
...this.aggregateEnvsWithValue.value,
|
...this.aggregateEnvsWithValue.value,
|
||||||
|
...collectionVariables,
|
||||||
]
|
]
|
||||||
|
|
||||||
const envKeys = environmentVariables.map((e) => e.key)
|
const envKeys = environmentVariables.map((e) => e.key)
|
||||||
|
|
@ -192,32 +194,35 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||||
const currentSelectedEnvironment = getCurrentEnvironment()
|
const currentSelectedEnvironment = getCurrentEnvironment()
|
||||||
|
|
||||||
const currentTab = this.restTabs.currentActiveTab.value
|
const currentTab = this.restTabs.currentActiveTab.value
|
||||||
|
const collectionVariables =
|
||||||
const currentTabRequest =
|
currentTab.document.type === "request" ||
|
||||||
currentTab.document.type === "request"
|
currentTab.document.type === "example-response"
|
||||||
? currentTab.document.request
|
? transformInheritedCollectionVariablesToAggregateEnv(
|
||||||
: currentTab.document.type === "example-response"
|
currentTab.document.inheritedProperties?.variables ?? [],
|
||||||
? currentTab.document.response.originalRequest
|
false
|
||||||
: null
|
)
|
||||||
|
: []
|
||||||
|
|
||||||
const environmentVariables =
|
const environmentVariables =
|
||||||
this.filterNonEmptyEnvironmentVariables([
|
this.filterNonEmptyEnvironmentVariables([
|
||||||
// Transform the request variables to environment variables
|
|
||||||
...(currentTabRequest?.requestVariables ?? []).map((env) => ({
|
|
||||||
key: env.key,
|
|
||||||
currentValue: env.value,
|
|
||||||
initialValue: env.value,
|
|
||||||
secret: false,
|
|
||||||
sourceEnv: "RequestVariable",
|
|
||||||
})),
|
|
||||||
...this.aggregateEnvsWithValue.value,
|
...this.aggregateEnvsWithValue.value,
|
||||||
|
...collectionVariables,
|
||||||
])
|
])
|
||||||
|
|
||||||
environmentVariables.forEach((env) => {
|
environmentVariables.forEach((env) => {
|
||||||
|
let tooltipSourceEnvID = "Global"
|
||||||
|
|
||||||
|
if (env?.sourceEnv === "Global") {
|
||||||
|
tooltipSourceEnvID = "Global"
|
||||||
|
} else {
|
||||||
|
tooltipSourceEnvID =
|
||||||
|
env?.sourceEnv === "CollectionVariable"
|
||||||
|
? env.sourceEnvID!
|
||||||
|
: currentSelectedEnvironment.id
|
||||||
|
}
|
||||||
|
|
||||||
const hasSecretEnv = this.secretEnvs.hasSecretValue(
|
const hasSecretEnv = this.secretEnvs.hasSecretValue(
|
||||||
env.sourceEnv !== "Global"
|
tooltipSourceEnvID,
|
||||||
? currentSelectedEnvironment.id
|
|
||||||
: "Global",
|
|
||||||
env.key
|
env.key
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ const DEFAULT_SETTINGS = getDefaultSettings()
|
||||||
|
|
||||||
export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
name: "Echo",
|
name: "Echo",
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
|
|
@ -51,13 +51,14 @@ export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
],
|
],
|
||||||
auth: { authType: "none", authActive: true },
|
auth: { authType: "none", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
folders: [],
|
folders: [],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
{
|
{
|
||||||
v: 9,
|
v: 10,
|
||||||
name: "Echo",
|
name: "Echo",
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +76,7 @@ export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
],
|
],
|
||||||
auth: { authType: "none", authActive: true },
|
auth: { authType: "none", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
folders: [],
|
folders: [],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
HoppRESTRequestResponse,
|
HoppRESTRequestResponse,
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
GlobalEnvironment,
|
GlobalEnvironment,
|
||||||
|
CollectionVariable,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
import { entityReference } from "verzod"
|
import { entityReference } from "verzod"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
@ -313,6 +314,15 @@ const HoppInheritedPropertySchema = z
|
||||||
inheritedHeader: z.union([HoppRESTHeaders, GQLHeader]),
|
inheritedHeader: z.union([HoppRESTHeaders, GQLHeader]),
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
variables: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
parentID: z.string(),
|
||||||
|
parentName: z.string(),
|
||||||
|
inheritedVariables: z.array(CollectionVariable),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch([]),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
|
|
||||||
|
|
@ -579,6 +589,7 @@ export const REST_TAB_STATE_SCHEMA = z
|
||||||
response: entityReference(HoppRESTRequestResponse),
|
response: entityReference(HoppRESTRequestResponse),
|
||||||
saveContext: z.optional(HoppRESTSaveContextSchema),
|
saveContext: z.optional(HoppRESTSaveContextSchema),
|
||||||
isDirty: z.boolean(),
|
isDirty: z.boolean(),
|
||||||
|
inheritedProperties: z.optional(HoppInheritedPropertySchema),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Service } from "dioc"
|
import { Container, Service } from "dioc"
|
||||||
import { reactive, computed } from "vue"
|
import { nextTick } from "vue"
|
||||||
|
import { reactive, computed, watch } from "vue"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a secret environment variable.
|
* Defines a secret environment variable.
|
||||||
|
|
@ -19,6 +20,12 @@ export type SecretVariable = {
|
||||||
export class SecretEnvironmentService extends Service {
|
export class SecretEnvironmentService extends Service {
|
||||||
public static readonly ID = "SECRET_ENVIRONMENT_SERVICE"
|
public static readonly ID = "SECRET_ENVIRONMENT_SERVICE"
|
||||||
|
|
||||||
|
constructor(c: Container) {
|
||||||
|
super(c)
|
||||||
|
// Initialize the secret environments map
|
||||||
|
this.watchSecretEnvironments()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of secret environments.
|
* Map of secret environments.
|
||||||
* The key is the ID of the secret environment.
|
* The key is the ID of the secret environment.
|
||||||
|
|
@ -137,4 +144,26 @@ export class SecretEnvironmentService extends Service {
|
||||||
})
|
})
|
||||||
return secretEnvironments
|
return secretEnvironments
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches the secret environments for changes.
|
||||||
|
* If a secret variable is removed or has an empty key, it will be deleted.
|
||||||
|
*/
|
||||||
|
protected watchSecretEnvironments() {
|
||||||
|
watch(
|
||||||
|
() => this.secretEnvironments,
|
||||||
|
() => {
|
||||||
|
nextTick(() => {
|
||||||
|
this.secretEnvironments.forEach((secretVars, id) => {
|
||||||
|
const filteredVars = secretVars.filter((v) => v.key !== "")
|
||||||
|
|
||||||
|
if (filteredVars.length === 0) {
|
||||||
|
this.secretEnvironments.delete(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { Ref, computed, effectScope, markRaw, ref, watch } from "vue"
|
||||||
import { getI18n } from "~/modules/i18n"
|
import { getI18n } from "~/modules/i18n"
|
||||||
import MiniSearch from "minisearch"
|
import MiniSearch from "minisearch"
|
||||||
import {
|
import {
|
||||||
cascadeParentCollectionForHeaderAuth,
|
cascadeParentCollectionForProperties,
|
||||||
graphqlCollectionStore,
|
graphqlCollectionStore,
|
||||||
restCollectionStore,
|
restCollectionStore,
|
||||||
} from "~/newstore/collections"
|
} from "~/newstore/collections"
|
||||||
|
|
@ -318,11 +318,6 @@ export class CollectionsSpotlightSearcherService
|
||||||
|
|
||||||
if (!req) return
|
if (!req) return
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
folderPath.join("/"),
|
|
||||||
"rest"
|
|
||||||
)
|
|
||||||
|
|
||||||
this.restTab.createNewTab(
|
this.restTab.createNewTab(
|
||||||
{
|
{
|
||||||
type: "request",
|
type: "request",
|
||||||
|
|
@ -333,10 +328,10 @@ export class CollectionsSpotlightSearcherService
|
||||||
folderPath: folderPath.join("/"),
|
folderPath: folderPath.join("/"),
|
||||||
requestIndex: reqIndex,
|
requestIndex: reqIndex,
|
||||||
},
|
},
|
||||||
inheritedProperties: {
|
inheritedProperties: cascadeParentCollectionForProperties(
|
||||||
auth,
|
folderPath.join("/"),
|
||||||
headers,
|
"rest"
|
||||||
},
|
),
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
@ -350,10 +345,6 @@ export class CollectionsSpotlightSearcherService
|
||||||
|
|
||||||
if (!req) return
|
if (!req) return
|
||||||
|
|
||||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
|
||||||
folderPath.join("/"),
|
|
||||||
"graphql"
|
|
||||||
)
|
|
||||||
this.gqlTab.createNewTab({
|
this.gqlTab.createNewTab({
|
||||||
saveContext: {
|
saveContext: {
|
||||||
originLocation: "user-collection",
|
originLocation: "user-collection",
|
||||||
|
|
@ -363,10 +354,10 @@ export class CollectionsSpotlightSearcherService
|
||||||
cursorPosition: 0,
|
cursorPosition: 0,
|
||||||
request: req,
|
request: req,
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
inheritedProperties: {
|
inheritedProperties: cascadeParentCollectionForProperties(
|
||||||
auth,
|
folderPath.join("/"),
|
||||||
headers,
|
"graphql"
|
||||||
},
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,12 +217,12 @@ export class TeamsSpotlightSearcherService
|
||||||
|
|
||||||
if (!selectedRequest) return
|
if (!selectedRequest) return
|
||||||
|
|
||||||
const collectionID = result.id
|
const collectionID = selectedRequest.collectionID
|
||||||
|
|
||||||
if (!collectionID) return
|
if (!collectionID) return
|
||||||
|
|
||||||
inheritedProperties =
|
inheritedProperties =
|
||||||
this.teamsSearch.cascadeParentCollectionForHeaderAuthForSearchResults(
|
this.teamsSearch.cascadeParentCollectionForPropertiesForSearchResults(
|
||||||
collectionID
|
collectionID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
|
HoppCollectionVariable,
|
||||||
HoppRESTHeaders,
|
HoppRESTHeaders,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
|
|
@ -15,6 +16,7 @@ import {
|
||||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||||
import { HoppTestData, HoppTestResult } from "~/helpers/types/HoppTestResult"
|
import { HoppTestData, HoppTestResult } from "~/helpers/types/HoppTestResult"
|
||||||
import { HoppTab } from "../tab"
|
import { HoppTab } from "../tab"
|
||||||
|
import { populateValuesInInheritedCollectionVars } from "~/helpers/utils/inheritedCollectionVarTransformer"
|
||||||
|
|
||||||
export type TestRunnerOptions = {
|
export type TestRunnerOptions = {
|
||||||
stopRef: Ref<boolean>
|
stopRef: Ref<boolean>
|
||||||
|
|
@ -59,6 +61,7 @@ export class TestRunnerService extends Service {
|
||||||
headers: collection.headers,
|
headers: collection.headers,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
this.runTestCollection(tab, collection, options)
|
this.runTestCollection(tab, collection, options)
|
||||||
|
|
@ -87,7 +90,9 @@ export class TestRunnerService extends Service {
|
||||||
options: TestRunnerOptions,
|
options: TestRunnerOptions,
|
||||||
parentPath: number[] = [],
|
parentPath: number[] = [],
|
||||||
parentHeaders?: HoppRESTHeaders,
|
parentHeaders?: HoppRESTHeaders,
|
||||||
parentAuth?: HoppRESTRequest["auth"]
|
parentAuth?: HoppRESTRequest["auth"],
|
||||||
|
parentVariables: HoppCollection["variables"] = [],
|
||||||
|
parentID?: string
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
// Compute inherited auth and headers for this collection
|
// Compute inherited auth and headers for this collection
|
||||||
|
|
@ -101,6 +106,17 @@ export class TestRunnerService extends Service {
|
||||||
...collection.headers,
|
...collection.headers,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const inheritedVariables = [
|
||||||
|
...(populateValuesInInheritedCollectionVars(
|
||||||
|
parentVariables,
|
||||||
|
parentID || collection._ref_id || collection.id
|
||||||
|
) || []),
|
||||||
|
...(populateValuesInInheritedCollectionVars(
|
||||||
|
collection.variables,
|
||||||
|
collection._ref_id || collection.id
|
||||||
|
) || []),
|
||||||
|
]
|
||||||
|
|
||||||
// Process folders progressively
|
// Process folders progressively
|
||||||
for (let i = 0; i < collection.folders.length; i++) {
|
for (let i = 0; i < collection.folders.length; i++) {
|
||||||
if (options.stopRef?.value) {
|
if (options.stopRef?.value) {
|
||||||
|
|
@ -129,7 +145,9 @@ export class TestRunnerService extends Service {
|
||||||
options,
|
options,
|
||||||
currentPath,
|
currentPath,
|
||||||
inheritedHeaders,
|
inheritedHeaders,
|
||||||
inheritedAuth
|
inheritedAuth,
|
||||||
|
inheritedVariables,
|
||||||
|
collection._ref_id || collection.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +183,8 @@ export class TestRunnerService extends Service {
|
||||||
finalRequest,
|
finalRequest,
|
||||||
collection,
|
collection,
|
||||||
options,
|
options,
|
||||||
currentPath
|
currentPath,
|
||||||
|
inheritedVariables
|
||||||
)
|
)
|
||||||
|
|
||||||
if (options.delay && options.delay > 0) {
|
if (options.delay && options.delay > 0) {
|
||||||
|
|
@ -255,7 +274,8 @@ export class TestRunnerService extends Service {
|
||||||
request: TestRunnerRequest,
|
request: TestRunnerRequest,
|
||||||
collection: HoppCollection,
|
collection: HoppCollection,
|
||||||
options: TestRunnerOptions,
|
options: TestRunnerOptions,
|
||||||
path: number[]
|
path: number[],
|
||||||
|
inheritedVariables: HoppCollectionVariable[] = []
|
||||||
) {
|
) {
|
||||||
if (options.stopRef?.value) {
|
if (options.stopRef?.value) {
|
||||||
throw new Error("Test execution stopped")
|
throw new Error("Test execution stopped")
|
||||||
|
|
@ -270,7 +290,8 @@ export class TestRunnerService extends Service {
|
||||||
|
|
||||||
const results = await runTestRunnerRequest(
|
const results = await runTestRunnerRequest(
|
||||||
request,
|
request,
|
||||||
options.keepVariableValues
|
options.keepVariableValues,
|
||||||
|
inheritedVariables
|
||||||
)
|
)
|
||||||
|
|
||||||
if (options.stopRef?.value) {
|
if (options.stopRef?.value) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ import V6_VERSION from "./v/6"
|
||||||
import V7_VERSION from "./v/7"
|
import V7_VERSION from "./v/7"
|
||||||
import V8_VERSION from "./v/8"
|
import V8_VERSION from "./v/8"
|
||||||
import V9_VERSION from "./v/9"
|
import V9_VERSION from "./v/9"
|
||||||
|
import V10_VERSION from "./v/10"
|
||||||
|
|
||||||
|
export { CollectionVariable } from "./v/10"
|
||||||
|
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { translateToNewRequest } from "../rest"
|
import { translateToNewRequest } from "../rest"
|
||||||
|
|
@ -20,7 +23,7 @@ const versionedObject = z.object({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const HoppCollection = createVersionedEntity({
|
export const HoppCollection = createVersionedEntity({
|
||||||
latestVersion: 9,
|
latestVersion: 10,
|
||||||
versionMap: {
|
versionMap: {
|
||||||
1: V1_VERSION,
|
1: V1_VERSION,
|
||||||
2: V2_VERSION,
|
2: V2_VERSION,
|
||||||
|
|
@ -31,6 +34,7 @@ export const HoppCollection = createVersionedEntity({
|
||||||
7: V7_VERSION,
|
7: V7_VERSION,
|
||||||
8: V8_VERSION,
|
8: V8_VERSION,
|
||||||
9: V9_VERSION,
|
9: V9_VERSION,
|
||||||
|
10: V10_VERSION,
|
||||||
},
|
},
|
||||||
getVersion(data) {
|
getVersion(data) {
|
||||||
const versionCheck = versionedObject.safeParse(data)
|
const versionCheck = versionedObject.safeParse(data)
|
||||||
|
|
@ -46,7 +50,11 @@ export const HoppCollection = createVersionedEntity({
|
||||||
|
|
||||||
export type HoppCollection = InferredEntity<typeof HoppCollection>
|
export type HoppCollection = InferredEntity<typeof HoppCollection>
|
||||||
|
|
||||||
export const CollectionSchemaVersion = 9
|
export type HoppCollectionVariable = InferredEntity<
|
||||||
|
typeof HoppCollection
|
||||||
|
>["variables"][number]
|
||||||
|
|
||||||
|
export const CollectionSchemaVersion = 10
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a Collection object. This ignores the version number object
|
* Generates a Collection object. This ignores the version number object
|
||||||
|
|
@ -74,6 +82,7 @@ export function translateToNewRESTCollection(x: any): HoppCollection {
|
||||||
|
|
||||||
const auth = x.auth ?? { authType: "inherit", authActive: true }
|
const auth = x.auth ?? { authType: "inherit", authActive: true }
|
||||||
const headers = x.headers ?? []
|
const headers = x.headers ?? []
|
||||||
|
const variables = x.variables ?? []
|
||||||
|
|
||||||
const obj = makeCollection({
|
const obj = makeCollection({
|
||||||
name,
|
name,
|
||||||
|
|
@ -81,6 +90,7 @@ export function translateToNewRESTCollection(x: any): HoppCollection {
|
||||||
requests,
|
requests,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
|
variables,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (x.id) obj.id = x.id
|
if (x.id) obj.id = x.id
|
||||||
|
|
@ -102,6 +112,7 @@ export function translateToNewGQLCollection(x: any): HoppCollection {
|
||||||
|
|
||||||
const auth = x.auth ?? { authType: "inherit", authActive: true }
|
const auth = x.auth ?? { authType: "inherit", authActive: true }
|
||||||
const headers = x.headers ?? []
|
const headers = x.headers ?? []
|
||||||
|
const variables = x.variables ?? []
|
||||||
|
|
||||||
const obj = makeCollection({
|
const obj = makeCollection({
|
||||||
name,
|
name,
|
||||||
|
|
@ -109,6 +120,7 @@ export function translateToNewGQLCollection(x: any): HoppCollection {
|
||||||
requests,
|
requests,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
|
variables,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (x.id) obj.id = x.id
|
if (x.id) obj.id = x.id
|
||||||
|
|
|
||||||
54
packages/hoppscotch-data/src/collection/v/10.ts
Normal file
54
packages/hoppscotch-data/src/collection/v/10.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { defineVersion, entityRefUptoVersion } from "verzod"
|
||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { HoppCollection } from ".."
|
||||||
|
import { v9_baseCollectionSchema } from "./9"
|
||||||
|
|
||||||
|
export const CollectionVariable = z.object({
|
||||||
|
key: z.string(),
|
||||||
|
initialValue: z.string(),
|
||||||
|
currentValue: z.string(),
|
||||||
|
secret: z.boolean(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type CollectionVariable = z.infer<typeof CollectionVariable>
|
||||||
|
|
||||||
|
export const v10_baseCollectionSchema = v9_baseCollectionSchema.extend({
|
||||||
|
v: z.literal(10),
|
||||||
|
variables: z.array(CollectionVariable),
|
||||||
|
})
|
||||||
|
|
||||||
|
type Input = z.input<typeof v10_baseCollectionSchema> & {
|
||||||
|
folders: Input[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = z.output<typeof v10_baseCollectionSchema> & {
|
||||||
|
folders: Output[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const V10_SCHEMA = v10_baseCollectionSchema.extend({
|
||||||
|
folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 10))),
|
||||||
|
}) as z.ZodType<Output, z.ZodTypeDef, Input>
|
||||||
|
|
||||||
|
export default defineVersion({
|
||||||
|
initial: false,
|
||||||
|
schema: V10_SCHEMA,
|
||||||
|
up(old: z.infer<typeof V10_SCHEMA>) {
|
||||||
|
const result: z.infer<typeof V10_SCHEMA> = {
|
||||||
|
...old,
|
||||||
|
v: 10 as const,
|
||||||
|
variables: [],
|
||||||
|
folders: old.folders.map((folder) => {
|
||||||
|
const result = HoppCollection.safeParseUpToVersion(folder, 10)
|
||||||
|
|
||||||
|
if (result.type !== "ok") {
|
||||||
|
throw new Error("Failed to migrate child collections")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.value
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -2,7 +2,6 @@ import { z } from "zod"
|
||||||
import { defineVersion } from "verzod"
|
import { defineVersion } from "verzod"
|
||||||
import { V1_SCHEMA } from "./1"
|
import { V1_SCHEMA } from "./1"
|
||||||
|
|
||||||
// add initialValue and currentValue to the schema and delete value and add it to initialValue and currentValue
|
|
||||||
export const V2_SCHEMA = V1_SCHEMA.extend({
|
export const V2_SCHEMA = V1_SCHEMA.extend({
|
||||||
v: z.literal(2),
|
v: z.literal(2),
|
||||||
variables: z.array(
|
variables: z.array(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
mutation CreateGQLChildUserCollection(
|
mutation CreateGQLChildUserCollection(
|
||||||
$title: String!
|
$title: String!
|
||||||
$parentUserCollectionID: ID!
|
$parentUserCollectionID: ID!
|
||||||
|
$data: String
|
||||||
) {
|
) {
|
||||||
createGQLChildUserCollection(
|
createGQLChildUserCollection(
|
||||||
title: $title
|
title: $title
|
||||||
parentUserCollectionID: $parentUserCollectionID
|
parentUserCollectionID: $parentUserCollectionID
|
||||||
|
data: $data
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mutation CreateGQLRootUserCollection($title: String!) {
|
mutation CreateGQLRootUserCollection($title: String!, $data: String) {
|
||||||
createGQLRootUserCollection(title: $title) {
|
createGQLRootUserCollection(title: $title, data: $data) {
|
||||||
id
|
id
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
mutation CreateRESTChildUserCollection(
|
mutation CreateRESTChildUserCollection(
|
||||||
$title: String!
|
$title: String!
|
||||||
$parentUserCollectionID: ID!
|
$parentUserCollectionID: ID!
|
||||||
|
$data: String
|
||||||
) {
|
) {
|
||||||
createRESTChildUserCollection(
|
createRESTChildUserCollection(
|
||||||
title: $title
|
title: $title
|
||||||
parentUserCollectionID: $parentUserCollectionID
|
parentUserCollectionID: $parentUserCollectionID
|
||||||
|
data: $data
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mutation CreateRESTRootUserCollection($title: String!) {
|
mutation CreateRESTRootUserCollection($title: String!, $data: String) {
|
||||||
createRESTRootUserCollection(title: $title) {
|
createRESTRootUserCollection(title: $title, data: $data) {
|
||||||
id
|
id
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
mutation UpdateUserCollection(
|
||||||
|
$userCollectionID: ID!
|
||||||
|
$newTitle: String
|
||||||
|
$data: String
|
||||||
|
) {
|
||||||
|
updateUserCollection(
|
||||||
|
userCollectionID: $userCollectionID
|
||||||
|
newTitle: $newTitle
|
||||||
|
data: $data
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -53,6 +53,9 @@ import {
|
||||||
UpdateRestUserRequestDocument,
|
UpdateRestUserRequestDocument,
|
||||||
UpdateRestUserRequestMutation,
|
UpdateRestUserRequestMutation,
|
||||||
UpdateRestUserRequestMutationVariables,
|
UpdateRestUserRequestMutationVariables,
|
||||||
|
UpdateUserCollectionDocument,
|
||||||
|
UpdateUserCollectionMutation,
|
||||||
|
UpdateUserCollectionMutationVariables,
|
||||||
UpdateUserCollectionOrderDocument,
|
UpdateUserCollectionOrderDocument,
|
||||||
UpdateUserCollectionOrderMutation,
|
UpdateUserCollectionOrderMutation,
|
||||||
UpdateUserCollectionOrderMutationVariables,
|
UpdateUserCollectionOrderMutationVariables,
|
||||||
|
|
@ -68,22 +71,24 @@ import {
|
||||||
UserRequestUpdatedDocument,
|
UserRequestUpdatedDocument,
|
||||||
} from "../../api/generated/graphql"
|
} from "../../api/generated/graphql"
|
||||||
|
|
||||||
export const createRESTRootUserCollection = (title: string) =>
|
export const createRESTRootUserCollection = (title: string, data?: string) =>
|
||||||
runMutation<
|
runMutation<
|
||||||
CreateRestRootUserCollectionMutation,
|
CreateRestRootUserCollectionMutation,
|
||||||
CreateRestRootUserCollectionMutationVariables,
|
CreateRestRootUserCollectionMutationVariables,
|
||||||
""
|
""
|
||||||
>(CreateRestRootUserCollectionDocument, {
|
>(CreateRestRootUserCollectionDocument, {
|
||||||
title,
|
title,
|
||||||
|
data,
|
||||||
})()
|
})()
|
||||||
|
|
||||||
export const createGQLRootUserCollection = (title: string) =>
|
export const createGQLRootUserCollection = (title: string, data?: string) =>
|
||||||
runMutation<
|
runMutation<
|
||||||
CreateGqlRootUserCollectionMutation,
|
CreateGqlRootUserCollectionMutation,
|
||||||
CreateGqlRootUserCollectionMutationVariables,
|
CreateGqlRootUserCollectionMutationVariables,
|
||||||
""
|
""
|
||||||
>(CreateGqlRootUserCollectionDocument, {
|
>(CreateGqlRootUserCollectionDocument, {
|
||||||
title,
|
title,
|
||||||
|
data,
|
||||||
})()
|
})()
|
||||||
|
|
||||||
export const createRESTUserRequest = (
|
export const createRESTUserRequest = (
|
||||||
|
|
@ -118,7 +123,8 @@ export const createGQLUserRequest = (
|
||||||
|
|
||||||
export const createRESTChildUserCollection = (
|
export const createRESTChildUserCollection = (
|
||||||
title: string,
|
title: string,
|
||||||
parentUserCollectionID: string
|
parentUserCollectionID: string,
|
||||||
|
data?: string
|
||||||
) =>
|
) =>
|
||||||
runMutation<
|
runMutation<
|
||||||
CreateRestChildUserCollectionMutation,
|
CreateRestChildUserCollectionMutation,
|
||||||
|
|
@ -127,11 +133,13 @@ export const createRESTChildUserCollection = (
|
||||||
>(CreateRestChildUserCollectionDocument, {
|
>(CreateRestChildUserCollectionDocument, {
|
||||||
title,
|
title,
|
||||||
parentUserCollectionID,
|
parentUserCollectionID,
|
||||||
|
data,
|
||||||
})()
|
})()
|
||||||
|
|
||||||
export const createGQLChildUserCollection = (
|
export const createGQLChildUserCollection = (
|
||||||
title: string,
|
title: string,
|
||||||
parentUserCollectionID: string
|
parentUserCollectionID: string,
|
||||||
|
data?: string
|
||||||
) =>
|
) =>
|
||||||
runMutation<
|
runMutation<
|
||||||
CreateGqlChildUserCollectionMutation,
|
CreateGqlChildUserCollectionMutation,
|
||||||
|
|
@ -140,6 +148,7 @@ export const createGQLChildUserCollection = (
|
||||||
>(CreateGqlChildUserCollectionDocument, {
|
>(CreateGqlChildUserCollectionDocument, {
|
||||||
title,
|
title,
|
||||||
parentUserCollectionID,
|
parentUserCollectionID,
|
||||||
|
data,
|
||||||
})()
|
})()
|
||||||
|
|
||||||
export const deleteUserCollection = (userCollectionID: string) =>
|
export const deleteUserCollection = (userCollectionID: string) =>
|
||||||
|
|
@ -161,6 +170,17 @@ export const renameUserCollection = (
|
||||||
""
|
""
|
||||||
>(RenameUserCollectionDocument, { userCollectionID, newTitle })()
|
>(RenameUserCollectionDocument, { userCollectionID, newTitle })()
|
||||||
|
|
||||||
|
export const updateUserCollection = (
|
||||||
|
userCollectionID: string,
|
||||||
|
newTitle?: string,
|
||||||
|
data?: string
|
||||||
|
) =>
|
||||||
|
runMutation<
|
||||||
|
UpdateUserCollectionMutation,
|
||||||
|
UpdateUserCollectionMutationVariables,
|
||||||
|
""
|
||||||
|
>(UpdateUserCollectionDocument, { userCollectionID, newTitle, data })()
|
||||||
|
|
||||||
export const moveUserCollection = (
|
export const moveUserCollection = (
|
||||||
sourceCollectionID: string,
|
sourceCollectionID: string,
|
||||||
destinationCollectionID?: string
|
destinationCollectionID?: string
|
||||||
|
|
|
||||||
|
|
@ -130,11 +130,12 @@ function exportedCollectionToHoppCollection(
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
v: 9,
|
v: 10,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -182,6 +183,7 @@ function exportedCollectionToHoppCollection(
|
||||||
}),
|
}),
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const gqlCollection = collection as ExportedUserCollectionGQL
|
const gqlCollection = collection as ExportedUserCollectionGQL
|
||||||
|
|
@ -192,11 +194,12 @@ function exportedCollectionToHoppCollection(
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
v: 9,
|
v: 10,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -224,6 +227,7 @@ function exportedCollectionToHoppCollection(
|
||||||
}),
|
}),
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -366,6 +370,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
runDispatchWithOutSyncing(() => {
|
runDispatchWithOutSyncing(() => {
|
||||||
|
|
@ -374,17 +379,19 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 9,
|
v: 10,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
})
|
})
|
||||||
: addRESTCollection({
|
: addRESTCollection({
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 9,
|
v: 10,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const localIndex = collectionStore.value.state.length - 1
|
const localIndex = collectionStore.value.state.length - 1
|
||||||
|
|
@ -587,12 +594,13 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Incoming data transformed to the respective internal representations
|
// Incoming data transformed to the respective internal representations
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
data && data != "null"
|
data && data != "null"
|
||||||
? JSON.parse(data)
|
? JSON.parse(data)
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
||||||
|
|
@ -607,9 +615,10 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 9,
|
v: 10,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
variables: variables ?? [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// only folders will have parent collection id
|
// only folders will have parent collection id
|
||||||
|
|
@ -1023,10 +1032,14 @@ function transformDuplicatedCollections(
|
||||||
requests: userRequests,
|
requests: userRequests,
|
||||||
title: name,
|
title: name,
|
||||||
}) => {
|
}) => {
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
data && data !== "null"
|
data && data !== "null"
|
||||||
? JSON.parse(data)
|
? JSON.parse(data)
|
||||||
: { auth: { authType: "inherit", authActive: true }, headers: [] }
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: true },
|
||||||
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
}
|
||||||
|
|
||||||
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
||||||
|
|
||||||
|
|
@ -1037,9 +1050,10 @@ function transformDuplicatedCollections(
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 9,
|
v: 10,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
variables: variables ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,11 @@ import {
|
||||||
settingsStore,
|
settingsStore,
|
||||||
} from "@hoppscotch/common/newstore/settings"
|
} from "@hoppscotch/common/newstore/settings"
|
||||||
|
|
||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
import {
|
||||||
|
generateUniqueRefId,
|
||||||
|
HoppCollection,
|
||||||
|
HoppRESTRequest,
|
||||||
|
} from "@hoppscotch/data"
|
||||||
|
|
||||||
import { getSyncInitFunction } from "../../lib/sync"
|
import { getSyncInitFunction } from "../../lib/sync"
|
||||||
|
|
||||||
|
|
@ -25,6 +29,7 @@ import {
|
||||||
moveUserCollection,
|
moveUserCollection,
|
||||||
moveUserRequest,
|
moveUserRequest,
|
||||||
renameUserCollection,
|
renameUserCollection,
|
||||||
|
updateUserCollection,
|
||||||
updateUserCollectionOrder,
|
updateUserCollectionOrder,
|
||||||
} from "./collections.api"
|
} from "./collections.api"
|
||||||
|
|
||||||
|
|
@ -47,27 +52,84 @@ const recursivelySyncCollections = async (
|
||||||
|
|
||||||
// if parentUserCollectionID does not exist, create the collection as a root collection
|
// if parentUserCollectionID does not exist, create the collection as a root collection
|
||||||
if (!parentUserCollectionID) {
|
if (!parentUserCollectionID) {
|
||||||
const res = await createRESTRootUserCollection(collection.name)
|
const data = {
|
||||||
|
auth: collection.auth ?? {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
|
}
|
||||||
|
const res = await createRESTRootUserCollection(
|
||||||
|
collection.name,
|
||||||
|
JSON.stringify(data)
|
||||||
|
)
|
||||||
|
|
||||||
if (E.isRight(res)) {
|
if (E.isRight(res)) {
|
||||||
parentCollectionID = res.right.createRESTRootUserCollection.id
|
parentCollectionID = res.right.createRESTRootUserCollection.id
|
||||||
|
|
||||||
|
const returnedData = res.right.createRESTRootUserCollection.data
|
||||||
|
? JSON.parse(res.right.createRESTRootUserCollection.data)
|
||||||
|
: {
|
||||||
|
auth: {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
|
||||||
collection.id = parentCollectionID
|
collection.id = parentCollectionID
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
|
collection.auth = returnedData.auth
|
||||||
|
collection.headers = returnedData.headers
|
||||||
|
collection.variables = returnedData.variables
|
||||||
removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath)
|
removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath)
|
||||||
} else {
|
} else {
|
||||||
parentCollectionID = undefined
|
parentCollectionID = undefined
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if parentUserCollectionID exists, create the collection as a child collection
|
// if parentUserCollectionID exists, create the collection as a child collection
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
auth: collection.auth ?? {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
|
}
|
||||||
|
|
||||||
const res = await createRESTChildUserCollection(
|
const res = await createRESTChildUserCollection(
|
||||||
collection.name,
|
collection.name,
|
||||||
parentUserCollectionID
|
parentUserCollectionID,
|
||||||
|
JSON.stringify(data)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (E.isRight(res)) {
|
if (E.isRight(res)) {
|
||||||
const childCollectionId = res.right.createRESTChildUserCollection.id
|
const childCollectionId = res.right.createRESTChildUserCollection.id
|
||||||
|
|
||||||
|
const returnedData = res.right.createRESTChildUserCollection.data
|
||||||
|
? JSON.parse(res.right.createRESTChildUserCollection.data)
|
||||||
|
: {
|
||||||
|
auth: {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: [],
|
||||||
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
|
}
|
||||||
|
|
||||||
collection.id = childCollectionId
|
collection.id = childCollectionId
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
|
collection.auth = returnedData.auth
|
||||||
|
collection.headers = returnedData.headers
|
||||||
|
parentCollectionID = childCollectionId
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
|
||||||
removeDuplicateRESTCollectionOrFolder(
|
removeDuplicateRESTCollectionOrFolder(
|
||||||
childCollectionId,
|
childCollectionId,
|
||||||
|
|
@ -155,8 +217,15 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
[collectionIndex]
|
[collectionIndex]
|
||||||
)?.id
|
)?.id
|
||||||
|
|
||||||
if (collectionID && collection.name) {
|
const data = {
|
||||||
renameUserCollection(collectionID, collection.name)
|
auth: collection.auth,
|
||||||
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectionID) {
|
||||||
|
updateUserCollection(collectionID, collection.name, JSON.stringify(data))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async addFolder({ name, path }) {
|
async addFolder({ name, path }) {
|
||||||
|
|
@ -195,9 +264,15 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
)?.id
|
)?.id
|
||||||
|
|
||||||
const folderName = folder.name
|
const folderName = folder.name
|
||||||
|
const data = {
|
||||||
|
auth: folder.auth,
|
||||||
|
headers: folder.headers,
|
||||||
|
variables: folder.variables,
|
||||||
|
_ref_id: folder._ref_id,
|
||||||
|
}
|
||||||
|
|
||||||
if (folderID && folderName) {
|
if (folderID) {
|
||||||
renameUserCollection(folderID, folderName)
|
updateUserCollection(folderID, folderName, JSON.stringify(data))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async removeFolder({ folderID }) {
|
async removeFolder({ folderID }) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@ import {
|
||||||
settingsStore,
|
settingsStore,
|
||||||
} from "@hoppscotch/common/newstore/settings"
|
} from "@hoppscotch/common/newstore/settings"
|
||||||
|
|
||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
import {
|
||||||
|
generateUniqueRefId,
|
||||||
|
HoppCollection,
|
||||||
|
HoppRESTRequest,
|
||||||
|
} from "@hoppscotch/data"
|
||||||
|
|
||||||
import { getSyncInitFunction } from "../../lib/sync"
|
import { getSyncInitFunction } from "../../lib/sync"
|
||||||
|
|
||||||
|
|
@ -22,6 +26,7 @@ import {
|
||||||
deleteUserRequest,
|
deleteUserRequest,
|
||||||
editGQLUserRequest,
|
editGQLUserRequest,
|
||||||
renameUserCollection,
|
renameUserCollection,
|
||||||
|
updateUserCollection,
|
||||||
} from "./collections.api"
|
} from "./collections.api"
|
||||||
|
|
||||||
import * as E from "fp-ts/Either"
|
import * as E from "fp-ts/Either"
|
||||||
|
|
@ -44,12 +49,41 @@ const recursivelySyncCollections = async (
|
||||||
|
|
||||||
// if parentUserCollectionID does not exist, create the collection as a root collection
|
// if parentUserCollectionID does not exist, create the collection as a root collection
|
||||||
if (!parentUserCollectionID) {
|
if (!parentUserCollectionID) {
|
||||||
const res = await createGQLRootUserCollection(collection.name)
|
const data = {
|
||||||
|
auth: collection.auth ?? {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id ?? generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
const res = await createGQLRootUserCollection(
|
||||||
|
collection.name,
|
||||||
|
JSON.stringify(data)
|
||||||
|
)
|
||||||
|
|
||||||
if (E.isRight(res)) {
|
if (E.isRight(res)) {
|
||||||
parentCollectionID = res.right.createGQLRootUserCollection.id
|
parentCollectionID = res.right.createGQLRootUserCollection.id
|
||||||
|
|
||||||
|
const returnedData = res.right.createGQLRootUserCollection.data
|
||||||
|
? JSON.parse(res.right.createGQLRootUserCollection.data)
|
||||||
|
: {
|
||||||
|
auth: {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
|
||||||
collection.id = parentCollectionID
|
collection.id = parentCollectionID
|
||||||
|
collection.auth = returnedData.auth
|
||||||
|
collection.headers = returnedData.headers
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
|
|
||||||
removeDuplicateGraphqlCollectionOrFolder(
|
removeDuplicateGraphqlCollectionOrFolder(
|
||||||
parentCollectionID,
|
parentCollectionID,
|
||||||
collectionPath
|
collectionPath
|
||||||
|
|
@ -59,15 +93,44 @@ const recursivelySyncCollections = async (
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if parentUserCollectionID exists, create the collection as a child collection
|
// if parentUserCollectionID exists, create the collection as a child collection
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
auth: collection.auth ?? {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id ?? generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
|
||||||
const res = await createGQLChildUserCollection(
|
const res = await createGQLChildUserCollection(
|
||||||
collection.name,
|
collection.name,
|
||||||
parentUserCollectionID
|
parentUserCollectionID,
|
||||||
|
JSON.stringify(data)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (E.isRight(res)) {
|
if (E.isRight(res)) {
|
||||||
const childCollectionId = res.right.createGQLChildUserCollection.id
|
const childCollectionId = res.right.createGQLChildUserCollection.id
|
||||||
|
|
||||||
|
const returnedData = res.right.createGQLChildUserCollection.data
|
||||||
|
? JSON.parse(res.right.createGQLChildUserCollection.data)
|
||||||
|
: {
|
||||||
|
auth: {
|
||||||
|
authType: "inherit",
|
||||||
|
authActive: true,
|
||||||
|
},
|
||||||
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
|
||||||
collection.id = childCollectionId
|
collection.id = childCollectionId
|
||||||
|
collection.auth = returnedData.auth
|
||||||
|
collection.headers = returnedData.headers
|
||||||
|
parentCollectionID = childCollectionId
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
|
|
||||||
removeDuplicateGraphqlCollectionOrFolder(
|
removeDuplicateGraphqlCollectionOrFolder(
|
||||||
childCollectionId,
|
childCollectionId,
|
||||||
|
|
@ -158,8 +221,15 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
[collectionIndex]
|
[collectionIndex]
|
||||||
)?.id
|
)?.id
|
||||||
|
|
||||||
if (collectionID && collection.name) {
|
const data = {
|
||||||
renameUserCollection(collectionID, collection.name)
|
auth: collection.auth,
|
||||||
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
|
_ref_id: collection._ref_id ?? generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectionID) {
|
||||||
|
updateUserCollection(collectionID, collection.name, JSON.stringify(data))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async addFolder({ name, path }) {
|
async addFolder({ name, path }) {
|
||||||
|
|
@ -197,8 +267,15 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
path.split("/").map((index) => parseInt(index))
|
path.split("/").map((index) => parseInt(index))
|
||||||
)?.id
|
)?.id
|
||||||
|
|
||||||
if (folderBackendId && folder.name) {
|
const data = {
|
||||||
renameUserCollection(folderBackendId, folder.name)
|
auth: folder.auth,
|
||||||
|
headers: folder.headers,
|
||||||
|
variables: folder.variables,
|
||||||
|
_ref_id: folder._ref_id ?? generateUniqueRefId("coll"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (folderBackendId) {
|
||||||
|
updateUserCollection(folderBackendId, folder.name, JSON.stringify(data))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async removeFolder({ folderID }) {
|
async removeFolder({ folderID }) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@ import {
|
||||||
settingsStore,
|
settingsStore,
|
||||||
} from "@hoppscotch/common/newstore/settings"
|
} from "@hoppscotch/common/newstore/settings"
|
||||||
|
|
||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
import {
|
||||||
|
generateUniqueRefId,
|
||||||
|
HoppCollection,
|
||||||
|
HoppRESTRequest,
|
||||||
|
} from "@hoppscotch/data"
|
||||||
|
|
||||||
import { getSyncInitFunction } from "@lib/sync"
|
import { getSyncInitFunction } from "@lib/sync"
|
||||||
|
|
||||||
|
|
@ -52,6 +56,8 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
const res = await createGQLRootUserCollection(
|
const res = await createGQLRootUserCollection(
|
||||||
collection.name,
|
collection.name,
|
||||||
|
|
@ -69,11 +75,15 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: collection._ref_id ?? generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
collection.id = parentCollectionID
|
collection.id = parentCollectionID
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
|
|
||||||
removeDuplicateGraphqlCollectionOrFolder(
|
removeDuplicateGraphqlCollectionOrFolder(
|
||||||
parentCollectionID,
|
parentCollectionID,
|
||||||
|
|
@ -91,6 +101,8 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await createGQLChildUserCollection(
|
const res = await createGQLChildUserCollection(
|
||||||
|
|
@ -110,12 +122,16 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: collection._ref_id ?? generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
collection.id = childCollectionId
|
collection.id = childCollectionId
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
parentCollectionID = childCollectionId
|
parentCollectionID = childCollectionId
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
|
|
||||||
removeDuplicateGraphqlCollectionOrFolder(
|
removeDuplicateGraphqlCollectionOrFolder(
|
||||||
childCollectionId,
|
childCollectionId,
|
||||||
|
|
@ -209,6 +225,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: collection.auth,
|
auth: collection.auth,
|
||||||
headers: collection.headers,
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionID) {
|
if (collectionID) {
|
||||||
|
|
@ -253,6 +271,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: folder.auth,
|
auth: folder.auth,
|
||||||
headers: folder.headers,
|
headers: folder.headers,
|
||||||
|
variables: folder.variables,
|
||||||
|
_ref_id: folder._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folderBackendId) {
|
if (folderBackendId) {
|
||||||
|
|
|
||||||
|
|
@ -135,12 +135,13 @@ function exportedCollectionToHoppCollection(
|
||||||
auth: { authType: "inherit", authActive: false },
|
auth: { authType: "inherit", authActive: false },
|
||||||
headers: [],
|
headers: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 9,
|
v: 10,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -188,6 +189,7 @@ function exportedCollectionToHoppCollection(
|
||||||
}),
|
}),
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const gqlCollection = collection as ExportedUserCollectionGQL
|
const gqlCollection = collection as ExportedUserCollectionGQL
|
||||||
|
|
@ -199,12 +201,13 @@ function exportedCollectionToHoppCollection(
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 9,
|
v: 10,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -232,6 +235,7 @@ function exportedCollectionToHoppCollection(
|
||||||
}),
|
}),
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,6 +379,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
runDispatchWithOutSyncing(() => {
|
runDispatchWithOutSyncing(() => {
|
||||||
|
|
@ -383,19 +388,21 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 9,
|
v: 10,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
})
|
})
|
||||||
: addRESTCollection({
|
: addRESTCollection({
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 9,
|
v: 10,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const localIndex = collectionStore.value.state.length - 1
|
const localIndex = collectionStore.value.state.length - 1
|
||||||
|
|
@ -598,12 +605,13 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Incoming data transformed to the respective internal representations
|
// Incoming data transformed to the respective internal representations
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
data && data != "null"
|
data && data != "null"
|
||||||
? JSON.parse(data)
|
? JSON.parse(data)
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
// Duplicated collection will have a unique ref id
|
// Duplicated collection will have a unique ref id
|
||||||
const _ref_id = generateUniqueRefId("coll")
|
const _ref_id = generateUniqueRefId("coll")
|
||||||
|
|
@ -620,10 +628,11 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 9,
|
v: 10,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
variables: variables ?? [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// only folders will have parent collection id
|
// only folders will have parent collection id
|
||||||
|
|
@ -1037,10 +1046,14 @@ function transformDuplicatedCollections(
|
||||||
requests: userRequests,
|
requests: userRequests,
|
||||||
title: name,
|
title: name,
|
||||||
}) => {
|
}) => {
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
data && data !== "null"
|
data && data !== "null"
|
||||||
? JSON.parse(data)
|
? JSON.parse(data)
|
||||||
: { auth: { authType: "inherit", authActive: true }, headers: [] }
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: true },
|
||||||
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
}
|
||||||
|
|
||||||
const _ref_id = generateUniqueRefId("coll")
|
const _ref_id = generateUniqueRefId("coll")
|
||||||
|
|
||||||
|
|
@ -1054,9 +1067,10 @@ function transformDuplicatedCollections(
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
v: 9,
|
v: 10,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
variables: variables ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
_ref_id: collection._ref_id,
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
const res = await createRESTRootUserCollection(
|
const res = await createRESTRootUserCollection(
|
||||||
|
|
@ -74,6 +75,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +83,7 @@ const recursivelySyncCollections = async (
|
||||||
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
|
collection.variables = returnedData.variables
|
||||||
removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath)
|
removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath)
|
||||||
} else {
|
} else {
|
||||||
parentCollectionID = undefined
|
parentCollectionID = undefined
|
||||||
|
|
@ -93,6 +96,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
_ref_id: collection._ref_id,
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,6 +117,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +126,7 @@ const recursivelySyncCollections = async (
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
parentCollectionID = childCollectionId
|
parentCollectionID = childCollectionId
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
|
||||||
removeDuplicateRESTCollectionOrFolder(
|
removeDuplicateRESTCollectionOrFolder(
|
||||||
childCollectionId,
|
childCollectionId,
|
||||||
|
|
@ -211,6 +217,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: collection.auth,
|
auth: collection.auth,
|
||||||
headers: collection.headers,
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionID) {
|
if (collectionID) {
|
||||||
|
|
@ -256,6 +264,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: folder.auth,
|
auth: folder.auth,
|
||||||
headers: folder.headers,
|
headers: folder.headers,
|
||||||
|
variables: folder.variables,
|
||||||
|
_ref_id: folder._ref_id,
|
||||||
}
|
}
|
||||||
if (folderID) {
|
if (folderID) {
|
||||||
updateUserCollection(folderID, folderName, JSON.stringify(data))
|
updateUserCollection(folderID, folderName, JSON.stringify(data))
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@ import {
|
||||||
settingsStore,
|
settingsStore,
|
||||||
} from "@hoppscotch/common/newstore/settings"
|
} from "@hoppscotch/common/newstore/settings"
|
||||||
|
|
||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
import {
|
||||||
|
generateUniqueRefId,
|
||||||
|
HoppCollection,
|
||||||
|
HoppRESTRequest,
|
||||||
|
} from "@hoppscotch/data"
|
||||||
|
|
||||||
import { getSyncInitFunction } from "@lib/sync"
|
import { getSyncInitFunction } from "@lib/sync"
|
||||||
|
|
||||||
|
|
@ -52,6 +56,8 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
const res = await createGQLRootUserCollection(
|
const res = await createGQLRootUserCollection(
|
||||||
collection.name,
|
collection.name,
|
||||||
|
|
@ -69,11 +75,15 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
collection.id = parentCollectionID
|
collection.id = parentCollectionID
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
|
||||||
removeDuplicateGraphqlCollectionOrFolder(
|
removeDuplicateGraphqlCollectionOrFolder(
|
||||||
parentCollectionID,
|
parentCollectionID,
|
||||||
|
|
@ -91,6 +101,8 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await createGQLChildUserCollection(
|
const res = await createGQLChildUserCollection(
|
||||||
|
|
@ -110,12 +122,16 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
collection.id = childCollectionId
|
collection.id = childCollectionId
|
||||||
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
parentCollectionID = childCollectionId
|
parentCollectionID = childCollectionId
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
|
||||||
removeDuplicateGraphqlCollectionOrFolder(
|
removeDuplicateGraphqlCollectionOrFolder(
|
||||||
childCollectionId,
|
childCollectionId,
|
||||||
|
|
@ -209,6 +225,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: collection.auth,
|
auth: collection.auth,
|
||||||
headers: collection.headers,
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionID) {
|
if (collectionID) {
|
||||||
|
|
@ -253,6 +271,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: folder.auth,
|
auth: folder.auth,
|
||||||
headers: folder.headers,
|
headers: folder.headers,
|
||||||
|
variables: folder.variables,
|
||||||
|
_ref_id: folder._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folderBackendId) {
|
if (folderBackendId) {
|
||||||
|
|
|
||||||
|
|
@ -135,12 +135,13 @@ function exportedCollectionToHoppCollection(
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 9,
|
v: 10,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -188,6 +189,7 @@ function exportedCollectionToHoppCollection(
|
||||||
}),
|
}),
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const gqlCollection = collection as ExportedUserCollectionGQL
|
const gqlCollection = collection as ExportedUserCollectionGQL
|
||||||
|
|
@ -199,12 +201,13 @@ function exportedCollectionToHoppCollection(
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 9,
|
v: 10,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -232,6 +235,7 @@ function exportedCollectionToHoppCollection(
|
||||||
}),
|
}),
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,6 +379,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
runDispatchWithOutSyncing(() => {
|
runDispatchWithOutSyncing(() => {
|
||||||
|
|
@ -383,19 +388,21 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 9,
|
v: 10,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
})
|
})
|
||||||
: addRESTCollection({
|
: addRESTCollection({
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 9,
|
v: 10,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
variables: data.variables ?? [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const localIndex = collectionStore.value.state.length - 1
|
const localIndex = collectionStore.value.state.length - 1
|
||||||
|
|
@ -598,12 +605,13 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Incoming data transformed to the respective internal representations
|
// Incoming data transformed to the respective internal representations
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
data && data != "null"
|
data && data != "null"
|
||||||
? JSON.parse(data)
|
? JSON.parse(data)
|
||||||
: {
|
: {
|
||||||
auth: { authType: "inherit", authActive: true },
|
auth: { authType: "inherit", authActive: true },
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
}
|
}
|
||||||
// Duplicated collection will have a unique ref id
|
// Duplicated collection will have a unique ref id
|
||||||
const _ref_id = generateUniqueRefId("coll")
|
const _ref_id = generateUniqueRefId("coll")
|
||||||
|
|
@ -620,10 +628,11 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 9,
|
v: 10,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
variables: variables ?? [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// only folders will have parent collection id
|
// only folders will have parent collection id
|
||||||
|
|
@ -1037,10 +1046,14 @@ function transformDuplicatedCollections(
|
||||||
requests: userRequests,
|
requests: userRequests,
|
||||||
title: name,
|
title: name,
|
||||||
}) => {
|
}) => {
|
||||||
const { auth, headers } =
|
const { auth, headers, variables } =
|
||||||
data && data !== "null"
|
data && data !== "null"
|
||||||
? JSON.parse(data)
|
? JSON.parse(data)
|
||||||
: { auth: { authType: "inherit", authActive: true }, headers: [] }
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: true },
|
||||||
|
headers: [],
|
||||||
|
variables: [],
|
||||||
|
}
|
||||||
|
|
||||||
const _ref_id = generateUniqueRefId("coll")
|
const _ref_id = generateUniqueRefId("coll")
|
||||||
|
|
||||||
|
|
@ -1054,9 +1067,10 @@ function transformDuplicatedCollections(
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
v: 9,
|
v: 10,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
variables: variables ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
_ref_id: collection._ref_id,
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
const res = await createRESTRootUserCollection(
|
const res = await createRESTRootUserCollection(
|
||||||
|
|
@ -74,6 +75,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +83,11 @@ const recursivelySyncCollections = async (
|
||||||
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
collection._ref_id = returnedData._ref_id ?? generateUniqueRefId("coll")
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath)
|
collection.variables = returnedData.variables
|
||||||
|
removeDuplicateRESTCollectionOrFolder(
|
||||||
|
parentCollectionID,
|
||||||
|
`${collectionPath}`
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parentCollectionID = undefined
|
parentCollectionID = undefined
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +99,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: collection.headers ?? [],
|
headers: collection.headers ?? [],
|
||||||
|
variables: collection.variables ?? [],
|
||||||
_ref_id: collection._ref_id,
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,6 +120,7 @@ const recursivelySyncCollections = async (
|
||||||
authActive: true,
|
authActive: true,
|
||||||
},
|
},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
variables: [],
|
||||||
_ref_id: generateUniqueRefId("coll"),
|
_ref_id: generateUniqueRefId("coll"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +129,7 @@ const recursivelySyncCollections = async (
|
||||||
collection.auth = returnedData.auth
|
collection.auth = returnedData.auth
|
||||||
collection.headers = returnedData.headers
|
collection.headers = returnedData.headers
|
||||||
parentCollectionID = childCollectionId
|
parentCollectionID = childCollectionId
|
||||||
|
collection.variables = returnedData.variables
|
||||||
|
|
||||||
removeDuplicateRESTCollectionOrFolder(
|
removeDuplicateRESTCollectionOrFolder(
|
||||||
childCollectionId,
|
childCollectionId,
|
||||||
|
|
@ -211,6 +220,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: collection.auth,
|
auth: collection.auth,
|
||||||
headers: collection.headers,
|
headers: collection.headers,
|
||||||
|
variables: collection.variables,
|
||||||
|
_ref_id: collection._ref_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionID) {
|
if (collectionID) {
|
||||||
|
|
@ -256,6 +267,8 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||||
const data = {
|
const data = {
|
||||||
auth: folder.auth,
|
auth: folder.auth,
|
||||||
headers: folder.headers,
|
headers: folder.headers,
|
||||||
|
variables: folder.variables,
|
||||||
|
_ref_id: folder._ref_id,
|
||||||
}
|
}
|
||||||
if (folderID) {
|
if (folderID) {
|
||||||
updateUserCollection(folderID, folderName, JSON.stringify(data))
|
updateUserCollection(folderID, folderName, JSON.stringify(data))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue