117 lines
3.3 KiB
TypeScript
117 lines
3.3 KiB
TypeScript
import { Text, View, ActivityIndicator } from 'react-native';
|
|
import { useEffect, useState } from 'react';
|
|
import { useLocalSearchParams, useGlobalSearchParams, Link } from 'expo-router';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
import { ScrollView } from 'react-native';
|
|
|
|
interface Container {
|
|
Id: string;
|
|
Names: string[];
|
|
Image: string;
|
|
ImageID: string;
|
|
Command: string;
|
|
Created: number;
|
|
State: string;
|
|
Status: string;
|
|
// Add other fields as needed
|
|
}
|
|
|
|
export default function Route() {
|
|
const glob = useGlobalSearchParams();
|
|
const local = useLocalSearchParams();
|
|
const { domain, username, authData } = useAuth();
|
|
const [containers, setContainers] = useState<Container[]>([]);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
fetchData();
|
|
}, []); // Empty dependency array means this runs once on mount
|
|
|
|
const fetchData = async () => {
|
|
setIsLoading(true);
|
|
try {
|
|
const response = await fetch(`${domain}/api/endpoints/${local.env}/docker/containers/json?all=true`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${authData.jwt}`
|
|
}
|
|
});
|
|
const data = await response.json();
|
|
setContainers(data);
|
|
} catch (error) {
|
|
console.error('Error fetching data:', error);
|
|
setError('Failed to fetch containers');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
<ActivityIndicator size="large" color="#0000ff" />
|
|
</View>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<View>
|
|
<Text>Error: {error}</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<SafeAreaProvider>
|
|
<SafeAreaView style={{ flex: 1, padding: 16, width: '100%' }}>
|
|
<ScrollView showsVerticalScrollIndicator={false}>
|
|
{containers.map((container) => (
|
|
<View key={container.Id} style={{
|
|
padding: 20,
|
|
marginVertical: 10,
|
|
backgroundColor: 'rgba(13, 71, 161, 0.1)',
|
|
borderRadius: 8,
|
|
borderLeftWidth: 6,
|
|
borderLeftColor: '#0D47A1',
|
|
shadowColor: '#000',
|
|
shadowOffset: {
|
|
width: 0,
|
|
height: 2,
|
|
},
|
|
shadowOpacity: 0.25,
|
|
shadowRadius: 3.84,
|
|
elevation: 5,
|
|
minHeight: 120,
|
|
borderWidth: 1,
|
|
borderColor: 'rgba(13, 71, 161, 0.2)',
|
|
}}>
|
|
<Text style={{
|
|
fontSize: 18,
|
|
fontWeight: 'bold',
|
|
color: '#0D47A1',
|
|
marginBottom: 8
|
|
}}>{container.Names[0].replace('/', '')}</Text>
|
|
<Text style={{
|
|
fontSize: 14,
|
|
color: '#1976D2',
|
|
marginBottom: 4
|
|
}}>Status: {container.Status}</Text>
|
|
<Text style={{
|
|
fontSize: 14,
|
|
color: container.State === 'running' ? '#2E7D32' : '#C62828',
|
|
marginBottom: 4
|
|
}}>State: {container.State}</Text>
|
|
<Text style={{
|
|
fontSize: 14,
|
|
color: '#1976D2',
|
|
marginBottom: 4
|
|
}}>Image: {container.Image}</Text>
|
|
</View>
|
|
))}
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
</SafeAreaProvider>
|
|
);
|
|
} |