From 5711450606a63b0a498c0a6a9069927e5320ecf5 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Mon, 1 Jun 2026 00:00:38 +0200 Subject: [PATCH] fix: UDB compact layout, mobile table view, DataSource ID attach Co-authored-by: Cursor --- .../FormGeneratorControls.module.css | 37 +++++++++-------- .../FormGeneratorTable.module.css | 41 +++++++++++++------ .../FormGeneratorTree.module.css | 31 ++++++++++++-- .../FormGeneratorTree/FormGeneratorTree.tsx | 2 +- src/components/UnifiedDataBar/SourcesTab.tsx | 26 +++++++----- .../UnifiedDataBar/UdbSourcesProvider.tsx | 6 +++ 6 files changed, 101 insertions(+), 42 deletions(-) diff --git a/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css b/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css index 329e7a3..9b09fac 100644 --- a/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css +++ b/src/components/FormGenerator/FormGeneratorControls/FormGeneratorControls.module.css @@ -300,40 +300,45 @@ /* Responsive Design */ @media (max-width: 768px) { .deleteControlsIntegrated { - flex-direction: column; - align-items: stretch; - gap: 10px; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + gap: 6px; width: 100%; } .controls { - flex-direction: column; - align-items: stretch; - gap: 15px; - padding: 10px; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + gap: 6px; + padding: 6px 8px; } .filtersContainer { - flex-direction: column; - align-items: stretch; - gap: 10px; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + gap: 6px; } .filterGroup { - flex-direction: column; - align-items: flex-start; + flex-direction: row; + align-items: center; gap: 4px; } .filterInput, .filterSelect { - width: 100%; - min-width: auto; + width: auto; + min-width: 100px; + max-width: 160px; + font-size: 12px; } .floatingLabelInput { - max-width: none; - width: 100%; + max-width: 160px; + width: auto; } .filterGroup .floatingLabelInput { diff --git a/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css b/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css index db2673e..a2344d8 100644 --- a/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css +++ b/src/components/FormGenerator/FormGeneratorTable/FormGeneratorTable.module.css @@ -962,10 +962,24 @@ tbody .actionsColumn { /* Responsive */ @media (max-width: 768px) { + .formGeneratorTable { + gap: 4px; + } + + .title { + font-size: 1.1rem; + margin-bottom: 4px; + } + + .tableWrapper { + border-radius: 4px; + } + .tableContainer { flex: 1; min-height: 0; max-height: 100%; + -webkit-overflow-scrolling: touch; } .emptyTable { @@ -974,31 +988,34 @@ tbody .actionsColumn { } .th { - padding: 6px 8px; + padding: 4px 6px; font-size: 10px; + letter-spacing: 0; } .td { - padding: 6px 8px; + padding: 4px 6px; font-size: 12px; } .actionButtons { - flex-direction: column; + flex-direction: row; gap: 2px; } .actionButton { - padding: 4px; + padding: 3px; font-size: 10px; - min-width: 22px; - min-height: 22px; + min-width: 20px; + min-height: 20px; } .pagination { - flex-direction: column; - gap: 10px; - padding: 10px; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + gap: 6px; + padding: 6px 8px; } .pageSizeSelector { @@ -1009,7 +1026,7 @@ tbody .actionsColumn { .paginationInfo { text-align: center; margin: 0; - font-size: 12px; + font-size: 11px; } .pageNumbers { @@ -1018,8 +1035,8 @@ tbody .actionsColumn { } .pageNumber { - min-width: 24px; - height: 24px; + min-width: 22px; + height: 22px; font-size: 11px; } } diff --git a/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.module.css b/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.module.css index 088de25..3269993 100644 --- a/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.module.css +++ b/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.module.css @@ -252,7 +252,7 @@ } .nodeRowCompact { - height: 32px; + height: 28px; } .nodeRow:hover { @@ -561,7 +561,7 @@ /* Compact mode */ .compactMode .sectionHeader { - padding: 6px 8px; + padding: 4px 6px; } .compactMode .sectionTitle { @@ -574,13 +574,38 @@ } .compactMode .nodeRow { - padding: 0 6px; + padding: 0 4px; + gap: 3px; } .compactMode .nodeName { font-size: 12px; } +.compactMode .expandChevron, +.compactMode .expandChevronPlaceholder { + width: 14px; + height: 14px; + font-size: 9px; +} + +.compactMode .nodeIcon { + width: 14px; + font-size: 13px; +} + +.compactMode .emojiBtn { + width: 18px; + font-size: 11px; + padding: 0 1px; +} + +.compactMode .nodeActionBtn { + width: 18px; + height: 18px; + font-size: 12px; +} + /* Dark theme */ @media (prefers-color-scheme: dark) { .sectionHeader { diff --git a/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx b/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx index cee9833..8ec8f0e 100644 --- a/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx +++ b/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx @@ -19,7 +19,7 @@ import { useConfirm } from '../../../hooks/useConfirm'; import { useLanguage } from '../../../providers/language/LanguageContext'; import styles from './FormGeneratorTree.module.css'; -const INDENT_PX = 24; +const INDENT_PX = 16; const DRAG_MIME = 'application/x-poweron-tree-items'; const SCOPE_ORDER: ScopeValue[] = ['personal', 'featureInstance', 'mandate', 'global']; diff --git a/src/components/UnifiedDataBar/SourcesTab.tsx b/src/components/UnifiedDataBar/SourcesTab.tsx index 5c241e6..703cfb2 100644 --- a/src/components/UnifiedDataBar/SourcesTab.tsx +++ b/src/components/UnifiedDataBar/SourcesTab.tsx @@ -48,7 +48,14 @@ const SourcesTab: React.FC = ({ setSettingsModal({ dataSourceId, title: label }); }, []); - const _handleSendToChat = useCallback((node: TreeNode) => { + const provider = useMemo( + () => instanceId + ? createUdbSourcesProvider(instanceId, _handleOpenSettings) + : null, + [instanceId, _handleOpenSettings], + ); + + const _handleSendToChat = useCallback(async (node: TreeNode) => { const data = node.data; if (!data) return; @@ -65,16 +72,15 @@ const SourcesTab: React.FC = ({ }); } else if (data.kind === 'connection' || data.kind === 'service' || data.kind === 'folder' || data.kind === 'file') { - onAttachDataSource?.(data.connectionId || data.key); + if (!provider) return; + const dsId = await provider.ensureDataSourceId(data); + if (dsId) { + onAttachDataSource?.(dsId); + } else { + console.warn('[SourcesTab] Could not resolve DataSource ID for', data.key); + } } - }, [onSendToChat_FeatureSource, onAttachDataSource]); - - const provider = useMemo( - () => instanceId - ? createUdbSourcesProvider(instanceId, _handleOpenSettings) - : null, - [instanceId, _handleOpenSettings], - ); + }, [onSendToChat_FeatureSource, onAttachDataSource, provider]); if (!instanceId || !provider) { return ( diff --git a/src/components/UnifiedDataBar/UdbSourcesProvider.tsx b/src/components/UnifiedDataBar/UdbSourcesProvider.tsx index 86e399d..96ffedd 100644 --- a/src/components/UnifiedDataBar/UdbSourcesProvider.tsx +++ b/src/components/UnifiedDataBar/UdbSourcesProvider.tsx @@ -212,6 +212,8 @@ function _mapBackendNode( // --------------------------------------------------------------------------- export interface UdbSourcesProviderHandle extends TreeNodeProvider { + /** Resolve the DataSource UUID for a node, creating a record if needed. */ + ensureDataSourceId(node: UdbBackendNode): Promise; /** Test/diagnostic hook only -- exposes the latest cached backend payloads * so consumers can inspect data flow without round-tripping through the * network. Not part of the contract used at runtime. */ @@ -375,6 +377,10 @@ export function createUdbSourcesProvider( } }, + async ensureDataSourceId(node: UdbBackendNode): Promise { + return _ensureRecordForSettings(node); + }, + _diagnosticGetCacheSize() { return nodeCache.size; },