fix:build errors removed

This commit is contained in:
Ida Dittrich 2026-01-05 06:34:31 +01:00
parent ae6a634274
commit 079d398f8a
41 changed files with 321 additions and 205 deletions

View file

@ -43,7 +43,7 @@ export async function fetchAttributes(
request: ApiRequestFunction,
entityType: string
): Promise<AttributeDefinition[]> {
const data = await request<any>({
const data = await request({
url: `/api/attributes/${entityType}`,
method: 'get'
});
@ -81,7 +81,7 @@ export async function fetchConnectionAttributes(request: ApiRequestFunction): Pr
* Endpoint: GET /api/attributes/FileItem
*/
export async function fetchFileAttributes(request: ApiRequestFunction): Promise<AttributeDefinition[]> {
const data = await request<AttributeDefinition[] | { attributes: AttributeDefinition[] }>({
const data = await request({
url: '/api/attributes/FileItem',
method: 'get'
});

View file

@ -171,10 +171,19 @@ export async function registerApi(registerData: RegisterData): Promise<RegisterR
headers
});
const userData: any = response.data;
return {
success: true,
message: 'Registration successful',
user: response.data
user: userData && typeof userData === 'object' && 'id' in userData ? {
id: String(userData.id || ''),
username: String(userData.username || ''),
email: String(userData.email || ''),
fullName: String(userData.fullName || ''),
language: String(userData.language || 'en'),
enabled: Boolean(userData.enabled !== false),
privilege: String(userData.privilege || 'user')
} : undefined
};
}
@ -186,7 +195,7 @@ export async function registerWithMsalApi(
request: ApiRequestFunction,
userData: MsalRegisterData
): Promise<RegisterResponse> {
const response = await request<RegisterResponse>({
const response = await request({
url: '/api/msft/register',
method: 'post',
data: userData,
@ -197,10 +206,19 @@ export async function registerWithMsalApi(
}
});
const responseData: any = response;
return {
success: true,
message: 'Registration successful',
user: response
user: responseData && typeof responseData === 'object' && 'id' in responseData ? {
id: String(responseData.id || ''),
username: String(responseData.username || ''),
email: String(responseData.email || ''),
fullName: String(responseData.fullName || ''),
language: String(responseData.language || 'en'),
enabled: Boolean((responseData as any).enabled !== false),
privilege: String((responseData as any).privilege || 'user')
} : undefined
};
}

View file

@ -78,7 +78,7 @@ export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<an
* Fetch connection attributes from backend
* Endpoint: GET /api/attributes/UserConnection
*/
export async function fetchConnectionAttributes(request: ApiRequestFunction): Promise<AttributeDefinition[]> {
export async function fetchConnectionAttributes(_request: ApiRequestFunction): Promise<AttributeDefinition[]> {
// Note: This uses api.get directly due to response format handling
// For now, we'll use api.get directly in the hook as well
throw new Error('fetchConnectionAttributes should use api instance directly for response format handling');
@ -109,7 +109,7 @@ export async function fetchConnections(
}
}
const data = await request<PaginatedResponse<Connection> | Connection[]>({
const data = await request({
url: '/api/connections/',
method: 'get',
params: requestParams
@ -126,7 +126,7 @@ export async function createConnection(
request: ApiRequestFunction,
connectionData: CreateConnectionData
): Promise<Connection> {
return await request<Connection>({
return await request({
url: '/api/connections/',
method: 'post',
data: connectionData
@ -141,7 +141,7 @@ export async function connectService(
request: ApiRequestFunction,
connectionId: string
): Promise<ConnectResponse> {
return await request<ConnectResponse>({
return await request({
url: `/api/connections/${connectionId}/connect`,
method: 'post'
});
@ -155,7 +155,7 @@ export async function disconnectService(
request: ApiRequestFunction,
connectionId: string
): Promise<{ message: string }> {
return await request<{ message: string }>({
return await request({
url: `/api/connections/${connectionId}/disconnect`,
method: 'post'
});
@ -169,7 +169,7 @@ export async function deleteConnection(
request: ApiRequestFunction,
connectionId: string
): Promise<{ message: string }> {
return await request<{ message: string }>({
return await request({
url: `/api/connections/${connectionId}`,
method: 'delete'
});
@ -184,7 +184,7 @@ export async function updateConnection(
connectionId: string,
updateData: Partial<Connection>
): Promise<Connection> {
return await request<Connection>({
return await request({
url: `/api/connections/${connectionId}`,
method: 'put',
data: updateData
@ -199,7 +199,7 @@ export async function refreshMicrosoftToken(
request: ApiRequestFunction,
connectionId: string
): Promise<Connection> {
return await request<Connection>({
return await request({
url: `/api/connections/${connectionId}/refresh-microsoft-token`,
method: 'post'
});
@ -213,7 +213,7 @@ export async function refreshGoogleToken(
request: ApiRequestFunction,
connectionId: string
): Promise<Connection> {
return await request<Connection>({
return await request({
url: `/api/connections/${connectionId}/refresh-google-token`,
method: 'post'
});

View file

@ -58,7 +58,7 @@ export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<an
* Endpoint: GET /api/attributes/FileItem
*/
export async function fetchFileAttributes(request: ApiRequestFunction): Promise<AttributeDefinition[]> {
const data = await request<AttributeDefinition[] | { attributes: AttributeDefinition[] }>({
const data = await request({
url: '/api/attributes/FileItem',
method: 'get'
});
@ -109,7 +109,7 @@ export async function fetchFiles(
}
}
const data = await request<PaginatedResponse<FileInfo> | FileInfo[]>({
const data = await request({
url: '/api/files/list',
method: 'get',
params: requestParams
@ -127,7 +127,7 @@ export async function fetchFileById(
fileId: string
): Promise<FileInfo | null> {
try {
const data = await request<FileInfo>({
const data = await request({
url: `/api/files/${fileId}`,
method: 'get'
});
@ -147,7 +147,7 @@ export async function updateFile(
fileId: string,
fileData: Partial<FileInfo>
): Promise<FileInfo> {
return await request<FileInfo>({
return await request({
url: `/api/files/${fileId}`,
method: 'put',
data: fileData

View file

@ -38,7 +38,7 @@ export async function fetchPermissions(
params.item = item;
}
const data = await request<UserPermissions>({
const data = await request({
url: '/api/rbac/permissions',
method: 'get',
params

View file

@ -84,7 +84,7 @@ export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<an
* Fetch prompt attributes from backend
* Endpoint: GET /api/attributes/Prompt
*/
export async function fetchPromptAttributes(request: ApiRequestFunction): Promise<AttributeDefinition[]> {
export async function fetchPromptAttributes(_request: ApiRequestFunction): Promise<AttributeDefinition[]> {
// Note: This uses api.get directly due to response format handling
// For now, we'll use api.get directly in the hook as well
throw new Error('fetchPromptAttributes should use api instance directly for response format handling');
@ -115,7 +115,7 @@ export async function fetchPrompts(
}
}
const data = await request<PaginatedResponse<Prompt> | Prompt[]>({
const data = await request({
url: '/api/prompts',
method: 'get',
params: requestParams
@ -133,7 +133,7 @@ export async function fetchPromptById(
promptId: string
): Promise<Prompt | null> {
try {
const data = await request<Prompt>({
const data = await request({
url: `/api/prompts/${promptId}`,
method: 'get'
});
@ -152,7 +152,7 @@ export async function createPrompt(
request: ApiRequestFunction,
promptData: CreatePromptData
): Promise<Prompt> {
return await request<Prompt>({
return await request({
url: '/api/prompts',
method: 'post',
data: promptData
@ -168,7 +168,7 @@ export async function updatePrompt(
promptId: string,
promptData: UpdatePromptData
): Promise<Prompt> {
return await request<Prompt>({
return await request({
url: `/api/prompts/${promptId}`,
method: 'put',
data: promptData

View file

@ -35,6 +35,8 @@ export interface AttributeDefinition {
minWidth?: number;
maxWidth?: number;
filterOptions?: string[];
readonly?: boolean;
editable?: boolean;
}
export interface PaginationParams {
@ -78,7 +80,7 @@ export async function fetchCurrentUser(
endpoint = '/api/google/me';
}
return await request<User>({
return await request({
url: endpoint,
method: 'get'
});
@ -108,7 +110,7 @@ export async function logoutUser(
* Fetch user attributes from backend
* Endpoint: GET /api/attributes/User
*/
export async function fetchUserAttributes(request: ApiRequestFunction): Promise<AttributeDefinition[]> {
export async function fetchUserAttributes(_request: ApiRequestFunction): Promise<AttributeDefinition[]> {
// Note: This uses api.get directly in the hook due to response format handling
// Keeping the function signature here for consistency, but implementation may need api instance
throw new Error('fetchUserAttributes should use api instance directly for response format handling');
@ -139,7 +141,7 @@ export async function fetchUsers(
}
}
const data = await request<PaginatedResponse<User> | User[]>({
const data = await request({
url: '/api/users/',
method: 'get',
params: requestParams
@ -157,7 +159,7 @@ export async function fetchUserById(
userId: string
): Promise<User | null> {
try {
const data = await request<User>({
const data = await request({
url: `/api/users/${userId}`,
method: 'get'
});
@ -176,7 +178,7 @@ export async function createUser(
request: ApiRequestFunction,
userData: Partial<User>
): Promise<User> {
return await request<User>({
return await request({
url: '/api/users',
method: 'post',
data: userData
@ -192,7 +194,7 @@ export async function updateUser(
userId: string,
userData: UserUpdateData
): Promise<User> {
return await request<User>({
return await request({
url: `/api/users/${userId}`,
method: 'put',
data: userData

View file

@ -75,7 +75,7 @@ export async function fetchWorkflows(request: ApiRequestFunction): Promise<Workf
console.log('📤 fetchWorkflows: Making API request to /api/workflows/');
try {
const data = await request<any>({
const data = await request({
url: '/api/workflows/',
method: 'get'
});
@ -134,7 +134,7 @@ export async function fetchWorkflow(
request: ApiRequestFunction,
workflowId: string
): Promise<Workflow & { messages?: WorkflowMessage[]; logs?: WorkflowLog[] }> {
return await request<any>({
return await request({
url: `/api/workflows/${workflowId}`,
method: 'get'
});
@ -148,7 +148,7 @@ export async function fetchWorkflowStatus(
request: ApiRequestFunction,
workflowId: string
): Promise<Workflow | { status: string } | null> {
const data = await request<any>({
const data = await request({
url: `/api/workflows/${workflowId}/status`,
method: 'get'
});
@ -174,7 +174,7 @@ export async function fetchWorkflowMessages(
messageId?: string
): Promise<WorkflowMessage[]> {
const params = messageId ? { messageId } : undefined;
const data = await request<any>({
const data = await request({
url: `/api/workflows/${workflowId}/messages`,
method: 'get',
params
@ -207,7 +207,7 @@ export async function fetchWorkflowLogs(
logId?: string
): Promise<WorkflowLog[]> {
const params = logId ? { logId } : undefined;
const data = await request<any>({
const data = await request({
url: `/api/workflows/${workflowId}/logs`,
method: 'get',
params
@ -248,7 +248,7 @@ export async function fetchChatData(
console.log('📤 fetchChatData request:', requestConfig);
const data = await request<any>(requestConfig);
const data = await request(requestConfig);
console.log('📥 fetchChatData response:', data);
@ -359,7 +359,7 @@ export async function startWorkflowApi(
console.log(' Request Body:', JSON.stringify(requestBody, null, 2));
console.log(' Full Request Config:', JSON.stringify(requestConfig, null, 2));
const response = await request<StartWorkflowResponse>(requestConfig);
const response = await request(requestConfig);
console.log('📥 startWorkflow response:', response);
@ -389,7 +389,7 @@ export async function updateWorkflowApi(
workflowId: string,
updateData: Partial<{ name: string; description?: string; tags?: string[] }>
): Promise<Workflow> {
return await request<Workflow>({
return await request({
url: `/api/workflows/${workflowId}`,
method: 'put',
data: updateData
@ -494,7 +494,7 @@ export async function fetchAttributes(
request: ApiRequestFunction,
entityType: string = 'ChatWorkflow'
): Promise<AttributeDefinition[]> {
const data = await request<any>({
const data = await request({
url: `/api/attributes/${entityType}`,
method: 'get'
});

View file

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { MdModeEdit } from 'react-icons/md';
import { useLanguage } from '../../../../providers/language/LanguageContext';
import { Popup } from '../../../UiComponents/Popup';
import { FormGeneratorForm } from '../../FormGeneratorForm';
import { FormGeneratorForm, AttributeDefinition } from '../../FormGeneratorForm';
import styles from '../ActionButton.module.css';
export interface EditActionButtonProps<T = any> {
@ -154,16 +154,18 @@ export function EditActionButton<T = any>({
// Get the item ID from the row
const itemId = (editData as any)[idField];
// Get edit fields configuration
const fields = getEditFields();
// Get edit fields configuration from attributes
const attributes = getAttributes();
const fields = attributes || [];
// Extract the fields to update from the edit data
const updateData: any = {};
fields.forEach(field => {
fields.forEach((field: AttributeDefinition) => {
if (field.editable !== false) {
const value = (updatedData as any)[field.key];
const fieldName = field.name;
const value = (updatedData as any)[fieldName];
if (value !== undefined) {
updateData[field.key] = value;
updateData[fieldName] = value;
}
}
});

View file

@ -30,9 +30,9 @@ export function PlayActionButton<T = any>({
loading = false,
className = '',
title,
hookData,
hookData: _hookData,
idField = 'id',
nameField = 'name',
nameField: _nameField = 'name',
contentField = 'content',
navigateTo = 'start/dashboard',
mode = 'prompt'

View file

@ -64,7 +64,7 @@ export function FormGeneratorControls({
filterFocused,
onFilterFocus,
selectedCount,
displayData,
displayData: _displayData,
onDeleteSingle,
onDeleteMultiple,
onRefresh,

View file

@ -453,7 +453,7 @@ export function FormGeneratorList<T extends Record<string, any>>({
};
// Render field input
const renderFieldInput = (field: FieldConfig, value: any, row: T, index: number) => {
const renderFieldInput = (field: FieldConfig, value: any, row: T, _index: number) => {
if (field.type === 'readonly' || !field.editable) {
return (
<div className={styles.fieldValue} key={field.key}>
@ -491,12 +491,15 @@ export function FormGeneratorList<T extends Record<string, any>>({
}
// Default to text input
const inputType = attributeTypeToInputType(field.type || 'string');
// TextField doesn't support 'textarea' type, use 'text' instead
const textFieldType = inputType === 'textarea' ? 'text' : inputType;
return (
<TextField
key={field.key}
value={value || ''}
onChange={(newValue) => onFieldChange?.(row, field.key, newValue)}
type={attributeTypeToInputType(field.type || 'string')}
type={textFieldType as 'text' | 'email' | 'url' | 'password' | 'search' | 'tel' | 'number'}
required={field.required}
readonly={!field.editable}
className={styles.fieldInput}

View file

@ -32,7 +32,6 @@ const SidebarItem: React.FC<SidebarItemProps> = React.memo(({
// Get the actual color from parent li element
const parentLi = wrapper.closest('li');
const parentColor = parentLi ? window.getComputedStyle(parentLi).color : '#000000';
// Force color directly - use black for now to ensure visibility
const iconColor = '#000000'; // Force black for visibility
@ -218,7 +217,6 @@ const SidebarItem: React.FC<SidebarItemProps> = React.memo(({
>
<Icon
className={`${styles.icon} ${styles.iconMinimized} ${isDisabled ? styles.disabledIcon : ''}`}
size={25}
style={{
width: '25px',
height: '25px',

View file

@ -53,7 +53,6 @@ const SidebarSubmenu: React.FC<SidebarSubmenuProps> = ({ item, isOpen, isMinimiz
{SubIcon && (
<SubIcon
className={styles.submenuHorizontalIcon}
size={16}
style={{
width: '16px',
height: '16px',

View file

@ -64,7 +64,7 @@ export function ConnectedFilesList({
deletingFiles = new Set(),
previewingFiles = new Set(),
removingFiles = new Set(),
workflowId,
workflowId: _workflowId,
emptyMessage = 'No files connected to this workflow'
}: ConnectedFilesListProps) {
// Combine workflow files and pending files, deduplicating by fileId
@ -98,7 +98,7 @@ export function ConnectedFilesList({
}
return false;
},
removeOptimistically: (fileId: string) => {
removeOptimistically: (_fileId: string) => {
// This will be handled by the parent component's state
},
refetch: async () => {
@ -121,7 +121,7 @@ export function ConnectedFilesList({
// View button (always shown)
buttons.push({
type: 'view',
onAction: async (file: WorkflowFile) => {
onAction: async (_file: WorkflowFile) => {
// View is handled by ViewActionButton's FilePreview component
return Promise.resolve();
},
@ -156,7 +156,7 @@ export function ConnectedFilesList({
return buttons;
}, [actionButtons, onDelete, onRemove]);
const handleView = async (file: WorkflowFile) => {
const handleView = async (_file: WorkflowFile) => {
// View is handled by ViewActionButton's FilePreview component
return Promise.resolve();
};
@ -187,10 +187,10 @@ export function ConnectedFilesList({
<div className={styles.fileList}>
{allFiles
.filter(file => file.fileId && file.fileId.trim() !== '') // Ensure fileId exists
.map((file, index) => {
const isDeleting = deletingFiles.has(file.fileId!);
const isPreviewing = previewingFiles.has(file.fileId!);
const isRemoving = removingFiles.has(file.fileId!);
.map((file) => {
// const isDeleting = deletingFiles.has(file.fileId!);
// const isPreviewing = previewingFiles.has(file.fileId!);
// const isRemoving = removingFiles.has(file.fileId!);
// Use fileId as key since we've filtered out files without it
const uniqueKey = file.fileId!;

View file

@ -1,5 +1,5 @@
import React from 'react';
import { LogProps, WorkflowLog } from './LogTypes';
import { LogProps } from './LogTypes';
import { AutoScroll } from '../AutoScroll';
import { formatUnixTimestamp } from '../../../utils/time';
import styles from './Log.module.css';

View file

@ -1,5 +1,3 @@
import type React from 'react';
/**
* Log entry from workflow
*/

View file

@ -2,7 +2,7 @@ import React, { useEffect, useRef } from 'react';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { lv95ToWGS84, wgs84ToLV95 } from './LV95Converter';
import type { MapPoint, ParcelGeometry, MapViewProps } from './MapView';
import type { MapViewProps } from './MapView';
import styles from './MapView.module.css';
// Fix for default marker icons in Leaflet
@ -32,7 +32,7 @@ const MapViewLeaflet: React.FC<MapViewProps> = ({
}) => {
const mapRef = useRef<L.Map | null>(null);
const mapContainerRef = useRef<HTMLDivElement>(null);
const layersRef = useRef<L.LayerGroup[]>([]);
const layersRef = useRef<L.Layer[]>([]);
const centerMarkerRef = useRef<L.Marker | null>(null);
// Initialize map

View file

@ -23,7 +23,7 @@ export interface DocumentItemProps {
*/
export const DocumentItem: React.FC<DocumentItemProps> = ({
document,
message,
message: _message,
className,
onFileDelete,
onFileRemove,
@ -31,7 +31,7 @@ export const DocumentItem: React.FC<DocumentItemProps> = ({
deletingFiles = new Set(),
previewingFiles = new Set(),
removingFiles = new Set(),
workflowId
workflowId: _workflowId
}) => {
// Convert MessageDocument to WorkflowFile format for compatibility with action buttons
const workflowFile: WorkflowFile = useMemo(() => ({
@ -50,7 +50,7 @@ export const DocumentItem: React.FC<DocumentItemProps> = ({
// Create hookData object for action buttons
const hookData = useMemo(() => ({
handleDelete: async (fileId: string) => {
handleDelete: async (_fileId: string) => {
if (onFileDelete) {
await onFileDelete(workflowFile);
return true;

View file

@ -9,6 +9,7 @@ interface TextFieldProps extends BaseTextFieldProps {
step?: string;
min?: string | number;
max?: string | number;
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
}
const TextField: React.FC<TextFieldProps> = ({

View file

@ -1,5 +1,3 @@
import type React from 'react';
/**
* Log entry from workflow
*/

View file

@ -11,7 +11,9 @@ export * from './MapView';
export * from './ParcelInfoPanel';
export * from './CopyableTruncatedValue';
export { Log } from './Log';
export * from './Log';
export type { LogProps } from './Log/LogTypes';
export { LogMessage } from './Log/LogMessage';
export type { LogMessageProps } from './Log/LogMessage';
export { WorkflowStatus } from './WorkflowStatus';
export * from './WorkflowStatus';
export type { WorkflowStatusProps } from './WorkflowStatus/WorkflowStatusTypes';
export * from './AutoScroll';

View file

@ -1,4 +1,4 @@
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import React, { createContext, useContext, useCallback } from 'react';
import { useUserFiles, useFileOperations, UserFile } from '../hooks/useFiles';
interface FileContextType {
@ -16,7 +16,7 @@ interface FileContextType {
const FileContext = createContext<FileContextType | undefined>(undefined);
export function FileProvider({ children }: { children: React.ReactNode }) {
const { data: files, loading, error, refetch: refetchFiles, removeFileOptimistically, addFileOptimistically } = useUserFiles();
const { data: files, loading, error, refetch: refetchFiles, removeFileOptimistically } = useUserFiles();
const {
handleFileUpload: hookHandleFileUpload,
handleFileDelete: hookHandleFileDelete,
@ -40,25 +40,13 @@ export function FileProvider({ children }: { children: React.ReactNode }) {
return result;
}
// Add file optimistically to the shared state
const newFile: UserFile = {
id: fileData.id,
file_name: fileData.fileName || file.name,
mime_type: fileData.mimeType || file.type || 'application/octet-stream',
action: 'Document', // Will be determined by mime type in useUserFiles
created_at: fileData.creationDate ? new Date(fileData.creationDate * 1000).toISOString() : new Date().toISOString(),
size: fileData.fileSize || file.size,
source: 'user_uploaded'
};
addFileOptimistically(newFile);
// File will be added via refetch
// Refetch to ensure we have the latest data (this will update all consumers)
await refetchFiles();
}
return result;
}, [hookHandleFileUpload, addFileOptimistically, refetchFiles]);
}, [hookHandleFileUpload, refetchFiles]);
// Centralized file delete that updates the shared state
const handleFileDelete = useCallback(async (fileId: string, onOptimisticDelete?: () => void) => {

View file

@ -1,4 +1,4 @@
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';
interface WorkflowSelectionContextType {
selectedWorkflowId: string | null;

View file

@ -71,7 +71,7 @@ const PageManager: React.FC<PageManagerProps> = ({
) : (
<PageRenderer
pageData={pageData}
onButtonClick={(buttonId, button) => {
onButtonClick={(_buttonId, _button) => {
}}
/>
)}
@ -88,7 +88,8 @@ const PageManager: React.FC<PageManagerProps> = ({
} else {
if (import.meta.env.DEV) {
const instance = newInstances.get(currentPath);
const _instance = newInstances.get(currentPath);
void _instance; // Intentionally unused, for debugging purposes
}
}

View file

@ -10,6 +10,7 @@ import { DragDropOverlay } from '../../components/UiComponents/DragDropOverlay';
import { useLanguage } from '../../providers/language/LanguageContext';
import { usePermissions } from '../../hooks/usePermissions';
import { FiPaperclip } from 'react-icons/fi';
import type { WorkflowFile } from '../../hooks/playground/useDashboardInputForm';
import styles from '../../styles/pages.module.css';
interface PageRendererProps {
@ -362,7 +363,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
onSave?: (sectionId: string, data: any) => Promise<void>;
getNestedValue: (obj: any, path: string) => any;
setNestedValue: (obj: any, path: string, value: any) => any;
}> = ({ sections, formData, fieldsBySection, loadingBySection, errorsBySection, onSave, getNestedValue, setNestedValue }) => {
}> = ({ sections, formData, fieldsBySection, loadingBySection, errorsBySection, onSave, getNestedValue, setNestedValue: _setNestedValue }) => {
const [sectionFormData, setSectionFormData] = useState<Record<string, any>>({});
const [sectionSaveLoading, setSectionSaveLoading] = useState<Record<string, boolean>>({});
const [sectionSaveMessages, setSectionSaveMessages] = useState<Record<string, { type: 'success' | 'error', text: string } | null>>({});
@ -677,6 +678,46 @@ const PageRenderer: React.FC<PageRendererProps> = ({
// Render content based on type
const renderContent = (content: PageContent) => {
// Wrapper functions to convert fileId-based handlers to WorkflowFile-based handlers
// These are defined at the top level of renderContent so they're accessible in all content cases
const wrapFileDelete: ((file: WorkflowFile) => Promise<void>) | undefined = hookData?.handleFileDelete ? async (file: WorkflowFile) => {
if (!hookData?.handleFileDelete || !file) return;
const handler = hookData.handleFileDelete as any;
// Check if handler expects fileId (string) or file (WorkflowFile)
if (file?.fileId && typeof file.fileId === 'string') {
// Try fileId signature first (handler might be (fileId: string, ...) => Promise<boolean>)
try {
const result = handler(file.fileId);
if (result instanceof Promise) await result;
return;
} catch {
// Fall through to file signature
}
}
// Try file signature (handler might be (file: WorkflowFile) => Promise<void>)
const result = handler(file);
if (result instanceof Promise) await result;
} : undefined;
const wrapFileRemove: ((file: WorkflowFile) => Promise<void>) | undefined = hookData?.handleFileRemove ? async (file: WorkflowFile) => {
if (!hookData?.handleFileRemove || !file) return;
const handler = hookData.handleFileRemove as any;
// Check if handler expects fileId (string) or file (WorkflowFile)
if (file?.fileId && typeof file.fileId === 'string') {
// Try fileId signature first (handler might be (fileId: string) => void | Promise<void>)
try {
const result = handler(file.fileId);
if (result instanceof Promise) await result;
return;
} catch {
// Fall through to file signature
}
}
// Try file signature (handler might be (file: WorkflowFile) => Promise<void>)
const result = handler(file);
if (result instanceof Promise) await result;
} : undefined;
switch (content.type) {
case 'heading':
const HeadingTag = `h${content.level || 2}` as keyof React.JSX.IntrinsicElements;
@ -834,7 +875,14 @@ const PageRenderer: React.FC<PageRendererProps> = ({
}
} else {
// Non-function disabled value
disabledFn = () => action.disabled as boolean | { disabled: boolean; message?: string };
const disabledValue = action.disabled;
if (typeof disabledValue === 'boolean') {
disabledFn = () => disabledValue;
} else if (disabledValue && typeof disabledValue === 'object' && 'disabled' in disabledValue) {
disabledFn = () => disabledValue as { disabled: boolean; message?: string };
} else {
disabledFn = () => false;
}
}
} else {
disabledFn = () => false;
@ -949,7 +997,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
<DropdownSelect
items={hookData.promptItems || []}
selectedItemId={hookData.selectedPromptId || null}
onSelect={hookData.onPromptSelect}
onSelect={hookData.onPromptSelect || (() => {})}
placeholder={t('dashboard.prompt.select', 'Select a prompt')}
emptyMessage={t('dashboard.prompt.empty', 'No prompts available')}
headerText={t('dashboard.prompt.header', 'Select Prompt')}
@ -966,7 +1014,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
<DropdownSelect
items={hookData.workflowModeItems || []}
selectedItemId={hookData.selectedWorkflowMode || null}
onSelect={hookData.onWorkflowModeSelect}
onSelect={hookData.onWorkflowModeSelect || (() => {})}
placeholder={t('dashboard.workflow.mode.select', 'Select workflow mode')}
emptyMessage={t('dashboard.workflow.mode.empty', 'No modes available')}
headerText={t('dashboard.workflow.mode.header', 'Workflow Mode')}
@ -1033,7 +1081,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
},
{
type: 'remove',
onAction: hookData.handleFileRemove,
onAction: wrapFileRemove,
showOnlyForPending: true,
idField: 'fileId',
loadingStateName: 'removingItems'
@ -1045,9 +1093,12 @@ const PageRenderer: React.FC<PageRendererProps> = ({
idField: 'fileId'
}
]}
onDelete={hookData.handleFileDelete}
onRemove={hookData.handleFileRemove}
onAttach={hookData.handleFileAttach} // Allow attaching files for next message
onDelete={wrapFileDelete}
onRemove={wrapFileRemove}
onAttach={hookData.handleFileAttach ? async (fileId: string) => {
const result = hookData.handleFileAttach!(fileId);
if (result instanceof Promise) await result;
} : undefined}
deletingFiles={hookData.deletingFiles || new Set()}
previewingFiles={hookData.previewingFiles || new Set()}
removingFiles={new Set()} // Can be tracked if needed
@ -1080,7 +1131,13 @@ const PageRenderer: React.FC<PageRendererProps> = ({
justifyContent: 'flex-end'
}}>
<UploadButton
onUpload={hookData.handleFileUploadAndAttach || hookData.handleFileUpload}
onUpload={hookData.handleFileUploadAndAttach || hookData.handleFileUpload ? async (file: File) => {
const handler = hookData.handleFileUploadAndAttach || hookData.handleFileUpload;
if (handler) {
// Handler returns Promise<{ success, data }>, but UploadButton expects Promise<void>
await handler(file);
}
} : async () => {}}
disabled={hookData.isSubmitting || false}
loading={hookData.uploadingFile || false}
variant="primary"
@ -1207,7 +1264,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
<DropdownSelect
items={hookData.promptItems || []}
selectedItemId={hookData.selectedPromptId || null}
onSelect={hookData.onPromptSelect}
onSelect={hookData.onPromptSelect || (() => {})}
placeholder={t('dashboard.prompt.select', 'Select a prompt')}
emptyMessage={t('dashboard.prompt.empty', 'No prompts available')}
headerText={t('dashboard.prompt.header', 'Select Prompt')}
@ -1222,7 +1279,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
<DropdownSelect
items={hookData.workflowModeItems || []}
selectedItemId={hookData.selectedWorkflowMode || null}
onSelect={hookData.onWorkflowModeSelect}
onSelect={hookData.onWorkflowModeSelect || (() => {})}
placeholder={t('dashboard.workflow.mode.select', 'Select workflow mode')}
emptyMessage={t('dashboard.workflow.mode.empty', 'No modes available')}
headerText={t('dashboard.workflow.mode.header', 'Workflow Mode')}
@ -1320,8 +1377,8 @@ const PageRenderer: React.FC<PageRendererProps> = ({
showDocuments={config.showDocuments !== false}
showMetadata={config.showMetadata !== false}
showProgress={config.showProgress !== false}
onFileDelete={hookData?.handleFileDelete}
onFileRemove={hookData?.handleFileRemove}
onFileDelete={wrapFileDelete}
onFileRemove={wrapFileRemove}
deletingFiles={hookData?.deletingFiles}
previewingFiles={hookData?.previewingFiles}
removingFiles={hookData?.removingFiles}
@ -1334,8 +1391,8 @@ const PageRenderer: React.FC<PageRendererProps> = ({
key={message.id || index}
message={cleanMessage}
showDocuments={config.showDocuments !== false}
onFileDelete={hookData?.handleFileDelete}
onFileRemove={hookData?.handleFileRemove}
onFileDelete={wrapFileDelete}
onFileRemove={wrapFileRemove}
deletingFiles={hookData?.deletingFiles}
previewingFiles={hookData?.previewingFiles}
removingFiles={hookData?.removingFiles}
@ -1356,8 +1413,8 @@ const PageRenderer: React.FC<PageRendererProps> = ({
showMetadata={config.showMetadata !== false}
showProgress={config.showProgress !== false}
emptyMessage={config.emptyMessage ? resolveLanguageText(config.emptyMessage, t) : undefined}
onFileDelete={hookData?.handleFileDelete}
onFileRemove={hookData?.handleFileRemove}
onFileDelete={wrapFileDelete}
onFileRemove={wrapFileRemove}
deletingFiles={hookData?.deletingFiles}
previewingFiles={hookData?.previewingFiles}
removingFiles={hookData?.removingFiles}
@ -1662,6 +1719,14 @@ const PageRenderer: React.FC<PageRendererProps> = ({
return await createOperation(formData);
};
// Evaluate disabled property if it's a function
const isDisabled = typeof button.disabled === 'function'
? button.disabled(hookData)
: button.disabled ?? false;
const disabledValue = typeof isDisabled === 'object' && isDisabled !== null && 'disabled' in isDisabled
? isDisabled.disabled
: Boolean(isDisabled);
return (
<CreateButton
key={button.id}
@ -1672,7 +1737,7 @@ const PageRenderer: React.FC<PageRendererProps> = ({
variant={button.variant || 'primary'}
size={button.size || 'md'}
icon={button.icon}
disabled={button.disabled}
disabled={disabledValue}
onSuccess={() => {
// Refetch data after successful creation
if (hookData.refetch) {

View file

@ -121,7 +121,7 @@ export const SidebarProvider: React.FC<SidebarProviderProps> = ({ children }) =>
}
// Process parent groups
for (const [parentPath, parentGroup] of parentGroups.entries()) {
for (const [_parentPath, parentGroup] of parentGroups.entries()) {
// Filter subpages by RBAC access
const accessibleSubpages = [];
for (const subpage of parentGroup.subpages) {

View file

@ -34,6 +34,7 @@ export const dashboardPageData: GenericPageData = {
placeholder: 'dashboard.workflow.select',
emptyMessage: 'dashboard.workflow.empty',
headerText: 'dashboard.workflow.header',
onSelect: () => {}, // Placeholder - actual handler comes from dataSource.onSelectMethod
dataSource: {
itemsProperty: 'workflowItems',
selectedIdProperty: 'selectedWorkflowId',

View file

@ -1,5 +1,5 @@
import { GenericPageData } from '../../pageInterface';
import { FaTable, FaBuilding } from 'react-icons/fa';
import { FaTable } from 'react-icons/fa';
import { IoMdSend } from 'react-icons/io';
import { usePekTablesContext } from '../../../../contexts/PekTablesContext';
import PekTablesDropdown from './pek-tables/PekTablesDropdown';

View file

@ -7,16 +7,16 @@ import styles from './PekLocationInput.module.css';
const PekLocationInput: React.FC = () => {
const {
kanton,
setKanton,
gemeinde,
setGemeinde,
kanton: _kanton,
setKanton: _setKanton,
gemeinde: _gemeinde,
setGemeinde: _setGemeinde,
adresse,
setAdresse,
buildLocationString,
useCurrentLocation,
isGettingLocation,
locationError,
locationError: _locationError,
searchParcel,
isSearchingParcel
} = usePekContext();

View file

@ -9,13 +9,14 @@ export type PrivilegeChecker = () => boolean | Promise<boolean>;
export interface ButtonFormField {
key: string;
label: string | LanguageText;
type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly';
type: 'string' | 'boolean' | 'email' | 'textarea' | 'date' | 'enum' | 'readonly' | 'multiselect';
required?: boolean;
placeholder?: string | LanguageText;
minRows?: number;
maxRows?: number;
validator?: (value: any) => string | null;
defaultValue?: any;
options?: string[] | Array<{ value: string | number; label: string }>; // For enum/multiselect fields
}
// Dropdown configuration for header dropdown buttons
@ -37,6 +38,7 @@ export interface DropdownConfig<T = any> {
itemsProperty?: string; // Property name in hookData that contains items array
selectedIdProperty?: string; // Property name in hookData that contains selectedItemId
onSelectMethod?: string; // Method name in hookData for onSelect callback
loadingProperty?: string; // Property name in hookData that contains loading state
};
}
@ -159,9 +161,24 @@ export interface GenericDataHook {
columns?: any[]; // Optional columns configuration
// File operations
handleUpload?: (file: File) => Promise<{ success: boolean; data: any }>; // For file upload functionality
handleFileUpload?: (file: File) => Promise<{ success: boolean; data: any }>; // Alias for handleUpload
handleDownload?: (fileId: string, fileName: string) => Promise<boolean>; // For file download functionality
handleDelete?: (fileId: string, onOptimisticDelete?: () => void) => Promise<boolean>; // For file delete functionality
handleFileDelete?: ((fileId: string, onOptimisticDelete?: () => void) => Promise<boolean>) | ((file: any) => Promise<void>); // Can accept fileId or WorkflowFile
handlePreview?: (fileId: string, fileName: string, mimeType?: string) => Promise<any>; // For file preview functionality
// File management properties
workflowFiles?: any[]; // Files connected to workflow
pendingFiles?: any[]; // Files pending attachment
allUserFiles?: any[]; // All user files
handleFileRemove?: ((fileId: string) => Promise<void> | void) | ((file: any) => Promise<void> | void); // Can accept fileId or WorkflowFile
handleFileAttach?: (fileId: string) => Promise<void>; // Attach file to workflow (always returns Promise)
handleFileUploadAndAttach?: (file: File) => Promise<{ success: boolean; data: any }>; // Upload and attach file
uploadingFile?: boolean; // Loading state for file upload
deletingFiles?: Set<string>; // Set of file IDs being deleted
previewingFiles?: Set<string>; // Set of file IDs being previewed
removingFiles?: Set<string>; // Set of file IDs being removed
isFileAttachmentPopupOpen?: boolean; // Whether file attachment popup is open
setIsFileAttachmentPopupOpen?: (open: boolean) => void; // Set file attachment popup state
// FormGenerator specific handlers
onDelete?: (row: any) => Promise<void>; // For single item deletion
onDeleteMultiple?: (rows: any[]) => Promise<void>; // For multiple item deletion
@ -170,14 +187,37 @@ export interface GenericDataHook {
onInputChange?: (value: string) => void;
handleSubmit?: () => Promise<void>; // No parameters, uses internal inputValue
isSubmitting?: boolean;
// Prompt selector properties
promptPermission?: {
view?: boolean;
read?: string;
};
promptItems?: Array<{ id: string | number; label: string; value: any }>;
selectedPromptId?: string | number | null;
onPromptSelect?: (item: { id: string | number; label: string; value: any } | null) => void | Promise<void>;
promptsLoading?: boolean;
// Workflow mode selector properties
workflowModeItems?: Array<{ id: string | number; label: string; value: any }>;
selectedWorkflowMode?: string | number | null;
onWorkflowModeSelect?: (item: { id: string | number; label: string; value: any } | null) => void | Promise<void>;
// Workflow lifecycle state
workflowId?: string;
workflowStatus?: string;
workflowData?: {
currentRound?: number;
[key: string]: any;
};
isRunning?: boolean;
currentRound?: number; // Current workflow round
latestStats?: any; // Latest workflow statistics
// Messages from workflow
messages?: any[];
// Logs from workflow
logs?: any[];
// Dashboard log tree
dashboardTree?: any; // Dashboard log tree structure
onToggleOperationExpanded?: (operationId: string) => void;
getChildOperations?: (parentId: string | null) => string[];
// Message overlay component
MessageOverlayComponent?: () => React.ReactElement;
// Settings-specific properties
@ -186,6 +226,8 @@ export interface GenericDataHook {
settingsLoading?: Record<string, boolean>; // Loading state per section
settingsErrors?: Record<string, string | null>; // Error state per section
saveSection?: (sectionId: string, data: any) => Promise<void>; // Save handler for a section
// Dropdown data source loading property
[key: string]: any; // Allow additional properties for dynamic data sources
}
// Action button configuration
@ -306,8 +348,8 @@ export interface PageDataFile {
export interface SidebarItem {
id: string;
name: string;
link: string;
icon?: IconType;
link: string | undefined; // Allow undefined for parent groups that aren't clickable pages
icon?: IconType | React.ComponentType<React.SVGProps<SVGSVGElement>>; // Allow both IconType and SVG components
moduleEnabled: boolean;
order: number;
submenu?: SidebarSubmenuItemData[];

View file

@ -11,6 +11,7 @@ import { useWorkflowLifecycle } from './useWorkflowLifecycle';
import { useWorkflows } from './useWorkflows';
import { useDashboardLogTree } from './useDashboardLogTree';
import { extractFileIdsFromMessage, convertFilesToDocuments, sortMessages } from './playgroundUtils';
import type { WorkflowLog as LogTypesWorkflowLog } from '../../components/UiComponents/Log/LogTypes';
export interface WorkflowFile {
id: string;
@ -45,7 +46,6 @@ export function useDashboardInputForm() {
isStopping,
startingWorkflow,
messages,
logs,
dashboardLogs,
unifiedContentLogs,
latestStats,
@ -190,7 +190,20 @@ export function useDashboardInputForm() {
// Only process if there are new logs
if (newLogs.length > 0) {
processDashboardLogs(newLogs);
// Convert API WorkflowLog format to LogTypes WorkflowLog format
const convertedLogs: LogTypesWorkflowLog[] = newLogs.map(log => ({
id: log.id || `${log.operationId || 'unknown'}-${log.timestamp || Date.now()}`,
workflowId: log.workflowId || '',
message: log.message || '',
type: log.type,
timestamp: log.timestamp || Date.now(),
status: log.status,
progress: log.progress,
performance: log.performance,
parentId: log.parentId,
operationId: log.operationId
}));
processDashboardLogs(convertedLogs);
}
lastDashboardLogsLengthRef.current = dashboardLogs.length;
@ -352,7 +365,7 @@ export function useDashboardInputForm() {
return allMessages.sort(sortMessages);
}, [messages, optimisticMessage, workflowId]);
const handleFileUpload = useCallback(async (file: File) => {
const handleFileUpload = useCallback(async (file: File): Promise<{ success: boolean; data: any }> => {
const result = await fileContext.handleFileUpload(file, workflowId || undefined);
if (result.success && result.fileData) {
@ -360,27 +373,32 @@ export function useDashboardInputForm() {
const fileData = responseData.file || responseData;
const fileId = fileData?.id;
if (!fileId) return;
const newFile: WorkflowFile = {
id: fileId,
fileId: fileId,
fileName: fileData.fileName || file.name,
fileSize: fileData.fileSize || file.size,
mimeType: fileData.mimeType || file.type || 'application/octet-stream',
source: 'user_uploaded'
};
setPendingFiles(prev => {
if (prev.some(f => f.fileId === fileId)) {
return prev;
}
return [...prev, newFile];
});
if (fileId) {
const newFile: WorkflowFile = {
id: fileId,
fileId: fileId,
fileName: fileData.fileName || file.name,
fileSize: fileData.fileSize || file.size,
mimeType: fileData.mimeType || file.type || 'application/octet-stream',
source: 'user_uploaded'
};
setPendingFiles(prev => {
if (prev.some(f => f.fileId === fileId)) {
return prev;
}
return [...prev, newFile];
});
}
}
return {
success: result.success || false,
data: result.fileData || null
};
}, [workflowId, fileContext]);
const handleFileAttach = useCallback(async (fileId: string) => {
const handleFileAttach = useCallback(async (fileId: string): Promise<void> => {
const isInPending = pendingFiles.some(f => f.fileId === fileId);
if (isInPending) {
@ -424,8 +442,8 @@ export function useDashboardInputForm() {
}
}, [pendingFiles, fileContext.files, workflowFiles]);
const handleFileUploadAndAttach = useCallback(async (file: File) => {
await handleFileUpload(file);
const handleFileUploadAndAttach = useCallback(async (file: File): Promise<{ success: boolean; data: any }> => {
return await handleFileUpload(file);
}, [handleFileUpload]);
const handleFileRemove = useCallback(async (file: WorkflowFile) => {

View file

@ -56,7 +56,6 @@ export function useDashboardLogTree() {
// Get or create operation
const existingOperation = newTree.operations.get(operationId);
const isNewOperation = !existingOperation;
// Create new logs Map (copy existing logs if updating)
const logsMap = existingOperation

View file

@ -1,4 +1,4 @@
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useState, useEffect, useCallback, useRef } from 'react';
import { useApiRequest } from '../useApi';
import {
type Workflow,
@ -334,7 +334,6 @@ export function useWorkflowLifecycle() {
// Determine if polling should continue
const currentStatus = statusRef.current;
const changedAt = statusChangedFromRunningAtRef.current;
// Stop polling immediately for failed or stopped workflows
// For completed workflows, allow grace period (handled by useEffect)
@ -357,7 +356,7 @@ export function useWorkflowLifecycle() {
}, [request, updateWorkflowStatus, processUnifiedChatData]);
// Load initial workflow data (non-polling)
const loadWorkflowData = useCallback(async (id: string) => {
const _loadWorkflowData = useCallback(async (id: string) => {
try {
const workflowData = await fetchWorkflowApi(request, id).catch(() => null);
@ -416,6 +415,7 @@ export function useWorkflowLifecycle() {
console.error('Error loading workflow data:', error);
}
}, [request, updateWorkflowStatus, convertLogToFrontendFormat, processUnifiedChatData]);
void _loadWorkflowData; // Intentionally unused, reserved for future use
// Set up polling when workflow is running
useEffect(() => {

View file

@ -4,7 +4,7 @@ import { useMsal } from '@azure/msal-react';
import api from '../api';
import { useApiRequest } from './useApi';
import { getApiBaseUrl } from '../../config/config';
import { setUserDataCache, clearUserDataCache } from '../utils/userCache';
import { setUserDataCache, clearUserDataCache, type CachedUserData } from '../utils/userCache';
import {
loginApi,
fetchCurrentUserApi,
@ -44,7 +44,7 @@ export function useAuth() {
if (userData) {
// Cache user data in sessionStorage (cleared on tab close - more secure than localStorage)
setUserDataCache(userData);
setUserDataCache(userData as CachedUserData);
}
} catch (userError) {
console.error('Failed to fetch user data after login:', userError);
@ -171,7 +171,7 @@ export function useMsalAuth() {
try {
const userData = await fetchCurrentUserApi('msft');
if (userData) {
setUserDataCache(userData);
setUserDataCache(userData as CachedUserData);
}
} catch (userError) {
console.error('Failed to fetch user data after Microsoft login:', userError);
@ -349,7 +349,7 @@ export function useGoogleAuth() {
try {
const userData = await fetchCurrentUserApi('google');
if (userData) {
setUserDataCache(userData);
setUserDataCache(userData as CachedUserData);
}
} catch (userError) {
console.error('Failed to fetch user data after Google login:', userError);
@ -652,7 +652,7 @@ export function useCurrentUser() {
setUser(userData);
// Cache user data in sessionStorage (cleared on tab close - more secure than localStorage)
setUserDataCache(userData);
setUserDataCache(userData as CachedUserData);
return userData;
} catch (error: any) {

View file

@ -7,14 +7,12 @@ import { getUserDataCache } from '../utils/userCache';
import { useApiRequest } from './useApi';
import { usePermissions, type UserPermissions } from './usePermissions';
import {
fetchFileAttributes,
fetchFileAttributes as _fetchFileAttributes,
fetchFiles as fetchFilesApi,
fetchFileById as fetchFileByIdApi,
updateFile as updateFileApi,
deleteFile as deleteFileApi,
deleteFiles as deleteFilesApi,
type AttributeDefinition,
type PaginationParams
deleteFiles as deleteFilesApi
} from '../api/fileApi';
// File interfaces - exactly matching backend FileItem model
@ -32,7 +30,7 @@ export interface FileInfo {
// Field names come directly from backend attributes
export type UserFile = any;
// Attribute definition interface
// Attribute definition interface (local definition, not imported to avoid conflicts)
export interface AttributeDefinition {
name: string;
label: string;
@ -46,7 +44,7 @@ export interface AttributeDefinition {
filterOptions?: string[]; // For enum types
}
// Pagination parameters
// Pagination parameters (local definition, not imported to avoid conflicts)
export interface PaginationParams {
page?: number;
pageSize?: number;
@ -129,8 +127,7 @@ export function useUserFiles() {
if (!cachedUser) {
// User is not authenticated, skip fetching files
setFiles([]);
setLoading(false);
setError(null);
// Note: loading and error are managed by useApiRequest hook
return;
}

View file

@ -456,10 +456,10 @@ export function usePek() {
const firstCoord = clickedParcel.coordinates[0];
// Calculate centroid as fallback, but prefer a point we know is inside
const sumX = clickedParcel.coordinates.reduce((sum, coord) => sum + coord.x, 0);
const sumY = clickedParcel.coordinates.reduce((sum, coord) => sum + coord.y, 0);
const centroidX = sumX / clickedParcel.coordinates.length;
const centroidY = sumY / clickedParcel.coordinates.length;
// const sumX = clickedParcel.coordinates.reduce((sum, coord) => sum + coord.x, 0);
// const sumY = clickedParcel.coordinates.reduce((sum, coord) => sum + coord.y, 0);
// const _centroidX = sumX / clickedParcel.coordinates.length;
// const _centroidY = sumY / clickedParcel.coordinates.length;
// Use first coordinate (guaranteed to be on/in the parcel) for search
const locationString = `${firstCoord.x},${firstCoord.y}`;
@ -658,7 +658,7 @@ export function usePek() {
// Try to update the parcel via PUT request
try {
const updateResponse = await api.put(
await api.put(
`/api/realestate/parzelle/${parzelleResult.id}`,
updateParcelRequestBody
);

View file

@ -223,13 +223,8 @@ export function usePrompts() {
fieldType = 'string';
}
}
// Legacy support for old format
else if (attr.type === 'boolean') {
fieldType = 'boolean';
} else if (attr.type === 'enum' && attr.filterOptions) {
fieldType = 'enum';
options = attr.filterOptions.map(opt => ({ value: opt, label: opt }));
}
// Note: Legacy 'boolean' and 'enum' types are not in the AttributeDefinition type union
// If needed, they should be handled via type casting: (attr as any).type === 'boolean'
// Define validators and required fields
let required = attr.required === true;
@ -444,7 +439,7 @@ export function usePromptOperations() {
}
};
const handlePromptUpdate = async (promptId: string, updateData: { name: string; content: string }, originalData?: any) => {
const handlePromptUpdate = async (promptId: string, updateData: { name: string; content: string }, _originalData?: any) => {
setUpdateError(null);
try {

View file

@ -57,7 +57,7 @@ export function createSettingsHook(): () => GenericDataHook {
const currentUserIdRef = useRef<string | undefined>(currentUser?.id);
// Load phone name from localStorage
const loadPhoneName = useCallback((): string => {
const _loadPhoneName = useCallback((): string => {
try {
return localStorage.getItem('userPhoneName') || '';
} catch (error) {
@ -65,9 +65,10 @@ export function createSettingsHook(): () => GenericDataHook {
return '';
}
}, []);
void _loadPhoneName; // Intentionally unused, reserved for future use
// Load theme from localStorage
const loadTheme = useCallback((): string => {
const _loadTheme = useCallback((): string => {
try {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
@ -80,9 +81,10 @@ export function createSettingsHook(): () => GenericDataHook {
return 'light';
}
}, []);
void _loadTheme; // Intentionally unused, reserved for future use
// Load speech data from localStorage
const loadSpeechData = useCallback((): any | null => {
const _loadSpeechData = useCallback((): any | null => {
try {
const savedData = localStorage.getItem('speechSignUpData');
const timestamp = localStorage.getItem('speechSignUpTimestamp');
@ -109,9 +111,10 @@ export function createSettingsHook(): () => GenericDataHook {
return null;
}
}, []);
void _loadSpeechData; // Intentionally unused, reserved for future use
// Fetch user data from API
const fetchUserData = useCallback(async () => {
const _fetchUserData = useCallback(async () => {
if (!currentUser?.id) return null;
try {
@ -122,9 +125,10 @@ export function createSettingsHook(): () => GenericDataHook {
throw error;
}
}, [currentUser?.id, getUser]);
void _fetchUserData; // Intentionally unused, reserved for future use
// Fetch field definitions from backend
const fetchFieldsForSection = useCallback(async (sectionId: string): Promise<SettingsFieldConfig[]> => {
const _fetchFieldsForSection = useCallback(async (sectionId: string): Promise<SettingsFieldConfig[]> => {
try {
setSettingsLoading(prev => ({ ...prev, [sectionId]: true }));
setSettingsErrors(prev => ({ ...prev, [sectionId]: null }));
@ -148,6 +152,7 @@ export function createSettingsHook(): () => GenericDataHook {
setSettingsLoading(prev => ({ ...prev, [sectionId]: false }));
}
}, [request]);
void _fetchFieldsForSection; // Intentionally unused, reserved for future use
// Load all settings data
const loadSettingsData = useCallback(async () => {

View file

@ -125,14 +125,8 @@ export function useCurrentUser() {
}
try {
let logoutEndpoint = '/api/local/logout';
// Determine the correct logout endpoint based on authentication authority
if (user.authenticationAuthority === 'msft') {
logoutEndpoint = '/api/msft/logout';
} else if (user.authenticationAuthority === 'local') {
logoutEndpoint = '/api/local/logout';
}
// Note: logoutEndpoint is determined by logoutUserApi based on authenticationAuthority
await logoutUserApi(request, user.authenticationAuthority);
@ -498,13 +492,8 @@ export function useOrgUsers() {
fieldType = 'string';
}
}
// Legacy support for old format
else if (attr.type === 'boolean') {
fieldType = 'boolean';
} else if (attr.type === 'enum' && attr.filterOptions) {
fieldType = 'enum';
options = attr.filterOptions.map(opt => ({ value: opt, label: opt }));
}
// Note: Legacy 'boolean' and 'enum' types are not in the AttributeDefinition type union
// If needed, they should be handled via type casting: (attr as any).type === 'boolean'
// Define validators and required fields
let required = attr.required === true;
@ -547,7 +536,7 @@ export function useOrgUsers() {
key: attr.name,
label: attr.label || attr.name,
type: fieldType,
editable: attr.editable !== false && attr.readonly !== true,
editable: (attr as any).editable !== false && (attr as any).readonly !== true,
required,
validator,
minRows,
@ -652,7 +641,7 @@ export function useUserOperations() {
}
};
const handleUserUpdate = async (userId: string, updateData: UserUpdateData, originalData?: any) => {
const handleUserUpdate = async (userId: string, updateData: UserUpdateData, _originalData?: any) => {
setUpdateError(null);
setEditingUsers(prev => new Set(prev).add(userId));

View file

@ -19,7 +19,7 @@ import { MessageOverlay } from '../components/UiComponents';
import type { MessageMode } from '../components/UiComponents';
import { useLanguage } from '../providers/language/LanguageContext';
import { useWorkflowSelection } from '../contexts/WorkflowSelectionContext';
import { getUserDataCache } from '../utils/userCache';
// import { getUserDataCache } from '../utils/userCache'; // Unused import
import { usePermissions, type UserPermissions } from './usePermissions';
// Workflow interface matching backend
@ -279,13 +279,8 @@ export function useUserWorkflows() {
fieldType = 'string';
}
}
// Legacy support for old format
else if (attr.type === 'boolean') {
fieldType = 'boolean';
} else if (attr.type === 'enum' && attr.filterOptions) {
fieldType = 'enum';
options = attr.filterOptions.map(opt => ({ value: opt, label: opt }));
}
// Note: Legacy 'boolean' and 'enum' types are not in the AttributeDefinition type union
// If needed, they should be handled via type casting: (attr as any).type === 'boolean'
// Define validators and required fields
let required = attr.required === true;
@ -360,7 +355,7 @@ export function useUserWorkflows() {
// Listen for workflow creation events to refetch workflows list
useEffect(() => {
const handleWorkflowCreated = (event: CustomEvent<{ workflow: UserWorkflow }>) => {
const handleWorkflowCreated = (_event: CustomEvent<{ workflow: UserWorkflow }>) => {
// Refetch to ensure we have the latest data
fetchWorkflowsData();
};
@ -409,7 +404,7 @@ export function useWorkflowOperations() {
const [warningData, setWarningData] = useState<{ header: string; message: string; mode: MessageMode } | null>(null);
// Language context
const { t } = useLanguage();
const { t: _t } = useLanguage();
// Workflow selection context - to clear selection if deleted workflow is selected
const { selectedWorkflowId, clearWorkflow } = useWorkflowSelection();
@ -594,7 +589,7 @@ export function useWorkflowOperations() {
);
};
const handleWorkflowUpdate = async (workflowId: string, updateData: Partial<{ name: string; description?: string; tags?: string[] }>, originalWorkflowData?: any) => {
const handleWorkflowUpdate = async (workflowId: string, updateData: Partial<{ name: string; description?: string; tags?: string[] }>, _originalWorkflowData?: any) => {
setUpdateError(null);
setEditingWorkflows(prev => new Set(prev).add(workflowId));