|
@@ -1,38 +1,43 @@
|
|
|
|
+'use client';
|
|
|
|
+
|
|
import React from 'react';
|
|
import React from 'react';
|
|
import semver from 'semver';
|
|
import semver from 'semver';
|
|
import { toast } from 'react-hot-toast';
|
|
import { toast } from 'react-hot-toast';
|
|
import Markdown from '@/components/Markdown/Markdown';
|
|
import Markdown from '@/components/Markdown/Markdown';
|
|
import { IconStar } from '@tabler/icons-react';
|
|
import { IconStar } from '@tabler/icons-react';
|
|
import { useTranslations } from 'next-intl';
|
|
import { useTranslations } from 'next-intl';
|
|
-import { MessageKey } from '@/server/utils/errors';
|
|
|
|
-import { Button } from '../../../../components/ui/Button';
|
|
|
|
-import { useDisclosure } from '../../../../hooks/useDisclosure';
|
|
|
|
-import { RestartModal } from '../../components/RestartModal';
|
|
|
|
-import { trpc } from '../../../../utils/trpc';
|
|
|
|
-import { useSystemStore } from '../../../../state/systemStore';
|
|
|
|
|
|
+import { useDisclosure } from '@/client/hooks/useDisclosure';
|
|
|
|
+import { Button } from '@/components/ui/Button';
|
|
|
|
+import { useSystemStore } from '@/client/state/systemStore';
|
|
|
|
+import { useAction } from 'next-safe-action/hook';
|
|
|
|
+import { restartAction } from '@/actions/settings/restart';
|
|
|
|
+import { RestartModal } from '../RestartModal';
|
|
|
|
+
|
|
|
|
+type Props = { version: { current: string; latest: string; body?: string | null } };
|
|
|
|
|
|
-export const GeneralActions = () => {
|
|
|
|
|
|
+export const GeneralActions = (props: Props) => {
|
|
const t = useTranslations();
|
|
const t = useTranslations();
|
|
- const versionQuery = trpc.system.getVersion.useQuery(undefined, { staleTime: 0 });
|
|
|
|
|
|
+ const { version } = props;
|
|
|
|
|
|
const [loading, setLoading] = React.useState(false);
|
|
const [loading, setLoading] = React.useState(false);
|
|
const { setPollStatus } = useSystemStore();
|
|
const { setPollStatus } = useSystemStore();
|
|
const restartDisclosure = useDisclosure();
|
|
const restartDisclosure = useDisclosure();
|
|
|
|
|
|
const defaultVersion = '0.0.0';
|
|
const defaultVersion = '0.0.0';
|
|
- const isLatest = semver.gte(versionQuery.data?.current || defaultVersion, versionQuery.data?.latest || defaultVersion);
|
|
|
|
|
|
+ const isLatest = semver.gte(version.current || defaultVersion, version.latest || defaultVersion);
|
|
|
|
|
|
- const restart = trpc.system.restart.useMutation({
|
|
|
|
- onMutate: () => {
|
|
|
|
- setLoading(true);
|
|
|
|
|
|
+ const restartMutation = useAction(restartAction, {
|
|
|
|
+ onSuccess: (data) => {
|
|
|
|
+ if (data.success) {
|
|
|
|
+ setPollStatus(true);
|
|
|
|
+ } else {
|
|
|
|
+ restartDisclosure.close();
|
|
|
|
+ setLoading(false);
|
|
|
|
+ toast.error(data.failure.reason);
|
|
|
|
+ }
|
|
},
|
|
},
|
|
- onSuccess: async () => {
|
|
|
|
- setPollStatus(true);
|
|
|
|
- },
|
|
|
|
- onError: (e) => {
|
|
|
|
- restartDisclosure.close();
|
|
|
|
- setLoading(false);
|
|
|
|
- toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables }));
|
|
|
|
|
|
+ onExecute: () => {
|
|
|
|
+ setLoading(true);
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
|
|
@@ -43,7 +48,7 @@ export const GeneralActions = () => {
|
|
|
|
|
|
return (
|
|
return (
|
|
<div>
|
|
<div>
|
|
- {versionQuery.data?.body && (
|
|
|
|
|
|
+ {version.body && (
|
|
<div className="mt-3 card col-12 col-md-8">
|
|
<div className="mt-3 card col-12 col-md-8">
|
|
<div className="card-stamp">
|
|
<div className="card-stamp">
|
|
<div className="card-stamp-icon bg-yellow">
|
|
<div className="card-stamp-icon bg-yellow">
|
|
@@ -51,7 +56,7 @@ export const GeneralActions = () => {
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="card-body">
|
|
<div className="card-body">
|
|
- <Markdown className="">{versionQuery.data.body}</Markdown>
|
|
|
|
|
|
+ <Markdown className="">{version.body}</Markdown>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
)}
|
|
@@ -63,8 +68,8 @@ export const GeneralActions = () => {
|
|
<>
|
|
<>
|
|
<div className="card-body">
|
|
<div className="card-body">
|
|
<h2 className="mb-4">{t('settings.actions.title')}</h2>
|
|
<h2 className="mb-4">{t('settings.actions.title')}</h2>
|
|
- <h3 className="card-title mt-4">{t('settings.actions.current-version', { version: versionQuery.data?.current })}</h3>
|
|
|
|
- <p className="card-subtitle">{isLatest ? t('settings.actions.stay-up-to-date') : t('settings.actions.new-version', { version: versionQuery.data?.latest })}</p>
|
|
|
|
|
|
+ <h3 className="card-title mt-4">{t('settings.actions.current-version', { version: version.current })}</h3>
|
|
|
|
+ <p className="card-subtitle">{isLatest ? t('settings.actions.stay-up-to-date') : t('settings.actions.new-version', { version: version.latest })}</p>
|
|
{renderUpdate()}
|
|
{renderUpdate()}
|
|
<h3 className="card-title mt-4">{t('settings.actions.maintenance-title')}</h3>
|
|
<h3 className="card-title mt-4">{t('settings.actions.maintenance-title')}</h3>
|
|
<p className="card-subtitle">{t('settings.actions.maintenance-subtitle')}</p>
|
|
<p className="card-subtitle">{t('settings.actions.maintenance-subtitle')}</p>
|
|
@@ -72,7 +77,7 @@ export const GeneralActions = () => {
|
|
<Button onClick={restartDisclosure.open}>{t('settings.actions.restart')}</Button>
|
|
<Button onClick={restartDisclosure.open}>{t('settings.actions.restart')}</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <RestartModal isOpen={restartDisclosure.isOpen} onClose={restartDisclosure.close} onConfirm={() => restart.mutate()} loading={loading} />
|
|
|
|
|
|
+ <RestartModal isOpen={restartDisclosure.isOpen} onClose={restartDisclosure.close} onConfirm={() => restartMutation.execute()} loading={loading} />
|
|
</>
|
|
</>
|
|
);
|
|
);
|
|
};
|
|
};
|