import { computed, ref } from 'vue' import { useRoute } from 'vue-router' import { useApps } from '@front/features/apps' import type { Bridge } from '@vue-devtools/shared-utils' import { BridgeEvents, getStorage, parse, searchDeepInObject, setStorage } from '@vue-devtools/shared-utils' import { getBridge, useBridge } from '@front/features/bridge' export interface InspectorFromBackend { id: string appId: string pluginId: string label: string icon: string treeFilterPlaceholder: string stateFilterPlaceholder: string noSelectionText: string actions?: { icon: string tooltip?: string }[] nodeActions?: { icon: string tooltip?: string }[] } export interface Inspector extends InspectorFromBackend { rootNodes: any[] treeFilter: string selectedNodeId: string selectedNode: any stateFilter: string state: any expandedMap: Record } const SELECTED_NODES_STORAGE = 'custom-inspector-selected-nodes' let selectedIdsStorage = {} function inspectorFactory(options: InspectorFromBackend): Inspector { return { ...options, rootNodes: [], treeFilter: '', selectedNodeId: selectedIdsStorage[options.id] || null, selectedNode: null, stateFilter: '', state: null, expandedMap: {}, } } const inspectors = ref([]) export function useInspectors() { const { currentAppId } = useApps() const currentAppInspectors = computed(() => inspectors.value.filter(i => i.appId === currentAppId.value)) return { inspectors: currentAppInspectors, } } export function useCurrentInspector() { const route = useRoute() const { inspectors } = useInspectors() const { bridge } = useBridge() const currentInspector = computed(() => inspectors.value.find(i => i.id === route.params.inspectorId)) const filteredState = computed(() => { if (currentInspector.value?.stateFilter) { const result = {} for (const groupKey in currentInspector.value.state) { const group = currentInspector.value.state[groupKey] const groupFields = group.filter(el => searchDeepInObject({ [el.key]: el.value, }, currentInspector.value?.stateFilter)) if (groupFields.length) { result[groupKey] = groupFields } } return result } else { return currentInspector.value?.state } }) function selectNode(node) { currentInspector.value.selectedNodeId = node.id currentInspector.value.selectedNode = node selectedIdsStorage[currentInspector.value.id] = node.id setStorage(SELECTED_NODES_STORAGE, selectedIdsStorage) fetchState(currentInspector.value) } function refreshInspector() { refreshTree() refreshState() } function refreshTree() { fetchTree(currentInspector.value) } function refreshState() { fetchState(currentInspector.value) } function editState(path: string, payload: any, type: string) { bridge.send(BridgeEvents.TO_BACK_CUSTOM_INSPECTOR_EDIT_STATE, { inspectorId: currentInspector.value.id, appId: currentInspector.value.appId, nodeId: currentInspector.value.selectedNodeId, path, type, payload, }) } return { currentInspector, filteredState, selectNode, refreshInspector, refreshTree, refreshState, editState, } } function fetchInspectors() { getBridge().send(BridgeEvents.TO_BACK_CUSTOM_INSPECTOR_LIST, {}) } function fetchTree(inspector: Inspector) { if (!inspector) { return } getBridge().send(BridgeEvents.TO_BACK_CUSTOM_INSPECTOR_TREE, { inspectorId: inspector.id, appId: inspector.appId, treeFilter: inspector.treeFilter, }) } function fetchState(inspector: Inspector) { if (!inspector || !inspector.selectedNodeId) { return } getBridge().send(BridgeEvents.TO_BACK_CUSTOM_INSPECTOR_STATE, { inspectorId: inspector.id, appId: inspector.appId, nodeId: inspector.selectedNodeId, }) } export function resetInspectors() { inspectors.value = [] fetchInspectors() } export function setupCustomInspectorBridgeEvents(bridge: Bridge) { selectedIdsStorage = getStorage(SELECTED_NODES_STORAGE, {}) bridge.on(BridgeEvents.TO_FRONT_CUSTOM_INSPECTOR_LIST, ({ inspectors: list }) => { list.forEach((inspector) => { if (!inspectors.value.some(i => i.id === inspector.id && i.appId === inspector.appId)) { inspectors.value.push(inspectorFactory(inspector)) } }) }) bridge.on(BridgeEvents.TO_FRONT_CUSTOM_INSPECTOR_ADD, () => { fetchInspectors() }) bridge.on(BridgeEvents.TO_FRONT_CUSTOM_INSPECTOR_TREE, ({ appId, inspectorId, rootNodes }) => { const inspector = inspectors.value.find(i => i.id === inspectorId && i.appId === appId) if (!inspector) { console.warn(`Inspector ${inspectorId} not found`) return } inspector.rootNodes = rootNodes }) bridge.on(BridgeEvents.TO_FRONT_CUSTOM_INSPECTOR_STATE, ({ appId, inspectorId, state }) => { const inspector = inspectors.value.find(i => i.id === inspectorId && i.appId === appId) if (!inspector) { console.warn(`Inspector ${inspectorId} not found`) return } inspector.state = parse(state) }) bridge.on(BridgeEvents.TO_FRONT_CUSTOM_INSPECTOR_SELECT_NODE, ({ appId, inspectorId, nodeId }) => { const inspector = inspectors.value.find(i => i.id === inspectorId && i.appId === appId) if (!inspector) { console.warn(`Inspector ${inspectorId} not found`) return } inspector.selectedNodeId = nodeId inspector.selectedNode = null selectedIdsStorage[inspector.id] = nodeId setStorage(SELECTED_NODES_STORAGE, selectedIdsStorage) fetchState(inspector) }) resetInspectors() }