123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889 |
- import { pluck } from "rxjs/operators"
- import {
- HoppGQLRequest,
- HoppRESTRequest,
- HoppCollection,
- makeCollection,
- } from "@hoppscotch/data"
- import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
- import { getRESTSaveContext, setRESTSaveContext } from "./RESTSession"
- const defaultRESTCollectionState = {
- state: [
- makeCollection<HoppRESTRequest>({
- name: "My Collection",
- folders: [],
- requests: [],
- }),
- ],
- }
- const defaultGraphqlCollectionState = {
- state: [
- makeCollection<HoppGQLRequest>({
- name: "My GraphQL Collection",
- folders: [],
- requests: [],
- }),
- ],
- }
- type RESTCollectionStoreType = typeof defaultRESTCollectionState
- type GraphqlCollectionStoreType = typeof defaultGraphqlCollectionState
- function navigateToFolderWithIndexPath(
- collections: HoppCollection<HoppRESTRequest | HoppGQLRequest>[],
- indexPaths: number[]
- ) {
- if (indexPaths.length === 0) return null
- let target = collections[indexPaths.shift() as number]
- while (indexPaths.length > 0)
- target = target.folders[indexPaths.shift() as number]
- return target !== undefined ? target : null
- }
- const restCollectionDispatchers = defineDispatchers({
- setCollections(
- _: RESTCollectionStoreType,
- { entries }: { entries: HoppCollection<HoppRESTRequest>[] }
- ) {
- return {
- state: entries,
- }
- },
- appendCollections(
- { state }: RESTCollectionStoreType,
- { entries }: { entries: HoppCollection<HoppRESTRequest>[] }
- ) {
- return {
- state: [...state, ...entries],
- }
- },
- addCollection(
- { state }: RESTCollectionStoreType,
- { collection }: { collection: HoppCollection<any> }
- ) {
- return {
- state: [...state, collection],
- }
- },
- removeCollection(
- { state }: RESTCollectionStoreType,
- { collectionIndex }: { collectionIndex: number }
- ) {
- return {
- state: (state as any).filter(
- (_: any, i: number) => i !== collectionIndex
- ),
- }
- },
- editCollection(
- { state }: RESTCollectionStoreType,
- {
- collectionIndex,
- collection,
- }: { collectionIndex: number; collection: HoppCollection<any> }
- ) {
- return {
- state: state.map((col, index) =>
- index === collectionIndex ? collection : col
- ),
- }
- },
- addFolder(
- { state }: RESTCollectionStoreType,
- { name, path }: { name: string; path: string }
- ) {
- const newFolder: HoppCollection<HoppRESTRequest> = makeCollection({
- name,
- folders: [],
- requests: [],
- })
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const target = navigateToFolderWithIndexPath(newState, indexPaths)
- if (target === null) {
- console.log(`Could not parse path '${path}'. Ignoring add folder request`)
- return {}
- }
- target.folders.push(newFolder)
- return {
- state: newState,
- }
- },
- editFolder(
- { state }: RESTCollectionStoreType,
- { path, folder }: { path: string; folder: string }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const target = navigateToFolderWithIndexPath(newState, indexPaths)
- if (target === null) {
- console.log(
- `Could not parse path '${path}'. Ignoring edit folder request`
- )
- return {}
- }
- Object.assign(target, folder)
- return {
- state: newState,
- }
- },
- removeFolder({ state }: RESTCollectionStoreType, { path }: { path: string }) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- if (indexPaths.length === 0) {
- console.log(
- "Given path too short. If this is a collection, use removeCollection dispatcher instead. Skipping request."
- )
- return {}
- }
- // We get the index path to the folder itself,
- // we have to find the folder containing the target folder,
- // so we pop the last path index
- const folderIndex = indexPaths.pop() as number
- const containingFolder = navigateToFolderWithIndexPath(newState, indexPaths)
- if (containingFolder === null) {
- console.log(
- `Could not resolve path '${path}'. Skipping removeFolder dispatch.`
- )
- return {}
- }
- containingFolder.folders.splice(folderIndex, 1)
- return {
- state: newState,
- }
- },
- editRequest(
- { state }: RESTCollectionStoreType,
- {
- path,
- requestIndex,
- requestNew,
- }: { path: string; requestIndex: number; requestNew: any }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve path '${path}'. Ignoring editRequest dispatch.`
- )
- return {}
- }
- targetLocation.requests = targetLocation.requests.map((req, index) =>
- index !== requestIndex ? req : requestNew
- )
- return {
- state: newState,
- }
- },
- saveRequestAs(
- { state }: RESTCollectionStoreType,
- { path, request }: { path: string; request: any }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve path '${path}'. Ignoring saveRequestAs dispatch.`
- )
- return {}
- }
- targetLocation.requests.push(request)
- return {
- state: newState,
- }
- },
- removeRequest(
- { state }: RESTCollectionStoreType,
- { path, requestIndex }: { path: string; requestIndex: number }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve path '${path}'. Ignoring removeRequest dispatch.`
- )
- return {}
- }
- targetLocation.requests.splice(requestIndex, 1)
- // If the save context is set and is set to the same source, we invalidate it
- const saveCtx = getRESTSaveContext()
- if (
- saveCtx?.originLocation === "user-collection" &&
- saveCtx.folderPath === path &&
- saveCtx.requestIndex === requestIndex
- ) {
- setRESTSaveContext(null)
- }
- return {
- state: newState,
- }
- },
- moveRequest(
- { state }: RESTCollectionStoreType,
- {
- path,
- requestIndex,
- destinationPath,
- }: { path: string; requestIndex: number; destinationPath: string }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve source path '${path}'. Skipping moveRequest dispatch.`
- )
- return {}
- }
- const req = targetLocation.requests[requestIndex]
- const destIndexPaths = destinationPath.split("/").map((x) => parseInt(x))
- const destLocation = navigateToFolderWithIndexPath(newState, destIndexPaths)
- if (destLocation === null) {
- console.log(
- `Could not resolve destination path '${destinationPath}'. Skipping moveRequest dispatch.`
- )
- return {}
- }
- destLocation.requests.push(req)
- targetLocation.requests.splice(requestIndex, 1)
- return {
- state: newState,
- }
- },
- })
- const gqlCollectionDispatchers = defineDispatchers({
- setCollections(
- _: GraphqlCollectionStoreType,
- { entries }: { entries: HoppCollection<any>[] }
- ) {
- return {
- state: entries,
- }
- },
- appendCollections(
- { state }: GraphqlCollectionStoreType,
- { entries }: { entries: HoppCollection<any>[] }
- ) {
- return {
- state: [...state, ...entries],
- }
- },
- addCollection(
- { state }: GraphqlCollectionStoreType,
- { collection }: { collection: HoppCollection<any> }
- ) {
- return {
- state: [...state, collection],
- }
- },
- removeCollection(
- { state }: GraphqlCollectionStoreType,
- { collectionIndex }: { collectionIndex: number }
- ) {
- return {
- state: (state as any).filter(
- (_: any, i: number) => i !== collectionIndex
- ),
- }
- },
- editCollection(
- { state }: GraphqlCollectionStoreType,
- {
- collectionIndex,
- collection,
- }: { collectionIndex: number; collection: HoppCollection<any> }
- ) {
- return {
- state: state.map((col, index) =>
- index === collectionIndex ? collection : col
- ),
- }
- },
- addFolder(
- { state }: GraphqlCollectionStoreType,
- { name, path }: { name: string; path: string }
- ) {
- const newFolder: HoppCollection<HoppGQLRequest> = makeCollection({
- name,
- folders: [],
- requests: [],
- })
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const target = navigateToFolderWithIndexPath(newState, indexPaths)
- if (target === null) {
- console.log(`Could not parse path '${path}'. Ignoring add folder request`)
- return {}
- }
- target.folders.push(newFolder)
- return {
- state: newState,
- }
- },
- editFolder(
- { state }: GraphqlCollectionStoreType,
- { path, folder }: { path: string; folder: string }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const target = navigateToFolderWithIndexPath(newState, indexPaths)
- if (target === null) {
- console.log(
- `Could not parse path '${path}'. Ignoring edit folder request`
- )
- return {}
- }
- Object.assign(target, folder)
- return {
- state: newState,
- }
- },
- removeFolder(
- { state }: GraphqlCollectionStoreType,
- { path }: { path: string }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- if (indexPaths.length === 0) {
- console.log(
- "Given path too short. If this is a collection, use removeCollection dispatcher instead. Skipping request."
- )
- return {}
- }
- // We get the index path to the folder itself,
- // we have to find the folder containing the target folder,
- // so we pop the last path index
- const folderIndex = indexPaths.pop() as number
- const containingFolder = navigateToFolderWithIndexPath(newState, indexPaths)
- if (containingFolder === null) {
- console.log(
- `Could not resolve path '${path}'. Skipping removeFolder dispatch.`
- )
- return {}
- }
- containingFolder.folders.splice(folderIndex, 1)
- return {
- state: newState,
- }
- },
- editRequest(
- { state }: GraphqlCollectionStoreType,
- {
- path,
- requestIndex,
- requestNew,
- }: { path: string; requestIndex: number; requestNew: any }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve path '${path}'. Ignoring editRequest dispatch.`
- )
- return {}
- }
- targetLocation.requests = targetLocation.requests.map((req, index) =>
- index !== requestIndex ? req : requestNew
- )
- return {
- state: newState,
- }
- },
- saveRequestAs(
- { state }: GraphqlCollectionStoreType,
- { path, request }: { path: string; request: any }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve path '${path}'. Ignoring saveRequestAs dispatch.`
- )
- return {}
- }
- targetLocation.requests.push(request)
- return {
- state: newState,
- }
- },
- removeRequest(
- { state }: GraphqlCollectionStoreType,
- { path, requestIndex }: { path: string; requestIndex: number }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve path '${path}'. Ignoring removeRequest dispatch.`
- )
- return {}
- }
- targetLocation.requests.splice(requestIndex, 1)
- // If the save context is set and is set to the same source, we invalidate it
- const saveCtx = getRESTSaveContext()
- if (
- saveCtx?.originLocation === "user-collection" &&
- saveCtx.folderPath === path &&
- saveCtx.requestIndex === requestIndex
- ) {
- setRESTSaveContext(null)
- }
- return {
- state: newState,
- }
- },
- moveRequest(
- { state }: GraphqlCollectionStoreType,
- {
- path,
- requestIndex,
- destinationPath,
- }: { path: string; requestIndex: number; destinationPath: string }
- ) {
- const newState = state
- const indexPaths = path.split("/").map((x) => parseInt(x))
- const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
- if (targetLocation === null) {
- console.log(
- `Could not resolve source path '${path}'. Skipping moveRequest dispatch.`
- )
- return {}
- }
- const req = targetLocation.requests[requestIndex]
- const destIndexPaths = destinationPath.split("/").map((x) => parseInt(x))
- const destLocation = navigateToFolderWithIndexPath(newState, destIndexPaths)
- if (destLocation === null) {
- console.log(
- `Could not resolve destination path '${destinationPath}'. Skipping moveRequest dispatch.`
- )
- return {}
- }
- destLocation.requests.push(req)
- targetLocation.requests.splice(requestIndex, 1)
- return {
- state: newState,
- }
- },
- })
- export const restCollectionStore = new DispatchingStore(
- defaultRESTCollectionState,
- restCollectionDispatchers
- )
- export const graphqlCollectionStore = new DispatchingStore(
- defaultGraphqlCollectionState,
- gqlCollectionDispatchers
- )
- export function setRESTCollections(entries: HoppCollection<HoppRESTRequest>[]) {
- restCollectionStore.dispatch({
- dispatcher: "setCollections",
- payload: {
- entries,
- },
- })
- }
- export const restCollections$ = restCollectionStore.subject$.pipe(
- pluck("state")
- )
- export const graphqlCollections$ = graphqlCollectionStore.subject$.pipe(
- pluck("state")
- )
- export function appendRESTCollections(
- entries: HoppCollection<HoppRESTRequest>[]
- ) {
- restCollectionStore.dispatch({
- dispatcher: "appendCollections",
- payload: {
- entries,
- },
- })
- }
- export function addRESTCollection(collection: HoppCollection<HoppRESTRequest>) {
- restCollectionStore.dispatch({
- dispatcher: "addCollection",
- payload: {
- collection,
- },
- })
- }
- export function removeRESTCollection(collectionIndex: number) {
- restCollectionStore.dispatch({
- dispatcher: "removeCollection",
- payload: {
- collectionIndex,
- },
- })
- }
- export function getRESTCollection(collectionIndex: number) {
- return restCollectionStore.value.state[collectionIndex]
- }
- export function editRESTCollection(
- collectionIndex: number,
- collection: HoppCollection<HoppRESTRequest>
- ) {
- restCollectionStore.dispatch({
- dispatcher: "editCollection",
- payload: {
- collectionIndex,
- collection,
- },
- })
- }
- export function addRESTFolder(name: string, path: string) {
- restCollectionStore.dispatch({
- dispatcher: "addFolder",
- payload: {
- name,
- path,
- },
- })
- }
- export function editRESTFolder(
- path: string,
- folder: HoppCollection<HoppRESTRequest>
- ) {
- restCollectionStore.dispatch({
- dispatcher: "editFolder",
- payload: {
- path,
- folder,
- },
- })
- }
- export function removeRESTFolder(path: string) {
- restCollectionStore.dispatch({
- dispatcher: "removeFolder",
- payload: {
- path,
- },
- })
- }
- export function editRESTRequest(
- path: string,
- requestIndex: number,
- requestNew: HoppRESTRequest
- ) {
- const indexPaths = path.split("/").map((x) => parseInt(x))
- if (
- !navigateToFolderWithIndexPath(restCollectionStore.value.state, indexPaths)
- )
- throw new Error("Path not found")
- restCollectionStore.dispatch({
- dispatcher: "editRequest",
- payload: {
- path,
- requestIndex,
- requestNew,
- },
- })
- }
- export function saveRESTRequestAs(path: string, request: HoppRESTRequest) {
- // For calculating the insertion request index
- const targetLocation = navigateToFolderWithIndexPath(
- restCollectionStore.value.state,
- path.split("/").map((x) => parseInt(x))
- )
- const insertionIndex = targetLocation!.requests.length
- restCollectionStore.dispatch({
- dispatcher: "saveRequestAs",
- payload: {
- path,
- request,
- },
- })
- return insertionIndex
- }
- export function removeRESTRequest(path: string, requestIndex: number) {
- restCollectionStore.dispatch({
- dispatcher: "removeRequest",
- payload: {
- path,
- requestIndex,
- },
- })
- }
- export function moveRESTRequest(
- path: string,
- requestIndex: number,
- destinationPath: string
- ) {
- restCollectionStore.dispatch({
- dispatcher: "moveRequest",
- payload: {
- path,
- requestIndex,
- destinationPath,
- },
- })
- }
- export function setGraphqlCollections(
- entries: HoppCollection<HoppGQLRequest>[]
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "setCollections",
- payload: {
- entries,
- },
- })
- }
- export function appendGraphqlCollections(
- entries: HoppCollection<HoppGQLRequest>[]
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "appendCollections",
- payload: {
- entries,
- },
- })
- }
- export function addGraphqlCollection(
- collection: HoppCollection<HoppGQLRequest>
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "addCollection",
- payload: {
- collection,
- },
- })
- }
- export function removeGraphqlCollection(collectionIndex: number) {
- graphqlCollectionStore.dispatch({
- dispatcher: "removeCollection",
- payload: {
- collectionIndex,
- },
- })
- }
- export function editGraphqlCollection(
- collectionIndex: number,
- collection: HoppCollection<HoppGQLRequest>
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "editCollection",
- payload: {
- collectionIndex,
- collection,
- },
- })
- }
- export function addGraphqlFolder(name: string, path: string) {
- graphqlCollectionStore.dispatch({
- dispatcher: "addFolder",
- payload: {
- name,
- path,
- },
- })
- }
- export function editGraphqlFolder(
- path: string,
- folder: HoppCollection<HoppGQLRequest>
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "editFolder",
- payload: {
- path,
- folder,
- },
- })
- }
- export function removeGraphqlFolder(path: string) {
- graphqlCollectionStore.dispatch({
- dispatcher: "removeFolder",
- payload: {
- path,
- },
- })
- }
- export function editGraphqlRequest(
- path: string,
- requestIndex: number,
- requestNew: HoppGQLRequest
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "editRequest",
- payload: {
- path,
- requestIndex,
- requestNew,
- },
- })
- }
- export function saveGraphqlRequestAs(path: string, request: HoppGQLRequest) {
- graphqlCollectionStore.dispatch({
- dispatcher: "saveRequestAs",
- payload: {
- path,
- request,
- },
- })
- }
- export function removeGraphqlRequest(path: string, requestIndex: number) {
- graphqlCollectionStore.dispatch({
- dispatcher: "removeRequest",
- payload: {
- path,
- requestIndex,
- },
- })
- }
- export function moveGraphqlRequest(
- path: string,
- requestIndex: number,
- destinationPath: string
- ) {
- graphqlCollectionStore.dispatch({
- dispatcher: "moveRequest",
- payload: {
- path,
- requestIndex,
- destinationPath,
- },
- })
- }
|