new view for containers, authProvider update
This commit is contained in:
parent
69d5082363
commit
8e6b0cc930
|
|
@ -1,11 +1,16 @@
|
||||||
import { Stack } from "expo-router";
|
import { Stack } from "expo-router";
|
||||||
|
import { AuthProvider } from './context/AuthContext';
|
||||||
|
|
||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
return (
|
return (
|
||||||
|
<AuthProvider>
|
||||||
<Stack
|
<Stack
|
||||||
screenOptions={{
|
screenOptions={{
|
||||||
headerTitle: "Portainer Manager"
|
headerTitle: "Portainer Manager"
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
</Stack>
|
||||||
|
</AuthProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,117 @@
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View, ActivityIndicator } from 'react-native';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocalSearchParams, useGlobalSearchParams, Link } from 'expo-router';
|
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() {
|
export default function Route() {
|
||||||
const glob = useGlobalSearchParams();
|
const glob = useGlobalSearchParams();
|
||||||
const local = useLocalSearchParams();
|
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 (
|
return (
|
||||||
<View>
|
<SafeAreaProvider>
|
||||||
<Text>Glob: {local.env}</Text>
|
<SafeAreaView style={{ flex: 1, padding: 16, width: '100%' }}>
|
||||||
<Text>Local: {glob.env}</Text>
|
<ScrollView showsVerticalScrollIndicator={false}>
|
||||||
</View>
|
{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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -20,18 +20,15 @@ interface Environment {
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<AuthProvider>
|
|
||||||
<View style={{ flex: 1, padding: 16, width: '100%' }}>
|
<View style={{ flex: 1, padding: 16, width: '100%' }}>
|
||||||
<MainContent />
|
<MainContent />
|
||||||
</View>
|
</View>
|
||||||
</AuthProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MainContent() {
|
function MainContent() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { isAuthenticated, domain, username, authData } = useAuth();
|
const { isAuthenticated, domain, username, authData, clearAuth } = useAuth();
|
||||||
const [environmentData, setEnvironmentData] = useState<Environment[] | null>(null);
|
const [environmentData, setEnvironmentData] = useState<Environment[] | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
@ -42,22 +39,35 @@ function MainContent() {
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://portainer.evansteele.net/api/endpoints', {
|
const response = await fetch(`${domain}/api/endpoints`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${authData.jwt}`
|
'Authorization': `Bearer ${authData.jwt}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
await clearAuth();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
await clearAuth();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setEnvironmentData(data);
|
setEnvironmentData(data);
|
||||||
} catch (err : any) {
|
} catch (err : any) {
|
||||||
setError(err.message);
|
setError(err.message);
|
||||||
|
await clearAuth();
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchEnvironmentData();
|
fetchEnvironmentData();
|
||||||
}, [isAuthenticated]);
|
}, [isAuthenticated, clearAuth]);
|
||||||
|
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -71,7 +81,7 @@ function MainContent() {
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<SafeAreaView style={{ flex: 1, padding: 16, width: '100%' }}>
|
<SafeAreaView style={{ flex: 1, padding: 16, width: '100%' }}>
|
||||||
<ScrollView showsVerticalScrollIndicator={false}>
|
<ScrollView showsVerticalScrollIndicator={false}>
|
||||||
{environmentData && environmentData.map((environment, index) => (
|
{Array.isArray(environmentData) && environmentData.map((environment, index) => (
|
||||||
<EnvironmentCard
|
<EnvironmentCard
|
||||||
key={index}
|
key={index}
|
||||||
name={environment.Name}
|
name={environment.Name}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue