feat: revamped spotlight (#3171)

Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
This commit is contained in:
Andrew Bastin
2023-07-11 23:02:33 +05:30
committed by GitHub
parent c3531c9d8b
commit 5230d2d3b8
36 changed files with 3941 additions and 1043 deletions

View File

@@ -2,8 +2,10 @@
* For example, sending a request.
*/
import { onBeforeUnmount, onMounted } from "vue"
import { Ref, onBeforeUnmount, onMounted, watch } from "vue"
import { BehaviorSubject } from "rxjs"
import { HoppRESTDocument } from "./rest/document"
import { HoppGQLRequest } from "@hoppscotch/data"
export type HoppAction =
| "request.send-cancel" // Send/Cancel a Hoppscotch Request
@@ -22,8 +24,6 @@ export type HoppAction =
| "modals.search.toggle" // Shows the search modal
| "modals.support.toggle" // Shows the support modal
| "modals.share.toggle" // Shows the share modal
| "modals.my.environment.edit" // Edit current personal environment
| "modals.team.environment.edit" // Edit current team environment
| "navigation.jump.rest" // Jump to REST page
| "navigation.jump.graphql" // Jump to GraphQL page
| "navigation.jump.realtime" // Jump to realtime page
@@ -38,6 +38,9 @@ export type HoppAction =
| "response.file.download" // Download response as file
| "response.copy" // Copy response to clipboard
| "modals.login.toggle" // Login to Hoppscotch
| "history.clear" // Clear REST History
| "user.login" // Login to Hoppscotch
| "user.logout" // Log out of Hoppscotch
/**
* Defines the arguments, if present for a given type that is required to be passed on
@@ -50,7 +53,7 @@ export type HoppAction =
* NOTE: We can't enforce type checks to make sure the key is Action, you
* will know if you got something wrong if there is a type error in this file
*/
type HoppActionArgs = {
type HoppActionArgsMap = {
"modals.my.environment.edit": {
envName: string
variableName: string
@@ -59,12 +62,18 @@ type HoppActionArgs = {
envName: string
variableName: string
}
"rest.request.open": {
doc: HoppRESTDocument
}
"gql.request.open": {
request: HoppGQLRequest
}
}
/**
* HoppActions which require arguments for their invocation
*/
type HoppActionWithArgs = keyof HoppActionArgs
export type HoppActionWithArgs = keyof HoppActionArgsMap
/**
* HoppActions which do not require arguments for their invocation
@@ -74,27 +83,27 @@ export type HoppActionWithNoArgs = Exclude<HoppAction, HoppActionWithArgs>
/**
* Resolves the argument type for a given HoppAction
*/
type ArgOfHoppAction<A extends HoppAction> = A extends HoppActionWithArgs
? HoppActionArgs[A]
: undefined
type ArgOfHoppAction<A extends HoppAction | HoppActionWithArgs> =
A extends HoppActionWithArgs ? HoppActionArgsMap[A] : undefined
/**
* Resolves the action function for a given HoppAction, used by action handler function defs
*/
type ActionFunc<A extends HoppAction> = A extends HoppActionWithArgs
? (arg: ArgOfHoppAction<A>) => void
: () => void
type ActionFunc<A extends HoppAction | HoppActionWithArgs> =
A extends HoppActionWithArgs ? (arg: ArgOfHoppAction<A>) => void : () => void
type BoundActionList = {
// eslint-disable-next-line no-unused-vars
[A in HoppAction]?: Array<ActionFunc<A>>
[A in HoppAction | HoppActionWithArgs]?: Array<ActionFunc<A>>
}
const boundActions: BoundActionList = {}
export const activeActions$ = new BehaviorSubject<HoppAction[]>([])
export const activeActions$ = new BehaviorSubject<
(HoppAction | HoppActionWithArgs)[]
>([])
export function bindAction<A extends HoppAction>(
export function bindAction<A extends HoppAction | HoppActionWithArgs>(
action: A,
handler: ActionFunc<A>
) {
@@ -110,7 +119,7 @@ export function bindAction<A extends HoppAction>(
type InvokeActionFunc = {
(action: HoppActionWithNoArgs, args?: undefined): void
<A extends HoppActionWithArgs>(action: A, args: ArgOfHoppAction<A>): void
<A extends HoppActionWithArgs>(action: A, args: HoppActionArgsMap[A]): void
}
/**
@@ -119,14 +128,16 @@ type InvokeActionFunc = {
* @param action The action to fire
* @param args The argument passed to the action handler. Optional if action has no args required
*/
export const invokeAction: InvokeActionFunc = <A extends HoppAction>(
export const invokeAction: InvokeActionFunc = <
A extends HoppAction | HoppActionWithArgs
>(
action: A,
args: ArgOfHoppAction<A>
) => {
boundActions[action]?.forEach((handler) => handler(args!))
boundActions[action]?.forEach((handler) => handler(args! as any))
}
export function unbindAction<A extends HoppAction>(
export function unbindAction<A extends HoppAction | HoppActionWithArgs>(
action: A,
handler: ActionFunc<A>
) {
@@ -142,15 +153,57 @@ export function unbindAction<A extends HoppAction>(
activeActions$.next(Object.keys(boundActions) as HoppAction[])
}
export function defineActionHandler<A extends HoppAction>(
/**
* A composable function that defines a component can handle a given
* HoppAction. The handler will be bound when the component is mounted
* and unbound when the component is unmounted.
* @param action The action to be bound
* @param handler The function to be called when the action is invoked
* @param isActive A ref that indicates whether the action is active
*/
export function defineActionHandler<A extends HoppAction | HoppActionWithArgs>(
action: A,
handler: ActionFunc<A>
handler: ActionFunc<A>,
isActive: Ref<boolean> | undefined = undefined
) {
let mounted = false
let bound = false
onMounted(() => {
bindAction(action, handler)
mounted = true
// Only bind if isActive is undefined or true
if (isActive === undefined || isActive.value === true) {
bound = true
bindAction(action, handler)
}
})
onBeforeUnmount(() => {
mounted = false
bound = false
unbindAction(action, handler)
})
if (isActive) {
watch(
isActive,
(active) => {
if (mounted) {
if (active) {
if (!bound) {
bound = true
bindAction(action, handler)
}
} else if (bound) {
bound = false
unbindAction(action, handler)
}
}
},
{ immediate: true }
)
}
}