udb fix
This commit is contained in:
parent
8e5a01df6d
commit
1c4233c7ea
2 changed files with 41 additions and 99 deletions
|
|
@ -606,17 +606,6 @@ const SourcesTab: React.FC<SourcesTabProps> = ({ context, onSourcesChanged, onSe
|
|||
}
|
||||
}, [instanceId, _fetchDataSources, onSourcesChanged]);
|
||||
|
||||
/* ── Remove DataSource ── */
|
||||
const _removeDatasource = useCallback(async (dsId: string) => {
|
||||
try {
|
||||
await api.delete(`/api/workspace/${instanceId}/datasources/${dsId}`);
|
||||
_fetchDataSources();
|
||||
onSourcesChanged?.();
|
||||
} catch (err) {
|
||||
console.error('Failed to remove data source:', err);
|
||||
}
|
||||
}, [instanceId, _fetchDataSources, onSourcesChanged]);
|
||||
|
||||
/* ── Check if a path is already added ── */
|
||||
const _isAdded = useCallback((connectionId: string, service: string | undefined, path: string | undefined): boolean => {
|
||||
const expectedSourceType = service ? (_SERVICE_TO_SOURCE_TYPE[service] || service) : undefined;
|
||||
|
|
@ -841,17 +830,6 @@ const SourcesTab: React.FC<SourcesTabProps> = ({ context, onSourcesChanged, onSe
|
|||
}
|
||||
}, [instanceId, _fetchFeatureDataSources, onSourcesChanged]);
|
||||
|
||||
/* ── Feature: Remove FeatureDataSource ── */
|
||||
const _removeFeatureDataSource = useCallback(async (fdsId: string) => {
|
||||
try {
|
||||
await api.delete(`/api/workspace/${instanceId}/feature-datasources/${fdsId}`);
|
||||
_fetchFeatureDataSources();
|
||||
onSourcesChanged?.();
|
||||
} catch (err) {
|
||||
console.error('Failed to remove feature data source:', err);
|
||||
}
|
||||
}, [instanceId, _fetchFeatureDataSources, onSourcesChanged]);
|
||||
|
||||
/* ── Feature: check if table already added (no record filter) ── */
|
||||
const _isFeatureTableAdded = useCallback((featureInstanceId: string, tableName: string): boolean => {
|
||||
return featureDataSources.some(fds =>
|
||||
|
|
@ -1021,7 +999,6 @@ const SourcesTab: React.FC<SourcesTabProps> = ({ context, onSourcesChanged, onSe
|
|||
dataSources={dataSources}
|
||||
onCycleScope={_cyclePersonalScope}
|
||||
onToggleNeutralize={_togglePersonalNeutralize}
|
||||
onRemoveDs={_removeDatasource}
|
||||
onSendToChat={_sendNodeToChat}
|
||||
scopeCycleTitle={_scopeCycleTitle}
|
||||
selectedKeys={selectedKeys}
|
||||
|
|
@ -1081,7 +1058,6 @@ const SourcesTab: React.FC<SourcesTabProps> = ({ context, onSourcesChanged, onSe
|
|||
onCycleScope={_cycleFeatureScope}
|
||||
onToggleNeutralize={_toggleFeatureNeutralize}
|
||||
onToggleNeutralizeField={_toggleNeutralizeField}
|
||||
onRemoveFds={_removeFeatureDataSource}
|
||||
featureTree={featureTree}
|
||||
/>
|
||||
))}
|
||||
|
|
@ -1110,7 +1086,6 @@ interface _TreeNodeViewProps {
|
|||
dataSources: UdbDataSource[];
|
||||
onCycleScope: (ds: UdbDataSource) => void;
|
||||
onToggleNeutralize: (ds: UdbDataSource) => void;
|
||||
onRemoveDs: (dsId: string) => void;
|
||||
onSendToChat?: (params: { connectionId: string; sourceType: string; path: string; label: string; displayPath?: string }) => void;
|
||||
scopeCycleTitle: (scope: string) => string;
|
||||
selectedKeys: Set<string>;
|
||||
|
|
@ -1121,7 +1096,7 @@ interface _TreeNodeViewProps {
|
|||
|
||||
const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
|
||||
node, depth, onToggle, onEnsureDs, isAdded, addingPath,
|
||||
dataSources, onCycleScope, onToggleNeutralize, onRemoveDs, onSendToChat, scopeCycleTitle,
|
||||
dataSources, onCycleScope, onToggleNeutralize, onSendToChat, scopeCycleTitle,
|
||||
selectedKeys, onSelect, inheritedScope, inheritedNeutralize,
|
||||
}) => {
|
||||
const { t } = useLanguage();
|
||||
|
|
@ -1216,19 +1191,11 @@ const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
|
|||
{node.label}
|
||||
</span>
|
||||
|
||||
{/* Dynamic action: Remove (only when DS exists) — placed LEFT of the
|
||||
* stable trio so the trio always anchors at the right edge. */}
|
||||
{ds && (
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); onRemoveDs(ds.id); }}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 10, color: '#999', padding: '0 2px', flexShrink: 0 }}
|
||||
title={t('Entfernen')}
|
||||
>
|
||||
{'\u2715'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* ── Stable trio: chat | scope | neutralize (always in this order) ── */}
|
||||
{/* ── Stable trio: chat | scope | neutralize (always in this order).
|
||||
* No "remove from workspace" button here by design: the UDB row only
|
||||
* exposes the catalog state. Detach from the *current chat* happens
|
||||
* via the chip "x" in WorkspaceInput; that chip is the single source
|
||||
* of truth for chat-scoped attachment lifecycle. */}
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); onSendToChat?.(_chatPayload); }}
|
||||
style={{
|
||||
|
|
@ -1290,7 +1257,6 @@ const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
|
|||
dataSources={dataSources}
|
||||
onCycleScope={onCycleScope}
|
||||
onToggleNeutralize={onToggleNeutralize}
|
||||
onRemoveDs={onRemoveDs}
|
||||
onSendToChat={onSendToChat}
|
||||
scopeCycleTitle={scopeCycleTitle}
|
||||
selectedKeys={selectedKeys}
|
||||
|
|
@ -1343,7 +1309,6 @@ interface _FeatureActionContext {
|
|||
onCycleScope: (fds: UdbFeatureDataSource) => void;
|
||||
onToggleNeutralize: (fds: UdbFeatureDataSource) => void;
|
||||
onToggleNeutralizeField: (fds: UdbFeatureDataSource, fieldName: string) => void;
|
||||
onRemoveFds: (fdsId: string) => void;
|
||||
featureTree: MandateGroupNode[];
|
||||
}
|
||||
|
||||
|
|
@ -1463,16 +1428,6 @@ const _FeatureNodeView: React.FC<_FeatureNodeViewProps> = (props) => {
|
|||
{node.tableCount} {t('Tabellen')}
|
||||
</span>
|
||||
|
||||
{wildcardFds && (
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); ctx.onRemoveFds(wildcardFds.id); }}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 10, color: '#999', padding: '0 2px', flexShrink: 0 }}
|
||||
title={t('Entfernen')}
|
||||
>
|
||||
{'\u2715'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
|
@ -1608,7 +1563,6 @@ const _FeatureItemView: React.FC<_FeatureItemViewProps> = (props) => {
|
|||
onCycleScope={ctx.onCycleScope}
|
||||
onToggleNeutralize={ctx.onToggleNeutralize}
|
||||
onToggleNeutralizeField={ctx.onToggleNeutralizeField}
|
||||
onRemoveFds={ctx.onRemoveFds}
|
||||
featureTree={ctx.featureTree}
|
||||
inheritedScope={inheritedScope}
|
||||
inheritedNeutralize={inheritedNeutralize}
|
||||
|
|
@ -1884,16 +1838,6 @@ const _RecordRowView: React.FC<_RecordRowViewProps> = (props) => {
|
|||
</button>
|
||||
)}
|
||||
|
||||
{fds && (
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); ctx.onRemoveFds(fds.id); }}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 10, color: '#999', padding: '0 2px', flexShrink: 0 }}
|
||||
title={t('Entfernen')}
|
||||
>
|
||||
{'\u2715'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); ctx.onSendToChat?.(_chatPayload); }}
|
||||
style={{
|
||||
|
|
@ -1975,7 +1919,6 @@ interface _FeatureTableRowProps {
|
|||
onCycleScope: (fds: UdbFeatureDataSource) => void;
|
||||
onToggleNeutralize: (fds: UdbFeatureDataSource) => void;
|
||||
onToggleNeutralizeField: (fds: UdbFeatureDataSource, fieldName: string) => void;
|
||||
onRemoveFds: (fdsId: string) => void;
|
||||
featureTree: MandateGroupNode[];
|
||||
inheritedScope?: string;
|
||||
inheritedNeutralize?: boolean;
|
||||
|
|
@ -1984,7 +1927,7 @@ interface _FeatureTableRowProps {
|
|||
const _FeatureTableRow: React.FC<_FeatureTableRowProps> = ({
|
||||
featureNode, table, depth, onAddFeatureTable, onSendToChat,
|
||||
featureDataSources, onCycleScope, onToggleNeutralize, onToggleNeutralizeField,
|
||||
onRemoveFds, featureTree, inheritedScope, inheritedNeutralize,
|
||||
featureTree, inheritedScope, inheritedNeutralize,
|
||||
}) => {
|
||||
const { t } = useLanguage();
|
||||
const [hovered, setHovered] = useState(false);
|
||||
|
|
@ -2052,16 +1995,6 @@ const _FeatureTableRow: React.FC<_FeatureTableRowProps> = ({
|
|||
)}
|
||||
</span>
|
||||
|
||||
{fds && (
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); onRemoveFds(fds.id); }}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: 10, color: '#999', padding: '0 2px', flexShrink: 0 }}
|
||||
title={t('Entfernen')}
|
||||
>
|
||||
{'\u2715'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={e => { e.stopPropagation(); onSendToChat?.(_chatPayload); }}
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -118,23 +118,43 @@ export const WorkspaceInput: React.FC<WorkspaceInputProps> = ({ instanceId,
|
|||
}
|
||||
}, [draftAppend, onDraftAppendConsumed]);
|
||||
|
||||
// Persist a changed attachment list to the backend so the next chat
|
||||
// reload reflects the current state. Defined early so the
|
||||
// pendingAttachDsId / pendingAttachFdsId effects below can also persist
|
||||
// immediately after a 💬-click or drag-drop attach.
|
||||
const _persistAttachments = useCallback((dsIds: string[], fdsIds: string[]) => {
|
||||
if (!instanceId || !workflowId) return;
|
||||
api.patch(`/api/workspace/${instanceId}/workflows/${workflowId}/attachments`, {
|
||||
dataSourceIds: dsIds,
|
||||
featureDataSourceIds: fdsIds,
|
||||
}).catch(err => console.warn('Failed to persist chat attachments:', err));
|
||||
}, [instanceId, workflowId]);
|
||||
|
||||
// 💬-click or drag-drop attach: parent sets pendingAttachDsId after
|
||||
// creating/finding the DataSource. Add to the chip bar AND persist
|
||||
// immediately so a chat reload before the user sends a message still
|
||||
// shows the chip.
|
||||
useEffect(() => {
|
||||
if (pendingAttachDsId) {
|
||||
setAttachedDataSourceIds(prev =>
|
||||
prev.includes(pendingAttachDsId) ? prev : [...prev, pendingAttachDsId],
|
||||
);
|
||||
onPendingAttachDsConsumed?.();
|
||||
}
|
||||
}, [pendingAttachDsId, onPendingAttachDsConsumed]);
|
||||
if (!pendingAttachDsId) return;
|
||||
setAttachedDataSourceIds(prev => {
|
||||
if (prev.includes(pendingAttachDsId)) return prev;
|
||||
const next = [...prev, pendingAttachDsId];
|
||||
_persistAttachments(next, attachedFeatureDataSourceIds);
|
||||
return next;
|
||||
});
|
||||
onPendingAttachDsConsumed?.();
|
||||
}, [pendingAttachDsId, onPendingAttachDsConsumed, _persistAttachments, attachedFeatureDataSourceIds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (pendingAttachFdsId) {
|
||||
setAttachedFeatureDataSourceIds(prev =>
|
||||
prev.includes(pendingAttachFdsId) ? prev : [...prev, pendingAttachFdsId],
|
||||
);
|
||||
onPendingAttachFdsConsumed?.();
|
||||
}
|
||||
}, [pendingAttachFdsId, onPendingAttachFdsConsumed]);
|
||||
if (!pendingAttachFdsId) return;
|
||||
setAttachedFeatureDataSourceIds(prev => {
|
||||
if (prev.includes(pendingAttachFdsId)) return prev;
|
||||
const next = [...prev, pendingAttachFdsId];
|
||||
_persistAttachments(attachedDataSourceIds, next);
|
||||
return next;
|
||||
});
|
||||
onPendingAttachFdsConsumed?.();
|
||||
}, [pendingAttachFdsId, onPendingAttachFdsConsumed, _persistAttachments, attachedDataSourceIds]);
|
||||
|
||||
// Rehydrate the chip-bar whenever the parent re-loads a chat (loadedNonce
|
||||
// bumps on every loadWorkflow call). We trust the loaded IDs initially;
|
||||
|
|
@ -184,17 +204,6 @@ export const WorkspaceInput: React.FC<WorkspaceInputProps> = ({ instanceId,
|
|||
});
|
||||
}, [loadedNonce, featureDataSources]);
|
||||
|
||||
// Persist a changed attachment list to the backend so the next chat
|
||||
// reload reflects the current state. We debounce slightly by sending on
|
||||
// the next animation frame to coalesce rapid clicks.
|
||||
const _persistAttachments = useCallback((dsIds: string[], fdsIds: string[]) => {
|
||||
if (!instanceId || !workflowId) return;
|
||||
api.patch(`/api/workspace/${instanceId}/workflows/${workflowId}/attachments`, {
|
||||
dataSourceIds: dsIds,
|
||||
featureDataSourceIds: fdsIds,
|
||||
}).catch(err => console.warn('Failed to persist chat attachments:', err));
|
||||
}, [instanceId, workflowId]);
|
||||
|
||||
const promptBeforeVoiceRef = useRef('');
|
||||
const finalizedTextRef = useRef('');
|
||||
const currentInterimRef = useRef('');
|
||||
|
|
|
|||
Loading…
Reference in a new issue