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) => (