feat: first time user spotlight animation (#3977)

This commit is contained in:
Nivedin
2024-04-22 12:21:30 +05:30
committed by GitHub
parent 18652ce400
commit 0e2887b4e9
11 changed files with 327 additions and 78 deletions

View File

@@ -66,6 +66,8 @@ const SettingsDefSchema = z.object({
cookie: z.boolean().catch(true),
})
),
HAS_OPENED_SPOTLIGHT: z.optional(z.boolean()),
})
// Common properties shared across REST & GQL collections

View File

@@ -15,6 +15,7 @@ import {
restCollectionStore,
} from "~/newstore/collections"
import IconFolder from "~icons/lucide/folder"
import IconImport from "~icons/lucide/folder-down"
import RESTRequestSpotlightEntry from "~/components/app/spotlight/entry/RESTRequest.vue"
import GQLRequestSpotlightEntry from "~/components/app/spotlight/entry/GQLRequest.vue"
import {
@@ -151,6 +152,10 @@ export class CollectionsSpotlightSearcherService
id: `create-collection`,
name: this.t("collection.new"),
})
minisearch.add({
id: "import-collection",
name: this.t("collection.import"),
})
}
if (pageCategory === "rest") {
@@ -168,6 +173,11 @@ export class CollectionsSpotlightSearcherService
text: this.t("collection.new"),
}
const importCollectionText: SpotlightResultTextType<any> = {
type: "text",
text: this.t("collection.import_collection"),
}
scopeHandle.run(() => {
const isPersonalWorkspace = computed(
() => this.workspaceService.currentWorkspace.value.type === "personal"
@@ -183,44 +193,37 @@ export class CollectionsSpotlightSearcherService
results.value = []
return
}
if (pageCategory === "rest") {
const searchResults = minisearch.search(query).slice(0, 10)
results.value = searchResults.map((result) => ({
id: result.id,
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 if (pageCategory === "graphql") {
const searchResults = minisearch.search(query).slice(0, 10)
results.value = searchResults.map((result) => ({
id: result.id,
text:
result.id === "create-collection"
? newCollectionText
: {
type: "custom",
component: markRaw(GQLRequestSpotlightEntry),
componentProps: {
folderPath: result.id.split("gql-")[1],
},
},
icon: markRaw(IconFolder),
score: result.score,
}))
const getResultText = (id: string): SpotlightResultTextType<any> => {
if (id === "create-collection") return newCollectionText
else if (id === "import-collection") return importCollectionText
return {
type: "custom",
component: markRaw(
pageCategory === "rest"
? RESTRequestSpotlightEntry
: GQLRequestSpotlightEntry
),
componentProps: {
folderPath: id.split(
pageCategory === "rest" ? "rest-" : "gql-"
)[1],
},
}
}
const getResultIcon = (id: string) => {
if (id === "import-collection") return markRaw(IconImport)
return markRaw(IconFolder)
}
const searchResults = minisearch.search(query).slice(0, 10)
results.value = searchResults.map((result) => ({
id: result.id,
text: getResultText(result.id),
icon: getResultIcon(result.id),
score: result.score,
}))
})
})
@@ -288,6 +291,9 @@ export class CollectionsSpotlightSearcherService
public onResultSelect(result: SpotlightSearcherResult): void {
if (result.id === "create-collection") return invokeAction("collection.new")
if (result.id === "import-collection")
return invokeAction(`modals.collection.import`)
const [type, path] = result.id.split("-")
if (type === "rest") {

View File

@@ -1,20 +1,24 @@
import { Service } from "dioc"
import {
SpotlightResultTextType,
SpotlightSearcher,
SpotlightSearcherResult,
SpotlightSearcherSessionState,
SpotlightService,
} from ".."
import { getI18n } from "~/modules/i18n"
import { Ref, computed, effectScope, markRaw, watch } from "vue"
import { Ref, computed, effectScope, markRaw, ref, watch } from "vue"
import { TeamSearchService } from "~/helpers/teams/TeamsSearch.service"
import { cloneDeep, debounce } from "lodash-es"
import IconFolder from "~icons/lucide/folder"
import IconImport from "~icons/lucide/folder-down"
import { WorkspaceService } from "~/services/workspace.service"
import RESTTeamRequestEntry from "~/components/app/spotlight/entry/RESTTeamRequestEntry.vue"
import { RESTTabService } from "~/services/tab/rest"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
import { HoppRESTRequest } from "@hoppscotch/data"
import MiniSearch from "minisearch"
import { invokeAction } from "~/helpers/actions"
export class TeamsSpotlightSearcherService
extends Service
@@ -41,9 +45,79 @@ export class TeamsSpotlightSearcherService
this.spotlight.registerSearcher(this)
}
private getCurrentPageCategory() {
// TODO: Better logic for this ?
try {
const url = new URL(window.location.href)
if (url.pathname.startsWith("/graphql")) {
return "graphql"
} else if (url.pathname === "/") {
return "rest"
}
return "other"
} catch (e) {
return "other"
}
}
createSearchSession(
query: Readonly<Ref<string>>
): [Ref<SpotlightSearcherSessionState>, () => void] {
const pageCategory = this.getCurrentPageCategory()
// Only show the searcher on the REST page
if (pageCategory !== "rest") {
return [computed(() => ({ loading: false, results: [] })), () => {}]
}
const results = ref<SpotlightSearcherResult[]>([])
const minisearch = new MiniSearch({
fields: ["name"],
storeFields: ["name"],
searchOptions: {
prefix: true,
fuzzy: true,
boost: {
name: 2,
},
weights: {
fuzzy: 0.2,
prefix: 0.8,
},
},
})
minisearch.add({
id: `create-collection`,
name: this.t("collection.new"),
})
minisearch.add({
id: "import-collection",
name: this.t("collection.import"),
})
const newCollectionText: SpotlightResultTextType<any> = {
type: "text",
text: this.t("collection.new"),
}
const importCollectionText: SpotlightResultTextType<any> = {
type: "text",
text: this.t("collection.import_collection"),
}
const getResultText = (id: string): SpotlightResultTextType<any> => {
if (id === "create-collection") return newCollectionText
return importCollectionText
}
const getResultIcon = (id: string) => {
if (id === "import-collection") return markRaw(IconImport)
return markRaw(IconFolder)
}
const isTeamWorkspace = computed(
() => this.workspaceService.currentWorkspace.value.type === "team"
)
@@ -59,6 +133,13 @@ export class TeamsSpotlightSearcherService
if (this.workspaceService.currentWorkspace.value.type === "team") {
const teamID = this.workspaceService.currentWorkspace.value.teamID
debouncedSearch(query, teamID)?.catch(() => {})
const searchResults = minisearch.search(query).slice(0, 10)
results.value = searchResults.map((result) => ({
id: result.id,
text: getResultText(result.id),
icon: getResultIcon(result.id),
score: result.score,
}))
}
},
{
@@ -91,36 +172,47 @@ export class TeamsSpotlightSearcherService
}
const resultObj = computed<SpotlightSearcherSessionState>(() => {
return isTeamWorkspace.value
? {
loading: this.teamsSearch.teamsSearchResultsLoading.value,
results:
this.teamsSearch.teamsSearchResultsFormattedForSpotlight.value.map(
(result) => ({
id: result.request.id,
icon: markRaw(IconFolder),
score: 1, // make a better scoring system for this
text: {
type: "custom",
component: markRaw(RESTTeamRequestEntry),
componentProps: {
collectionTitles: result.collectionTitles,
request: result.request,
},
},
})
),
}
: {
loading: false,
results: [],
}
})
if (isTeamWorkspace.value) {
const teamsSearchResults =
this.teamsSearch.teamsSearchResultsFormattedForSpotlight.value
const minisearchResults = results.value
const mergedResults = [
...teamsSearchResults.map((result) => ({
id: result.request.id,
icon: markRaw(IconFolder),
score: 1, // make a better scoring system for this
text: {
type: "custom",
component: markRaw(RESTTeamRequestEntry),
componentProps: {
collectionTitles: result.collectionTitles,
request: result.request,
},
},
})),
...minisearchResults,
] as SpotlightSearcherResult[]
return {
loading: this.teamsSearch.teamsSearchResultsLoading.value,
results: mergedResults,
}
}
return {
loading: false,
results: [],
}
})
return [resultObj, onSessionEnd]
}
onResultSelect(result: SpotlightSearcherResult): void {
if (result.id === "create-collection") return invokeAction("collection.new")
if (result.id === "import-collection")
return invokeAction(`modals.collection.import`)
let inheritedProperties: HoppInheritedProperty | undefined = undefined
const selectedRequest = this.teamsSearch.searchResultsRequests[result.id]