fix: subscription streams
This commit is contained in:
@@ -30,6 +30,7 @@ import { GQLLanguage } from "@hoppscotch/codemirror-lang-graphql"
|
|||||||
import { pipe } from "fp-ts/function"
|
import { pipe } from "fp-ts/function"
|
||||||
import * as O from "fp-ts/Option"
|
import * as O from "fp-ts/Option"
|
||||||
import { isJSONContentType } from "../utils/contenttypes"
|
import { isJSONContentType } from "../utils/contenttypes"
|
||||||
|
import { useStreamSubscriber } from "../utils/composables"
|
||||||
import { Completer } from "./completion"
|
import { Completer } from "./completion"
|
||||||
import { LinterDefinition } from "./linting/linter"
|
import { LinterDefinition } from "./linting/linter"
|
||||||
import { basicSetup, baseTheme, baseHighlightStyle } from "./themes/baseTheme"
|
import { basicSetup, baseTheme, baseHighlightStyle } from "./themes/baseTheme"
|
||||||
@@ -152,6 +153,7 @@ export function useCodemirror(
|
|||||||
value: Ref<string>,
|
value: Ref<string>,
|
||||||
options: CodeMirrorOptions
|
options: CodeMirrorOptions
|
||||||
): { cursor: Ref<{ line: number; ch: number }> } {
|
): { cursor: Ref<{ line: number; ch: number }> } {
|
||||||
|
const { subscribeToStream } = useStreamSubscriber()
|
||||||
const language = new Compartment()
|
const language = new Compartment()
|
||||||
const lineWrapping = new Compartment()
|
const lineWrapping = new Compartment()
|
||||||
const placeholderConfig = new Compartment()
|
const placeholderConfig = new Compartment()
|
||||||
@@ -178,7 +180,7 @@ export function useCodemirror(
|
|||||||
basicSetup,
|
basicSetup,
|
||||||
baseTheme,
|
baseTheme,
|
||||||
baseHighlightStyle,
|
baseHighlightStyle,
|
||||||
environmentTooltip,
|
environmentTooltip(subscribeToStream),
|
||||||
environmentHighlightStyle,
|
environmentHighlightStyle,
|
||||||
ViewPlugin.fromClass(
|
ViewPlugin.fromClass(
|
||||||
class {
|
class {
|
||||||
|
|||||||
@@ -1,56 +1,64 @@
|
|||||||
import { Extension } from "@codemirror/state"
|
import { Extension } from "@codemirror/state"
|
||||||
import { hoverTooltip } from "@codemirror/tooltip"
|
import { hoverTooltip } from "@codemirror/tooltip"
|
||||||
import { Decoration, MatchDecorator, ViewPlugin } from "@codemirror/view"
|
import { Decoration, MatchDecorator, ViewPlugin } from "@codemirror/view"
|
||||||
import { useReadonlyStream } from "~/helpers/utils/composables"
|
import {
|
||||||
|
StreamSubscriberFunc,
|
||||||
|
useReadonlyStream,
|
||||||
|
} from "~/helpers/utils/composables"
|
||||||
import { aggregateEnvs$ } from "~/newstore/environments"
|
import { aggregateEnvs$ } from "~/newstore/environments"
|
||||||
|
|
||||||
const cursorTooltipField = hoverTooltip((view, pos, side) => {
|
const cursorTooltipField = (subscribeToStream: StreamSubscriberFunc) =>
|
||||||
const { from, to, text } = view.state.doc.lineAt(pos)
|
hoverTooltip((view, pos, side) => {
|
||||||
let start = pos
|
const { from, to, text } = view.state.doc.lineAt(pos)
|
||||||
let end = pos
|
let start = pos
|
||||||
|
let end = pos
|
||||||
|
|
||||||
while (start > from && /\w/.test(text[start - from - 1])) start--
|
while (start > from && /\w/.test(text[start - from - 1])) start--
|
||||||
while (end < to && /\w/.test(text[end - from])) end++
|
while (end < to && /\w/.test(text[end - from])) end++
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(start === pos && side < 0) ||
|
(start === pos && side < 0) ||
|
||||||
(end === pos && side > 0) ||
|
(end === pos && side > 0) ||
|
||||||
!/(<<\w+>>)/g.test(text.slice(start - from - 2, end - from + 2))
|
!/(<<\w+>>)/g.test(text.slice(start - from - 2, end - from + 2))
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
const aggregateEnvs = useReadonlyStream(aggregateEnvs$, null)
|
let textContent: string
|
||||||
const envName = getEnvName(
|
subscribeToStream(aggregateEnvs$, (envs) => {
|
||||||
aggregateEnvs.value?.find(
|
const envName = getEnvName(
|
||||||
(env: { key: string }) => env.key === text.slice(start - from, end - from)
|
envs.find(
|
||||||
)?.sourceEnv
|
(env: { key: string }) =>
|
||||||
)
|
env.key === text.slice(start - from, end - from)
|
||||||
const envValue = getEnvValue(
|
)?.sourceEnv
|
||||||
aggregateEnvs.value?.find(
|
)
|
||||||
(env: { key: string }) => env.key === text.slice(start - from, end - from)
|
const envValue = getEnvValue(
|
||||||
)?.value
|
envs.find(
|
||||||
)
|
(env: { key: string }) =>
|
||||||
const textContent = `${envName} <kbd>${envValue}</kbd>`
|
env.key === text.slice(start - from, end - from)
|
||||||
|
)?.value
|
||||||
|
)
|
||||||
|
textContent = `${envName} <kbd>${envValue}</kbd>`
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pos: start,
|
pos: start,
|
||||||
end,
|
end,
|
||||||
above: true,
|
above: true,
|
||||||
create() {
|
create() {
|
||||||
const dom = document.createElement("span")
|
const dom = document.createElement("span")
|
||||||
dom.innerHTML = textContent
|
dom.innerHTML = textContent
|
||||||
dom.className = "tooltip-theme"
|
dom.className = "tooltip-theme"
|
||||||
return { dom }
|
return { dom }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function getEnvName(name: any) {
|
function getEnvName(name: any) {
|
||||||
if (name) return name
|
if (name) return name
|
||||||
return "choose an environment"
|
return "choose an environment"
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEnvValue(value: string) {
|
function getEnvValue(value: string | undefined) {
|
||||||
if (value) return value.replace(/"/g, """)
|
if (value) return value.replace(/"/g, """)
|
||||||
// it does not filter special characters before adding them to HTML.
|
// it does not filter special characters before adding them to HTML.
|
||||||
return "not found"
|
return "not found"
|
||||||
@@ -63,8 +71,9 @@ function checkEnv(env: string) {
|
|||||||
const envNotFound = "bg-red-400 text-red-50 hover:bg-red-600"
|
const envNotFound = "bg-red-400 text-red-50 hover:bg-red-600"
|
||||||
const aggregateEnvs = useReadonlyStream(aggregateEnvs$, null)
|
const aggregateEnvs = useReadonlyStream(aggregateEnvs$, null)
|
||||||
const className =
|
const className =
|
||||||
aggregateEnvs.value.find((k: { key: string }) => k.key === env.slice(2, -2))
|
aggregateEnvs.value?.find(
|
||||||
?.value === undefined
|
(k: { key: string }) => k.key === env.slice(2, -2)
|
||||||
|
)?.value === undefined
|
||||||
? envNotFound
|
? envNotFound
|
||||||
: envFound
|
: envFound
|
||||||
return Decoration.mark({
|
return Decoration.mark({
|
||||||
@@ -89,7 +98,8 @@ export const environmentHighlightStyle = ViewPlugin.define(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const environmentTooltip: Extension = [
|
export const environmentTooltip: (
|
||||||
cursorTooltipField,
|
subscribeToStream: StreamSubscriberFunc
|
||||||
environmentHighlightStyle,
|
) => Extension = (subscribeToStream: StreamSubscriberFunc) => {
|
||||||
]
|
return [cursorTooltipField(subscribeToStream), environmentHighlightStyle]
|
||||||
|
}
|
||||||
|
|||||||
@@ -100,11 +100,20 @@ export function pluckMultipleFromRef<T, K extends Array<keyof T>>(
|
|||||||
return Object.fromEntries(keys.map((x) => [x, pluckRef(sourceRef, x)])) as any
|
return Object.fromEntries(keys.map((x) => [x, pluckRef(sourceRef, x)])) as any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type StreamSubscriberFunc = <T>(
|
||||||
|
stream: Observable<T>,
|
||||||
|
next?: ((value: T) => void) | undefined,
|
||||||
|
error?: ((e: any) => void) | undefined,
|
||||||
|
complete?: (() => void) | undefined
|
||||||
|
) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A composable that provides the ability to run streams
|
* A composable that provides the ability to run streams
|
||||||
* and subscribe to them and respect the component lifecycle.
|
* and subscribe to them and respect the component lifecycle.
|
||||||
*/
|
*/
|
||||||
export function useStreamSubscriber() {
|
export function useStreamSubscriber(): {
|
||||||
|
subscribeToStream: StreamSubscriberFunc
|
||||||
|
} {
|
||||||
const subs: Subscription[] = []
|
const subs: Subscription[] = []
|
||||||
|
|
||||||
const runAndSubscribe = <T>(
|
const runAndSubscribe = <T>(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { cloneDeep } from "lodash"
|
import { cloneDeep } from "lodash"
|
||||||
import isEqual from "lodash/isEqual"
|
import isEqual from "lodash/isEqual"
|
||||||
import { combineLatest } from "rxjs"
|
import { combineLatest, Observable } from "rxjs"
|
||||||
import { distinctUntilChanged, map, pluck } from "rxjs/operators"
|
import { distinctUntilChanged, map, pluck } from "rxjs/operators"
|
||||||
import DispatchingStore, {
|
import DispatchingStore, {
|
||||||
defineDispatchers,
|
defineDispatchers,
|
||||||
@@ -285,17 +285,22 @@ export const currentEnvironment$ = combineLatest([
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AggregateEnvironment = {
|
||||||
|
key: string
|
||||||
|
value: string
|
||||||
|
sourceEnv: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream returning all the environment variables accessible in
|
* Stream returning all the environment variables accessible in
|
||||||
* the current state (Global + The Selected Environment).
|
* the current state (Global + The Selected Environment).
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export const aggregateEnvs$ = combineLatest([
|
export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
||||||
currentEnvironment$,
|
[currentEnvironment$, globalEnv$]
|
||||||
globalEnv$,
|
).pipe(
|
||||||
]).pipe(
|
|
||||||
map(([selectedEnv, globalVars]) => {
|
map(([selectedEnv, globalVars]) => {
|
||||||
const results: { key: string; value: string; sourceEnv: string }[] = []
|
const results: AggregateEnvironment[] = []
|
||||||
|
|
||||||
selectedEnv.variables.forEach(({ key, value }) =>
|
selectedEnv.variables.forEach(({ key, value }) =>
|
||||||
results.push({ key, value, sourceEnv: selectedEnv.name })
|
results.push({ key, value, sourceEnv: selectedEnv.name })
|
||||||
|
|||||||
Reference in New Issue
Block a user