多维表格
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

187 lines
4.9 KiB

import type { Ref } from 'vue'
import { homeCommands } from './commands'
interface CmdAction {
id: string
title: string
hotkey?: string
parent?: string
handler?: Function
icon?: VNode | string
keywords?: string[]
projectName?: string
section?: string
}
export const useCommandPalette = createSharedComposable(() => {
const { $api } = useNuxtApp()
const router = useRouter()
const route = router.currentRoute
const commandPalette = ref()
const refreshCommandPalette = createEventHook<void>()
const activeScope: Ref<{ scope: string; data: any }> = ref({ scope: 'disabled', data: {} })
const cmdLoading = ref(false)
const cmdPlaceholder = ref('Search...')
const { token, user, signOut } = useGlobal()
const commands = ref({
homeCommands,
baseCommands: [],
} as Record<string, CmdAction[]>)
const staticData = computed(() => {
const staticCmd = commands.value.homeCommands
// Static Commands
staticCmd.map((cmd) => {
if (cmd.id === 'user') {
if (user.value && user.value.display_name && user.value.email) {
cmd.title = user.value.display_name ?? user.value.email.split('@')[0] ?? 'User'
}
} else if (cmd.id === 'user_account-logout') {
cmd.handler = async () => {
await signOut()
window.location.reload()
}
}
return cmd
})
if (activeScope.value.scope === 'root') return staticCmd
staticCmd.push(...commands.value.baseCommands)
return staticCmd
})
const dynamicData = ref<any>([])
const tempData = ref<any>([])
const loadedTemporaryScopes = ref<any>([])
const cmdData = computed(() => {
if (cmdLoading.value) {
return [{ id: 'loading', title: 'Loading...' }, ...staticData.value]
} else {
return [...dynamicData.value, ...staticData.value, ...tempData.value]
}
})
function processHandler(handler: { type: string; payload: string }) {
switch (handler.type) {
case 'navigate':
return () => navigateTo(handler.payload)
default:
break
}
}
async function loadTemporaryScope(scope: { scope: string; data: any }) {
if (loadedTemporaryScopes.value.find((s: any) => s.scope === scope.scope)) return
if (
activeScope.value.scope === scope.scope &&
Object.keys(scope.data).every((k) => activeScope.value.data[k] && scope.data[k] === activeScope.value.data[k])
)
return
$api.utils.commandPalette(scope).then((res) => {
const fetchData = res.map((item: any) => {
if (item.handler) item.handler = processHandler(item.handler)
return item
})
for (const d of fetchData) {
const fnd = tempData.value.find((t: any) => t.id === d.id)
if (fnd) {
Object.assign(fnd, d)
} else {
tempData.value.push(d)
}
}
loadedTemporaryScopes.value.push(scope)
})
}
async function loadScope() {
if (activeScope.value.scope === 'disabled') {
activeScope.value = { scope: activeScope.value.scope, data: activeScope.value.data }
return
}
dynamicData.value = []
tempData.value = []
loadedTemporaryScopes.value = []
cmdLoading.value = true
$api.utils
.commandPalette(activeScope.value)
.then((res) => {
dynamicData.value = res.map((item: any) => {
if (item.handler) item.handler = processHandler(item.handler)
return item
})
cmdLoading.value = false
})
.catch((e) => {
cmdLoading.value = false
console.log(e)
})
}
refreshCommandPalette.on(() => {
loadScope()
})
watch(
() => route.value.params,
() => {
// if user is not authenticated, don't load scope
if (!token.value) return
if (route.value.params.typeOrId && typeof route.value.params.typeOrId === 'string') {
if (route.value.params.typeOrId === 'base') {
if (activeScope.value.scope === 'disabled') return
activeScope.value = { scope: 'disabled', data: {} }
loadScope()
} else if (route.value.params.typeOrId === 'nc') {
if (activeScope.value.data.base_id === route.value.params.baseId) return
activeScope.value = {
scope: `p-${route.value.params.baseId}`,
data: { base_id: route.value.params.baseId },
}
}
} else {
if (route.value.path.startsWith('/account')) {
if (activeScope.value.scope === 'account_settings') return
activeScope.value = { scope: 'account_settings', data: {} }
loadScope()
} else {
if (activeScope.value.scope === 'root') return
activeScope.value = { scope: 'root', data: {} }
loadScope()
}
}
},
{ immediate: true, deep: true },
)
return {
commandPalette,
cmdData,
activeScope,
loadScope,
cmdPlaceholder,
refreshCommandPalette: refreshCommandPalette.trigger,
loadTemporaryScope,
}
})