Faas semi worfking

This commit is contained in:
2025-08-30 23:52:37 -04:00
parent 2778cbc512
commit 67bce24899
23 changed files with 1089 additions and 135 deletions

View File

@ -8,7 +8,7 @@ import { ExecutionModal } from './components/ExecutionModal';
import { FunctionDefinition } from './types';
// Default Mantine theme
const theme = {
const theme: any = {
colorScheme: 'light',
};
@ -20,6 +20,7 @@ const App: React.FC = () => {
const [refreshKey, setRefreshKey] = useState(0);
const handleCreateFunction = () => {
console.log('handleCreateFunction called');
setEditingFunction(null);
setFunctionFormOpened(true);
};
@ -94,4 +95,4 @@ const App: React.FC = () => {
);
};
export default App;
export default App;

View File

@ -16,7 +16,7 @@ import {
ActionIcon,
Tooltip,
} from '@mantine/core';
import { IconPlay, IconPlayerStop, IconRefresh, IconCopy } from '@tabler/icons-react';
import { IconPlayerPlay, IconPlayerStop, IconRefresh, IconCopy } from '@tabler/icons-react';
import { notifications } from '@mantine/notifications';
import { functionApi, executionApi } from '../services/api';
import { FunctionDefinition, ExecuteFunctionResponse, FunctionExecution } from '../types';
@ -209,7 +209,7 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
/>
<Group>
<Button
leftSection={<IconPlay size={16} />}
leftSection={<IconPlayerPlay size={16} />}
onClick={handleExecute}
loading={executing}
disabled={executing}
@ -320,4 +320,4 @@ export const ExecutionModal: React.FC<ExecutionModalProps> = ({
</Stack>
</Modal>
);
};
};

View File

@ -15,7 +15,7 @@ import {
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { notifications } from '@mantine/notifications';
import { functionApi } from '../services/api';
import { functionApi, runtimeApi } from '../services/api';
import { FunctionDefinition, CreateFunctionRequest, UpdateFunctionRequest, RuntimeType } from '../types';
interface FunctionFormProps {
@ -25,7 +25,6 @@ interface FunctionFormProps {
editFunction?: FunctionDefinition;
}
export const FunctionForm: React.FC<FunctionFormProps> = ({
opened,
onClose,
@ -34,14 +33,20 @@ export const FunctionForm: React.FC<FunctionFormProps> = ({
}) => {
const isEditing = !!editFunction;
const [runtimeOptions, setRuntimeOptions] = useState<Array<{value: string; label: string}>>([]);
// Default images for each runtime
const DEFAULT_IMAGES: Record<string, string> = {
'nodejs18': 'node:18-alpine',
'python3.9': 'python:3.9-alpine',
'go1.20': 'golang:1.20-alpine',
};
useEffect(() => {
// Fetch available runtimes from backend
const fetchRuntimes = async () => {
try {
const response = await fetch('http://localhost:8083/api/runtimes');
const data = await response.json();
setRuntimeOptions(data.runtimes || []);
const response = await runtimeApi.getRuntimes();
setRuntimeOptions(response.data.runtimes || []);
} catch (error) {
console.error('Failed to fetch runtimes:', error);
// Fallback to default options
@ -63,7 +68,7 @@ export const FunctionForm: React.FC<FunctionFormProps> = ({
name: editFunction?.name || '',
app_id: editFunction?.app_id || 'default',
runtime: editFunction?.runtime || 'nodejs18' as RuntimeType,
image: editFunction?.image || '',
image: editFunction?.image || DEFAULT_IMAGES['nodejs18'] || '',
handler: editFunction?.handler || 'index.handler',
code: editFunction?.code || '',
environment: editFunction?.environment ? JSON.stringify(editFunction.environment, null, 2) : '{}',
@ -87,19 +92,35 @@ export const FunctionForm: React.FC<FunctionFormProps> = ({
});
const handleRuntimeChange = (runtime: string | null) => {
// if (runtime && DEFAULT_IMAGES[runtime]) {
// form.setFieldValue('image', DEFAULT_IMAGES[runtime]);
// }
if (runtime && DEFAULT_IMAGES[runtime]) {
form.setFieldValue('image', DEFAULT_IMAGES[runtime]);
}
form.setFieldValue('runtime', runtime as RuntimeType);
};
const handleSubmit = async (values: typeof form.values) => {
console.log('handleSubmit called with values:', values);
console.log('Form validation errors:', form.errors);
console.log('Is form valid?', form.isValid());
// Check each field individually
const fieldNames = ['name', 'app_id', 'runtime', 'image', 'handler', 'timeout', 'memory'];
fieldNames.forEach(field => {
const error = form.validateField(field);
console.log(`Field ${field} error:`, error);
});
if (!form.isValid()) {
console.log('Form is not valid, validation errors:', form.errors);
return;
}
try {
// Parse environment variables JSON
let parsedEnvironment;
try {
parsedEnvironment = values.environment ? JSON.parse(values.environment) : undefined;
} catch (error) {
console.error('Error parsing environment variables:', error);
notifications.show({
title: 'Error',
message: 'Invalid JSON in environment variables',
@ -165,7 +186,15 @@ export const FunctionForm: React.FC<FunctionFormProps> = ({
title={isEditing ? 'Edit Function' : 'Create Function'}
size="lg"
>
<form onSubmit={form.onSubmit(handleSubmit)}>
<form onSubmit={(e) => {
console.log('Form submit event triggered');
console.log('Form values:', form.values);
console.log('Form errors:', form.errors);
console.log('Is form valid?', form.isValid());
const result = form.onSubmit(handleSubmit)(e);
console.log('Form onSubmit result:', result);
return result;
}}>
<Stack gap="md">
<Group grow>
<TextInput
@ -296,4 +325,4 @@ def handler(event, context):
</form>
</Modal>
);
};
};

View File

@ -15,7 +15,7 @@ import {
Tooltip,
} from '@mantine/core';
import {
IconPlay,
IconPlayerPlay,
IconSettings,
IconTrash,
IconRocket,
@ -49,7 +49,9 @@ export const FunctionList: React.FC<FunctionListProps> = ({
setLoading(true);
setError(null);
const response = await functionApi.list();
setFunctions(response.data.functions || []);
// Ensure we have a valid array
const functionsArray = response.data?.functions || [];
setFunctions(functionsArray);
} catch (err) {
console.error('Failed to load functions:', err);
setError('Failed to load functions');
@ -210,13 +212,15 @@ export const FunctionList: React.FC<FunctionListProps> = ({
</Table.Td>
<Table.Td>
<Text size="sm">
{func.owner.name}
<Text size="xs" c="dimmed">({func.owner.type})</Text>
{func.owner?.name || 'Unknown'}
{func.owner?.type && (
<Text size="xs" c="dimmed">({func.owner.type})</Text>
)}
</Text>
</Table.Td>
<Table.Td>
<Text size="sm">
{new Date(func.created_at).toLocaleDateString()}
{func.created_at ? new Date(func.created_at).toLocaleDateString() : 'N/A'}
</Text>
</Table.Td>
<Table.Td>
@ -228,7 +232,7 @@ export const FunctionList: React.FC<FunctionListProps> = ({
size="sm"
onClick={() => onExecuteFunction(func)}
>
<IconPlay size={16} />
<IconPlayerPlay size={16} />
</ActionIcon>
</Tooltip>
<Menu position="bottom-end">
@ -268,4 +272,4 @@ export const FunctionList: React.FC<FunctionListProps> = ({
)}
</Paper>
);
};
};

View File

@ -37,8 +37,10 @@ export const functionApi = {
params: { app_id: appId, limit, offset },
}),
create: (data: CreateFunctionRequest) =>
api.post<FunctionDefinition>('/functions', data),
create: (data: CreateFunctionRequest) => {
console.log('Making API call to create function with data:', data);
return api.post<FunctionDefinition>('/functions', data);
},
getById: (id: string) =>
api.get<FunctionDefinition>(`/functions/${id}`),
@ -85,4 +87,6 @@ export const healthApi = {
ready: () => api.get('/ready'),
};
export default api;
export const runtimeApi = {
getRuntimes: () => api.get('/runtimes'),
};