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 */
|
||||
@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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
|
|
|
|||
|
|
@ -48,7 +48,14 @@ const SourcesTab: React.FC<SourcesTabProps> = ({
|
|||
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;
|
||||
if (!data) return;
|
||||
|
||||
|
|
@ -65,16 +72,15 @@ const SourcesTab: React.FC<SourcesTabProps> = ({
|
|||
});
|
||||
} 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 (
|
||||
|
|
|
|||
|
|
@ -212,6 +212,8 @@ function _mapBackendNode(
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
* 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<string | null> {
|
||||
return _ensureRecordForSettings(node);
|
||||
},
|
||||
|
||||
_diagnosticGetCacheSize() {
|
||||
return nodeCache.size;
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue