diff --git a/app/_layout.tsx b/app/_layout.tsx index 6ec2267..a0419e6 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,11 +1,16 @@ import { Stack } from "expo-router"; +import { AuthProvider } from './context/AuthContext'; + export default function RootLayout() { return ( + + }} + > + + ); } diff --git a/app/envs/[env].tsx b/app/envs/[env].tsx index a17e0f4..6c5c6f8 100644 --- a/app/envs/[env].tsx +++ b/app/envs/[env].tsx @@ -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 { 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([]); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(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 ( + + + + ); + } + + if (error) { + return ( + + Error: {error} + + ); + } return ( - - Glob: {local.env} - Local: {glob.env} - + + + + {containers.map((container) => ( + + {container.Names[0].replace('/', '')} + Status: {container.Status} + State: {container.State} + Image: {container.Image} + + ))} + + + ); -} +} \ No newline at end of file diff --git a/app/index.tsx b/app/index.tsx index 3ff99ce..0fc5532 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -20,18 +20,15 @@ interface Environment { export default function Index() { return ( - - - ); } function MainContent() { const router = useRouter(); - const { isAuthenticated, domain, username, authData } = useAuth(); + const { isAuthenticated, domain, username, authData, clearAuth } = useAuth(); const [environmentData, setEnvironmentData] = useState(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -42,22 +39,35 @@ function MainContent() { setIsLoading(true); try { - const response = await fetch('https://portainer.evansteele.net/api/endpoints', { + const response = await fetch(`${domain}/api/endpoints`, { headers: { 'Authorization': `Bearer ${authData.jwt}` } }); + + if (!response.ok) { + await clearAuth(); + return; + } + const data = await response.json(); + + if (!data) { + await clearAuth(); + return; + } + setEnvironmentData(data); } catch (err : any) { setError(err.message); + await clearAuth(); } finally { setIsLoading(false); } }; fetchEnvironmentData(); - }, [isAuthenticated]); + }, [isAuthenticated, clearAuth]); if (!isAuthenticated) { return ( @@ -71,7 +81,7 @@ function MainContent() { - {environmentData && environmentData.map((environment, index) => ( + {Array.isArray(environmentData) && environmentData.map((environment, index) => (