From b460cb3ed239b6ce4565896efa74f2cfebd96b42 Mon Sep 17 00:00:00 2001 From: vwfox Date: Thu, 7 May 2026 09:59:02 +0200 Subject: [PATCH] feat: DataGen File-Preview und Laden im File-Explorer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DataGenPreview-Komponente: zeigt Config-Name, Version, Locale, Klassen-Configs, Instanz-Anzahl und Target-Models - Als FileViewerContribution für .dgen/.datagen registriert - "Open in Data Generator"-Button wechselt zur DataGen-Perspektive - WorkspacePreview erweitert: rendert registrierte FileViewer-Plugins für beliebige Dateiendungen (nicht nur XMI/Ecore/C-OCL) --- .../src/components/DataGenPreview.vue | 267 ++++++++++++++++++ .../data-generator/src/components/index.ts | 1 + packages/data-generator/src/index.ts | 37 ++- .../src/components/WorkspacePreview.vue | 28 +- 4 files changed, 327 insertions(+), 6 deletions(-) create mode 100644 packages/data-generator/src/components/DataGenPreview.vue diff --git a/packages/data-generator/src/components/DataGenPreview.vue b/packages/data-generator/src/components/DataGenPreview.vue new file mode 100644 index 0000000..9c8cfa2 --- /dev/null +++ b/packages/data-generator/src/components/DataGenPreview.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/packages/data-generator/src/components/index.ts b/packages/data-generator/src/components/index.ts index bcd6eef..9c2c714 100644 --- a/packages/data-generator/src/components/index.ts +++ b/packages/data-generator/src/components/index.ts @@ -6,3 +6,4 @@ export { default as DataGenTree } from './DataGenTree.vue' export { default as DataGenEditor } from './DataGenEditor.vue' export { default as GeneratorPicker } from './GeneratorPicker.vue' export { default as GenerationDialog } from './GenerationDialog.vue' +export { default as DataGenPreview } from './DataGenPreview.vue' diff --git a/packages/data-generator/src/index.ts b/packages/data-generator/src/index.ts index bb70bcb..1b9cdf0 100644 --- a/packages/data-generator/src/index.ts +++ b/packages/data-generator/src/index.ts @@ -22,13 +22,17 @@ export { useDataGenAtlas } from './composables/useDataGenAtlas' export { DataGenPerspective } from './components' // Import for service registration -import { DataGenPerspective } from './components' +import { DataGenPerspective, DataGenPreview } from './components' import { setSharedAtlasBrowser } from './composables/useRemoteDataGen' import { setDataGenTsm } from './composables/useDataGenAtlas' +import { useDataGenerator } from './composables/useDataGenerator' +import { useFileViewerRegistry } from 'ui-xmi-viewer' // Type imports import type { PanelRegistry, ActivityRegistry, PerspectiveManager } from 'ui-perspectives' +const DATAGEN_EXTENSIONS = ['.dgen', '.datagen'] + /** * TSM lifecycle: activate */ @@ -103,6 +107,32 @@ export async function activate(context: ModuleContext): Promise { context.log.info('Data Generator activity registered') } + // Register file preview for .dgen/.datagen files + const fileViewers = useFileViewerRegistry() + fileViewers.registerViewer({ + id: 'gene.viewer.datagen', + name: 'DataGen Preview', + extensions: DATAGEN_EXTENSIONS, + priority: 20, + component: markRaw(DataGenPreview), + canHandle: (content: string) => { + return content.includes('datagen:DataGenConfig') || content.includes('DataGenConfig') + } + }) + context.log.info('DataGen file preview registered') + + // Register loader service so DataGenPreview can open files in the editor + context.services.register('gene.datagen.loader', { + load(content: string, filePath: string) { + // Store content for DataGenPerspective to pick up + context.services.register('gene.datagen.data', { content, filePath }) + // Switch to data-generator perspective + const pm = context.services.get('ui.registry.perspectives') + if (pm) pm.switchTo('data-generator') + } + }) + context.log.info('DataGen loader service registered') + // Auto-register Atlas Browser for remote data generation try { const composables = context.services.get('ui.atlas-browser.composables') @@ -130,6 +160,11 @@ export async function deactivate(context: ModuleContext): Promise { perspectiveManager.registry.unregister('data-generator') } + // Unregister file preview + const fileViewers = useFileViewerRegistry() + fileViewers.unregisterViewer('gene.viewer.datagen') + + context.services.unregister('gene.datagen.loader') context.services.unregister('ui.data-generator.components') context.log.info('Data Generator plugin deactivated') } diff --git a/packages/ui-file-explorer/src/components/WorkspacePreview.vue b/packages/ui-file-explorer/src/components/WorkspacePreview.vue index cff87a5..d3f3c48 100644 --- a/packages/ui-file-explorer/src/components/WorkspacePreview.vue +++ b/packages/ui-file-explorer/src/components/WorkspacePreview.vue @@ -12,15 +12,15 @@ import { Card } from 'tsm:primevue' import { Message } from 'tsm:primevue' import type { FileEntry } from '../types' import { useSharedFileSystem } from '../composables/useFileSystem' +import { useFileViewerRegistry } from 'ui-xmi-viewer' const fileSystem = useSharedFileSystem() +const fileViewerRegistry = useFileViewerRegistry() // TSM for service access const tsm = inject('tsm') // XMI Viewer via TSM service (avoids static dependency on ui-xmi-viewer) const XmiViewer = ref(null) -const useFileViewerRegistry = () => tsm?.getService('ui.xmi-viewer.registry')?.() - // WorkspaceActionService for direct App-level actions (replaces emits) function getActions() { return tsm?.getService('gene.workspace.actions') @@ -34,7 +34,6 @@ const props = defineProps<{ // Resolved selectedFile: prop takes priority, otherwise shared state const selectedFile = computed(() => props.selectedFile ?? fileSystem.selectedFile.value) -const fileViewerRegistry = useFileViewerRegistry() // Re-resolve XmiViewer on file selection (service may register after us) watch(selectedFile, () => { @@ -80,6 +79,15 @@ const isEcoreFile = computed(() => { return ext === '.ecore' }) +// Check if file has a registered viewer (e.g. .dgen from data-generator plugin) +const registeredViewer = computed(() => { + if (!selectedFile.value) return null + const ext = selectedFile.value.extension?.toLowerCase() + if (!ext) return null + if (WORKSPACE_EXTENSIONS.includes(ext) || XMI_LIKE_EXTENSIONS.includes(ext) || COCL_EXTENSIONS.includes(ext)) return null + return fileViewerRegistry.getViewerForExtension(ext, fileContent.value ?? undefined) ?? null +}) + // Check if file is a C-OCL constraint file const isCoclFile = computed(() => { if (!selectedFile.value) return false @@ -118,9 +126,10 @@ watch(selectedFile, async (file) => { return } - // Only load workspace, XMI-like, and C-OCL files + // Check which file types to load const ext = file.extension?.toLowerCase() - if (!WORKSPACE_EXTENSIONS.includes(ext ?? '') && !XMI_LIKE_EXTENSIONS.includes(ext ?? '') && !COCL_EXTENSIONS.includes(ext ?? '')) { + const hasRegisteredViewer = ext ? fileViewerRegistry.isExtensionSupported(ext) : false + if (!WORKSPACE_EXTENSIONS.includes(ext ?? '') && !XMI_LIKE_EXTENSIONS.includes(ext ?? '') && !COCL_EXTENSIONS.includes(ext ?? '') && !hasRegisteredViewer) { return } @@ -318,6 +327,15 @@ function handleLoadCocl() { + +
+ +
+