runtipi/packages/dashboard/src/modules/Apps/containers/AppDetails.tsx
2022-05-23 21:06:48 +02:00

137 lines
4.7 KiB
TypeScript

import { SlideFade, Image, VStack, Flex, Divider, useDisclosure, useToast } from '@chakra-ui/react';
import React from 'react';
import { FiExternalLink } from 'react-icons/fi';
import { AppConfig } from '../../../core/types';
import { useAppsStore } from '../../../state/appsStore';
import { useSytemStore } from '../../../state/systemStore';
import AppActions from '../components/AppActions';
import InstallModal from '../components/InstallModal';
import StopModal from '../components/StopModal';
import UninstallModal from '../components/UninstallModal';
import UpdateModal from '../components/UpdateModal';
interface IProps {
app: AppConfig;
}
const AppDetails: React.FC<IProps> = ({ app }) => {
const toast = useToast();
const installDisclosure = useDisclosure();
const uninstallDisclosure = useDisclosure();
const stopDisclosure = useDisclosure();
const updateDisclosure = useDisclosure();
const { install, update, uninstall, stop, start, fetchApp } = useAppsStore();
const { internalIp } = useSytemStore();
const handleError = (error: unknown) => {
if (error instanceof Error) {
toast({
title: 'Error',
description: error.message,
status: 'error',
position: 'top',
isClosable: true,
});
fetchApp(app.id);
}
};
const handleInstallSubmit = async (values: Record<string, any>) => {
installDisclosure.onClose();
try {
await install(app.id, values);
} catch (error) {
handleError(error);
}
};
const handleUnistallSubmit = async () => {
uninstallDisclosure.onClose();
try {
await uninstall(app.id);
} catch (error) {
handleError(error);
}
};
const handleStopSubmit = async () => {
stopDisclosure.onClose();
try {
await stop(app.id);
} catch (error) {
handleError(error);
}
};
const handleStartSubmit = async () => {
try {
await start(app.id);
} catch (e: unknown) {
handleError(e);
}
};
const handleUpdateSubmit = async (values: Record<string, any>) => {
try {
await update(app.id, values);
toast({
title: 'Success',
description: 'App config updated successfully',
position: 'top',
status: 'success',
});
updateDisclosure.onClose();
} catch (error) {
handleError(error);
}
};
const handleOpen = () => {
window.open(`http://${internalIp}:${app.port}`, '_blank');
};
return (
<SlideFade in className="flex flex-1" offsetY="20px">
<div className="flex flex-1 p-4 mt-3 rounded-lg flex-col">
<Flex className="flex-col md:flex-row">
<Image src={app?.image} height={180} width={180} className="rounded-xl self-center sm:self-auto" alt={app.name} />
<VStack align="flex-start" justify="space-between" className="ml-0 md:ml-4">
<div className="mt-3 items-center self-center flex flex-col sm:items-start sm:self-start md:mt-0">
<h1 className="font-bold text-2xl">{app?.name}</h1>
<h2 className="text-center md:text-left">{app?.short_desc}</h2>
{app.source && (
<a target="_blank" rel="noreferrer" className="text-blue-500 text-xs" href={app?.source}>
<Flex className="mt-2 items-center">
Source
<FiExternalLink className="ml-1" />
</Flex>
</a>
)}
<p className="text-xs text-gray-600">By {app?.author}</p>
</div>
<div className="flex justify-center sm:absolute md:static top-0 right-5 self-center sm:self-auto">
<AppActions
onUpdate={updateDisclosure.onOpen}
onOpen={handleOpen}
onStart={handleStartSubmit}
onStop={stopDisclosure.onOpen}
onUninstall={uninstallDisclosure.onOpen}
onInstall={installDisclosure.onOpen}
app={app}
/>
</div>
</VStack>
</Flex>
<Divider className="mt-5" />
<p className="mt-3">{app?.description}</p>
<InstallModal onSubmit={handleInstallSubmit} isOpen={installDisclosure.isOpen} onClose={installDisclosure.onClose} app={app} />
<UninstallModal onConfirm={handleUnistallSubmit} isOpen={uninstallDisclosure.isOpen} onClose={uninstallDisclosure.onClose} app={app} />
<StopModal onConfirm={handleStopSubmit} isOpen={stopDisclosure.isOpen} onClose={stopDisclosure.onClose} app={app} />
<UpdateModal onSubmit={handleUpdateSubmit} isOpen={updateDisclosure.isOpen} onClose={updateDisclosure.onClose} app={app} />
</div>
</SlideFade>
);
};
export default AppDetails;