mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-30 19:39:10 +00:00
fix: server port settings has lifecycle
This commit is contained in:
committed by
Carlos Valente
parent
ef5c0a371e
commit
d8cef11a25
@@ -3,6 +3,7 @@ import { serverURL } from '../../externals';
|
|||||||
// keys in tanstack store
|
// keys in tanstack store
|
||||||
export const APP_INFO = ['appinfo'];
|
export const APP_INFO = ['appinfo'];
|
||||||
export const APP_SETTINGS = ['appSettings'];
|
export const APP_SETTINGS = ['appSettings'];
|
||||||
|
export const APP_SERVER_PORT = ['appServerPort'];
|
||||||
export const APP_VERSION = ['appVersion'];
|
export const APP_VERSION = ['appVersion'];
|
||||||
export const AUTOMATION = ['automation'];
|
export const AUTOMATION = ['automation'];
|
||||||
export const CUSTOM_FIELDS = ['customFields'];
|
export const CUSTOM_FIELDS = ['customFields'];
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ export async function postShowWelcomeDialog(show: boolean) {
|
|||||||
/**
|
/**
|
||||||
* HTTP request to retrieve server port
|
* HTTP request to retrieve server port
|
||||||
*/
|
*/
|
||||||
export async function getServerPort(): Promise<PortInfo> {
|
export async function getServerPort(options?: RequestOptions): Promise<PortInfo> {
|
||||||
const res = await axios.get(`${settingsPath}/serverport`);
|
const res = await axios.get(`${settingsPath}/serverport`, { signal: options?.signal });
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
|
import { PortInfo } from 'ontime-types';
|
||||||
|
|
||||||
|
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||||
|
import { APP_SERVER_PORT } from '../api/constants';
|
||||||
|
import { getServerPort, postServerPort } from '../api/settings';
|
||||||
|
import { ontimeQueryClient } from '../queryClient';
|
||||||
|
|
||||||
|
const serverPortPlaceholder: PortInfo = {
|
||||||
|
port: 4001,
|
||||||
|
pendingRestart: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useServerPort() {
|
||||||
|
const { data, status, isError, refetch } = useQuery<PortInfo>({
|
||||||
|
queryKey: APP_SERVER_PORT,
|
||||||
|
queryFn: ({ signal }) => getServerPort({ signal }),
|
||||||
|
placeholderData: (previousData) => previousData,
|
||||||
|
refetchInterval: queryRefetchIntervalSlow,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { mutateAsync } = useMutation({
|
||||||
|
mutationFn: async (serverPort: number) => {
|
||||||
|
const response = await postServerPort(serverPort);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
onMutate: () => {
|
||||||
|
ontimeQueryClient.cancelQueries({ queryKey: APP_SERVER_PORT });
|
||||||
|
},
|
||||||
|
onSuccess: (newData) => {
|
||||||
|
ontimeQueryClient.setQueryData(APP_SERVER_PORT, newData);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data: data ?? serverPortPlaceholder, status, isError, refetch, mutateAsync };
|
||||||
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import { PortInfo } from 'ontime-types';
|
import { useEffect } from 'react';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { getServerPort, postServerPort } from '../../../../common/api/settings';
|
|
||||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||||
import Button from '../../../../common/components/buttons/Button';
|
import Button from '../../../../common/components/buttons/Button';
|
||||||
import Input from '../../../../common/components/input/input/Input';
|
import Input from '../../../../common/components/input/input/Input';
|
||||||
import Tag from '../../../../common/components/tag/Tag';
|
import Tag from '../../../../common/components/tag/Tag';
|
||||||
|
import useServerPort from '../../../../common/hooks-query/useServerPort';
|
||||||
import { preventEscape } from '../../../../common/utils/keyEvent';
|
import { preventEscape } from '../../../../common/utils/keyEvent';
|
||||||
import { isOnlyNumbers } from '../../../../common/utils/regex';
|
import { isOnlyNumbers } from '../../../../common/utils/regex';
|
||||||
import * as Panel from '../../panel-utils/PanelUtils';
|
import * as Panel from '../../panel-utils/PanelUtils';
|
||||||
@@ -16,29 +15,22 @@ interface ServerPortForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function ServerPortSettings() {
|
export default function ServerPortSettings() {
|
||||||
|
const { data, status, isError, refetch, mutateAsync } = useServerPort();
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
register,
|
register,
|
||||||
reset,
|
reset,
|
||||||
setError,
|
setError,
|
||||||
|
clearErrors,
|
||||||
formState: { isSubmitting, isDirty, isValid, errors },
|
formState: { isSubmitting, isDirty, isValid, errors },
|
||||||
} = useForm<ServerPortForm>({
|
} = useForm<ServerPortForm>({
|
||||||
mode: 'onChange',
|
mode: 'onChange',
|
||||||
defaultValues: { serverPort: 4001 },
|
defaultValues: { serverPort: 4001 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const [pendingRestart, setPendingRestart] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const setPort = useCallback((info: PortInfo) => {
|
|
||||||
reset({ serverPort: info.port });
|
|
||||||
setPendingRestart(info.pendingRestart);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getServerPort()
|
reset({ serverPort: data.port });
|
||||||
.then(setPort)
|
}, [data.pendingRestart, data.port, reset]);
|
||||||
.catch(() => setError('root', { message: 'Failed to load server port' }));
|
|
||||||
}, [reset, setError, setPort]);
|
|
||||||
|
|
||||||
const onSubmit = async (formData: ServerPortForm) => {
|
const onSubmit = async (formData: ServerPortForm) => {
|
||||||
if (formData.serverPort < 1024 || formData.serverPort > 65535) {
|
if (formData.serverPort < 1024 || formData.serverPort > 65535) {
|
||||||
@@ -46,21 +38,27 @@ export default function ServerPortSettings() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await postServerPort(formData.serverPort);
|
clearErrors('root');
|
||||||
setPort(await getServerPort());
|
await mutateAsync(formData.serverPort);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError('root', { message: maybeAxiosError(error) });
|
setError('root', { message: maybeAxiosError(error) });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onReset = async () => {
|
const onReset = async () => {
|
||||||
try {
|
clearErrors('root');
|
||||||
setPort(await getServerPort());
|
const result = await refetch();
|
||||||
} catch (error) {
|
|
||||||
|
if (result.isError) {
|
||||||
setError('root', { message: 'Failed to load server port' });
|
setError('root', { message: 'Failed to load server port' });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset({ serverPort: result.data?.port ?? data.port });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const rootError = isError ? 'Failed to load server port' : errors.root?.message;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Panel.Section
|
<Panel.Section
|
||||||
as='form'
|
as='form'
|
||||||
@@ -72,7 +70,7 @@ export default function ServerPortSettings() {
|
|||||||
<Panel.SubHeader>
|
<Panel.SubHeader>
|
||||||
Server port
|
Server port
|
||||||
<Panel.InlineElements>
|
<Panel.InlineElements>
|
||||||
{pendingRestart && <Tag>A port change is pending and will happen on the next restart</Tag>}
|
{data.pendingRestart && <Tag>A port change is pending and will happen on the next restart</Tag>}
|
||||||
<Button disabled={!isDirty || isSubmitting} variant='ghosted' onClick={onReset}>
|
<Button disabled={!isDirty || isSubmitting} variant='ghosted' onClick={onReset}>
|
||||||
Revert to saved
|
Revert to saved
|
||||||
</Button>
|
</Button>
|
||||||
@@ -88,7 +86,8 @@ export default function ServerPortSettings() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Panel.InlineElements>
|
</Panel.InlineElements>
|
||||||
</Panel.SubHeader>
|
</Panel.SubHeader>
|
||||||
{errors.root && <Panel.Error>{errors.root.message}</Panel.Error>}
|
<Panel.Loader isLoading={status === 'pending'} />
|
||||||
|
{rootError && <Panel.Error>{rootError}</Panel.Error>}
|
||||||
<Panel.Divider />
|
<Panel.Divider />
|
||||||
<Panel.Section>
|
<Panel.Section>
|
||||||
<Panel.ListGroup>
|
<Panel.ListGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user