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,
textarea::placeholder {
textarea::placeholder,
.CodeMirror-empty {
@apply text-secondaryDark;
@apply opacity-25;
}

View File

@@ -42,9 +42,7 @@
/>
<ButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="`${$t(
'action.prettify'
)} <kbd>${getSpecialKey()}</kbd><kbd>P</kbd>`"
:title="$t('action.prettify')"
:svg="prettifyQueryIcon"
@click.native="prettifyQuery"
/>
@@ -174,25 +172,7 @@
</div>
</div>
<div v-if="bulkMode" class="flex">
<textarea-autosize
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 ref="bulkEditor" class="w-full block"></div>
</div>
<div v-else>
<div
@@ -229,7 +209,9 @@
/>
<input
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}`"
:value="header.value"
autofocus
@@ -311,17 +293,9 @@
</div>
</template>
<script lang="ts">
import {
defineComponent,
onMounted,
PropType,
ref,
useContext,
watch,
} from "@nuxtjs/composition-api"
<script setup lang="ts">
import { onMounted, ref, useContext, watch } from "@nuxtjs/composition-api"
import clone from "lodash/clone"
import { getPlatformSpecialKey } from "~/helpers/platformutils"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import {
useNuxt,
@@ -348,208 +322,180 @@ import { makeGQLHistoryEntry, addGraphqlHistoryEntry } from "~/newstore/history"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { getCurrentStrategyID } from "~/helpers/network"
import { makeGQLRequest } from "~/helpers/types/HoppGQLRequest"
import { useCodemirror } from "~/helpers/editor/codemirror"
export default defineComponent({
props: {
conn: {
type: Object as PropType<GQLConnection>,
required: true,
},
},
setup(props) {
const {
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const nuxt = useNuxt()
const props = defineProps<{
conn: GQLConnection
}>()
const bulkMode = ref(false)
const bulkHeaders = ref("")
const {
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const nuxt = useNuxt()
watch(bulkHeaders, () => {
try {
const transformation = bulkHeaders.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"),
}))
setGQLHeaders(transformation)
} catch (e) {
$toast.error(t("error.something_went_wrong").toString(), {
icon: "error_outline",
})
console.error(e)
}
const bulkMode = ref(false)
const bulkHeaders = ref("")
watch(bulkHeaders, () => {
try {
const transformation = bulkHeaders.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"),
}))
setGQLHeaders(transformation)
} catch (e) {
$toast.error(t("error.something_went_wrong").toString(), {
icon: "error_outline",
})
console.error(e)
}
})
const url = useReadonlyStream(gqlURL$, "")
const gqlQueryString = useStream(gqlQuery$, "", setGQLQuery)
const variableString = useStream(gqlVariables$, "", setGQLVariables)
const headers = useStream(gqlHeaders$, [], setGQLHeaders)
const url = useReadonlyStream(gqlURL$, "")
const gqlQueryString = useStream(gqlQuery$, "", setGQLQuery)
const variableString = useStream(gqlVariables$, "", setGQLVariables)
const headers = useStream(gqlHeaders$, [], setGQLHeaders)
const queryEditor = ref<any | null>(null)
const bulkEditor = ref<any | null>(null)
const copyQueryIcon = ref("copy")
const prettifyQueryIcon = ref("align-left")
const copyVariablesIcon = ref("copy")
useCodemirror(bulkEditor, bulkHeaders, {
extendedEditorConfig: {
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(
headers,
() => {
if (
(headers.value[headers.value.length - 1]?.key !== "" ||
headers.value[headers.value.length - 1]?.value !== "") &&
headers.value.length
)
addRequestHeader()
},
{ deep: true }
const showSaveRequestModal = ref(false)
watch(
headers,
() => {
if (
(headers.value[headers.value.length - 1]?.key !== "" ||
headers.value[headers.value.length - 1]?.value !== "") &&
headers.value.length
)
addRequestHeader()
},
{ deep: true }
)
onMounted(() => {
if (!headers.value?.length) {
addRequestHeader()
}
})
const copyQuery = () => {
copyToClipboard(gqlQueryString.value)
copyQueryIcon.value = "check"
setTimeout(() => (copyQueryIcon.value = "copy"), 1000)
}
const response = useStream(gqlResponse$, "", setGQLResponse)
const runQuery = async () => {
const startTime = Date.now()
nuxt.value.$loading.start()
response.value = t("state.loading").toString()
try {
const runURL = clone(url.value)
const runHeaders = clone(headers.value)
const runQuery = clone(gqlQueryString.value)
const runVariables = clone(variableString.value)
const responseText = await props.conn.runQuery(
runURL,
runHeaders,
runQuery,
runVariables
)
const duration = Date.now() - startTime
nuxt.value.$loading.finish()
response.value = JSON.stringify(JSON.parse(responseText), null, 2)
addGraphqlHistoryEntry(
makeGQLHistoryEntry({
request: makeGQLRequest({
name: "",
url: runURL,
query: runQuery,
headers: runHeaders,
variables: runVariables,
}),
response: response.value,
star: false,
})
)
onMounted(() => {
if (!headers.value?.length) {
addRequestHeader()
}
$toast.success(t("state.finished_in", { duration }).toString(), {
icon: "done",
})
} catch (e: any) {
response.value = `${e}. ${t("error.check_console_details")}`
nuxt.value.$loading.finish()
const copyQuery = () => {
copyToClipboard(gqlQueryString.value)
copyQueryIcon.value = "check"
setTimeout(() => (copyQueryIcon.value = "copy"), 1000)
}
$toast.error(`${e} ${t("error.f12_details").toString()}`, {
icon: "error_outline",
})
console.error(e)
}
const response = useStream(gqlResponse$, "", setGQLResponse)
logHoppRequestRunToAnalytics({
platform: "graphql-query",
strategy: getCurrentStrategyID(),
})
}
const runQuery = async () => {
const startTime = Date.now()
const hideRequestModal = () => {
showSaveRequestModal.value = false
}
nuxt.value.$loading.start()
response.value = t("state.loading").toString()
const prettifyQuery = () => {
queryEditor.value.prettifyQuery()
prettifyQueryIcon.value = "check"
setTimeout(() => (prettifyQueryIcon.value = "align-left"), 1000)
}
try {
const runURL = clone(url.value)
const runHeaders = clone(headers.value)
const runQuery = clone(gqlQueryString.value)
const runVariables = clone(variableString.value)
const saveRequest = () => {
showSaveRequestModal.value = true
}
const responseText = await props.conn.runQuery(
runURL,
runHeaders,
runQuery,
runVariables
)
const duration = Date.now() - startTime
// Why ?
const updateQuery = (updatedQuery: string) => {
gqlQueryString.value = updatedQuery
}
nuxt.value.$loading.finish()
const copyVariables = () => {
copyToClipboard(variableString.value)
copyVariablesIcon.value = "check"
setTimeout(() => (copyVariablesIcon.value = "copy"), 1000)
}
response.value = JSON.stringify(JSON.parse(responseText), null, 2)
const addRequestHeader = () => {
addGQLHeader({
key: "",
value: "",
active: true,
})
}
addGraphqlHistoryEntry(
makeGQLHistoryEntry({
request: makeGQLRequest({
name: "",
url: runURL,
query: runQuery,
headers: runHeaders,
variables: runVariables,
}),
response: response.value,
star: false,
})
)
$toast.success(t("state.finished_in", { duration }).toString(), {
icon: "done",
})
} catch (e: any) {
response.value = `${e}. ${t("error.check_console_details")}`
nuxt.value.$loading.finish()
$toast.error(`${e} ${t("error.f12_details").toString()}`, {
icon: "error_outline",
})
console.error(e)
}
logHoppRequestRunToAnalytics({
platform: "graphql-query",
strategy: getCurrentStrategyID(),
})
}
const hideRequestModal = () => {
showSaveRequestModal.value = false
}
const prettifyQuery = () => {
queryEditor.value.prettifyQuery()
prettifyQueryIcon.value = "check"
setTimeout(() => (prettifyQueryIcon.value = "align-left"), 1000)
}
const saveRequest = () => {
showSaveRequestModal.value = true
}
// Why ?
const updateQuery = (updatedQuery: string) => {
gqlQueryString.value = updatedQuery
}
const copyVariables = () => {
copyToClipboard(variableString.value)
copyVariablesIcon.value = "check"
setTimeout(() => (copyVariablesIcon.value = "copy"), 1000)
}
const addRequestHeader = () => {
addGQLHeader({
key: "",
value: "",
active: true,
})
}
const removeRequestHeader = (index: number) => {
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,
}
},
})
const removeRequestHeader = (index: number) => {
removeGQLHeader(index)
}
</script>

View File

@@ -48,25 +48,7 @@
</div>
</div>
<div v-if="bulkMode" class="flex">
<textarea-autosize
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 ref="bulkEditor" class="w-full block"></div>
</div>
<div v-else>
<div
@@ -193,96 +175,86 @@
</AppSection>
</template>
<script lang="ts">
<script setup lang="ts">
import { ref, useContext, watch } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror"
import {
defineComponent,
ref,
useContext,
watch,
} from "@nuxtjs/composition-api"
import {
restHeaders$,
addRESTHeader,
updateRESTHeader,
deleteRESTHeader,
deleteAllRESTHeaders,
deleteRESTHeader,
restHeaders$,
setRESTHeaders,
updateRESTHeader,
} from "~/newstore/RESTSession"
import { commonHeaders } from "~/helpers/headers"
import { useSetting } from "~/newstore/settings"
import { useReadonlyStream } from "~/helpers/utils/composables"
import { HoppRESTHeader } from "~/helpers/types/HoppRESTRequest"
export default defineComponent({
setup() {
const {
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const {
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const bulkMode = ref(false)
const bulkHeaders = ref("")
const bulkMode = ref(false)
const bulkHeaders = ref("")
const bulkEditor = ref<any | null>(null)
watch(bulkHeaders, () => {
try {
const transformation = bulkHeaders.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"),
}))
setRESTHeaders(transformation)
} catch (e) {
$toast.error(t("error.something_went_wrong").toString(), {
icon: "error_outline",
})
console.error(e)
}
})
return {
headers$: useReadonlyStream(restHeaders$, []),
EXPERIMENTAL_URL_BAR_ENABLED: useSetting("EXPERIMENTAL_URL_BAR_ENABLED"),
bulkMode,
bulkHeaders,
}
},
data() {
return {
commonHeaders,
}
},
watch: {
headers$: {
handler(newValue) {
if (
(newValue[newValue.length - 1]?.key !== "" ||
newValue[newValue.length - 1]?.value !== "") &&
newValue.length
)
this.addHeader()
},
deep: true,
},
},
// mounted() {
// if (!this.headers$?.length) {
// this.addHeader()
// }
// },
methods: {
addHeader() {
addRESTHeader({ key: "", value: "", active: true })
},
updateHeader(index: number, item: HoppRESTHeader) {
updateRESTHeader(index, item)
},
deleteHeader(index: number) {
deleteRESTHeader(index)
},
clearContent() {
deleteAllRESTHeaders()
},
useCodemirror(bulkEditor, bulkHeaders, {
extendedEditorConfig: {
mode: "text/x-yaml",
placeholder: t("state.bulk_mode_placeholder").toString(),
},
linter: null,
completer: null,
})
watch(bulkHeaders, () => {
try {
const transformation = bulkHeaders.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"),
}))
setRESTHeaders(transformation)
} catch (e) {
$toast.error(t("error.something_went_wrong").toString(), {
icon: "error_outline",
})
console.error(e)
}
})
const headers$ = useReadonlyStream(restHeaders$, [])
watch(
headers$,
(newValue) => {
if (
(newValue[newValue.length - 1]?.key !== "" ||
newValue[newValue.length - 1]?.value !== "") &&
newValue.length
)
addHeader()
},
{ deep: true }
)
const addHeader = () => {
addRESTHeader({ key: "", value: "", active: true })
}
const updateHeader = (index: number, item: HoppRESTHeader) => {
updateRESTHeader(index, item)
}
const deleteHeader = (index: number) => {
deleteRESTHeader(index)
}
const clearContent = () => {
deleteAllRESTHeaders()
}
const EXPERIMENTAL_URL_BAR_ENABLED = useSetting("EXPERIMENTAL_URL_BAR_ENABLED")
</script>

View File

@@ -48,25 +48,7 @@
</div>
</div>
<div v-if="bulkMode" class="flex">
<textarea-autosize
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 ref="bulkEditor" class="w-full block"></div>
</div>
<div v-else>
<div
@@ -96,7 +78,7 @@
<input
v-else
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"
:value="param.key"
autofocus
@@ -130,7 +112,7 @@
<input
v-else
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"
:value="param.value"
@change="
@@ -202,13 +184,9 @@
</AppSection>
</template>
<script lang="ts">
import {
defineComponent,
ref,
useContext,
watch,
} from "@nuxtjs/composition-api"
<script setup lang="ts">
import { ref, useContext, watch } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror"
import { HoppRESTParam } from "~/helpers/types/HoppRESTRequest"
import { useReadonlyStream } from "~/helpers/utils/composables"
import {
@@ -220,72 +198,74 @@ import {
setRESTParams,
} from "~/newstore/RESTSession"
import { useSetting } from "~/newstore/settings"
import "codemirror/mode/yaml/yaml"
export default defineComponent({
setup() {
const {
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const {
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const bulkMode = ref(false)
const bulkParams = ref("")
const bulkMode = ref(false)
const bulkParams = ref("")
watch(bulkParams, () => {
try {
const transformation = bulkParams.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"),
}))
setRESTParams(transformation)
} catch (e) {
$toast.error(t("error.something_went_wrong").toString(), {
icon: "error_outline",
})
console.error(e)
}
watch(bulkParams, () => {
try {
const transformation = bulkParams.value.split("\n").map((item) => ({
key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"),
}))
setRESTParams(transformation)
} catch (e) {
$toast.error(t("error.something_went_wrong").toString(), {
icon: "error_outline",
})
return {
params$: useReadonlyStream(restParams$, []),
EXPERIMENTAL_URL_BAR_ENABLED: useSetting("EXPERIMENTAL_URL_BAR_ENABLED"),
bulkMode,
bulkParams,
}
},
watch: {
params$: {
handler(newValue) {
if (
(newValue[newValue.length - 1]?.key !== "" ||
newValue[newValue.length - 1]?.value !== "") &&
newValue.length
)
this.addParam()
},
deep: true,
},
},
// mounted() {
// if (!this.params$?.length) {
// this.addParam()
// }
// },
methods: {
addParam() {
addRESTParam({ key: "", value: "", active: true })
},
updateParam(index: number, item: HoppRESTParam) {
updateRESTParam(index, item)
},
deleteParam(index: number) {
deleteRESTParam(index)
},
clearContent() {
deleteAllRESTParams()
},
},
console.error(e)
}
})
const bulkEditor = ref<any | null>(null)
useCodemirror(bulkEditor, bulkParams, {
extendedEditorConfig: {
mode: "text/x-yaml",
placeholder: t("state.bulk_mode_placeholder").toString(),
},
linter: null,
completer: null,
})
const params$ = useReadonlyStream(restParams$, [])
watch(
params$,
(newValue) => {
if (
(newValue[newValue.length - 1]?.key !== "" ||
newValue[newValue.length - 1]?.value !== "") &&
newValue.length
)
addParam()
},
{ deep: true }
)
const addParam = () => {
addRESTParam({ key: "", value: "", active: true })
}
const updateParam = (index: number, item: HoppRESTParam) => {
updateRESTParam(index, item)
}
const deleteParam = (index: number) => {
deleteRESTParam(index)
}
const clearContent = () => {
deleteAllRESTParams()
}
const EXPERIMENTAL_URL_BAR_ENABLED = useSetting("EXPERIMENTAL_URL_BAR_ENABLED")
</script>