refactor(get-status): use client-side fetch and API route instead of server action

This commit is contained in:
Nicolas Meienberger 2023-10-14 13:07:39 +02:00
parent 454ade2e2c
commit 06bf92daa5
5 changed files with 32 additions and 50 deletions

View file

@ -20,7 +20,7 @@ export const GeneralActions = (props: Props) => {
const { version } = props;
const [loading, setLoading] = React.useState(false);
const { setPollStatus } = useSystemStore();
const { setPollStatus, setStatus } = useSystemStore();
const restartDisclosure = useDisclosure();
const defaultVersion = '0.0.0';
@ -30,6 +30,7 @@ export const GeneralActions = (props: Props) => {
onSuccess: (data) => {
if (data.success) {
setPollStatus(true);
setStatus('RESTARTING');
} else {
restartDisclosure.close();
setLoading(false);

View file

@ -1,22 +0,0 @@
'use server';
import { z } from 'zod';
import { action } from '@/lib/safe-action';
import { getConfig } from '@/server/core/TipiConfig';
import { handleActionError } from '../utils/handle-action-error';
const input = z.object({ currentStatus: z.string() });
/**
* Fetches the system status and compares it to the current status
* If the status has changed, it will revalidate the whole app
*/
export const getStatusAction = action(input, async () => {
try {
const { status } = getConfig();
return { success: true, status };
} catch (e) {
return handleActionError(e);
}
});

View file

@ -0,0 +1,9 @@
import { TipiCache } from '@/server/core/TipiCache';
export async function GET() {
const cache = new TipiCache('getStatus');
const status = (await cache.get('status')) || 'RUNNING';
await cache.close();
return Response.json({ success: true, status });
}

View file

@ -1,39 +1,31 @@
'use client';
import React, { useRef, useEffect } from 'react';
import { useAction } from 'next-safe-action/hook';
import { useInterval } from 'usehooks-ts';
import { getStatusAction } from '@/actions/settings/get-status';
import { useSystemStore } from '@/client/state/systemStore';
import { SystemStatus, useSystemStore } from '@/client/state/systemStore';
import { useRouter } from 'next/navigation';
import useSWR, { Fetcher } from 'swr';
import { StatusScreen } from '../../StatusScreen';
interface IProps {
children: React.ReactNode;
}
const fetcher: Fetcher<{ status: SystemStatus }> = () => fetch('/api/get-status').then((res) => res.json() as Promise<{ status: SystemStatus }>);
export const StatusProvider: React.FC<IProps> = ({ children }) => {
const { status, setStatus, pollStatus, setPollStatus } = useSystemStore();
const s = useRef(status);
const router = useRouter();
const getStatusMutation = useAction(getStatusAction, {
onSuccess: (data) => {
if (data?.success) {
setStatus(data.status);
}
useSWR('/api/get-status', fetcher, {
refreshInterval: pollStatus ? 2000 : 0,
isPaused: () => !pollStatus,
onSuccess: (res) => {
setStatus(res.status);
},
});
// Poll status every 5 seconds
useInterval(
() => {
getStatusMutation.execute({ currentStatus: status });
},
pollStatus ? 2000 : null,
);
useEffect(() => {
// If previous was not running and current is running, we need to refresh the page
if (status === 'RUNNING' && s.current !== 'RUNNING') {

View file

@ -5,7 +5,7 @@ import { EventDispatcher } from '@/server/core/EventDispatcher';
import { TipiCache } from '@/server/core/TipiCache';
import { readJsonFile } from '../../common/fs.helpers';
import { Logger } from '../../core/Logger';
import * as TipiConfig from '../../core/TipiConfig';
import { getConfig } from '../../core/TipiConfig';
const SYSTEM_STATUS = ['UPDATING', 'RESTARTING', 'RUNNING'] as const;
type SystemStatus = (typeof SYSTEM_STATUS)[keyof typeof SYSTEM_STATUS];
@ -35,8 +35,7 @@ export class SystemServiceClass {
public getVersion = async () => {
const cache = new TipiCache('getVersion');
try {
const { seePreReleaseVersions } = TipiConfig.getConfig();
const currentVersion = TipiConfig.getConfig().version;
const { seePreReleaseVersions, version: currentVersion } = getConfig();
if (seePreReleaseVersions) {
const { data } = await axios.get<{ tag_name: string; body: string }[]>('https://api.github.com/repos/runtipi/runtipi/releases');
@ -57,10 +56,10 @@ export class SystemServiceClass {
await cache.set('latestVersionBody', body || '', 60 * 60);
}
return { current: TipiConfig.getConfig().version, latest: version, body };
return { current: getConfig().version, latest: version, body };
} catch (e) {
Logger.error(e);
return { current: TipiConfig.getConfig().version, latest: TipiConfig.getConfig().version, body: '' };
return { current: getConfig().version, latest: getConfig().version, body: '' };
} finally {
await cache.close();
}
@ -79,15 +78,18 @@ export class SystemServiceClass {
};
public restart = async (): Promise<boolean> => {
if (TipiConfig.getConfig().NODE_ENV === 'development') {
if (getConfig().NODE_ENV === 'development') {
throw new TranslatedError('server-messages.errors.not-allowed-in-dev');
}
if (TipiConfig.getConfig().demoMode) {
if (getConfig().demoMode) {
throw new TranslatedError('server-messages.errors.not-allowed-in-demo');
}
TipiConfig.setConfig('status', 'RESTARTING');
const cache = new TipiCache('restart');
await cache.set('status', 'RESTARTING', 360);
await cache.close();
const dispatcher = new EventDispatcher('restart');
dispatcher.dispatchEvent({ type: 'system', command: 'restart' });
await dispatcher.close();
@ -95,7 +97,7 @@ export class SystemServiceClass {
return true;
};
public static status = async (): Promise<{ status: SystemStatus }> => ({
status: TipiConfig.getConfig().status,
public static status = (): { status: SystemStatus } => ({
status: getConfig().status,
});
}