diff --git a/packages/hoppscotch-common/locales/en.json b/packages/hoppscotch-common/locales/en.json index 8bb18e889..99bfe5a9b 100644 --- a/packages/hoppscotch-common/locales/en.json +++ b/packages/hoppscotch-common/locales/en.json @@ -670,7 +670,13 @@ "tab_headers": "Headers tab", "tab_authorization": "Authorization tab", "tab_pre_request_script": "Pre-request script tab", - "tab_tests": "Tests tab" + "tab_tests": "Tests tab", + "tab_query": "Query tab", + "tab_variables": "Variables tab" + }, + "graphql": { + "connect": "Connect to server", + "disconnect": "Disconnect from server" }, "response": { "copy": "Copy response", diff --git a/packages/hoppscotch-common/src/components/graphql/Request.vue b/packages/hoppscotch-common/src/components/graphql/Request.vue index 1400b604c..894ef6238 100644 --- a/packages/hoppscotch-common/src/components/graphql/Request.vue +++ b/packages/hoppscotch-common/src/components/graphql/Request.vue @@ -71,6 +71,7 @@ import { connect } from "~/helpers/graphql/connection" import { disconnect } from "~/helpers/graphql/connection" import { InterceptorService } from "~/services/interceptor.service" import { useService } from "dioc/vue" +import { defineActionHandler } from "~/helpers/actions" const t = useI18n() @@ -140,4 +141,12 @@ const cancelSwitch = () => { if (connected.value) disconnect() connectionSwitchModal.value = false } + +defineActionHandler( + "gql.connect", + gqlConnect, + computed(() => !connected.value) +) + +defineActionHandler("gql.disconnect", disconnect, connected) diff --git a/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue b/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue index ce4a9acdd..4d643c936 100644 --- a/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue +++ b/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue @@ -69,8 +69,8 @@ import { useService } from "dioc/vue" import { InterceptorService } from "~/services/interceptor.service" import { editGraphqlRequest } from "~/newstore/collections" -type OptionTabs = "query" | "headers" | "variables" | "authorization" -const selectedOptionTab = ref("query") +export type GQLOptionTabs = "query" | "headers" | "variables" | "authorization" +const selectedOptionTab = ref("query") const interceptorService = useService(InterceptorService) const t = useI18n() @@ -206,4 +206,8 @@ defineActionHandler("request.save-as", () => { showSaveRequestModal.value = true }) defineActionHandler("request.reset", clearGQLQuery) + +defineActionHandler("request.open-tab", ({ tab }) => { + selectedOptionTab.value = tab as GQLOptionTabs +}) diff --git a/packages/hoppscotch-common/src/components/graphql/Response.vue b/packages/hoppscotch-common/src/components/graphql/Response.vue index 4d5bc25dd..e2823070e 100644 --- a/packages/hoppscotch-common/src/components/graphql/Response.vue +++ b/packages/hoppscotch-common/src/components/graphql/Response.vue @@ -128,8 +128,14 @@ const downloadResponse = (str: string) => { }, 1000) } -defineActionHandler("response.file.download", () => - downloadResponse(responseString.value) +defineActionHandler( + "response.file.download", + () => downloadResponse(responseString.value), + computed(() => !!props.response && props.response.length > 0) +) +defineActionHandler( + "response.copy", + () => copyResponse(responseString.value), + computed(() => !!props.response && props.response.length > 0) ) -defineActionHandler("response.copy", () => copyResponse(responseString.value)) diff --git a/packages/hoppscotch-common/src/components/http/RequestOptions.vue b/packages/hoppscotch-common/src/components/http/RequestOptions.vue index 0ed5237e8..9f9625909 100644 --- a/packages/hoppscotch-common/src/components/http/RequestOptions.vue +++ b/packages/hoppscotch-common/src/components/http/RequestOptions.vue @@ -101,6 +101,6 @@ const newActiveHeadersCount$ = computed(() => { }) defineActionHandler("request.open-tab", ({ tab }) => { - selectedOptionsTab.value = tab + selectedOptionsTab.value = tab as RequestOptionTabs }) diff --git a/packages/hoppscotch-common/src/helpers/actions.ts b/packages/hoppscotch-common/src/helpers/actions.ts index a08437692..d59df7839 100644 --- a/packages/hoppscotch-common/src/helpers/actions.ts +++ b/packages/hoppscotch-common/src/helpers/actions.ts @@ -2,12 +2,14 @@ * For example, sending a request. */ -import { Ref, onBeforeUnmount, onMounted, watch } from "vue" +import { Ref, onBeforeUnmount, onMounted, reactive, watch } from "vue" import { BehaviorSubject } from "rxjs" import { HoppRESTDocument } from "./rest/document" import { HoppGQLRequest, HoppRESTRequest } from "@hoppscotch/data" import { RequestOptionTabs } from "~/components/http/RequestOptions.vue" import { HoppGQLSaveContext } from "./graphql/document" +import { GQLOptionTabs } from "~/components/graphql/RequestOptions.vue" +import { computed } from "vue" export type HoppAction = | "contextmenu.open" // Send/Cancel a Hoppscotch Request @@ -16,7 +18,7 @@ export type HoppAction = | "request.copy-link" // Copy Request Link | "request.save" // Save to Collections | "request.save-as" // Save As - | "rest.request.rename" // Rename + | "request.rename" // Rename request on REST or GraphQL | "request.method.next" // Select Next Method | "request.method.prev" // Select Previous Method | "request.method.get" // Select GET Method @@ -26,6 +28,11 @@ export type HoppAction = | "request.method.delete" // Select DELETE Method | "request.import-curl" // Import cURL | "request.show-code" // Show generated code + | "gql.connect" // Connect to GraphQL endpoint given + | "gql.disconnect" // Disconnect from GraphQL endpoint given + | "tab.close-current" // Close current tab + | "tab.close-other" // Close other tabs + | "tab.open-new" // Open new tab | "collection.new" // Create root collection | "flyouts.chat.open" // Shows the keybinds flyout | "flyouts.keybinds.toggle" // Shows the keybinds flyout @@ -106,11 +113,11 @@ type HoppActionArgsMap = { request: HoppGQLRequest } "request.open-tab": { - tab: RequestOptionTabs + tab: RequestOptionTabs | GQLOptionTabs } - "request.duplicate-tab": { - tabID: string + "tab.duplicate-tab": { + tabID?: string } "gql.request.open": { @@ -150,7 +157,7 @@ type BoundActionList = { [A in HoppAction | HoppActionWithArgs]?: Array> } -const boundActions: BoundActionList = {} +const boundActions: BoundActionList = reactive({}) export const activeActions$ = new BehaviorSubject< (HoppAction | HoppActionWithArgs)[] @@ -206,6 +213,15 @@ export function unbindAction( activeActions$.next(Object.keys(boundActions) as HoppAction[]) } +/** + * Returns a ref that indicates whether a given action is bound at a given time + * + * @param action The action to check + */ +export function isActionBound(action: HoppAction): Ref { + return computed(() => !!boundActions[action]) +} + /** * A composable function that defines a component can handle a given * HoppAction. The handler will be bound when the component is mounted diff --git a/packages/hoppscotch-common/src/pages/graphql.vue b/packages/hoppscotch-common/src/pages/graphql.vue index 9e39ce201..cb960411d 100644 --- a/packages/hoppscotch-common/src/pages/graphql.vue +++ b/packages/hoppscotch-common/src/pages/graphql.vue @@ -27,7 +27,7 @@ @open-rename-modal="openReqRenameModal(tab)" @close-tab="removeTab(tab.id)" @close-other-tabs="closeOtherTabsAction(tab.id)" - @duplicate-tab="duplicateTab(tab)" + @duplicate-tab="duplicateTab(tab.id)" /> @@ -203,12 +203,15 @@ const renameReqName = () => { showRenamingReqNameModalForTabID.value = undefined } -const duplicateTab = (tab: HoppGQLTab) => { - const newTab = createNewTab({ - request: tab.document.request, - isDirty: true, - }) - currentTabID.value = newTab.id +const duplicateTab = (tabID: string) => { + const tab = getTabRef(tabID) + if (tab.value) { + const newTab = createNewTab({ + request: tab.value.document.request, + isDirty: true, + }) + currentTabID.value = newTab.id + } } defineActionHandler("gql.request.open", ({ request, saveContext }) => { @@ -218,4 +221,19 @@ defineActionHandler("gql.request.open", ({ request, saveContext }) => { isDirty: false, }) }) + +defineActionHandler("request.rename", () => { + openReqRenameModal(getTabRef(currentTabID.value).value!) +}) + +defineActionHandler("tab.duplicate-tab", ({ tabID }) => { + duplicateTab(tabID ?? currentTabID.value) +}) +defineActionHandler("tab.close-current", () => { + removeTab(currentTabID.value) +}) +defineActionHandler("tab.close-other", () => { + closeOtherTabs(currentTabID.value) +}) +defineActionHandler("tab.open-new", addNewTab) diff --git a/packages/hoppscotch-common/src/pages/index.vue b/packages/hoppscotch-common/src/pages/index.vue index 397c4d7b8..a0d5378e8 100644 --- a/packages/hoppscotch-common/src/pages/index.vue +++ b/packages/hoppscotch-common/src/pages/index.vue @@ -461,10 +461,17 @@ defineActionHandler("rest.request.open", ({ doc }) => { createNewTab(doc) }) -defineActionHandler("rest.request.rename", openReqRenameModal) -defineActionHandler("request.duplicate-tab", ({ tabID }) => { - duplicateTab(tabID) +defineActionHandler("request.rename", openReqRenameModal) +defineActionHandler("tab.duplicate-tab", ({ tabID }) => { + duplicateTab(tabID ?? currentTabID.value) }) +defineActionHandler("tab.close-current", () => { + removeTab(currentTabID.value) +}) +defineActionHandler("tab.close-other", () => { + closeOtherTabs(currentTabID.value) +}) +defineActionHandler("tab.open-new", addNewTab) useService(HeaderInspectorService) useService(EnvironmentInspectorService) diff --git a/packages/hoppscotch-common/src/services/spotlight/searchers/environment.searcher.ts b/packages/hoppscotch-common/src/services/spotlight/searchers/environment.searcher.ts index 15b421e67..291baabbd 100644 --- a/packages/hoppscotch-common/src/services/spotlight/searchers/environment.searcher.ts +++ b/packages/hoppscotch-common/src/services/spotlight/searchers/environment.searcher.ts @@ -45,8 +45,11 @@ import { setSelectedEnvironmentIndex, } from "~/newstore/environments" +import IconCheckCircle from "~/components/app/spotlight/entry/IconSelected.vue" +import IconCircle from "~icons/lucide/circle" + type Doc = { - text: string + text: string | string[] alternates: string[] icon: object | Component excludeFromSearch?: boolean @@ -88,40 +91,61 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche private documents: Record = reactive({ new_environment: { - text: this.t("spotlight.environments.new"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.new"), + ], alternates: ["new", "environment"], icon: markRaw(IconLayers), }, new_environment_variable: { - text: this.t("spotlight.environments.new_variable"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.new_variable"), + ], alternates: ["new", "environment", "variable"], icon: markRaw(IconLayers), }, edit_selected_env: { - text: this.t("spotlight.environments.edit"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.edit"), + ], alternates: ["edit", "environment"], icon: markRaw(IconEdit), excludeFromSearch: computed(() => !this.hasSelectedEnv.value), }, delete_selected_env: { - text: this.t("spotlight.environments.delete"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.delete"), + ], alternates: ["delete", "environment"], icon: markRaw(IconTrash2), excludeFromSearch: computed(() => !this.hasSelectedEnv.value), }, duplicate_selected_env: { - text: this.t("spotlight.environments.duplicate"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.duplicate"), + ], alternates: ["duplicate", "environment"], icon: markRaw(IconCopy), excludeFromSearch: computed(() => !this.hasSelectedEnv.value), }, edit_global_env: { - text: this.t("spotlight.environments.edit_global"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.edit_global"), + ], alternates: ["edit", "global", "environment"], icon: markRaw(IconEdit), }, duplicate_global_env: { - text: this.t("spotlight.environments.duplicate_global"), + text: [ + this.t("spotlight.environments.title"), + this.t("spotlight.environments.duplicate_global"), + ], alternates: ["duplicate", "global", "environment"], icon: markRaw(IconCopy), }, @@ -245,6 +269,16 @@ export class SwitchEnvSpotlightSearcherService this.spotlight.registerSearcher(this) } + private selectedEnvIndex = useStreamStatic( + selectedEnvironmentIndex$, + { + type: "NO_ENV_SELECTED", + }, + () => { + /* noop */ + } + )[0] + private environmentSearchable = useStreamStatic( activeActions$.pipe( map((actions) => actions.includes("modals.environment.add")) @@ -262,16 +296,25 @@ export class SwitchEnvSpotlightSearcherService const results = ref([]) const minisearch = new MiniSearch({ - fields: ["name"], + fields: ["name", "alternates"], storeFields: ["name"], }) if (this.environmentSearchable.value) { minisearch.addAll( environmentsStore.value.environments.map((entry, index) => { + let id = `environment-${index}` + + if ( + this.selectedEnvIndex.value?.type === "MY_ENV" && + this.selectedEnvIndex.value.index === index + ) { + id += "-selected" + } return { - id: `environment-${index}`, + id, name: entry.name, + alternates: ["environment", "change", entry.name], } }) ) @@ -298,7 +341,9 @@ export class SwitchEnvSpotlightSearcherService .map((x) => { return { id: x.id, - icon: markRaw(IconLayers), + icon: markRaw( + x.id.endsWith("-selected") ? IconCheckCircle : IconCircle + ), score: x.score, text: { type: "text", diff --git a/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts b/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts index 9d1589b7c..49163a5b4 100644 --- a/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts +++ b/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts @@ -1,5 +1,5 @@ import { Component, computed, markRaw, reactive } from "vue" -import { invokeAction } from "~/helpers/actions" +import { invokeAction, isActionBound } from "~/helpers/actions" import { getI18n } from "~/modules/i18n" import { SpotlightSearcherResult, SpotlightService } from ".." import { @@ -19,6 +19,7 @@ import IconRename from "~icons/lucide/file-edit" import IconPlay from "~icons/lucide/play" import IconRotateCCW from "~icons/lucide/rotate-ccw" import IconSave from "~icons/lucide/save" +import { GQLOptionTabs } from "~/components/graphql/RequestOptions.vue" type Doc = { text: string | string[] @@ -46,39 +47,51 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ private route = useRoute() private isRESTPage = computed(() => this.route.name === "index") private isGQLPage = computed(() => this.route.name === "graphql") + private isRESTOrGQLPage = computed( + () => this.isRESTPage.value || this.isGQLPage.value + ) + private isGQLConnectBound = isActionBound("gql.connect") + private isGQLDisconnectBound = isActionBound("gql.disconnect") private documents: Record = reactive({ send_request: { text: this.t("shortcut.request.send_request"), alternates: ["request", "send"], icon: markRaw(IconPlay), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), + }, + gql_connect: { + text: [this.t("navigation.graphql"), this.t("spotlight.graphql.connect")], + alternates: ["connect", "server", "graphql"], + icon: markRaw(IconPlay), + excludeFromSearch: computed(() => !this.isGQLConnectBound.value), + }, + gql_disconnect: { + text: [ + this.t("navigation.graphql"), + this.t("spotlight.graphql.disconnect"), + ], + alternates: ["disconnect", "stop", "graphql"], + icon: markRaw(IconPlay), + excludeFromSearch: computed(() => !this.isGQLDisconnectBound.value), }, save_to_collections: { text: this.t("spotlight.request.save_as_new"), alternates: ["save", "collections"], icon: markRaw(IconSave), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, save_request: { text: this.t("shortcut.request.save_request"), alternates: ["save", "request"], icon: markRaw(IconSave), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, rename_request: { text: this.t("shortcut.request.rename"), alternates: ["rename", "request"], icon: markRaw(IconRename), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, copy_request_link: { text: this.t("shortcut.request.copy_request_link"), @@ -90,7 +103,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ text: this.t("shortcut.request.reset_request"), alternates: ["reset", "request"], icon: markRaw(IconRotateCCW), - excludeFromSearch: computed(() => !this.isRESTPage.value), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, import_curl: { text: this.t("shortcut.request.import_curl"), @@ -143,9 +156,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ ], alternates: ["parameters", "tab"], icon: markRaw(IconWindow), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, tab_body: { text: [ @@ -154,9 +165,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ ], alternates: ["body", "tab"], icon: markRaw(IconWindow), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, tab_headers: { text: [ @@ -165,9 +174,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ ], alternates: ["headers", "tab"], icon: markRaw(IconWindow), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, tab_authorization: { text: [ @@ -176,9 +183,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ ], alternates: ["authorization", "tab"], icon: markRaw(IconWindow), - excludeFromSearch: computed( - () => !this.isRESTPage.value ?? !this.isGQLPage.value - ), + excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, tab_pre_request_script: { text: [ @@ -198,6 +203,24 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ icon: markRaw(IconWindow), excludeFromSearch: computed(() => !this.isRESTPage.value), }, + tab_query: { + text: [ + this.t("spotlight.request.switch_to"), + this.t("spotlight.request.tab_query"), + ], + alternates: ["query", "tab"], + icon: markRaw(IconWindow), + excludeFromSearch: computed(() => !this.isGQLPage.value), + }, + tab_variables: { + text: [ + this.t("spotlight.request.switch_to"), + this.t("spotlight.request.tab_variables"), + ], + alternates: ["variables", "tab"], + icon: markRaw(IconWindow), + excludeFromSearch: computed(() => !this.isGQLPage.value), + }, }) constructor() { @@ -224,7 +247,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ } } - private openRequestTab(tab: RequestOptionTabs): void { + private openRequestTab(tab: RequestOptionTabs | GQLOptionTabs): void { invokeAction("request.open-tab", { tab, }) @@ -235,6 +258,12 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ case "send_request": invokeAction("request.send-cancel") break + case "gql_connect": + invokeAction("gql.connect") + break + case "gql_disconnect": + invokeAction("gql.disconnect") + break case "save_to_collections": invokeAction("request.save-as", { requestType: "rest", @@ -245,7 +274,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ invokeAction("request.save") break case "rename_request": - invokeAction("rest.request.rename") + invokeAction("request.rename") break case "copy_request_link": invokeAction("request.copy-link") @@ -292,6 +321,12 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ case "tab_tests": this.openRequestTab("tests") break + case "tab_query": + this.openRequestTab("query") + break + case "tab_variables": + this.openRequestTab("variables") + break } } } diff --git a/packages/hoppscotch-common/src/services/spotlight/searchers/response.searcher.ts b/packages/hoppscotch-common/src/services/spotlight/searchers/response.searcher.ts index de8503374..3d6b107e5 100644 --- a/packages/hoppscotch-common/src/services/spotlight/searchers/response.searcher.ts +++ b/packages/hoppscotch-common/src/services/spotlight/searchers/response.searcher.ts @@ -1,5 +1,5 @@ import { Component, computed, markRaw, reactive } from "vue" -import { activeActions$, invokeAction } from "~/helpers/actions" +import { invokeAction, isActionBound } from "~/helpers/actions" import { getI18n } from "~/modules/i18n" import { SpotlightSearcherResult, SpotlightService } from ".." import { @@ -9,8 +9,6 @@ import { import IconDownload from "~icons/lucide/download" import IconCopy from "~icons/lucide/copy" -import { map } from "rxjs" -import { useStreamStatic } from "~/composables/stream" type Doc = { text: string @@ -35,23 +33,11 @@ export class ResponseSpotlightSearcherService extends StaticSpotlightSearcherSer private readonly spotlight = this.bind(SpotlightService) - private copyResponseActionEnabled = useStreamStatic( - activeActions$.pipe(map((actions) => actions.includes("response.copy"))), - activeActions$.value.includes("response.copy"), - () => { - /* noop */ - } - )[0] + private copyResponseActionEnabled = isActionBound("response.copy") - private downloadResponseActionEnabled = useStreamStatic( - activeActions$.pipe( - map((actions) => actions.includes("response.file.download")) - ), - activeActions$.value.includes("response.file.download"), - () => { - /* noop */ - } - )[0] + private downloadResponseActionEnabled = isActionBound( + "response.file.download" + ) private documents: Record = reactive({ copy_response: { diff --git a/packages/hoppscotch-common/src/services/spotlight/searchers/tab.searcher.ts b/packages/hoppscotch-common/src/services/spotlight/searchers/tab.searcher.ts index c36d9f0e5..8888ac6de 100644 --- a/packages/hoppscotch-common/src/services/spotlight/searchers/tab.searcher.ts +++ b/packages/hoppscotch-common/src/services/spotlight/searchers/tab.searcher.ts @@ -7,22 +7,16 @@ import { } from "./base/static.searcher" import { useRoute } from "vue-router" -import { getDefaultRESTRequest } from "~/helpers/rest/default" -import { - closeOtherTabs, - closeTab, - createNewTab, - currentTabID, - getActiveTabs, -} from "~/helpers/rest/tab" import IconCopy from "~icons/lucide/copy" import IconCopyPlus from "~icons/lucide/copy-plus" import IconXCircle from "~icons/lucide/x-circle" import IconXSquare from "~icons/lucide/x-square" import { invokeAction } from "~/helpers/actions" +import { getActiveTabs as getRESTActiveTabs } from "~/helpers/rest/tab" +import { getActiveTabs as getGQLActiveTabs } from "~/helpers/graphql/tab" type Doc = { - text: string + text: string | string[] alternates: string[] icon: object | Component excludeFromSearch?: boolean @@ -46,34 +40,47 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService< private route = useRoute() private showAction = computed( - () => this.route.name === "index" ?? this.route.name === "graphql" + () => this.route.name === "index" || this.route.name === "graphql" + ) + private gqlActiveTabs = getGQLActiveTabs() + private restActiveTabs = getRESTActiveTabs() + private isOnlyTab = computed(() => + this.route.name === "graphql" + ? this.gqlActiveTabs.value.length === 1 + : this.restActiveTabs.value.length === 1 ) private documents: Record = reactive({ duplicate_tab: { - text: this.t("spotlight.tab.duplicate"), + text: [this.t("spotlight.tab.title"), this.t("spotlight.tab.duplicate")], alternates: ["tab", "duplicate", "duplicate tab"], icon: markRaw(IconCopy), excludeFromSearch: computed(() => !this.showAction.value), }, close_current_tab: { - text: this.t("spotlight.tab.close_current"), + text: [ + this.t("spotlight.tab.title"), + this.t("spotlight.tab.close_current"), + ], alternates: ["tab", "close", "close tab"], icon: markRaw(IconXCircle), excludeFromSearch: computed( - () => !this.showAction.value || getActiveTabs().value.length === 1 + () => !this.showAction.value || this.isOnlyTab.value ), }, close_other_tabs: { - text: this.t("spotlight.tab.close_others"), + text: [ + this.t("spotlight.tab.title"), + this.t("spotlight.tab.close_others"), + ], alternates: ["tab", "close", "close all"], icon: markRaw(IconXSquare), excludeFromSearch: computed( - () => !this.showAction.value || getActiveTabs().value.length < 2 + () => !this.showAction.value || this.isOnlyTab.value ), }, open_new_tab: { - text: this.t("spotlight.tab.new_tab"), + text: [this.t("spotlight.tab.title"), this.t("spotlight.tab.new_tab")], alternates: ["tab", "new", "open tab"], icon: markRaw(IconCopyPlus), excludeFromSearch: computed(() => !this.showAction.value), @@ -105,16 +112,9 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService< } public onDocSelected(id: string): void { - if (id === "duplicate_tab") - invokeAction("request.duplicate-tab", { - tabID: currentTabID.value, - }) - if (id === "close_current_tab") closeTab(currentTabID.value) - if (id === "close_other_tabs") closeOtherTabs(currentTabID.value) - if (id === "open_new_tab") - createNewTab({ - request: getDefaultRESTRequest(), - isDirty: false, - }) + if (id === "duplicate_tab") invokeAction("tab.duplicate-tab", {}) + if (id === "close_current_tab") invokeAction("tab.close-current") + if (id === "close_other_tabs") invokeAction("tab.close-other") + if (id === "open_new_tab") invokeAction("tab.open-new") } }