Skip to content

Commit

Permalink
feat(ui): Response tag implemented - use response data from other req…
Browse files Browse the repository at this point in the history
…uests in any request input without using env vars
  • Loading branch information
flawiddsouza committed Sep 19, 2024
1 parent 472047b commit d2e6a67
Show file tree
Hide file tree
Showing 29 changed files with 1,171 additions and 219 deletions.
82 changes: 51 additions & 31 deletions packages/ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
"ci-test": "start-server-and-test dev http://127.0.0.1:5173/ e2e-test"
},
"dependencies": {
"@codemirror/autocomplete": "^6.16.0",
"@codemirror/commands": "^6.5.0",
"@codemirror/autocomplete": "^6.18.0",
"@codemirror/commands": "^6.6.1",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/language": "^6.10.1",
"@codemirror/language": "^6.10.2",
"@codemirror/search": "^6.5.6",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.26.3",
"@codemirror/view": "^6.33.0",
"@flawiddsouza/quickjs-emscripten-sync": "^1.5.2",
"@jitl/quickjs-singlefile-browser-release-asyncify": "^0.29.1",
"chai": "^4.3.10",
Expand All @@ -38,6 +38,7 @@
"graphql-request": "^7.1.0",
"httpsnippet-browser": "github:flawiddsouza/httpsnippet-browser#ed12aba",
"insomnia-importers-browser": "github:flawiddsouza/insomnia-importers-browser",
"js-base64": "^3.7.7",
"js-yaml": "^4.1.0",
"jsonpath-plus": "9.0.0",
"jszip": "^3.7.1",
Expand Down
79 changes: 79 additions & 0 deletions packages/ui/src/codemirror-extensions/tags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { ViewPlugin, Decoration, EditorView, ViewUpdate, MatchDecorator, WidgetType, DecorationSet } from '@codemirror/view'
import { parseFunction } from '@/parsers/tag'
import type { ParsedResult } from '@/parsers/tag'

type OnClickType = (parsedFunc: ParsedResult, updateFunc: (updatedTag: string) => void) => void

class PlaceholderWidget extends WidgetType {
readonly #onClick: () => void
#parsed: ParsedResult
readonly #view: EditorView
readonly #pos: number

constructor(readonly placeholder: string, readonly onClick: OnClickType, readonly view: EditorView, readonly pos: number) {
super()
this.#parsed = parseFunction(placeholder)
this.#onClick = () => {
onClick(this.#parsed, this.updateTag)
}
this.#view = view
this.#pos = pos
}

eq(other: PlaceholderWidget) {
return this.placeholder === other.placeholder
}

toDOM() {
const span = document.createElement('span')
span.className = 'tag'
span.textContent = `${this.#parsed.functionName}(...)`
span.title = this.placeholder
span.addEventListener('click', this.#onClick)
return span
}

ignoreEvent(): boolean {
return false
}

destroy(dom: HTMLElement): void {
dom.removeEventListener('click', this.#onClick)
}

updateTag = (updatedTag: string) => {
this.#parsed = parseFunction(updatedTag)
this.#view.dispatch({
changes: { from: this.#pos + 3, to: this.#pos + this.placeholder.length + 3, insert: updatedTag }
})
}
}

export function tags(onClick: OnClickType) {
const placeholderMatcher = new MatchDecorator({
regexp: /{% (.+?) %}/g,
decoration: (match, view, pos) => Decoration.replace({
widget: new PlaceholderWidget(match[1], onClick, view, pos),
})
})

const tags = ViewPlugin.fromClass(
class {
placeholders: DecorationSet
constructor(view: EditorView) {
this.placeholders = placeholderMatcher.createDeco(view)
}
update(update: ViewUpdate) {
this.placeholders = placeholderMatcher.updateDeco(update, this.placeholders)
}
},
{
decorations: instance => instance.placeholders,
provide: plugin => EditorView.atomicRanges.of(view => {
return view.plugin(plugin)?.placeholders || Decoration.none
})
}
)

return tags
}
25 changes: 22 additions & 3 deletions packages/ui/src/components/CodeMirrorEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
<script lang="ts">
import { EditorView, highlightActiveLine, keymap, highlightSpecialChars, lineNumbers, highlightActiveLineGutter, drawSelection } from '@codemirror/view'
import { EditorState, StateEffect } from '@codemirror/state'
import { json } from '@codemirror/lang-json'
import { json, jsonLanguage } from '@codemirror/lang-json'
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript'
import { graphql } from 'cm6-graphql'
import { graphql, graphqlLanguage } from 'cm6-graphql'
import { closeBrackets, completeFromList, autocompletion } from '@codemirror/autocomplete'
import { indentOnInput, indentUnit, bracketMatching, foldGutter, syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language'
import { defaultKeymap, indentWithTab, history, historyKeymap, selectLine, selectLineBoundaryForward } from '@codemirror/commands'
import { searchKeymap, highlightSelectionMatches } from '@codemirror/search'
import { codeMirrorSyntaxHighlighting } from '@/helpers'
import { envVarDecoration } from '@/utils/codemirror-extensions'
import { tags } from '@/codemirror-extensions/tags'
import { codeMirrorStyleOverrides } from '@/utils/code-mirror-style-overrides'
import type { ParsedResult } from '@/parsers/tag'
/**
* "Mod-Enter" is "Ctrl-Enter" inside codemirror
Expand Down Expand Up @@ -42,6 +44,7 @@ function getLanguageFuncAndHighlightStyle(language) {
if(language === 'json') {
languageFunc = json()
languageData = jsonLanguage
highlightStyle = codeMirrorSyntaxHighlighting()
}
Expand All @@ -53,6 +56,7 @@ function getLanguageFuncAndHighlightStyle(language) {
if(language === 'graphql') {
languageFunc = graphql()
languageData = graphqlLanguage
highlightStyle = codeMirrorSyntaxHighlighting()
}
Expand All @@ -74,10 +78,24 @@ function getExtensions(vueInstance, language) {
}) : null,
].filter(Boolean)
let autocompletionExtension = autocompletion()
if(languageData === null && vueInstance.autocompletions.length > 0) {
autocompletionExtension = autocompletion({
override: [
completeFromList(vueInstance.autocompletions)
]
})
}
const tagClickHandler = (parsedFunc: ParsedResult, updateFunc: (updatedTag: string) => void) => {
vueInstance.$emit('tag-click', parsedFunc, updateFunc)
}
return [
...languageArray,
...autocompletionsArray,
autocompletion(),
autocompletionExtension,
syntaxHighlighting(highlightStyle, { fallback: true }),
lineNumbers(),
highlightActiveLineGutter(),
Expand Down Expand Up @@ -108,6 +126,7 @@ function getExtensions(vueInstance, language) {
]),
vueInstance.readonly ? EditorState.readOnly.of(true) : EditorState.readOnly.of(false),
envVarDecoration(vueInstance.envVariables),
tags(tagClickHandler),
]
}
Expand Down
Loading

0 comments on commit d2e6a67

Please sign in to comment.