This commit is contained in:
ValueOn AG 2026-02-12 01:40:04 +01:00
parent eb02c1073d
commit 95780a9911
4 changed files with 48 additions and 34 deletions

View file

@ -429,26 +429,26 @@ export function useDashboardInputForm(instanceId: string) {
// Immediately remove document from UI for instant feedback
setDeletedDocumentFileIds(prev => new Set([...prev, file.fileId]));
if (workflowId && file.messageId) {
// Document in a message: only remove the ChatDocument reference, keep the file itself
try {
await deleteFileFromMessageApi(request, workflowId, file.messageId, file.fileId);
} catch (error) {
// Restore document in UI on failure
setDeletedDocumentFileIds(prev => {
const next = new Set(prev);
next.delete(file.fileId);
return next;
});
}
} else {
// Standalone file (pending file not yet in a message): delete the actual file
const success = await fileContext.handleFileDelete(file.fileId, () => {
setPendingFiles(prev => prev.filter(f => f.fileId !== file.fileId));
});
if (success) {
setPendingFiles(prev => prev.filter(f => f.fileId !== file.fileId));
if (workflowId) {
const messagesWithFile = messages.filter((msg: WorkflowMessage) => {
const docs = (msg as any).documents as MessageDocument[] | undefined;
return docs?.some(doc => doc.fileId === file.fileId);
});
for (const message of messagesWithFile) {
try {
await deleteFileFromMessageApi(request, workflowId, message.id, file.fileId);
} catch (error) {
}
}
}
} else {
// Restore document in UI on failure
setDeletedDocumentFileIds(prev => {
@ -457,7 +457,8 @@ export function useDashboardInputForm(instanceId: string) {
return next;
});
}
}, [workflowId, messages, fileContext, request]);
}
}, [workflowId, fileContext, request]);
// handleFileView is a no-op because ViewActionButton's ContentPreview handles the preview internally
const handleFileView = useCallback(async (_file: WorkflowFile) => {

View file

@ -74,6 +74,13 @@ export function useApiRequest<RequestData = any, ResponseData = any>() {
// Generate cache key for GET requests (only cache GET requests)
const cacheKey = method === 'get' ? generateCacheKey(url, method, params) : null;
// Mutating requests (POST/PUT/DELETE) invalidate the entire GET cache.
// This ensures refetch() after create/update/delete returns fresh data.
if (method !== 'get') {
requestCache.clear();
cacheTimestamps.clear();
}
// Check if we have a valid cached request for GET requests
if (cacheKey && requestCache.has(cacheKey) && isCacheValid(cacheKey)) {
console.log('🔧 useApiRequest: Using cached request', { url, method, cacheKey });

View file

@ -81,16 +81,6 @@ function MandateContent({
return (
<div className={hierarchyStyles.mandateContentInner}>
<div className={hierarchyStyles.levelMandate}>
<span className={hierarchyStyles.mandateIcon} />
<div className={hierarchyStyles.mandateContent}>
<span className={hierarchyStyles.mandateLabel}>{mandateName}</span>
<span className={hierarchyStyles.mandateMeta}>
{mandateMeta.featureCount} Feature{mandateMeta.featureCount !== 1 ? 's' : ''} · {mandateMeta.instanceCount} Instanz{mandateMeta.instanceCount !== 1 ? 'en' : ''}
</span>
</div>
</div>
{Object.entries(byFeature).map(([featureCode, featureInstances]) => {
const featureUserCount = featureInstances.reduce(
(sum, inst) => sum + (instanceUsersMap[inst.id]?.length ?? 0),

View file

@ -127,6 +127,17 @@ export const PromptsPage: React.FC = () => {
}
};
// Handle duplicate prompt
const handleDuplicate = async (prompt: Prompt) => {
const result = await handlePromptCreate({
name: `Kopie von ${prompt.name || 'Prompt'}`,
content: prompt.content || ''
});
if (result?.success) {
refetch();
}
};
// Handle delete single prompt (confirmation handled by DeleteActionButton)
const handleDelete = async (prompt: Prompt) => {
const success = await handlePromptDelete(prompt.id);
@ -217,6 +228,11 @@ export const PromptsPage: React.FC = () => {
sortable={true}
selectable={false}
actionButtons={[
...(canCreate ? [{
type: 'copy' as const,
title: 'Duplizieren',
onAction: handleDuplicate,
}] : []),
...(canUpdate ? [{
type: 'edit' as const,
onAction: handleEditClick,