fix: corrections for spotlight searchers (#3275)
This commit is contained in:
@@ -606,7 +606,7 @@
|
||||
"delete_method": "Select DELETE method",
|
||||
"get_method": "Select GET method",
|
||||
"head_method": "Select HEAD method",
|
||||
"rename": "Rename Current Request",
|
||||
"rename": "Rename Request",
|
||||
"import_curl": "Import cURL",
|
||||
"show_code": "Generate code snippet",
|
||||
"method": "Method",
|
||||
@@ -649,11 +649,11 @@
|
||||
},
|
||||
"spotlight": {
|
||||
"general": {
|
||||
"help_menu": "Open help and support menu",
|
||||
"help_menu": "Help and support",
|
||||
"chat": "Chat with support",
|
||||
"open_docs": "Read Documentation",
|
||||
"open_keybindings": "Open keyboard shortcuts",
|
||||
"social": "Social links and GitHub",
|
||||
"open_keybindings": "Keyboard shortcuts",
|
||||
"social": "Social",
|
||||
"title": "General"
|
||||
},
|
||||
"miscellaneous": {
|
||||
@@ -661,15 +661,18 @@
|
||||
"title": "Miscellaneous"
|
||||
},
|
||||
"request": {
|
||||
"tab_parameters": "Open parameters tab",
|
||||
"tab_body": "Open body tab",
|
||||
"tab_headers": "Open headers tab",
|
||||
"tab_authorization": "Open authorization tab",
|
||||
"tab_pre_request_script": "Open pre-request script tab",
|
||||
"tab_tests": "Open tests tab"
|
||||
"switch_to": "Switch to",
|
||||
"select_method": "Select method",
|
||||
"save_as_new": "Save as new request",
|
||||
"tab_parameters": "Parameters tab",
|
||||
"tab_body": "Body tab",
|
||||
"tab_headers": "Headers tab",
|
||||
"tab_authorization": "Authorization tab",
|
||||
"tab_pre_request_script": "Pre-request script tab",
|
||||
"tab_tests": "Tests tab"
|
||||
},
|
||||
"response": {
|
||||
"copy": "Copy response as JSON",
|
||||
"copy": "Copy response",
|
||||
"download": "Download response as file",
|
||||
"title": "Response"
|
||||
},
|
||||
@@ -692,6 +695,7 @@
|
||||
"title": "Teams"
|
||||
},
|
||||
"tab": {
|
||||
"duplicate": "Duplicate tab",
|
||||
"close_current": "Close current tab",
|
||||
"close_others": "Close other tabs",
|
||||
"new_tab": "Open a new tab",
|
||||
@@ -703,9 +707,7 @@
|
||||
"interface": "Interface",
|
||||
"interceptor": "Interceptor"
|
||||
},
|
||||
"change_interceptor": "Change Interceptor",
|
||||
"change_language": "Change Language",
|
||||
"install_extension": "Install Browser Extension",
|
||||
"settings": {
|
||||
"theme": {
|
||||
"black": "Black Mode",
|
||||
@@ -719,8 +721,7 @@
|
||||
"size_lg": "Change to Large"
|
||||
},
|
||||
"change_interceptor": "Change Interceptor",
|
||||
"change_language": "Change Language",
|
||||
"install_extension": "Install Browser Extension"
|
||||
"change_language": "Change Language"
|
||||
}
|
||||
},
|
||||
"sse": {
|
||||
|
||||
@@ -29,6 +29,7 @@ declare module 'vue' {
|
||||
AppSpotlightEntry: typeof import('./components/app/spotlight/Entry.vue')['default']
|
||||
AppSpotlightEntryGQLHistory: typeof import('./components/app/spotlight/entry/GQLHistory.vue')['default']
|
||||
AppSpotlightEntryGQLRequest: typeof import('./components/app/spotlight/entry/GQLRequest.vue')['default']
|
||||
AppSpotlightEntryIconSelected: typeof import('./components/app/spotlight/entry/IconSelected.vue')['default']
|
||||
AppSpotlightEntryRESTHistory: typeof import('./components/app/spotlight/entry/RESTHistory.vue')['default']
|
||||
AppSpotlightEntryRESTRequest: typeof import('./components/app/spotlight/entry/RESTRequest.vue')['default']
|
||||
AppSupport: typeof import('./components/app/Support.vue')['default']
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<AppShortcuts :show="showShortcuts" @close="showShortcuts = false" />
|
||||
<AppShare :show="showShare" @hide-modal="showShare = false" />
|
||||
<AppSocial :show="showSocial" @hide-modal="showSocial = false" />
|
||||
<FirebaseLogin :show="showLogin" @hide-modal="showLogin = false" />
|
||||
|
||||
<HoppSmartConfirmModal
|
||||
@@ -27,7 +26,6 @@ const t = useI18n()
|
||||
|
||||
const showShortcuts = ref(false)
|
||||
const showShare = ref(false)
|
||||
const showSocial = ref(false)
|
||||
const showLogin = ref(false)
|
||||
|
||||
const confirmRemove = ref(false)
|
||||
@@ -60,10 +58,6 @@ defineActionHandler("modals.share.toggle", () => {
|
||||
showShare.value = !showShare.value
|
||||
})
|
||||
|
||||
defineActionHandler("modals.social.toggle", () => {
|
||||
showSocial.value = !showSocial.value
|
||||
})
|
||||
|
||||
defineActionHandler("modals.login.toggle", () => {
|
||||
showLogin.value = !showLogin.value
|
||||
})
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
<template>
|
||||
<HoppSmartModal
|
||||
v-if="show"
|
||||
dialog
|
||||
:title="t('app.social_links')"
|
||||
@close="hideModal"
|
||||
>
|
||||
<template #body>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<a
|
||||
v-for="(platform, index) in platforms"
|
||||
:key="`platform-${index}`"
|
||||
:href="platform.link"
|
||||
target="_blank"
|
||||
class="social-link"
|
||||
tabindex="0"
|
||||
>
|
||||
<component :is="platform.icon" class="w-6 h-6" />
|
||||
<span class="mt-3">
|
||||
{{ platform.name }}
|
||||
</span>
|
||||
</a>
|
||||
<button class="social-link" @click="copyAppLink">
|
||||
<component :is="copyIcon" class="w-6 h-6 text-xl" />
|
||||
<span class="mt-3">
|
||||
{{ t("app.copy") }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<p class="text-secondaryLight">
|
||||
{{ t("app.social_description") }}
|
||||
</p>
|
||||
</template>
|
||||
</HoppSmartModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { refAutoReset } from "@vueuse/core"
|
||||
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
||||
import IconFacebook from "~icons/brands/facebook"
|
||||
import IconLinkedIn from "~icons/brands/linkedin"
|
||||
import IconReddit from "~icons/brands/reddit"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const toast = useToast()
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "hide-modal"): void
|
||||
}>()
|
||||
|
||||
const url = "https://hoppscotch.io"
|
||||
|
||||
const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(
|
||||
IconCopy,
|
||||
1000
|
||||
)
|
||||
|
||||
const platforms = [
|
||||
{
|
||||
name: "GitHub",
|
||||
icon: IconGitHub,
|
||||
link: `https://hoppscotch.io/github`,
|
||||
},
|
||||
{
|
||||
name: "Twitter",
|
||||
icon: IconTwitter,
|
||||
link: `https://twitter.com/hoppscotch_io`,
|
||||
},
|
||||
{
|
||||
name: "Facebook",
|
||||
icon: IconFacebook,
|
||||
link: `https://www.facebook.com/hoppscotch.io`,
|
||||
},
|
||||
{
|
||||
name: "Reddit",
|
||||
icon: IconReddit,
|
||||
link: `https://www.reddit.com/r/hoppscotch`,
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
icon: IconLinkedIn,
|
||||
link: `https://www.linkedin.com/company/hoppscotch/`,
|
||||
},
|
||||
]
|
||||
|
||||
const copyAppLink = () => {
|
||||
copyToClipboard(url)
|
||||
copyIcon.value = IconCheck
|
||||
toast.success(`${t("state.copied_to_clipboard")}`)
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
emit("hide-modal")
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.social-link {
|
||||
@apply border border-dividerLight;
|
||||
@apply rounded;
|
||||
@apply flex-col flex;
|
||||
@apply p-4;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply font-semibold;
|
||||
@apply hover: (bg-primaryLight text-secondaryDark);
|
||||
@apply focus: outline-none;
|
||||
@apply focus-visible: border-divider;
|
||||
|
||||
svg {
|
||||
@apply opacity-80;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
@apply opacity-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<IconLucideCheckCircle class="text-accent" />
|
||||
</template>
|
||||
@@ -111,6 +111,7 @@ import {
|
||||
SwitchWorkspaceSpotlightSearcherService,
|
||||
WorkspaceSpotlightSearcherService,
|
||||
} from "~/services/spotlight/searchers/workspace.searcher"
|
||||
import { InterceptorSpotlightSearcherService } from "~/services/spotlight/searchers/interceptor.searcher"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -138,6 +139,7 @@ useService(EnvironmentsSpotlightSearcherService)
|
||||
useService(SwitchEnvSpotlightSearcherService)
|
||||
useService(WorkspaceSpotlightSearcherService)
|
||||
useService(SwitchWorkspaceSpotlightSearcherService)
|
||||
useService(InterceptorSpotlightSearcherService)
|
||||
|
||||
const search = ref("")
|
||||
|
||||
@@ -264,4 +266,3 @@ function newUseArrowKeysForNavigation() {
|
||||
return { selectedEntry }
|
||||
}
|
||||
</script>
|
||||
~/services/spotlight/searchers/workspace.searcher
|
||||
|
||||
@@ -239,6 +239,7 @@ import {
|
||||
resetTeamRequestsContext,
|
||||
} from "~/helpers/collection/collection"
|
||||
import { currentReorderingStatus$ } from "~/newstore/reordering"
|
||||
import { defineActionHandler } from "~/helpers/actions"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -2067,4 +2068,8 @@ const getErrorMessage = (err: GQLError<string>) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineActionHandler("collection.new", () => {
|
||||
displayModalAdd(true)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -34,6 +34,13 @@
|
||||
@hide-modal="displayModalNew(false)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<HoppSmartConfirmModal
|
||||
:show="showConfirmRemoveEnvModal"
|
||||
:title="t('confirm.remove_team')"
|
||||
@hide-modal="showConfirmRemoveEnvModal = false"
|
||||
@resolve="removeSelectedEnvironment()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -44,6 +51,7 @@ import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
|
||||
import { useReadonlyStream, useStream } from "@composables/stream"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import {
|
||||
getSelectedEnvironmentIndex,
|
||||
globalEnv$,
|
||||
selectedEnvironmentIndex$,
|
||||
setSelectedEnvironmentIndex,
|
||||
@@ -54,8 +62,15 @@ import { workspaceStatus$ } from "~/newstore/workspace"
|
||||
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
|
||||
import { useLocalState } from "~/newstore/localstate"
|
||||
import { onLoggedIn } from "~/composables/auth"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { deleteEnvironment } from "~/newstore/environments"
|
||||
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import { useToast } from "~/composables/toast"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
||||
type EnvironmentType = "my-environments" | "team-environments"
|
||||
|
||||
@@ -168,6 +183,7 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const showConfirmRemoveEnvModal = ref(false)
|
||||
const showModalNew = ref(false)
|
||||
const showModalDetails = ref(false)
|
||||
const action = ref<"new" | "edit">("edit")
|
||||
@@ -194,6 +210,30 @@ const editEnvironment = (environmentIndex: "Global") => {
|
||||
displayModalEdit(true)
|
||||
}
|
||||
|
||||
const removeSelectedEnvironment = () => {
|
||||
const selectedEnvIndex = getSelectedEnvironmentIndex()
|
||||
if (selectedEnvIndex?.type === "NO_ENV_SELECTED") return
|
||||
|
||||
if (selectedEnvIndex?.type === "MY_ENV") {
|
||||
deleteEnvironment(selectedEnvIndex.index)
|
||||
toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
||||
if (selectedEnvIndex?.type === "TEAM_ENV") {
|
||||
pipe(
|
||||
deleteTeamEnvironment(selectedEnvIndex.teamEnvID),
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
console.error(err)
|
||||
},
|
||||
() => {
|
||||
toast.success(`${t("team_environment.deleted")}`)
|
||||
}
|
||||
)
|
||||
)()
|
||||
}
|
||||
}
|
||||
|
||||
const resetSelectedData = () => {
|
||||
editingEnvironmentIndex.value = null
|
||||
}
|
||||
@@ -203,6 +243,10 @@ defineActionHandler("modals.environment.new", () => {
|
||||
showModalDetails.value = true
|
||||
})
|
||||
|
||||
defineActionHandler("modals.environment.delete-selected", () => {
|
||||
showConfirmRemoveEnvModal.value = true
|
||||
})
|
||||
|
||||
defineActionHandler(
|
||||
"modals.my.environment.edit",
|
||||
({ envName, variableName }) => {
|
||||
|
||||
@@ -129,9 +129,7 @@ const downloadResponse = (str: string) => {
|
||||
}
|
||||
|
||||
defineActionHandler("response.file.download", () =>
|
||||
downloadResponse.bind(responseString.value)
|
||||
)
|
||||
defineActionHandler("response.copy", () =>
|
||||
copyResponse.bind(responseString.value)
|
||||
downloadResponse(responseString.value)
|
||||
)
|
||||
defineActionHandler("response.copy", () => copyResponse(responseString.value))
|
||||
</script>
|
||||
|
||||
@@ -26,14 +26,15 @@ export type HoppAction =
|
||||
| "request.method.delete" // Select DELETE Method
|
||||
| "request.import-curl" // Import cURL
|
||||
| "request.show-code" // Show generated code
|
||||
| "collection.new" // Create root collection
|
||||
| "flyouts.chat.open" // Shows the keybinds flyout
|
||||
| "flyouts.keybinds.toggle" // Shows the keybinds flyout
|
||||
| "modals.search.toggle" // Shows the search modal
|
||||
| "modals.support.toggle" // Shows the support modal
|
||||
| "modals.share.toggle" // Shows the share modal
|
||||
| "modals.social.toggle" // Shows the social links modal
|
||||
| "modals.environment.add" // Show add environment modal via context menu
|
||||
| "modals.environment.new" // Add new environment
|
||||
| "modals.environment.delete-selected" // Delete Selected Environment
|
||||
| "modals.my.environment.edit" // Edit current personal environment
|
||||
| "modals.team.environment.edit" // Edit current team environment
|
||||
| "modals.team.new" // Add new team
|
||||
@@ -108,6 +109,10 @@ type HoppActionArgsMap = {
|
||||
tab: RequestOptionTabs
|
||||
}
|
||||
|
||||
"request.duplicate-tab": {
|
||||
tabID: string
|
||||
}
|
||||
|
||||
"gql.request.open": {
|
||||
request: HoppGQLRequest
|
||||
saveContext?: HoppGQLSaveContext
|
||||
@@ -177,7 +182,7 @@ type InvokeActionFunc = {
|
||||
* @param args The argument passed to the action handler. Optional if action has no args required
|
||||
*/
|
||||
export const invokeAction: InvokeActionFunc = <
|
||||
A extends HoppAction | HoppActionWithArgs,
|
||||
A extends HoppAction | HoppActionWithArgs
|
||||
>(
|
||||
action: A,
|
||||
args: ArgOfHoppAction<A>
|
||||
|
||||
@@ -427,6 +427,10 @@ export function getCurrentEnvironment(): Environment {
|
||||
}
|
||||
}
|
||||
|
||||
export function getSelectedEnvironmentIndex() {
|
||||
return environmentsStore.value.selectedEnvironmentIndex
|
||||
}
|
||||
|
||||
export function getSelectedEnvironmentType() {
|
||||
return environmentsStore.value.selectedEnvironmentIndex.type
|
||||
}
|
||||
|
||||
@@ -461,6 +461,9 @@ defineActionHandler("rest.request.open", ({ doc }) => {
|
||||
})
|
||||
|
||||
defineActionHandler("rest.request.rename", openReqRenameModal)
|
||||
defineActionHandler("request.duplicate-tab", ({ tabID }) => {
|
||||
duplicateTab(tabID)
|
||||
})
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
useService(HeaderInspectorService)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Service } from "dioc"
|
||||
import {
|
||||
SpotlightResultTextType,
|
||||
SpotlightSearcher,
|
||||
SpotlightSearcherResult,
|
||||
SpotlightSearcherSessionState,
|
||||
@@ -26,6 +27,7 @@ import {
|
||||
} from "@hoppscotch/data"
|
||||
import { hoppWorkspaceStore } from "~/newstore/workspace"
|
||||
import { changeWorkspace } from "~/newstore/workspace"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
|
||||
/**
|
||||
* A spotlight searcher that searches through the user's collections
|
||||
@@ -143,6 +145,13 @@ export class CollectionsSpotlightSearcherService
|
||||
},
|
||||
})
|
||||
|
||||
if (pageCategory === "rest" || pageCategory === "graphql") {
|
||||
minisearch.add({
|
||||
id: `create-collection`,
|
||||
name: this.t("collection.new"),
|
||||
})
|
||||
}
|
||||
|
||||
if (pageCategory === "rest") {
|
||||
this.loadRESTDocsIntoMinisearch(minisearch)
|
||||
} else if (pageCategory === "graphql") {
|
||||
@@ -153,6 +162,11 @@ export class CollectionsSpotlightSearcherService
|
||||
|
||||
const scopeHandle = effectScope()
|
||||
|
||||
const newCollectionText: SpotlightResultTextType<any> = {
|
||||
type: "text",
|
||||
text: this.t("collection.new"),
|
||||
}
|
||||
|
||||
scopeHandle.run(() => {
|
||||
watch(query, (query) => {
|
||||
if (pageCategory === "other") {
|
||||
@@ -165,28 +179,34 @@ export class CollectionsSpotlightSearcherService
|
||||
|
||||
results.value = searchResults.map((result) => ({
|
||||
id: result.id,
|
||||
text: {
|
||||
type: "custom",
|
||||
component: markRaw(RESTRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("rest-")[1],
|
||||
},
|
||||
},
|
||||
text:
|
||||
result.id === "create-collection"
|
||||
? newCollectionText
|
||||
: {
|
||||
type: "custom",
|
||||
component: markRaw(RESTRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("rest-")[1],
|
||||
},
|
||||
},
|
||||
icon: markRaw(IconFolder),
|
||||
score: result.score,
|
||||
}))
|
||||
} else {
|
||||
} else if (pageCategory === "graphql") {
|
||||
const searchResults = minisearch.search(query).slice(0, 10)
|
||||
|
||||
results.value = searchResults.map((result) => ({
|
||||
id: result.id,
|
||||
text: {
|
||||
type: "custom",
|
||||
component: markRaw(GQLRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("gql-")[1],
|
||||
},
|
||||
},
|
||||
text:
|
||||
result.id === "create-collection"
|
||||
? newCollectionText
|
||||
: {
|
||||
type: "custom",
|
||||
component: markRaw(GQLRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("gql-")[1],
|
||||
},
|
||||
},
|
||||
icon: markRaw(IconFolder),
|
||||
score: result.score,
|
||||
}))
|
||||
@@ -256,6 +276,8 @@ export class CollectionsSpotlightSearcherService
|
||||
}
|
||||
|
||||
public onResultSelect(result: SpotlightSearcherResult): void {
|
||||
if (result.id === "create-collection") return invokeAction("collection.new")
|
||||
|
||||
const [type, path] = result.id.split("-")
|
||||
|
||||
if (type === "rest") {
|
||||
|
||||
@@ -21,30 +21,29 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconLayers from "~icons/lucide/layers"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
|
||||
import { Service } from "dioc"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import MiniSearch from "minisearch"
|
||||
import { map } from "rxjs"
|
||||
import { useStreamStatic } from "~/composables/stream"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import {
|
||||
createEnvironment,
|
||||
currentEnvironment$,
|
||||
deleteEnvironment,
|
||||
duplicateEnvironment,
|
||||
environmentsStore,
|
||||
getGlobalVariables,
|
||||
selectedEnvironmentIndex$,
|
||||
setSelectedEnvironmentIndex,
|
||||
} from "~/newstore/environments"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import { Service } from "dioc"
|
||||
import MiniSearch from "minisearch"
|
||||
import { map } from "rxjs"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
@@ -188,29 +187,6 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
||||
}
|
||||
}
|
||||
|
||||
removeSelectedEnvironment = () => {
|
||||
if (this.selectedEnvIndex.value?.type === "NO_ENV_SELECTED") return
|
||||
|
||||
if (this.selectedEnvIndex.value?.type === "MY_ENV") {
|
||||
deleteEnvironment(this.selectedEnvIndex.value.index)
|
||||
// this.toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
||||
if (this.selectedEnvIndex.value?.type === "TEAM_ENV") {
|
||||
pipe(
|
||||
deleteTeamEnvironment(this.selectedEnvIndex.value.teamEnvID),
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
console.error(err)
|
||||
},
|
||||
() => {
|
||||
// this.toast.success(`${this.t("team_environment.deleted")}`)
|
||||
}
|
||||
)
|
||||
)()
|
||||
}
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
switch (id) {
|
||||
case "new_environment":
|
||||
@@ -229,7 +205,7 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
||||
})
|
||||
break
|
||||
case "delete_selected_env":
|
||||
this.removeSelectedEnvironment()
|
||||
invokeAction(`modals.environment.delete-selected`)
|
||||
break
|
||||
case "duplicate_selected_env":
|
||||
this.duplicateSelectedEnv()
|
||||
|
||||
@@ -7,14 +7,17 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import IconLinkedIn from "~icons/brands/linkedin"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconGithub from "~icons/lucide/github"
|
||||
import IconDiscord from "~icons/lucide/link"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
import IconLifeBuoy from "~icons/lucide/life-buoy"
|
||||
import IconMessageCircle from "~icons/lucide/message-circle"
|
||||
import IconZap from "~icons/lucide/zap"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
}
|
||||
@@ -56,10 +59,25 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
alternates: ["key", "shortcuts", "binding"],
|
||||
icon: markRaw(IconZap),
|
||||
},
|
||||
social_links: {
|
||||
text: this.t("spotlight.general.social"),
|
||||
alternates: ["social", "github", "binding"],
|
||||
icon: markRaw(IconGithub),
|
||||
link_github: {
|
||||
text: [this.t("spotlight.general.social"), "GitHub"],
|
||||
alternates: ["social", "github", "link"],
|
||||
icon: markRaw(IconGitHub),
|
||||
},
|
||||
link_twitter: {
|
||||
text: [this.t("spotlight.general.social"), "Twitter"],
|
||||
alternates: ["social", "twitter", "link"],
|
||||
icon: markRaw(IconTwitter),
|
||||
},
|
||||
link_discord: {
|
||||
text: [this.t("spotlight.general.social"), "Discord"],
|
||||
alternates: ["social", "discord", "link"],
|
||||
icon: markRaw(IconDiscord),
|
||||
},
|
||||
link_linkedin: {
|
||||
text: [this.t("spotlight.general.social"), "LinkedIn"],
|
||||
alternates: ["social", "linkedin", "link"],
|
||||
icon: markRaw(IconLinkedIn),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -87,8 +105,7 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
}
|
||||
}
|
||||
|
||||
private openDocs() {
|
||||
const url = "https://docs.hoppscotch.io"
|
||||
private openURL(url: string) {
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
|
||||
@@ -101,13 +118,22 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
invokeAction("flyouts.chat.open")
|
||||
break
|
||||
case "open_docs":
|
||||
this.openDocs()
|
||||
this.openURL("https://docs.hoppscotch.io")
|
||||
break
|
||||
case "open_keybindings":
|
||||
invokeAction("flyouts.keybinds.toggle")
|
||||
break
|
||||
case "social_links":
|
||||
invokeAction("modals.social.toggle")
|
||||
case "link_github":
|
||||
this.openURL("https://hoppscotch.io/github")
|
||||
break
|
||||
case "link_twitter":
|
||||
this.openURL("https://twitter.com/hoppscotch_io")
|
||||
break
|
||||
case "link_discord":
|
||||
this.openURL("https://hoppscotch.io/discord")
|
||||
break
|
||||
case "link_linkedin":
|
||||
this.openURL("https://www.linkedin.com/company/hoppscotch/")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import { Ref, computed, effectScope, markRaw, ref, unref, watch } from "vue"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import {
|
||||
SpotlightSearcher,
|
||||
SpotlightSearcherResult,
|
||||
SpotlightSearcherSessionState,
|
||||
SpotlightService,
|
||||
} from ".."
|
||||
|
||||
import { Service } from "dioc"
|
||||
import { useService } from "dioc/vue"
|
||||
import MiniSearch from "minisearch"
|
||||
import IconCheckCircle from "~/components/app/spotlight/entry/IconSelected.vue"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
|
||||
/**
|
||||
* This searcher is responsible for searching through the interceptor.
|
||||
* And switching between them.
|
||||
*/
|
||||
export class InterceptorSpotlightSearcherService
|
||||
extends Service
|
||||
implements SpotlightSearcher
|
||||
{
|
||||
public static readonly ID = "INTERCEPTOR_SPOTLIGHT_SEARCHER_SERVICE"
|
||||
|
||||
private t = getI18n()
|
||||
|
||||
public searcherID = "interceptor"
|
||||
public searcherSectionTitle = this.t("settings.interceptor")
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.spotlight.registerSearcher(this)
|
||||
}
|
||||
|
||||
private interceptorService = useService(InterceptorService)
|
||||
|
||||
createSearchSession(
|
||||
query: Readonly<Ref<string>>
|
||||
): [Ref<SpotlightSearcherSessionState>, () => void] {
|
||||
const loading = ref(false)
|
||||
const results = ref<SpotlightSearcherResult[]>([])
|
||||
|
||||
const minisearch = new MiniSearch({
|
||||
fields: ["name", "alternates"],
|
||||
storeFields: ["name"],
|
||||
})
|
||||
|
||||
const interceptorSelection = this.interceptorService
|
||||
.currentInterceptorID as Ref<string>
|
||||
|
||||
const interceptors = this.interceptorService.availableInterceptors
|
||||
|
||||
minisearch.addAll(
|
||||
interceptors.value.map((entry) => {
|
||||
let id = `interceptor-${entry.interceptorID}`
|
||||
if (entry.interceptorID === interceptorSelection.value) {
|
||||
id += "-selected"
|
||||
}
|
||||
const name = unref(entry.name(this.t))
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
alternates: ["interceptor", "change", name],
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const scopeHandle = effectScope()
|
||||
|
||||
scopeHandle.run(() => {
|
||||
watch(
|
||||
[query],
|
||||
([query]) => {
|
||||
results.value = minisearch
|
||||
.search(query, {
|
||||
prefix: true,
|
||||
fuzzy: true,
|
||||
boost: {
|
||||
reltime: 2,
|
||||
},
|
||||
weights: {
|
||||
fuzzy: 0.2,
|
||||
prefix: 0.8,
|
||||
},
|
||||
})
|
||||
.map((x) => {
|
||||
return {
|
||||
id: x.id,
|
||||
icon: markRaw(
|
||||
x.id.endsWith("-selected") ? IconCheckCircle : IconCircle
|
||||
),
|
||||
score: x.score,
|
||||
text: {
|
||||
type: "text",
|
||||
text: [this.t("spotlight.section.interceptor"), x.name],
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
})
|
||||
|
||||
const onSessionEnd = () => {
|
||||
scopeHandle.stop()
|
||||
minisearch.removeAll()
|
||||
}
|
||||
|
||||
const resultObj = computed<SpotlightSearcherSessionState>(() => ({
|
||||
loading: loading.value,
|
||||
results: results.value,
|
||||
}))
|
||||
|
||||
return [resultObj, onSessionEnd]
|
||||
}
|
||||
|
||||
onResultSelect(result: SpotlightSearcherResult): void {
|
||||
const selectedInterceptor = result.id.split("-")[1]
|
||||
this.interceptorService.currentInterceptorID.value = selectedInterceptor
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, markRaw, reactive } from "vue"
|
||||
import { Component, computed, markRaw, reactive } from "vue"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { SpotlightSearcherResult, SpotlightService } from ".."
|
||||
@@ -7,12 +7,11 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import { useRoute } from "vue-router"
|
||||
import { RequestOptionTabs } from "~/components/http/RequestOptions.vue"
|
||||
import { currentActiveTab } from "~/helpers/rest/tab"
|
||||
import IconWindow from "~icons/lucide/app-window"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
import IconChevronLeft from "~icons/lucide/chevron-left"
|
||||
import IconChevronRight from "~icons/lucide/chevron-right"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCode2 from "~icons/lucide/code-2"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconFileCode from "~icons/lucide/file-code"
|
||||
@@ -25,6 +24,7 @@ type Doc = {
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,116 +43,160 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
private route = useRoute()
|
||||
private isRESTPage = computed(() => this.route.name === "index")
|
||||
private isGQLPage = computed(() => this.route.name === "graphql")
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
send_request: {
|
||||
text: this.t("shortcut.request.send_request"),
|
||||
alternates: ["request", "send"],
|
||||
icon: markRaw(IconPlay),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
save_to_collections: {
|
||||
text: [
|
||||
this.t("request.save_as"),
|
||||
this.t("shortcut.request.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
|
||||
),
|
||||
},
|
||||
save_request: {
|
||||
text: this.t("shortcut.request.save_request"),
|
||||
alternates: ["save", "request"],
|
||||
icon: markRaw(IconSave),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
rename_request: {
|
||||
text: this.t("shortcut.request.rename"),
|
||||
alternates: ["rename", "request"],
|
||||
icon: markRaw(IconRename),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
copy_request_link: {
|
||||
text: this.t("shortcut.request.copy_request_link"),
|
||||
alternates: ["copy", "link"],
|
||||
icon: markRaw(IconCopy),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
reset_request: {
|
||||
text: this.t("shortcut.request.reset_request"),
|
||||
alternates: ["reset", "request"],
|
||||
icon: markRaw(IconRotateCCW),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
import_curl: {
|
||||
text: this.t("shortcut.request.import_curl"),
|
||||
alternates: ["import", "curl"],
|
||||
icon: markRaw(IconFileCode),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
show_code: {
|
||||
text: this.t("shortcut.request.show_code"),
|
||||
alternates: ["show", "code"],
|
||||
icon: markRaw(IconCode2),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
// Change request method
|
||||
next_method: {
|
||||
text: this.t("shortcut.request.next_method"),
|
||||
alternates: ["next", "method"],
|
||||
icon: markRaw(IconChevronRight),
|
||||
},
|
||||
previous_method: {
|
||||
text: this.t("shortcut.request.previous_method"),
|
||||
alternates: ["previous", "method"],
|
||||
icon: markRaw(IconChevronLeft),
|
||||
},
|
||||
get_method: {
|
||||
text: this.t("shortcut.request.get_method"),
|
||||
text: [this.t("spotlight.request.select_method"), "GET"],
|
||||
alternates: ["get", "method"],
|
||||
icon: markRaw(IconCheck),
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
head_method: {
|
||||
text: this.t("shortcut.request.head_method"),
|
||||
text: [this.t("spotlight.request.select_method"), "HEAD"],
|
||||
alternates: ["head", "method"],
|
||||
icon: markRaw(IconCheck),
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
post_method: {
|
||||
text: this.t("shortcut.request.post_method"),
|
||||
text: [this.t("spotlight.request.select_method"), "POST"],
|
||||
alternates: ["post", "method"],
|
||||
icon: markRaw(IconCheck),
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
put_method: {
|
||||
text: this.t("shortcut.request.put_method"),
|
||||
text: [this.t("spotlight.request.select_method"), "PUT"],
|
||||
alternates: ["put", "method"],
|
||||
icon: markRaw(IconCheck),
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
delete_method: {
|
||||
text: this.t("shortcut.request.delete_method"),
|
||||
text: [this.t("spotlight.request.select_method"), "DELETE"],
|
||||
alternates: ["delete", "method"],
|
||||
icon: markRaw(IconCheck),
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
// Change sub tabs
|
||||
tab_parameters: {
|
||||
text: this.t("spotlight.request.tab_parameters"),
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_parameters"),
|
||||
],
|
||||
alternates: ["parameters", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_body: {
|
||||
text: this.t("spotlight.request.tab_body"),
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_body"),
|
||||
],
|
||||
alternates: ["body", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_headers: {
|
||||
text: this.t("spotlight.request.tab_headers"),
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_headers"),
|
||||
],
|
||||
alternates: ["headers", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_authorization: {
|
||||
text: this.t("spotlight.request.tab_authorization"),
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_authorization"),
|
||||
],
|
||||
alternates: ["authorization", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_pre_request_script: {
|
||||
text: this.t("spotlight.request.tab_pre_request_script"),
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_pre_request_script"),
|
||||
],
|
||||
alternates: ["pre-request", "script", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
tab_tests: {
|
||||
text: this.t("spotlight.request.tab_tests"),
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_tests"),
|
||||
],
|
||||
alternates: ["tests", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -209,12 +253,6 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
case "reset_request":
|
||||
invokeAction("request.reset")
|
||||
break
|
||||
case "next_method":
|
||||
invokeAction("request.method.next")
|
||||
break
|
||||
case "previous_method":
|
||||
invokeAction("request.method.prev")
|
||||
break
|
||||
case "get_method":
|
||||
invokeAction("request.method.get")
|
||||
break
|
||||
|
||||
@@ -10,11 +10,10 @@ import {
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import IconCloud from "~icons/lucide/cloud"
|
||||
import IconGlobe from "~icons/lucide/globe"
|
||||
import IconMonitor from "~icons/lucide/monitor"
|
||||
import IconMoon from "~icons/lucide/moon"
|
||||
import IconSun from "~icons/lucide/sun"
|
||||
import IconGlobe from "~icons/lucide/globe"
|
||||
import IconShieldCheck from "~icons/lucide/shield-check"
|
||||
import IconType from "~icons/lucide/type"
|
||||
|
||||
type Doc = {
|
||||
@@ -128,22 +127,6 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
alternates: ["language", "change language"],
|
||||
icon: markRaw(IconGlobe),
|
||||
},
|
||||
change_interceptor: {
|
||||
text: [
|
||||
this.t("spotlight.section.interceptor"),
|
||||
this.t("spotlight.settings.change_interceptor"),
|
||||
],
|
||||
alternates: ["interceptor", "change interceptor"],
|
||||
icon: markRaw(IconShieldCheck),
|
||||
},
|
||||
install_ext: {
|
||||
text: [
|
||||
this.t("spotlight.section.interceptor"),
|
||||
this.t("spotlight.settings.install_extension"),
|
||||
],
|
||||
alternates: ["install extension", "extension", "interceptor"],
|
||||
icon: markRaw(IconShieldCheck),
|
||||
},
|
||||
})
|
||||
|
||||
constructor() {
|
||||
@@ -174,27 +157,12 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
applySetting("BG_COLOR", theme)
|
||||
}
|
||||
|
||||
installExtension() {
|
||||
const url = navigator.userAgent.includes("Firefox")
|
||||
? "https://addons.mozilla.org/en-US/firefox/addon/hoppscotch"
|
||||
: "https://chrome.google.com/webstore/detail/hoppscotch-browser-extens/amknoiejhlmhancpahfcfcfhllgkpbld"
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
switch (id) {
|
||||
case "change_interceptor":
|
||||
invokeAction("navigation.jump.settings")
|
||||
break
|
||||
|
||||
case "change_lang":
|
||||
invokeAction("navigation.jump.settings")
|
||||
break
|
||||
|
||||
case "install_ext":
|
||||
this.installExtension()
|
||||
break
|
||||
|
||||
// theme actions
|
||||
case "theme_system":
|
||||
invokeAction("settings.theme.system")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, markRaw, reactive } from "vue"
|
||||
import { Component, computed, markRaw, reactive } from "vue"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { SpotlightSearcherResult, SpotlightService } from ".."
|
||||
import {
|
||||
@@ -6,19 +6,23 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} 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 IconWindow from "~icons/lucide/app-window"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,21 +41,39 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
private route = useRoute()
|
||||
private showAction = computed(
|
||||
() => this.route.name === "index" ?? this.route.name === "graphql"
|
||||
)
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
duplicate_tab: {
|
||||
text: this.t("spotlight.tab.duplicate"),
|
||||
alternates: ["tab", "duplicate", "duplicate tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.showAction.value),
|
||||
},
|
||||
close_current_tab: {
|
||||
text: this.t("spotlight.tab.close_current"),
|
||||
alternates: ["tab", "close", "close tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.showAction.value ?? getActiveTabs().value.length === 1
|
||||
),
|
||||
},
|
||||
close_other_tabs: {
|
||||
text: this.t("spotlight.tab.close_others"),
|
||||
alternates: ["tab", "close", "close all"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.showAction.value ?? getActiveTabs().value.length < 2
|
||||
),
|
||||
},
|
||||
open_new_tab: {
|
||||
text: this.t("spotlight.tab.new_tab"),
|
||||
alternates: ["tab", "new", "open tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.showAction.value),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -80,6 +102,10 @@ 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")
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ref,
|
||||
watch,
|
||||
} from "vue"
|
||||
import { activeActions$, invokeAction } from "~/helpers/actions"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import {
|
||||
SpotlightSearcher,
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import { Service } from "dioc"
|
||||
import * as E from "fp-ts/Either"
|
||||
import MiniSearch from "minisearch"
|
||||
import IconCheckCircle from "~/components/app/spotlight/entry/IconSelected.vue"
|
||||
import { useStreamStatic } from "~/composables/stream"
|
||||
import { runGQLQuery } from "~/helpers/backend/GQLClient"
|
||||
import { GetMyTeamsDocument, GetMyTeamsQuery } from "~/helpers/backend/graphql"
|
||||
@@ -36,7 +37,7 @@ import IconUserPlus from "~icons/lucide/user-plus"
|
||||
import IconUsers from "~icons/lucide/users"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
@@ -66,14 +67,6 @@ export class WorkspaceSpotlightSearcherService extends StaticSpotlightSearcherSe
|
||||
}
|
||||
)[0]
|
||||
|
||||
private activeActions = useStreamStatic(activeActions$, [], () => {
|
||||
/* noop */
|
||||
})[0]
|
||||
|
||||
private isLoggedInUser = computed(() =>
|
||||
this.activeActions.value.includes("user.logout")
|
||||
)
|
||||
|
||||
private isTeamSelected = computed(
|
||||
() =>
|
||||
this.workspace.value.type === "team" &&
|
||||
@@ -82,31 +75,33 @@ export class WorkspaceSpotlightSearcherService extends StaticSpotlightSearcherSe
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
new_team: {
|
||||
text: this.t("spotlight.workspace.new"),
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.new")],
|
||||
alternates: ["new", "team", "workspace"],
|
||||
icon: markRaw(IconUsers),
|
||||
excludeFromSearch: computed(() => !this.isLoggedInUser.value),
|
||||
},
|
||||
edit_team: {
|
||||
text: this.t("spotlight.workspace.edit"),
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.edit")],
|
||||
alternates: ["edit", "team", "workspace"],
|
||||
icon: markRaw(IconEdit),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
},
|
||||
invite_members: {
|
||||
text: this.t("spotlight.workspace.invite"),
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.invite")],
|
||||
alternates: ["invite", "members", "workspace"],
|
||||
icon: markRaw(IconUserPlus),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
},
|
||||
delete_team: {
|
||||
text: this.t("spotlight.workspace.delete"),
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.delete")],
|
||||
alternates: ["delete", "team", "workspace"],
|
||||
icon: markRaw(IconTrash2),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
},
|
||||
switch_to_personal: {
|
||||
text: this.t("spotlight.workspace.switch_to_personal"),
|
||||
text: [
|
||||
this.t("team.title"),
|
||||
this.t("spotlight.workspace.switch_to_personal"),
|
||||
],
|
||||
alternates: ["switch", "team", "workspace", "personal"],
|
||||
icon: markRaw(IconUser),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
@@ -145,8 +140,13 @@ export class WorkspaceSpotlightSearcherService extends StaticSpotlightSearcherSe
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
if (id === "new_team") invokeAction(`modals.team.new`)
|
||||
else if (id === "edit_team") invokeAction(`modals.team.edit`)
|
||||
if (id === "new_team") {
|
||||
if (platform.auth.getCurrentUser()) {
|
||||
invokeAction(`modals.team.new`)
|
||||
} else {
|
||||
invokeAction(`modals.login.toggle`)
|
||||
}
|
||||
} else if (id === "edit_team") invokeAction(`modals.team.edit`)
|
||||
else if (id === "invite_members") invokeAction(`modals.team.invite`)
|
||||
else if (id === "delete_team") this.deleteTeam()
|
||||
else if (id === "switch_to_personal")
|
||||
@@ -197,6 +197,14 @@ export class SwitchWorkspaceSpotlightSearcherService
|
||||
})
|
||||
}
|
||||
|
||||
private workspace = useStreamStatic(
|
||||
workspaceStatus$,
|
||||
{ type: "personal" },
|
||||
() => {
|
||||
/* noop */
|
||||
}
|
||||
)[0]
|
||||
|
||||
createSearchSession(
|
||||
query: Readonly<Ref<string>>
|
||||
): [Ref<SpotlightSearcherSessionState>, () => void] {
|
||||
@@ -211,8 +219,16 @@ export class SwitchWorkspaceSpotlightSearcherService
|
||||
this.fetchMyTeams().then((teams) => {
|
||||
minisearch.addAll(
|
||||
teams.map((entry) => {
|
||||
let id = `workspace-${entry.id}`
|
||||
// if id matches add -selected to it
|
||||
if (
|
||||
this.workspace.value.type === "team" &&
|
||||
this.workspace.value.teamID === entry.id
|
||||
) {
|
||||
id += "-selected"
|
||||
}
|
||||
return {
|
||||
id: `workspace-${entry.id}`,
|
||||
id,
|
||||
name: entry.name,
|
||||
alternates: ["team", "workspace", "change", "switch"],
|
||||
}
|
||||
@@ -241,7 +257,9 @@ export class SwitchWorkspaceSpotlightSearcherService
|
||||
.map((x) => {
|
||||
return {
|
||||
id: x.id,
|
||||
icon: markRaw(IconUsers),
|
||||
icon: markRaw(
|
||||
x.id.endsWith("-selected") ? IconCheckCircle : IconUsers
|
||||
),
|
||||
score: x.score,
|
||||
text: {
|
||||
type: "text",
|
||||
|
||||
Reference in New Issue
Block a user