mirror of
https://github.com/enso-org/enso.git
synced 2025-01-03 19:21:54 +03:00
Filter visualization types based on node type (#8004)
- Closes #7925 # Important Notes The type -> matching visualization lookup is populated using a `Promise`, so there is a race condition where the selector will incorrectly show the full list of visualizations if it is opened before the `Promise` resolves.
This commit is contained in:
parent
b64a7d392f
commit
62019f6334
@ -20,6 +20,7 @@ import {
|
||||
import { colorFromString } from '@/util/colors'
|
||||
import { usePointer, useResizeObserver } from '@/util/events'
|
||||
import { methodNameToIcon, typeNameToIcon } from '@/util/getIconName'
|
||||
import type { UnsafeMutable } from '@/util/mutable'
|
||||
import type { Opt } from '@/util/opt'
|
||||
import type { Vec2 } from '@/util/vec2'
|
||||
import type { ContentRange, ExprId, VisualizationIdentifier } from 'shared/yjsModel'
|
||||
@ -307,9 +308,11 @@ function switchToDefaultPreprocessor() {
|
||||
visPreprocessor.value = DEFAULT_VISUALIZATION_CONFIGURATION
|
||||
}
|
||||
|
||||
const visualizationConfig = ref<VisualizationConfig>({
|
||||
// This usage of `UnsafeMutable` is SAFE, as it is being used on a type without an associated value.
|
||||
const visualizationConfig = ref<UnsafeMutable<VisualizationConfig>>({
|
||||
fullscreen: false,
|
||||
types: visualizationStore.types,
|
||||
// We do not know the type yet.
|
||||
types: visualizationStore.types(undefined),
|
||||
width: null,
|
||||
height: 150,
|
||||
hide() {
|
||||
@ -426,6 +429,10 @@ const icon = computed(() => {
|
||||
return 'in_out'
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
visualizationConfig.value.types = visualizationStore.types(expressionInfo.value?.typename)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -3,7 +3,7 @@ import { visIdentifierEquals, type VisualizationIdentifier } from 'shared/yjsMod
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
types: VisualizationIdentifier[]
|
||||
types: readonly VisualizationIdentifier[]
|
||||
modelValue: VisualizationIdentifier
|
||||
}>()
|
||||
const emit = defineEmits<{ hide: []; 'update:modelValue': [type: VisualizationIdentifier] }>()
|
||||
|
@ -5,7 +5,7 @@ import { inject, provide, type InjectionKey, type Ref } from 'vue'
|
||||
export interface VisualizationConfig {
|
||||
/** Possible visualization types that can be switched to. */
|
||||
background?: string
|
||||
readonly types: VisualizationIdentifier[]
|
||||
readonly types: readonly VisualizationIdentifier[]
|
||||
readonly currentType: VisualizationIdentifier
|
||||
readonly isCircularMenuVisible: boolean
|
||||
readonly nodeSize: Vec2
|
||||
|
@ -1,3 +1,6 @@
|
||||
import * as vue from 'vue'
|
||||
import { reactive, ref, type DefineComponent, type PropType } from 'vue'
|
||||
|
||||
import VisualizationContainer from '@/components/VisualizationContainer.vue'
|
||||
import { useVisualizationConfig } from '@/providers/visualizationConfig'
|
||||
import { defineKeybinds } from '@/util/shortcuts'
|
||||
@ -18,8 +21,6 @@ import Compiler from '@/workers/visualizationCompiler?worker'
|
||||
import { defineStore } from 'pinia'
|
||||
import type { VisualizationConfiguration } from 'shared/languageServerTypes'
|
||||
import type { VisualizationIdentifier } from 'shared/yjsModel'
|
||||
import * as vue from 'vue'
|
||||
import { type DefineComponent } from 'vue'
|
||||
|
||||
/** A module containing the default visualization function. */
|
||||
const DEFAULT_VISUALIZATION_MODULE = 'Standard.Visualization.Preprocessor'
|
||||
@ -52,7 +53,7 @@ window.__visualizationModules = moduleCache
|
||||
|
||||
export type Visualization = DefineComponent<
|
||||
// Props
|
||||
{ data: { type: vue.PropType<unknown>; required: true } },
|
||||
{ data: { type: PropType<unknown>; required: true } },
|
||||
{},
|
||||
unknown,
|
||||
{},
|
||||
@ -89,23 +90,73 @@ const dynamicVisualizationPaths: Record<string, string> = {
|
||||
}
|
||||
|
||||
export const useVisualizationStore = defineStore('visualization', () => {
|
||||
// TODO [sb]: Figure out how to list visualizations defined by a project.
|
||||
const imports = { ...builtinVisualizationImports }
|
||||
const paths = { ...dynamicVisualizationPaths }
|
||||
let cache: Record<string, VisualizationModule> = {}
|
||||
const builtinTypes = [...Object.keys(imports), ...Object.keys(paths)]
|
||||
const types = builtinTypes.map(
|
||||
(name): VisualizationIdentifier => ({
|
||||
module: { kind: 'Builtin' },
|
||||
name,
|
||||
}),
|
||||
)
|
||||
let worker: Worker | undefined
|
||||
let workerMessageId = 0
|
||||
const workerCallbacks: Record<
|
||||
string,
|
||||
{ resolve: (result: VisualizationModule) => void; reject: () => void }
|
||||
> = {}
|
||||
const allVisualizations = [
|
||||
...Object.keys(imports),
|
||||
...Object.keys(paths),
|
||||
].map<VisualizationIdentifier>((name) => ({
|
||||
module: { kind: 'Builtin' },
|
||||
name,
|
||||
}))
|
||||
const visualizationsForType = reactive(new Map<string, readonly VisualizationIdentifier[]>())
|
||||
const visualizationsForAny = ref<readonly VisualizationIdentifier[]>([])
|
||||
|
||||
Promise.all([
|
||||
...Object.values(builtinVisualizationImports).map((importer) => importer()),
|
||||
...Object.values(dynamicVisualizationPaths).map(compile),
|
||||
])
|
||||
.then((modules) =>
|
||||
Object.fromEntries(
|
||||
modules.map((module) => [
|
||||
module.name,
|
||||
new Set(
|
||||
module.inputType == null
|
||||
? ['Any']
|
||||
: module.inputType.split('|').map((type) => type.trim()),
|
||||
),
|
||||
]),
|
||||
),
|
||||
)
|
||||
.then((moduleInputTypes) => {
|
||||
const types = Object.values(moduleInputTypes).flatMap((set) => Array.from(set))
|
||||
for (const type of types) {
|
||||
if (visualizationsForType.has(type)) {
|
||||
continue
|
||||
}
|
||||
const matchingTypes = Object.entries(moduleInputTypes).flatMap<VisualizationIdentifier>(
|
||||
([name, inputTypes]) =>
|
||||
inputTypes.has(type) || inputTypes.has('Any')
|
||||
? [
|
||||
{
|
||||
module: { kind: 'Builtin' },
|
||||
name,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
)
|
||||
if (type === 'Any') {
|
||||
visualizationsForAny.value = matchingTypes
|
||||
}
|
||||
visualizationsForType.set(type, matchingTypes)
|
||||
}
|
||||
})
|
||||
|
||||
function types(type: string | undefined) {
|
||||
const ret =
|
||||
type === undefined
|
||||
? allVisualizations
|
||||
: visualizationsForType.get(type) ?? visualizationsForAny.value
|
||||
console.log(type, ret, allVisualizations, visualizationsForType, visualizationsForAny)
|
||||
return ret
|
||||
}
|
||||
|
||||
function register(module: VisualizationModule) {
|
||||
console.log(`registering visualization: name=${module.name}, inputType=${module.inputType}`)
|
||||
|
2
app/gui2/src/util/mutable.ts
Normal file
2
app/gui2/src/util/mutable.ts
Normal file
@ -0,0 +1,2 @@
|
||||
/** Removes `readonly` from all keys in a type. UNSAFE. */
|
||||
export type UnsafeMutable<T> = { -readonly [K in keyof T]: T[K] }
|
Loading…
Reference in New Issue
Block a user