"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "packages/hoppscotch-app/components/graphql/Sidebar.vue" between
hoppscotch-2.2.1.tar.gz and hoppscotch-3.0.0.tar.gz

About: Hoppscotch is a light-weight, web based API development suite.

Sidebar.vue  (hoppscotch-2.2.1):Sidebar.vue  (hoppscotch-3.0.0)
<template> <template>
<SmartTabs styles="sticky bg-primary z-10 top-0" vertical> <SmartTabs
<SmartTab v-model="selectedNavigationTab"
:id="'history'" styles="sticky bg-primary z-10 top-0"
icon="clock" vertical
:label="`${t('tab.history')}`" render-inactive-tabs
:selected="true" >
> <SmartTab :id="'history'" :icon="IconClock" :label="`${t('tab.history')}`">
<History <History :page="'graphql'" @use-history="handleUseHistory" />
ref="graphqlHistoryComponent"
:page="'graphql'"
@useHistory="handleUseHistory"
/>
</SmartTab> </SmartTab>
<SmartTab <SmartTab
:id="'collections'" :id="'collections'"
icon="folder" :icon="IconFolder"
:label="`${t('tab.collections')}`" :label="`${t('tab.collections')}`"
> >
<CollectionsGraphql /> <CollectionsGraphql />
</SmartTab> </SmartTab>
<SmartTab <SmartTab
:id="'docs'" :id="'docs'"
icon="book-open" :icon="IconBookOpen"
:label="`${t('tab.documentation')}`" :label="`${t('tab.documentation')}`"
> >
<div <div
v-if=" v-if="
queryFields.length === 0 && queryFields.length === 0 &&
mutationFields.length === 0 && mutationFields.length === 0 &&
subscriptionFields.length === 0 && subscriptionFields.length === 0 &&
graphqlTypes.length === 0 graphqlTypes.length === 0
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight " class="flex flex-col items-center justify-center p-4 text-secondaryLight "
> >
<img <img
:src="`/images/states/${$colorMode.value}/add_comment.svg`" :src="`/images/states/${colorMode.value}/add_comment.svg`"
loading="lazy" loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my- 4" class="inline-flex flex-col object-contain object-center w-16 h-16 my- 4"
:alt="`${t('empty.documentation')}`" :alt="`${t('empty.documentation')}`"
/> />
<span class="mb-4 text-center"> <span class="mb-4 text-center">
{{ t("empty.documentation") }} {{ t("empty.documentation") }}
</span> </span>
</div> </div>
<div v-else> <div v-else>
<div class="sticky top-0 z-10 flex bg-primary"> <div class="sticky top-0 z-10 flex bg-primary">
<input <input
v-model="graphqlFieldsFilterText" v-model="graphqlFieldsFilterText"
type="search" type="search"
autocomplete="off" autocomplete="off"
:placeholder="`${t('action.search')}`" :placeholder="`${t('action.search')}`"
class="flex w-full p-4 py-2 bg-transparent" class="flex flex-1 p-4 py-2 bg-transparent"
/> />
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/quickstart/graphql" to="https://docs.hoppscotch.io/quickstart/graphql"
blank blank
:title="t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" :icon="IconHelpCircle"
/> />
</div> </div>
</div> </div>
<SmartTabs <SmartTabs
ref="gqlTabs" v-model="selectedGqlTab"
styles="border-t border-b border-dividerLight bg-primary sticky z-10 t op-sidebarPrimaryStickyFold" styles="border-t border-b border-dividerLight bg-primary sticky z-10 t op-sidebarPrimaryStickyFold"
render-inactive-tabs
> >
<div class="gqlTabs"> <SmartTab
<SmartTab v-if="queryFields.length > 0"
v-if="queryFields.length > 0" :id="'queries'"
:id="'queries'" :label="`${t('tab.queries')}`"
:label="`${t('tab.queries')}`" class="divide-y divide-dividerLight"
:selected="true" >
class="divide-y divide-dividerLight" <GraphqlField
> v-for="(field, index) in filteredQueryFields"
<GraphqlField :key="`field-${index}`"
v-for="(field, index) in filteredQueryFields" :gql-field="field"
:key="`field-${index}`" :jump-type-callback="handleJumpToType"
:gql-field="field" class="p-4"
:jump-type-callback="handleJumpToType" />
class="p-4" </SmartTab>
/> <SmartTab
</SmartTab> v-if="mutationFields.length > 0"
<SmartTab :id="'mutations'"
v-if="mutationFields.length > 0" :label="`${t('graphql.mutations')}`"
:id="'mutations'" class="divide-y divide-dividerLight"
:label="`${t('graphql.mutations')}`" >
class="divide-y divide-dividerLight" <GraphqlField
> v-for="(field, index) in filteredMutationFields"
<GraphqlField :key="`field-${index}`"
v-for="(field, index) in filteredMutationFields" :gql-field="field"
:key="`field-${index}`" :jump-type-callback="handleJumpToType"
:gql-field="field" class="p-4"
:jump-type-callback="handleJumpToType" />
class="p-4" </SmartTab>
/> <SmartTab
</SmartTab> v-if="subscriptionFields.length > 0"
<SmartTab :id="'subscriptions'"
v-if="subscriptionFields.length > 0" :label="`${t('graphql.subscriptions')}`"
:id="'subscriptions'" class="divide-y divide-dividerLight"
:label="`${t('graphql.subscriptions')}`" >
class="divide-y divide-dividerLight" <GraphqlField
> v-for="(field, index) in filteredSubscriptionFields"
<GraphqlField :key="`field-${index}`"
v-for="(field, index) in filteredSubscriptionFields" :gql-field="field"
:key="`field-${index}`" :jump-type-callback="handleJumpToType"
:gql-field="field" class="p-4"
:jump-type-callback="handleJumpToType" />
class="p-4" </SmartTab>
/> <SmartTab
</SmartTab> v-if="graphqlTypes.length > 0"
<SmartTab :id="'types'"
v-if="graphqlTypes.length > 0" :label="`${t('tab.types')}`"
:id="'types'" class="divide-y divide-dividerLight"
ref="typesTab" >
:label="`${t('tab.types')}`" <GraphqlType
class="divide-y divide-dividerLight" v-for="(type, index) in filteredGraphqlTypes"
> :key="`type-${index}`"
<GraphqlType :gql-type="type"
v-for="(type, index) in filteredGraphqlTypes" :gql-types="graphqlTypes"
:key="`type-${index}`" :is-highlighted="isGqlTypeHighlighted(type)"
:gql-type="type" :highlighted-fields="getGqlTypeHighlightedFields(type)"
:gql-types="graphqlTypes" :jump-type-callback="handleJumpToType"
:is-highlighted="isGqlTypeHighlighted(type)" />
:highlighted-fields="getGqlTypeHighlightedFields(type)" </SmartTab>
:jump-type-callback="handleJumpToType"
/>
</SmartTab>
</div>
</SmartTabs> </SmartTabs>
</div> </div>
</SmartTab> </SmartTab>
<SmartTab :id="'schema'" :icon="IconBox" :label="`${t('tab.schema')}`">
<SmartTab :id="'schema'" icon="box" :label="`${t('tab.schema')}`">
<div <div
v-if="schemaString" v-if="schemaString"
class="sticky top-0 z-10 flex items-center justify-between flex-1 pl-4 b order-b bg-primary border-dividerLight" class="sticky top-0 z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight"
> >
<label class="font-semibold text-secondaryLight"> <label class="font-semibold text-secondaryLight">
{{ t("graphql.schema") }} {{ t("graphql.schema") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/quickstart/graphql" to="https://docs.hoppscotch.io/quickstart/graphql"
blank blank
:title="t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" :icon="IconHelpCircle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="wrap-text" :icon="IconWrapText"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.prevent="linewrapEnabled = !linewrapEnabled"
/> />
<ButtonSecondary <ButtonSecondary
ref="downloadSchema"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="t('action.download_file')" :title="t('action.download_file')"
:svg="downloadSchemaIcon" :icon="downloadSchemaIcon"
@click.native="downloadSchema" @click="downloadSchema"
/> />
<ButtonSecondary <ButtonSecondary
ref="copySchemaCode"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="t('action.copy')" :title="t('action.copy')"
:svg="copySchemaIcon" :icon="copySchemaIcon"
@click.native="copySchema" @click="copySchema"
/> />
</div> </div>
</div> </div>
<div v-if="schemaString" ref="schemaEditor"></div> <div
v-if="schemaString"
ref="schemaEditor"
class="flex flex-col flex-1"
></div>
<div <div
v-else v-else
class="flex flex-col items-center justify-center p-4 text-secondaryLight " class="flex flex-col items-center justify-center p-4 text-secondaryLight "
> >
<img <img
:src="`/images/states/${$colorMode.value}/blockchain.svg`" :src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy" loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my- 4" class="inline-flex flex-col object-contain object-center w-16 h-16 my- 4"
:alt="`${t('empty.schema')}`" :alt="`${t('empty.schema')}`"
/> />
<span class="mb-4 text-center"> <span class="mb-4 text-center">
{{ t("empty.schema") }} {{ t("empty.schema") }}
</span> </span>
</div> </div>
</SmartTab> </SmartTab>
</SmartTabs> </SmartTabs>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, reactive, ref } from "@nuxtjs/composition-api" import IconFolder from "~icons/lucide/folder"
import IconBookOpen from "~icons/lucide/book-open"
import IconHelpCircle from "~icons/lucide/help-circle"
import IconWrapText from "~icons/lucide/wrap-text"
import IconDownload from "~icons/lucide/download"
import IconCheck from "~icons/lucide/check"
import IconClock from "~icons/lucide/clock"
import IconCopy from "~icons/lucide/copy"
import IconBox from "~icons/lucide/box"
import { computed, nextTick, reactive, ref } from "vue"
import { GraphQLField, GraphQLType } from "graphql" import { GraphQLField, GraphQLType } from "graphql"
import { map } from "rxjs/operators" import { map } from "rxjs/operators"
import { GQLHeader } from "@hoppscotch/data" import { GQLHeader } from "@hoppscotch/data"
import { useCodemirror } from "~/helpers/editor/codemirror" import { refAutoReset } from "@vueuse/core"
import { GQLConnection } from "~/helpers/GQLConnection" import { useCodemirror } from "@composables/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { GQLConnection } from "@helpers/GQLConnection"
import { import { copyToClipboard } from "@helpers/utils/clipboard"
useReadonlyStream, import { useReadonlyStream } from "@composables/stream"
useI18n, import { useI18n } from "@composables/i18n"
useToast, import { useToast } from "@composables/toast"
} from "~/helpers/utils/composables" import { useColorMode } from "@composables/theming"
import { import {
setGQLAuth,
setGQLHeaders, setGQLHeaders,
setGQLQuery, setGQLQuery,
setGQLResponse, setGQLResponse,
setGQLURL, setGQLURL,
setGQLVariables, setGQLVariables,
} from "~/newstore/GQLSession" } from "~/newstore/GQLSession"
type NavigationTabs = "history" | "collection" | "docs" | "schema"
type GqlTabs = "queries" | "mutations" | "subscriptions" | "types"
const selectedNavigationTab = ref<NavigationTabs>("history")
const selectedGqlTab = ref<GqlTabs>("queries")
const t = useI18n() const t = useI18n()
const colorMode = useColorMode()
function isTextFoundInGraphqlFieldObject( function isTextFoundInGraphqlFieldObject(
text: string, text: string,
field: GraphQLField<any, any> field: GraphQLField<any, any>
) { ) {
const normalizedText = text.toLowerCase() const normalizedText = text.toLowerCase()
const isFilterTextFoundInDescription = field.description const isFilterTextFoundInDescription = field.description
? field.description.toLowerCase().includes(normalizedText) ? field.description.toLowerCase().includes(normalizedText)
: false : false
skipping to change at line 306 skipping to change at line 315
const subscriptionFields = useReadonlyStream( const subscriptionFields = useReadonlyStream(
props.conn.subscriptionFields$.pipe(map((x) => x ?? [])), props.conn.subscriptionFields$.pipe(map((x) => x ?? [])),
[] []
) )
const graphqlTypes = useReadonlyStream( const graphqlTypes = useReadonlyStream(
props.conn.graphqlTypes$.pipe(map((x) => x ?? [])), props.conn.graphqlTypes$.pipe(map((x) => x ?? [])),
[] []
) )
const downloadSchemaIcon = ref("download") const downloadSchemaIcon = refAutoReset<typeof IconDownload | typeof IconCheck>(
const copySchemaIcon = ref("copy") IconDownload,
1000
)
const copySchemaIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(
IconCopy,
1000
)
const graphqlFieldsFilterText = ref("") const graphqlFieldsFilterText = ref("")
const gqlTabs = ref<any | null>(null)
const typesTab = ref<any | null>(null)
const filteredQueryFields = computed(() => { const filteredQueryFields = computed(() => {
return getFilteredGraphqlFields( return getFilteredGraphqlFields(
graphqlFieldsFilterText.value, graphqlFieldsFilterText.value,
queryFields.value as any queryFields.value as any
) )
}) })
const filteredMutationFields = computed(() => { const filteredMutationFields = computed(() => {
return getFilteredGraphqlFields( return getFilteredGraphqlFields(
graphqlFieldsFilterText.value, graphqlFieldsFilterText.value,
skipping to change at line 363 skipping to change at line 375
const fields = Object.values((gqlType as any)._fields || {}) const fields = Object.values((gqlType as any)._fields || {})
if (!fields || fields.length === 0) return [] if (!fields || fields.length === 0) return []
return fields.filter((field) => return fields.filter((field) =>
isTextFoundInGraphqlFieldObject(graphqlFieldsFilterText.value, field as any) isTextFoundInGraphqlFieldObject(graphqlFieldsFilterText.value, field as any)
) )
} }
const handleJumpToType = async (type: GraphQLType) => { const handleJumpToType = async (type: GraphQLType) => {
gqlTabs.value.selectTab(typesTab.value) selectedGqlTab.value = "types"
await nextTick() await nextTick()
const rootTypeName = resolveRootType(type).name const rootTypeName = resolveRootType(type).name
const target = document.getElementById(`type_${rootTypeName}`) const target = document.getElementById(`type_${rootTypeName}`)
if (target) { if (target) {
target.scrollIntoView({ block: "center", behavior: "smooth" }) target.scrollIntoView({ block: "center", behavior: "smooth" })
target.classList.add( target.classList.add(
"transition-all", "transition-all",
"ring-inset", "ring-inset",
"ring-accentLight", "ring-accentLight",
skipping to change at line 421 skipping to change at line 433
const downloadSchema = () => { const downloadSchema = () => {
const dataToWrite = JSON.stringify(schemaString.value, null, 2) const dataToWrite = JSON.stringify(schemaString.value, null, 2)
const file = new Blob([dataToWrite], { type: "application/graphql" }) const file = new Blob([dataToWrite], { type: "application/graphql" })
const a = document.createElement("a") const a = document.createElement("a")
const url = URL.createObjectURL(file) const url = URL.createObjectURL(file)
a.href = url a.href = url
a.download = `${url.split("/").pop()!.split("#")[0].split("?")[0]}.graphql` a.download = `${url.split("/").pop()!.split("#")[0].split("?")[0]}.graphql`
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadSchemaIcon.value = "check" downloadSchemaIcon.value = IconCheck
toast.success(`${t("state.download_started")}`) toast.success(`${t("state.download_started")}`)
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
downloadSchemaIcon.value = "download"
}, 1000) }, 1000)
} }
const copySchema = () => { const copySchema = () => {
if (!schemaString.value) return if (!schemaString.value) return
copyToClipboard(schemaString.value) copyToClipboard(schemaString.value)
copySchemaIcon.value = "check" copySchemaIcon.value = IconCheck
setTimeout(() => (copySchemaIcon.value = "copy"), 1000)
} }
const handleUseHistory = (entry: GQLHistoryEntry) => { const handleUseHistory = (entry: GQLHistoryEntry) => {
const url = entry.url const url = entry.url
const headers = entry.headers const headers = entry.headers
const gqlQueryString = entry.query const gqlQueryString = entry.query
const variableString = entry.variables const variableString = entry.variables
const responseText = entry.response const responseText = entry.response
setGQLURL(url) setGQLURL(url)
setGQLHeaders(headers) setGQLHeaders(headers)
setGQLQuery(gqlQueryString) setGQLQuery(gqlQueryString)
setGQLVariables(variableString) setGQLVariables(variableString)
setGQLResponse(responseText) setGQLResponse(responseText)
setGQLAuth({
authType: "none",
authActive: true,
})
props.conn.reset() props.conn.reset()
} }
</script> </script>
 End of changes. 33 change blocks. 
115 lines changed or deleted 129 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)