collections.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. import { pluck } from "rxjs/operators"
  2. import {
  3. HoppGQLRequest,
  4. HoppRESTRequest,
  5. HoppCollection,
  6. makeCollection,
  7. } from "@hoppscotch/data"
  8. import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
  9. import { getRESTSaveContext, setRESTSaveContext } from "./RESTSession"
  10. const defaultRESTCollectionState = {
  11. state: [
  12. makeCollection<HoppRESTRequest>({
  13. name: "My Collection",
  14. folders: [],
  15. requests: [],
  16. }),
  17. ],
  18. }
  19. const defaultGraphqlCollectionState = {
  20. state: [
  21. makeCollection<HoppGQLRequest>({
  22. name: "My GraphQL Collection",
  23. folders: [],
  24. requests: [],
  25. }),
  26. ],
  27. }
  28. type RESTCollectionStoreType = typeof defaultRESTCollectionState
  29. type GraphqlCollectionStoreType = typeof defaultGraphqlCollectionState
  30. function navigateToFolderWithIndexPath(
  31. collections: HoppCollection<HoppRESTRequest | HoppGQLRequest>[],
  32. indexPaths: number[]
  33. ) {
  34. if (indexPaths.length === 0) return null
  35. let target = collections[indexPaths.shift() as number]
  36. while (indexPaths.length > 0)
  37. target = target.folders[indexPaths.shift() as number]
  38. return target !== undefined ? target : null
  39. }
  40. const restCollectionDispatchers = defineDispatchers({
  41. setCollections(
  42. _: RESTCollectionStoreType,
  43. { entries }: { entries: HoppCollection<HoppRESTRequest>[] }
  44. ) {
  45. return {
  46. state: entries,
  47. }
  48. },
  49. appendCollections(
  50. { state }: RESTCollectionStoreType,
  51. { entries }: { entries: HoppCollection<HoppRESTRequest>[] }
  52. ) {
  53. return {
  54. state: [...state, ...entries],
  55. }
  56. },
  57. addCollection(
  58. { state }: RESTCollectionStoreType,
  59. { collection }: { collection: HoppCollection<any> }
  60. ) {
  61. return {
  62. state: [...state, collection],
  63. }
  64. },
  65. removeCollection(
  66. { state }: RESTCollectionStoreType,
  67. { collectionIndex }: { collectionIndex: number }
  68. ) {
  69. return {
  70. state: (state as any).filter(
  71. (_: any, i: number) => i !== collectionIndex
  72. ),
  73. }
  74. },
  75. editCollection(
  76. { state }: RESTCollectionStoreType,
  77. {
  78. collectionIndex,
  79. collection,
  80. }: { collectionIndex: number; collection: HoppCollection<any> }
  81. ) {
  82. return {
  83. state: state.map((col, index) =>
  84. index === collectionIndex ? collection : col
  85. ),
  86. }
  87. },
  88. addFolder(
  89. { state }: RESTCollectionStoreType,
  90. { name, path }: { name: string; path: string }
  91. ) {
  92. const newFolder: HoppCollection<HoppRESTRequest> = makeCollection({
  93. name,
  94. folders: [],
  95. requests: [],
  96. })
  97. const newState = state
  98. const indexPaths = path.split("/").map((x) => parseInt(x))
  99. const target = navigateToFolderWithIndexPath(newState, indexPaths)
  100. if (target === null) {
  101. console.log(`Could not parse path '${path}'. Ignoring add folder request`)
  102. return {}
  103. }
  104. target.folders.push(newFolder)
  105. return {
  106. state: newState,
  107. }
  108. },
  109. editFolder(
  110. { state }: RESTCollectionStoreType,
  111. { path, folder }: { path: string; folder: string }
  112. ) {
  113. const newState = state
  114. const indexPaths = path.split("/").map((x) => parseInt(x))
  115. const target = navigateToFolderWithIndexPath(newState, indexPaths)
  116. if (target === null) {
  117. console.log(
  118. `Could not parse path '${path}'. Ignoring edit folder request`
  119. )
  120. return {}
  121. }
  122. Object.assign(target, folder)
  123. return {
  124. state: newState,
  125. }
  126. },
  127. removeFolder({ state }: RESTCollectionStoreType, { path }: { path: string }) {
  128. const newState = state
  129. const indexPaths = path.split("/").map((x) => parseInt(x))
  130. if (indexPaths.length === 0) {
  131. console.log(
  132. "Given path too short. If this is a collection, use removeCollection dispatcher instead. Skipping request."
  133. )
  134. return {}
  135. }
  136. // We get the index path to the folder itself,
  137. // we have to find the folder containing the target folder,
  138. // so we pop the last path index
  139. const folderIndex = indexPaths.pop() as number
  140. const containingFolder = navigateToFolderWithIndexPath(newState, indexPaths)
  141. if (containingFolder === null) {
  142. console.log(
  143. `Could not resolve path '${path}'. Skipping removeFolder dispatch.`
  144. )
  145. return {}
  146. }
  147. containingFolder.folders.splice(folderIndex, 1)
  148. return {
  149. state: newState,
  150. }
  151. },
  152. editRequest(
  153. { state }: RESTCollectionStoreType,
  154. {
  155. path,
  156. requestIndex,
  157. requestNew,
  158. }: { path: string; requestIndex: number; requestNew: any }
  159. ) {
  160. const newState = state
  161. const indexPaths = path.split("/").map((x) => parseInt(x))
  162. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  163. if (targetLocation === null) {
  164. console.log(
  165. `Could not resolve path '${path}'. Ignoring editRequest dispatch.`
  166. )
  167. return {}
  168. }
  169. targetLocation.requests = targetLocation.requests.map((req, index) =>
  170. index !== requestIndex ? req : requestNew
  171. )
  172. return {
  173. state: newState,
  174. }
  175. },
  176. saveRequestAs(
  177. { state }: RESTCollectionStoreType,
  178. { path, request }: { path: string; request: any }
  179. ) {
  180. const newState = state
  181. const indexPaths = path.split("/").map((x) => parseInt(x))
  182. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  183. if (targetLocation === null) {
  184. console.log(
  185. `Could not resolve path '${path}'. Ignoring saveRequestAs dispatch.`
  186. )
  187. return {}
  188. }
  189. targetLocation.requests.push(request)
  190. return {
  191. state: newState,
  192. }
  193. },
  194. removeRequest(
  195. { state }: RESTCollectionStoreType,
  196. { path, requestIndex }: { path: string; requestIndex: number }
  197. ) {
  198. const newState = state
  199. const indexPaths = path.split("/").map((x) => parseInt(x))
  200. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  201. if (targetLocation === null) {
  202. console.log(
  203. `Could not resolve path '${path}'. Ignoring removeRequest dispatch.`
  204. )
  205. return {}
  206. }
  207. targetLocation.requests.splice(requestIndex, 1)
  208. // If the save context is set and is set to the same source, we invalidate it
  209. const saveCtx = getRESTSaveContext()
  210. if (
  211. saveCtx?.originLocation === "user-collection" &&
  212. saveCtx.folderPath === path &&
  213. saveCtx.requestIndex === requestIndex
  214. ) {
  215. setRESTSaveContext(null)
  216. }
  217. return {
  218. state: newState,
  219. }
  220. },
  221. moveRequest(
  222. { state }: RESTCollectionStoreType,
  223. {
  224. path,
  225. requestIndex,
  226. destinationPath,
  227. }: { path: string; requestIndex: number; destinationPath: string }
  228. ) {
  229. const newState = state
  230. const indexPaths = path.split("/").map((x) => parseInt(x))
  231. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  232. if (targetLocation === null) {
  233. console.log(
  234. `Could not resolve source path '${path}'. Skipping moveRequest dispatch.`
  235. )
  236. return {}
  237. }
  238. const req = targetLocation.requests[requestIndex]
  239. const destIndexPaths = destinationPath.split("/").map((x) => parseInt(x))
  240. const destLocation = navigateToFolderWithIndexPath(newState, destIndexPaths)
  241. if (destLocation === null) {
  242. console.log(
  243. `Could not resolve destination path '${destinationPath}'. Skipping moveRequest dispatch.`
  244. )
  245. return {}
  246. }
  247. destLocation.requests.push(req)
  248. targetLocation.requests.splice(requestIndex, 1)
  249. return {
  250. state: newState,
  251. }
  252. },
  253. })
  254. const gqlCollectionDispatchers = defineDispatchers({
  255. setCollections(
  256. _: GraphqlCollectionStoreType,
  257. { entries }: { entries: HoppCollection<any>[] }
  258. ) {
  259. return {
  260. state: entries,
  261. }
  262. },
  263. appendCollections(
  264. { state }: GraphqlCollectionStoreType,
  265. { entries }: { entries: HoppCollection<any>[] }
  266. ) {
  267. return {
  268. state: [...state, ...entries],
  269. }
  270. },
  271. addCollection(
  272. { state }: GraphqlCollectionStoreType,
  273. { collection }: { collection: HoppCollection<any> }
  274. ) {
  275. return {
  276. state: [...state, collection],
  277. }
  278. },
  279. removeCollection(
  280. { state }: GraphqlCollectionStoreType,
  281. { collectionIndex }: { collectionIndex: number }
  282. ) {
  283. return {
  284. state: (state as any).filter(
  285. (_: any, i: number) => i !== collectionIndex
  286. ),
  287. }
  288. },
  289. editCollection(
  290. { state }: GraphqlCollectionStoreType,
  291. {
  292. collectionIndex,
  293. collection,
  294. }: { collectionIndex: number; collection: HoppCollection<any> }
  295. ) {
  296. return {
  297. state: state.map((col, index) =>
  298. index === collectionIndex ? collection : col
  299. ),
  300. }
  301. },
  302. addFolder(
  303. { state }: GraphqlCollectionStoreType,
  304. { name, path }: { name: string; path: string }
  305. ) {
  306. const newFolder: HoppCollection<HoppGQLRequest> = makeCollection({
  307. name,
  308. folders: [],
  309. requests: [],
  310. })
  311. const newState = state
  312. const indexPaths = path.split("/").map((x) => parseInt(x))
  313. const target = navigateToFolderWithIndexPath(newState, indexPaths)
  314. if (target === null) {
  315. console.log(`Could not parse path '${path}'. Ignoring add folder request`)
  316. return {}
  317. }
  318. target.folders.push(newFolder)
  319. return {
  320. state: newState,
  321. }
  322. },
  323. editFolder(
  324. { state }: GraphqlCollectionStoreType,
  325. { path, folder }: { path: string; folder: string }
  326. ) {
  327. const newState = state
  328. const indexPaths = path.split("/").map((x) => parseInt(x))
  329. const target = navigateToFolderWithIndexPath(newState, indexPaths)
  330. if (target === null) {
  331. console.log(
  332. `Could not parse path '${path}'. Ignoring edit folder request`
  333. )
  334. return {}
  335. }
  336. Object.assign(target, folder)
  337. return {
  338. state: newState,
  339. }
  340. },
  341. removeFolder(
  342. { state }: GraphqlCollectionStoreType,
  343. { path }: { path: string }
  344. ) {
  345. const newState = state
  346. const indexPaths = path.split("/").map((x) => parseInt(x))
  347. if (indexPaths.length === 0) {
  348. console.log(
  349. "Given path too short. If this is a collection, use removeCollection dispatcher instead. Skipping request."
  350. )
  351. return {}
  352. }
  353. // We get the index path to the folder itself,
  354. // we have to find the folder containing the target folder,
  355. // so we pop the last path index
  356. const folderIndex = indexPaths.pop() as number
  357. const containingFolder = navigateToFolderWithIndexPath(newState, indexPaths)
  358. if (containingFolder === null) {
  359. console.log(
  360. `Could not resolve path '${path}'. Skipping removeFolder dispatch.`
  361. )
  362. return {}
  363. }
  364. containingFolder.folders.splice(folderIndex, 1)
  365. return {
  366. state: newState,
  367. }
  368. },
  369. editRequest(
  370. { state }: GraphqlCollectionStoreType,
  371. {
  372. path,
  373. requestIndex,
  374. requestNew,
  375. }: { path: string; requestIndex: number; requestNew: any }
  376. ) {
  377. const newState = state
  378. const indexPaths = path.split("/").map((x) => parseInt(x))
  379. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  380. if (targetLocation === null) {
  381. console.log(
  382. `Could not resolve path '${path}'. Ignoring editRequest dispatch.`
  383. )
  384. return {}
  385. }
  386. targetLocation.requests = targetLocation.requests.map((req, index) =>
  387. index !== requestIndex ? req : requestNew
  388. )
  389. return {
  390. state: newState,
  391. }
  392. },
  393. saveRequestAs(
  394. { state }: GraphqlCollectionStoreType,
  395. { path, request }: { path: string; request: any }
  396. ) {
  397. const newState = state
  398. const indexPaths = path.split("/").map((x) => parseInt(x))
  399. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  400. if (targetLocation === null) {
  401. console.log(
  402. `Could not resolve path '${path}'. Ignoring saveRequestAs dispatch.`
  403. )
  404. return {}
  405. }
  406. targetLocation.requests.push(request)
  407. return {
  408. state: newState,
  409. }
  410. },
  411. removeRequest(
  412. { state }: GraphqlCollectionStoreType,
  413. { path, requestIndex }: { path: string; requestIndex: number }
  414. ) {
  415. const newState = state
  416. const indexPaths = path.split("/").map((x) => parseInt(x))
  417. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  418. if (targetLocation === null) {
  419. console.log(
  420. `Could not resolve path '${path}'. Ignoring removeRequest dispatch.`
  421. )
  422. return {}
  423. }
  424. targetLocation.requests.splice(requestIndex, 1)
  425. // If the save context is set and is set to the same source, we invalidate it
  426. const saveCtx = getRESTSaveContext()
  427. if (
  428. saveCtx?.originLocation === "user-collection" &&
  429. saveCtx.folderPath === path &&
  430. saveCtx.requestIndex === requestIndex
  431. ) {
  432. setRESTSaveContext(null)
  433. }
  434. return {
  435. state: newState,
  436. }
  437. },
  438. moveRequest(
  439. { state }: GraphqlCollectionStoreType,
  440. {
  441. path,
  442. requestIndex,
  443. destinationPath,
  444. }: { path: string; requestIndex: number; destinationPath: string }
  445. ) {
  446. const newState = state
  447. const indexPaths = path.split("/").map((x) => parseInt(x))
  448. const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
  449. if (targetLocation === null) {
  450. console.log(
  451. `Could not resolve source path '${path}'. Skipping moveRequest dispatch.`
  452. )
  453. return {}
  454. }
  455. const req = targetLocation.requests[requestIndex]
  456. const destIndexPaths = destinationPath.split("/").map((x) => parseInt(x))
  457. const destLocation = navigateToFolderWithIndexPath(newState, destIndexPaths)
  458. if (destLocation === null) {
  459. console.log(
  460. `Could not resolve destination path '${destinationPath}'. Skipping moveRequest dispatch.`
  461. )
  462. return {}
  463. }
  464. destLocation.requests.push(req)
  465. targetLocation.requests.splice(requestIndex, 1)
  466. return {
  467. state: newState,
  468. }
  469. },
  470. })
  471. export const restCollectionStore = new DispatchingStore(
  472. defaultRESTCollectionState,
  473. restCollectionDispatchers
  474. )
  475. export const graphqlCollectionStore = new DispatchingStore(
  476. defaultGraphqlCollectionState,
  477. gqlCollectionDispatchers
  478. )
  479. export function setRESTCollections(entries: HoppCollection<HoppRESTRequest>[]) {
  480. restCollectionStore.dispatch({
  481. dispatcher: "setCollections",
  482. payload: {
  483. entries,
  484. },
  485. })
  486. }
  487. export const restCollections$ = restCollectionStore.subject$.pipe(
  488. pluck("state")
  489. )
  490. export const graphqlCollections$ = graphqlCollectionStore.subject$.pipe(
  491. pluck("state")
  492. )
  493. export function appendRESTCollections(
  494. entries: HoppCollection<HoppRESTRequest>[]
  495. ) {
  496. restCollectionStore.dispatch({
  497. dispatcher: "appendCollections",
  498. payload: {
  499. entries,
  500. },
  501. })
  502. }
  503. export function addRESTCollection(collection: HoppCollection<HoppRESTRequest>) {
  504. restCollectionStore.dispatch({
  505. dispatcher: "addCollection",
  506. payload: {
  507. collection,
  508. },
  509. })
  510. }
  511. export function removeRESTCollection(collectionIndex: number) {
  512. restCollectionStore.dispatch({
  513. dispatcher: "removeCollection",
  514. payload: {
  515. collectionIndex,
  516. },
  517. })
  518. }
  519. export function getRESTCollection(collectionIndex: number) {
  520. return restCollectionStore.value.state[collectionIndex]
  521. }
  522. export function editRESTCollection(
  523. collectionIndex: number,
  524. collection: HoppCollection<HoppRESTRequest>
  525. ) {
  526. restCollectionStore.dispatch({
  527. dispatcher: "editCollection",
  528. payload: {
  529. collectionIndex,
  530. collection,
  531. },
  532. })
  533. }
  534. export function addRESTFolder(name: string, path: string) {
  535. restCollectionStore.dispatch({
  536. dispatcher: "addFolder",
  537. payload: {
  538. name,
  539. path,
  540. },
  541. })
  542. }
  543. export function editRESTFolder(
  544. path: string,
  545. folder: HoppCollection<HoppRESTRequest>
  546. ) {
  547. restCollectionStore.dispatch({
  548. dispatcher: "editFolder",
  549. payload: {
  550. path,
  551. folder,
  552. },
  553. })
  554. }
  555. export function removeRESTFolder(path: string) {
  556. restCollectionStore.dispatch({
  557. dispatcher: "removeFolder",
  558. payload: {
  559. path,
  560. },
  561. })
  562. }
  563. export function editRESTRequest(
  564. path: string,
  565. requestIndex: number,
  566. requestNew: HoppRESTRequest
  567. ) {
  568. const indexPaths = path.split("/").map((x) => parseInt(x))
  569. if (
  570. !navigateToFolderWithIndexPath(restCollectionStore.value.state, indexPaths)
  571. )
  572. throw new Error("Path not found")
  573. restCollectionStore.dispatch({
  574. dispatcher: "editRequest",
  575. payload: {
  576. path,
  577. requestIndex,
  578. requestNew,
  579. },
  580. })
  581. }
  582. export function saveRESTRequestAs(path: string, request: HoppRESTRequest) {
  583. // For calculating the insertion request index
  584. const targetLocation = navigateToFolderWithIndexPath(
  585. restCollectionStore.value.state,
  586. path.split("/").map((x) => parseInt(x))
  587. )
  588. const insertionIndex = targetLocation!.requests.length
  589. restCollectionStore.dispatch({
  590. dispatcher: "saveRequestAs",
  591. payload: {
  592. path,
  593. request,
  594. },
  595. })
  596. return insertionIndex
  597. }
  598. export function removeRESTRequest(path: string, requestIndex: number) {
  599. restCollectionStore.dispatch({
  600. dispatcher: "removeRequest",
  601. payload: {
  602. path,
  603. requestIndex,
  604. },
  605. })
  606. }
  607. export function moveRESTRequest(
  608. path: string,
  609. requestIndex: number,
  610. destinationPath: string
  611. ) {
  612. restCollectionStore.dispatch({
  613. dispatcher: "moveRequest",
  614. payload: {
  615. path,
  616. requestIndex,
  617. destinationPath,
  618. },
  619. })
  620. }
  621. export function setGraphqlCollections(
  622. entries: HoppCollection<HoppGQLRequest>[]
  623. ) {
  624. graphqlCollectionStore.dispatch({
  625. dispatcher: "setCollections",
  626. payload: {
  627. entries,
  628. },
  629. })
  630. }
  631. export function appendGraphqlCollections(
  632. entries: HoppCollection<HoppGQLRequest>[]
  633. ) {
  634. graphqlCollectionStore.dispatch({
  635. dispatcher: "appendCollections",
  636. payload: {
  637. entries,
  638. },
  639. })
  640. }
  641. export function addGraphqlCollection(
  642. collection: HoppCollection<HoppGQLRequest>
  643. ) {
  644. graphqlCollectionStore.dispatch({
  645. dispatcher: "addCollection",
  646. payload: {
  647. collection,
  648. },
  649. })
  650. }
  651. export function removeGraphqlCollection(collectionIndex: number) {
  652. graphqlCollectionStore.dispatch({
  653. dispatcher: "removeCollection",
  654. payload: {
  655. collectionIndex,
  656. },
  657. })
  658. }
  659. export function editGraphqlCollection(
  660. collectionIndex: number,
  661. collection: HoppCollection<HoppGQLRequest>
  662. ) {
  663. graphqlCollectionStore.dispatch({
  664. dispatcher: "editCollection",
  665. payload: {
  666. collectionIndex,
  667. collection,
  668. },
  669. })
  670. }
  671. export function addGraphqlFolder(name: string, path: string) {
  672. graphqlCollectionStore.dispatch({
  673. dispatcher: "addFolder",
  674. payload: {
  675. name,
  676. path,
  677. },
  678. })
  679. }
  680. export function editGraphqlFolder(
  681. path: string,
  682. folder: HoppCollection<HoppGQLRequest>
  683. ) {
  684. graphqlCollectionStore.dispatch({
  685. dispatcher: "editFolder",
  686. payload: {
  687. path,
  688. folder,
  689. },
  690. })
  691. }
  692. export function removeGraphqlFolder(path: string) {
  693. graphqlCollectionStore.dispatch({
  694. dispatcher: "removeFolder",
  695. payload: {
  696. path,
  697. },
  698. })
  699. }
  700. export function editGraphqlRequest(
  701. path: string,
  702. requestIndex: number,
  703. requestNew: HoppGQLRequest
  704. ) {
  705. graphqlCollectionStore.dispatch({
  706. dispatcher: "editRequest",
  707. payload: {
  708. path,
  709. requestIndex,
  710. requestNew,
  711. },
  712. })
  713. }
  714. export function saveGraphqlRequestAs(path: string, request: HoppGQLRequest) {
  715. graphqlCollectionStore.dispatch({
  716. dispatcher: "saveRequestAs",
  717. payload: {
  718. path,
  719. request,
  720. },
  721. })
  722. }
  723. export function removeGraphqlRequest(path: string, requestIndex: number) {
  724. graphqlCollectionStore.dispatch({
  725. dispatcher: "removeRequest",
  726. payload: {
  727. path,
  728. requestIndex,
  729. },
  730. })
  731. }
  732. export function moveGraphqlRequest(
  733. path: string,
  734. requestIndex: number,
  735. destinationPath: string
  736. ) {
  737. graphqlCollectionStore.dispatch({
  738. dispatcher: "moveRequest",
  739. payload: {
  740. path,
  741. requestIndex,
  742. destinationPath,
  743. },
  744. })
  745. }