refactor(get-status): use client-side fetch and API route instead of server action
This commit is contained in:
parent
454ade2e2c
commit
06bf92daa5
5 changed files with 32 additions and 50 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
9
src/app/api/get-status/route.ts
Normal file
9
src/app/api/get-status/route.ts
Normal 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 });
|
||||
}
|
|
@ -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') {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue