feat: port bulk editor textareas to codemirror

This commit is contained in:
liyasthomas
2021-09-08 21:52:26 +05:30
parent e1a25fa894
commit b15fd6c75a
4 changed files with 303 additions and 404 deletions

View File

@@ -36,7 +36,8 @@
} }
input::placeholder, input::placeholder,
textarea::placeholder { textarea::placeholder,
.CodeMirror-empty {
@apply text-secondaryDark; @apply text-secondaryDark;
@apply opacity-25; @apply opacity-25;
} }

View File

@@ -42,9 +42,7 @@
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="`${$t( :title="$t('action.prettify')"
'action.prettify'
)} <kbd>${getSpecialKey()}</kbd><kbd>P</kbd>`"
:svg="prettifyQueryIcon" :svg="prettifyQueryIcon"
@click.native="prettifyQuery" @click.native="prettifyQuery"
/> />
@@ -174,25 +172,7 @@
</div> </div>
</div> </div>
<div v-if="bulkMode" class="flex"> <div v-if="bulkMode" class="flex">
<textarea-autosize <div ref="bulkEditor" class="w-full block"></div>
v-model="bulkHeaders"
v-focus
name="bulk-parameters"
class="
bg-transparent
border-b border-dividerLight
flex
font-mono
flex-1
py-2
px-4
whitespace-pre
resize-y
overflow-auto
"
rows="10"
:placeholder="$t('state.bulk_mode_placeholder')"
/>
</div> </div>
<div v-else> <div v-else>
<div <div
@@ -229,7 +209,9 @@
/> />
<input <input
class="bg-transparent flex flex-1 py-2 px-4" class="bg-transparent flex flex-1 py-2 px-4"
:placeholder="$t('count.value', { count: index + 1 })" :placeholder="
$t('count.value', { count: index + 1 }).toString()
"
:name="`value ${index}`" :name="`value ${index}`"
:value="header.value" :value="header.value"
autofocus autofocus
@@ -311,17 +293,9 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { import { onMounted, ref, useContext, watch } from "@nuxtjs/composition-api"
defineComponent,
onMounted,
PropType,
ref,
useContext,
watch,
} from "@nuxtjs/composition-api"
import clone from "lodash/clone" import clone from "lodash/clone"
import { getPlatformSpecialKey } from "~/helpers/platformutils"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { import {
useNuxt, useNuxt,
@@ -348,26 +322,23 @@ import { makeGQLHistoryEntry, addGraphqlHistoryEntry } from "~/newstore/history"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { getCurrentStrategyID } from "~/helpers/network" import { getCurrentStrategyID } from "~/helpers/network"
import { makeGQLRequest } from "~/helpers/types/HoppGQLRequest" import { makeGQLRequest } from "~/helpers/types/HoppGQLRequest"
import { useCodemirror } from "~/helpers/editor/codemirror"
export default defineComponent({ const props = defineProps<{
props: { conn: GQLConnection
conn: { }>()
type: Object as PropType<GQLConnection>,
required: true, const {
},
},
setup(props) {
const {
$toast, $toast,
app: { i18n }, app: { i18n },
} = useContext() } = useContext()
const t = i18n.t.bind(i18n) const t = i18n.t.bind(i18n)
const nuxt = useNuxt() const nuxt = useNuxt()
const bulkMode = ref(false) const bulkMode = ref(false)
const bulkHeaders = ref("") const bulkHeaders = ref("")
watch(bulkHeaders, () => { watch(bulkHeaders, () => {
try { try {
const transformation = bulkHeaders.value.split("\n").map((item) => ({ const transformation = bulkHeaders.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""), key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
@@ -381,24 +352,33 @@ export default defineComponent({
}) })
console.error(e) console.error(e)
} }
}) })
const url = useReadonlyStream(gqlURL$, "") const url = useReadonlyStream(gqlURL$, "")
const gqlQueryString = useStream(gqlQuery$, "", setGQLQuery) const gqlQueryString = useStream(gqlQuery$, "", setGQLQuery)
const variableString = useStream(gqlVariables$, "", setGQLVariables) const variableString = useStream(gqlVariables$, "", setGQLVariables)
const headers = useStream(gqlHeaders$, [], setGQLHeaders) const headers = useStream(gqlHeaders$, [], setGQLHeaders)
const queryEditor = ref<any | null>(null) const bulkEditor = ref<any | null>(null)
const copyQueryIcon = ref("copy") useCodemirror(bulkEditor, bulkHeaders, {
const prettifyQueryIcon = ref("align-left") extendedEditorConfig: {
const copyVariablesIcon = ref("copy") mode: "text/x-yaml",
placeholder: t("state.bulk_mode_placeholder").toString(),
},
linter: null,
completer: null,
})
const showSaveRequestModal = ref(false) const queryEditor = ref<any | null>(null)
const schema = useReadonlyStream(props.conn.schemaString$, "") const copyQueryIcon = ref("copy")
const prettifyQueryIcon = ref("align-left")
const copyVariablesIcon = ref("copy")
watch( const showSaveRequestModal = ref(false)
watch(
headers, headers,
() => { () => {
if ( if (
@@ -409,23 +389,23 @@ export default defineComponent({
addRequestHeader() addRequestHeader()
}, },
{ deep: true } { deep: true }
) )
onMounted(() => { onMounted(() => {
if (!headers.value?.length) { if (!headers.value?.length) {
addRequestHeader() addRequestHeader()
} }
}) })
const copyQuery = () => { const copyQuery = () => {
copyToClipboard(gqlQueryString.value) copyToClipboard(gqlQueryString.value)
copyQueryIcon.value = "check" copyQueryIcon.value = "check"
setTimeout(() => (copyQueryIcon.value = "copy"), 1000) setTimeout(() => (copyQueryIcon.value = "copy"), 1000)
} }
const response = useStream(gqlResponse$, "", setGQLResponse) const response = useStream(gqlResponse$, "", setGQLResponse)
const runQuery = async () => { const runQuery = async () => {
const startTime = Date.now() const startTime = Date.now()
nuxt.value.$loading.start() nuxt.value.$loading.start()
@@ -480,76 +460,42 @@ export default defineComponent({
platform: "graphql-query", platform: "graphql-query",
strategy: getCurrentStrategyID(), strategy: getCurrentStrategyID(),
}) })
} }
const hideRequestModal = () => { const hideRequestModal = () => {
showSaveRequestModal.value = false showSaveRequestModal.value = false
} }
const prettifyQuery = () => { const prettifyQuery = () => {
queryEditor.value.prettifyQuery() queryEditor.value.prettifyQuery()
prettifyQueryIcon.value = "check" prettifyQueryIcon.value = "check"
setTimeout(() => (prettifyQueryIcon.value = "align-left"), 1000) setTimeout(() => (prettifyQueryIcon.value = "align-left"), 1000)
} }
const saveRequest = () => { const saveRequest = () => {
showSaveRequestModal.value = true showSaveRequestModal.value = true
} }
// Why ? // Why ?
const updateQuery = (updatedQuery: string) => { const updateQuery = (updatedQuery: string) => {
gqlQueryString.value = updatedQuery gqlQueryString.value = updatedQuery
} }
const copyVariables = () => { const copyVariables = () => {
copyToClipboard(variableString.value) copyToClipboard(variableString.value)
copyVariablesIcon.value = "check" copyVariablesIcon.value = "check"
setTimeout(() => (copyVariablesIcon.value = "copy"), 1000) setTimeout(() => (copyVariablesIcon.value = "copy"), 1000)
} }
const addRequestHeader = () => { const addRequestHeader = () => {
addGQLHeader({ addGQLHeader({
key: "", key: "",
value: "", value: "",
active: true, active: true,
}) })
} }
const removeRequestHeader = (index: number) => { const removeRequestHeader = (index: number) => {
removeGQLHeader(index) removeGQLHeader(index)
} }
return {
gqlQueryString,
variableString,
headers,
copyQueryIcon,
prettifyQueryIcon,
copyVariablesIcon,
queryEditor,
showSaveRequestModal,
hideRequestModal,
schema,
copyQuery,
runQuery,
prettifyQuery,
saveRequest,
updateQuery,
copyVariables,
addRequestHeader,
removeRequestHeader,
getSpecialKey: getPlatformSpecialKey,
commonHeaders,
updateGQLHeader,
bulkMode,
bulkHeaders,
}
},
})
</script> </script>

View File

@@ -48,25 +48,7 @@
</div> </div>
</div> </div>
<div v-if="bulkMode" class="flex"> <div v-if="bulkMode" class="flex">
<textarea-autosize <div ref="bulkEditor" class="w-full block"></div>
v-model="bulkHeaders"
v-focus
name="bulk-headers"
class="
bg-transparent
border-b border-dividerLight
flex
font-mono
flex-1
py-2
px-4
whitespace-pre
resize-y
overflow-auto
"
rows="10"
:placeholder="$t('state.bulk_mode_placeholder')"
/>
</div> </div>
<div v-else> <div v-else>
<div <div
@@ -193,38 +175,42 @@
</AppSection> </AppSection>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { ref, useContext, watch } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror"
import { import {
defineComponent,
ref,
useContext,
watch,
} from "@nuxtjs/composition-api"
import {
restHeaders$,
addRESTHeader, addRESTHeader,
updateRESTHeader,
deleteRESTHeader,
deleteAllRESTHeaders, deleteAllRESTHeaders,
deleteRESTHeader,
restHeaders$,
setRESTHeaders, setRESTHeaders,
updateRESTHeader,
} from "~/newstore/RESTSession" } from "~/newstore/RESTSession"
import { commonHeaders } from "~/helpers/headers" import { commonHeaders } from "~/helpers/headers"
import { useSetting } from "~/newstore/settings" import { useSetting } from "~/newstore/settings"
import { useReadonlyStream } from "~/helpers/utils/composables" import { useReadonlyStream } from "~/helpers/utils/composables"
import { HoppRESTHeader } from "~/helpers/types/HoppRESTRequest" import { HoppRESTHeader } from "~/helpers/types/HoppRESTRequest"
export default defineComponent({ const {
setup() {
const {
$toast, $toast,
app: { i18n }, app: { i18n },
} = useContext() } = useContext()
const t = i18n.t.bind(i18n) const t = i18n.t.bind(i18n)
const bulkMode = ref(false) const bulkMode = ref(false)
const bulkHeaders = ref("") const bulkHeaders = ref("")
const bulkEditor = ref<any | null>(null)
watch(bulkHeaders, () => { useCodemirror(bulkEditor, bulkHeaders, {
extendedEditorConfig: {
mode: "text/x-yaml",
placeholder: t("state.bulk_mode_placeholder").toString(),
},
linter: null,
completer: null,
})
watch(bulkHeaders, () => {
try { try {
const transformation = bulkHeaders.value.split("\n").map((item) => ({ const transformation = bulkHeaders.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""), key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
@@ -238,51 +224,37 @@ export default defineComponent({
}) })
console.error(e) console.error(e)
} }
}) })
return { const headers$ = useReadonlyStream(restHeaders$, [])
headers$: useReadonlyStream(restHeaders$, []),
EXPERIMENTAL_URL_BAR_ENABLED: useSetting("EXPERIMENTAL_URL_BAR_ENABLED"), watch(
bulkMode, headers$,
bulkHeaders, (newValue) => {
}
},
data() {
return {
commonHeaders,
}
},
watch: {
headers$: {
handler(newValue) {
if ( if (
(newValue[newValue.length - 1]?.key !== "" || (newValue[newValue.length - 1]?.key !== "" ||
newValue[newValue.length - 1]?.value !== "") && newValue[newValue.length - 1]?.value !== "") &&
newValue.length newValue.length
) )
this.addHeader() addHeader()
}, },
deep: true, { deep: true }
}, )
},
// mounted() { const addHeader = () => {
// if (!this.headers$?.length) {
// this.addHeader()
// }
// },
methods: {
addHeader() {
addRESTHeader({ key: "", value: "", active: true }) addRESTHeader({ key: "", value: "", active: true })
}, }
updateHeader(index: number, item: HoppRESTHeader) {
const updateHeader = (index: number, item: HoppRESTHeader) => {
updateRESTHeader(index, item) updateRESTHeader(index, item)
}, }
deleteHeader(index: number) {
const deleteHeader = (index: number) => {
deleteRESTHeader(index) deleteRESTHeader(index)
}, }
clearContent() {
const clearContent = () => {
deleteAllRESTHeaders() deleteAllRESTHeaders()
}, }
}, const EXPERIMENTAL_URL_BAR_ENABLED = useSetting("EXPERIMENTAL_URL_BAR_ENABLED")
})
</script> </script>

View File

@@ -48,25 +48,7 @@
</div> </div>
</div> </div>
<div v-if="bulkMode" class="flex"> <div v-if="bulkMode" class="flex">
<textarea-autosize <div ref="bulkEditor" class="w-full block"></div>
v-model="bulkParams"
v-focus
name="bulk-parameters"
class="
bg-transparent
border-b border-dividerLight
flex
font-mono font-medium
flex-1
py-2
px-4
whitespace-pre
resize-y
overflow-auto
"
rows="10"
:placeholder="$t('state.bulk_mode_placeholder')"
/>
</div> </div>
<div v-else> <div v-else>
<div <div
@@ -96,7 +78,7 @@
<input <input
v-else v-else
class="bg-transparent flex flex-1 py-2 px-4" class="bg-transparent flex flex-1 py-2 px-4"
:placeholder="$t('count.parameter', { count: index + 1 })" :placeholder="$t('count.parameter', { count: index + 1 }).toString()"
:name="'param' + index" :name="'param' + index"
:value="param.key" :value="param.key"
autofocus autofocus
@@ -130,7 +112,7 @@
<input <input
v-else v-else
class="bg-transparent flex flex-1 py-2 px-4" class="bg-transparent flex flex-1 py-2 px-4"
:placeholder="$t('count.value', { count: index + 1 })" :placeholder="$t('count.value', { count: index + 1 }).toString()"
:name="'value' + index" :name="'value' + index"
:value="param.value" :value="param.value"
@change=" @change="
@@ -202,13 +184,9 @@
</AppSection> </AppSection>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { import { ref, useContext, watch } from "@nuxtjs/composition-api"
defineComponent, import { useCodemirror } from "~/helpers/editor/codemirror"
ref,
useContext,
watch,
} from "@nuxtjs/composition-api"
import { HoppRESTParam } from "~/helpers/types/HoppRESTRequest" import { HoppRESTParam } from "~/helpers/types/HoppRESTRequest"
import { useReadonlyStream } from "~/helpers/utils/composables" import { useReadonlyStream } from "~/helpers/utils/composables"
import { import {
@@ -220,19 +198,18 @@ import {
setRESTParams, setRESTParams,
} from "~/newstore/RESTSession" } from "~/newstore/RESTSession"
import { useSetting } from "~/newstore/settings" import { useSetting } from "~/newstore/settings"
import "codemirror/mode/yaml/yaml"
export default defineComponent({ const {
setup() {
const {
$toast, $toast,
app: { i18n }, app: { i18n },
} = useContext() } = useContext()
const t = i18n.t.bind(i18n) const t = i18n.t.bind(i18n)
const bulkMode = ref(false) const bulkMode = ref(false)
const bulkParams = ref("") const bulkParams = ref("")
watch(bulkParams, () => { watch(bulkParams, () => {
try { try {
const transformation = bulkParams.value.split("\n").map((item) => ({ const transformation = bulkParams.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""), key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
@@ -246,46 +223,49 @@ export default defineComponent({
}) })
console.error(e) console.error(e)
} }
}) })
return { const bulkEditor = ref<any | null>(null)
params$: useReadonlyStream(restParams$, []),
EXPERIMENTAL_URL_BAR_ENABLED: useSetting("EXPERIMENTAL_URL_BAR_ENABLED"), useCodemirror(bulkEditor, bulkParams, {
bulkMode, extendedEditorConfig: {
bulkParams, mode: "text/x-yaml",
} placeholder: t("state.bulk_mode_placeholder").toString(),
}, },
watch: { linter: null,
params$: { completer: null,
handler(newValue) { })
const params$ = useReadonlyStream(restParams$, [])
watch(
params$,
(newValue) => {
if ( if (
(newValue[newValue.length - 1]?.key !== "" || (newValue[newValue.length - 1]?.key !== "" ||
newValue[newValue.length - 1]?.value !== "") && newValue[newValue.length - 1]?.value !== "") &&
newValue.length newValue.length
) )
this.addParam() addParam()
}, },
deep: true, { deep: true }
}, )
},
// mounted() { const addParam = () => {
// if (!this.params$?.length) {
// this.addParam()
// }
// },
methods: {
addParam() {
addRESTParam({ key: "", value: "", active: true }) addRESTParam({ key: "", value: "", active: true })
}, }
updateParam(index: number, item: HoppRESTParam) {
const updateParam = (index: number, item: HoppRESTParam) => {
updateRESTParam(index, item) updateRESTParam(index, item)
}, }
deleteParam(index: number) {
const deleteParam = (index: number) => {
deleteRESTParam(index) deleteRESTParam(index)
}, }
clearContent() {
const clearContent = () => {
deleteAllRESTParams() deleteAllRESTParams()
}, }
},
}) const EXPERIMENTAL_URL_BAR_ENABLED = useSetting("EXPERIMENTAL_URL_BAR_ENABLED")
</script> </script>