fix: UDB compact layout, mobile table view, DataSource ID attach
All checks were successful
Deploy Nyla Frontend to Production / deploy (push) Successful in 48s
All checks were successful
Deploy Nyla Frontend to Production / deploy (push) Successful in 48s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7da7ad5041
commit
5711450606
6 changed files with 101 additions and 42 deletions
|
|
@ -300,40 +300,45 @@
|
||||||
/* Responsive Design */
|
/* Responsive Design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.deleteControlsIntegrated {
|
.deleteControlsIntegrated {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
flex-wrap: wrap;
|
||||||
gap: 10px;
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
flex-wrap: wrap;
|
||||||
gap: 15px;
|
align-items: center;
|
||||||
padding: 10px;
|
gap: 6px;
|
||||||
|
padding: 6px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filtersContainer {
|
.filtersContainer {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
flex-wrap: wrap;
|
||||||
gap: 10px;
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterGroup {
|
.filterGroup {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterInput,
|
.filterInput,
|
||||||
.filterSelect {
|
.filterSelect {
|
||||||
width: 100%;
|
width: auto;
|
||||||
min-width: auto;
|
min-width: 100px;
|
||||||
|
max-width: 160px;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.floatingLabelInput {
|
.floatingLabelInput {
|
||||||
max-width: none;
|
max-width: 160px;
|
||||||
width: 100%;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filterGroup .floatingLabelInput {
|
.filterGroup .floatingLabelInput {
|
||||||
|
|
|
||||||
|
|
@ -962,10 +962,24 @@ tbody .actionsColumn {
|
||||||
|
|
||||||
/* Responsive */
|
/* Responsive */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
.formGeneratorTable {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableWrapper {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.tableContainer {
|
.tableContainer {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emptyTable {
|
.emptyTable {
|
||||||
|
|
@ -974,31 +988,34 @@ tbody .actionsColumn {
|
||||||
}
|
}
|
||||||
|
|
||||||
.th {
|
.th {
|
||||||
padding: 6px 8px;
|
padding: 4px 6px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
letter-spacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.td {
|
.td {
|
||||||
padding: 6px 8px;
|
padding: 4px 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionButtons {
|
.actionButtons {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionButton {
|
.actionButton {
|
||||||
padding: 4px;
|
padding: 3px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
min-width: 22px;
|
min-width: 20px;
|
||||||
min-height: 22px;
|
min-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination {
|
.pagination {
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
gap: 10px;
|
flex-wrap: wrap;
|
||||||
padding: 10px;
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageSizeSelector {
|
.pageSizeSelector {
|
||||||
|
|
@ -1009,7 +1026,7 @@ tbody .actionsColumn {
|
||||||
.paginationInfo {
|
.paginationInfo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageNumbers {
|
.pageNumbers {
|
||||||
|
|
@ -1018,8 +1035,8 @@ tbody .actionsColumn {
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageNumber {
|
.pageNumber {
|
||||||
min-width: 24px;
|
min-width: 22px;
|
||||||
height: 24px;
|
height: 22px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.nodeRowCompact {
|
.nodeRowCompact {
|
||||||
height: 32px;
|
height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nodeRow:hover {
|
.nodeRow:hover {
|
||||||
|
|
@ -561,7 +561,7 @@
|
||||||
|
|
||||||
/* Compact mode */
|
/* Compact mode */
|
||||||
.compactMode .sectionHeader {
|
.compactMode .sectionHeader {
|
||||||
padding: 6px 8px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactMode .sectionTitle {
|
.compactMode .sectionTitle {
|
||||||
|
|
@ -574,13 +574,38 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactMode .nodeRow {
|
.compactMode .nodeRow {
|
||||||
padding: 0 6px;
|
padding: 0 4px;
|
||||||
|
gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactMode .nodeName {
|
.compactMode .nodeName {
|
||||||
font-size: 12px;
|
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 */
|
/* Dark theme */
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.sectionHeader {
|
.sectionHeader {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import { useConfirm } from '../../../hooks/useConfirm';
|
||||||
import { useLanguage } from '../../../providers/language/LanguageContext';
|
import { useLanguage } from '../../../providers/language/LanguageContext';
|
||||||
import styles from './FormGeneratorTree.module.css';
|
import styles from './FormGeneratorTree.module.css';
|
||||||
|
|
||||||
const INDENT_PX = 24;
|
const INDENT_PX = 16;
|
||||||
const DRAG_MIME = 'application/x-poweron-tree-items';
|
const DRAG_MIME = 'application/x-poweron-tree-items';
|
||||||
|
|
||||||
const SCOPE_ORDER: ScopeValue[] = ['personal', 'featureInstance', 'mandate', 'global'];
|
const SCOPE_ORDER: ScopeValue[] = ['personal', 'featureInstance', 'mandate', 'global'];
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,14 @@ const SourcesTab: React.FC<SourcesTabProps> = ({
|
||||||
setSettingsModal({ dataSourceId, title: label });
|
setSettingsModal({ dataSourceId, title: label });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const _handleSendToChat = useCallback((node: TreeNode<UdbBackendNode>) => {
|
const provider = useMemo(
|
||||||
|
() => instanceId
|
||||||
|
? createUdbSourcesProvider(instanceId, _handleOpenSettings)
|
||||||
|
: null,
|
||||||
|
[instanceId, _handleOpenSettings],
|
||||||
|
);
|
||||||
|
|
||||||
|
const _handleSendToChat = useCallback(async (node: TreeNode<UdbBackendNode>) => {
|
||||||
const data = node.data;
|
const data = node.data;
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
|
|
@ -65,16 +72,15 @@ const SourcesTab: React.FC<SourcesTabProps> = ({
|
||||||
});
|
});
|
||||||
} else if (data.kind === 'connection' || data.kind === 'service'
|
} else if (data.kind === 'connection' || data.kind === 'service'
|
||||||
|| data.kind === 'folder' || data.kind === 'file') {
|
|| 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]);
|
}, [onSendToChat_FeatureSource, onAttachDataSource, provider]);
|
||||||
|
|
||||||
const provider = useMemo(
|
|
||||||
() => instanceId
|
|
||||||
? createUdbSourcesProvider(instanceId, _handleOpenSettings)
|
|
||||||
: null,
|
|
||||||
[instanceId, _handleOpenSettings],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!instanceId || !provider) {
|
if (!instanceId || !provider) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,8 @@ function _mapBackendNode(
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export interface UdbSourcesProviderHandle extends TreeNodeProvider<UdbBackendNode> {
|
export interface UdbSourcesProviderHandle extends TreeNodeProvider<UdbBackendNode> {
|
||||||
|
/** Resolve the DataSource UUID for a node, creating a record if needed. */
|
||||||
|
ensureDataSourceId(node: UdbBackendNode): Promise<string | null>;
|
||||||
/** Test/diagnostic hook only -- exposes the latest cached backend payloads
|
/** Test/diagnostic hook only -- exposes the latest cached backend payloads
|
||||||
* so consumers can inspect data flow without round-tripping through the
|
* so consumers can inspect data flow without round-tripping through the
|
||||||
* network. Not part of the contract used at runtime. */
|
* network. Not part of the contract used at runtime. */
|
||||||
|
|
@ -375,6 +377,10 @@ export function createUdbSourcesProvider(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async ensureDataSourceId(node: UdbBackendNode): Promise<string | null> {
|
||||||
|
return _ensureRecordForSettings(node);
|
||||||
|
},
|
||||||
|
|
||||||
_diagnosticGetCacheSize() {
|
_diagnosticGetCacheSize() {
|
||||||
return nodeCache.size;
|
return nodeCache.size;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue