mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-14 11:53:49 +00:00
v2 about (#362)
* chore: remove unused assets * feat: about ontime * refactor: cleanup unused
This commit is contained in:
@@ -4,6 +4,7 @@ import { Box, useDisclosure } from '@chakra-ui/react';
|
||||
import ErrorBoundary from '../../common/components/error-boundary/ErrorBoundary';
|
||||
import UploadModal from '../../common/components/upload-modal/UploadModal';
|
||||
import MenuBar from '../menu/MenuBar';
|
||||
import AboutModal from '../modals/about-modal/AboutModal';
|
||||
import IntegrationModal from '../modals/integration-modal/IntegrationModal';
|
||||
import ModalManager from '../modals/ModalManager';
|
||||
|
||||
@@ -23,6 +24,7 @@ export default function Editor() {
|
||||
onOpen: onIntegrationModalOpen,
|
||||
onClose: onIntegrationModalClose,
|
||||
} = useDisclosure();
|
||||
const { isOpen: isAboutModalOpen, onOpen: onAboutModalOpen, onClose: onAboutModalClose } = useDisclosure();
|
||||
|
||||
// Set window title
|
||||
useEffect(() => {
|
||||
@@ -31,9 +33,10 @@ export default function Editor() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<UploadModal onClose={onUploadModalClose} isOpen={isUploadModalOpen} />
|
||||
<IntegrationModal onClose={onIntegrationModalClose} isOpen={isIntegrationModalOpen} />
|
||||
<ErrorBoundary>
|
||||
<UploadModal onClose={onUploadModalClose} isOpen={isUploadModalOpen} />
|
||||
<IntegrationModal onClose={onIntegrationModalClose} isOpen={isIntegrationModalOpen} />
|
||||
<AboutModal onClose={onAboutModalClose} isOpen={isAboutModalOpen} />
|
||||
<ModalManager isOpen={isSettingsOpen} onClose={onSettingsClose} />
|
||||
</ErrorBoundary>
|
||||
<div className={styles.mainContainer} data-testid='event-editor'>
|
||||
@@ -47,6 +50,8 @@ export default function Editor() {
|
||||
onUploadOpen={onUploadModalOpen}
|
||||
isIntegrationOpen={isIntegrationModalOpen}
|
||||
onIntegrationOpen={onIntegrationModalOpen}
|
||||
isAboutOpen={isAboutModalOpen}
|
||||
onAboutOpen={onAboutModalOpen}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
|
||||
@@ -25,10 +25,10 @@ interface MenuBarProps {
|
||||
onUploadOpen: () => void;
|
||||
isIntegrationOpen: boolean;
|
||||
onIntegrationOpen: () => void;
|
||||
isAboutOpen: boolean;
|
||||
onAboutOpen: () => void;
|
||||
}
|
||||
|
||||
type Actions = 'min' | 'max' | 'shutdown' | 'help';
|
||||
|
||||
const buttonStyle = {
|
||||
fontSize: '1.5em',
|
||||
size: 'lg',
|
||||
@@ -50,6 +50,8 @@ export default function MenuBar(props: MenuBarProps) {
|
||||
onUploadOpen,
|
||||
isIntegrationOpen,
|
||||
onIntegrationOpen,
|
||||
isAboutOpen,
|
||||
onAboutOpen,
|
||||
} = props;
|
||||
const { isElectron, sendToElectron } = useElectronEvent();
|
||||
|
||||
@@ -58,28 +60,11 @@ export default function MenuBar(props: MenuBarProps) {
|
||||
|
||||
const setRunMode = () => setAppMode(AppMode.Run);
|
||||
const setEditMode = () => setAppMode(AppMode.Edit);
|
||||
|
||||
const actionHandler = useCallback(
|
||||
(action: Actions) => {
|
||||
if (!isElectron) {
|
||||
if (action === 'help') {
|
||||
window.open('https://cpvalente.gitbook.io/ontime/');
|
||||
}
|
||||
} else {
|
||||
switch (action) {
|
||||
case 'shutdown':
|
||||
sendToElectron('shutdown', 'now');
|
||||
break;
|
||||
case 'help':
|
||||
sendToElectron('send-to-link', 'help');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
[sendToElectron, isElectron],
|
||||
);
|
||||
const sendShutdown = () => {
|
||||
if (isElectron) {
|
||||
sendToElectron('shutdown', 'now');
|
||||
}
|
||||
};
|
||||
|
||||
// Handle keyboard shortcuts
|
||||
const handleKeyPress = useCallback(
|
||||
@@ -112,7 +97,7 @@ export default function MenuBar(props: MenuBarProps) {
|
||||
|
||||
return (
|
||||
<VStack>
|
||||
<QuitIconBtn clickHandler={() => actionHandler('shutdown')} />
|
||||
<QuitIconBtn disabled={!isElectron} clickHandler={sendShutdown} />
|
||||
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
@@ -169,10 +154,11 @@ export default function MenuBar(props: MenuBarProps) {
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
className={isAboutOpen ? style.open : ''}
|
||||
icon={<IoHelpCircleOutline />}
|
||||
clickHandler={() => actionHandler('help')}
|
||||
tooltip='Help'
|
||||
aria-label='Help'
|
||||
clickHandler={onAboutOpen}
|
||||
tooltip='About'
|
||||
aria-label='About'
|
||||
/>
|
||||
</VStack>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import isEqual from 'react-fast-compare';
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
@@ -17,8 +16,7 @@ import { FiX } from '@react-icons/all-files/fi/FiX';
|
||||
|
||||
import { useEmitLog } from '@/common/stores/logger';
|
||||
|
||||
import { version } from '../../../package.json';
|
||||
import { getLatestVersion, postSettings } from '../../common/api/ontimeApi';
|
||||
import { postSettings } from '../../common/api/ontimeApi';
|
||||
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
||||
import useSettings from '../../common/hooks-query/useSettings';
|
||||
import { ontimePlaceholderSettings } from '../../common/models/OntimeSettings';
|
||||
@@ -42,9 +40,6 @@ export default function AppSettingsModal() {
|
||||
|
||||
const [formSettings, setFormSettings] = useState(eventSettings);
|
||||
|
||||
const [updateMessage, setUpdateMessage] = useState(<a>Using ontime version: {version}</a>);
|
||||
const [isFetching, setIsFetching] = useState(false);
|
||||
|
||||
/**
|
||||
* Set formdata from server state
|
||||
*/
|
||||
@@ -55,9 +50,6 @@ export default function AppSettingsModal() {
|
||||
pinCode: data.pinCode,
|
||||
timeFormat: data.timeFormat,
|
||||
});
|
||||
// getLatestVersion().then((data) => {
|
||||
// setVersionData(data);
|
||||
// });
|
||||
}, [changed, data]);
|
||||
|
||||
/**
|
||||
@@ -137,32 +129,6 @@ export default function AppSettingsModal() {
|
||||
setChanged(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles version comparison and returns component with message
|
||||
*/
|
||||
const versionCheck = async () => {
|
||||
let message = <a>Using latest version</a>;
|
||||
setIsFetching(true);
|
||||
getLatestVersion()
|
||||
.then((data) => {
|
||||
const remoteVersion = data;
|
||||
if (!remoteVersion.version.includes(version)) {
|
||||
message = (
|
||||
<a href={remoteVersion.url} target='_blank' rel='noreferrer'>
|
||||
Update to version {remoteVersion.version} available
|
||||
</a>
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
message = <a>Error reaching server</a>;
|
||||
})
|
||||
.finally(function () {
|
||||
setUpdateMessage(message);
|
||||
setIsFetching(false);
|
||||
});
|
||||
};
|
||||
|
||||
const disableModal = status !== 'success';
|
||||
|
||||
return (
|
||||
@@ -283,12 +249,6 @@ export default function AppSettingsModal() {
|
||||
Event default public
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div className={style.notes}>
|
||||
{updateMessage}
|
||||
<Button onClick={versionCheck} isLoading={isFetching}>
|
||||
Check for updates
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<SubmitContainer revert={revert} submitting={submitting} changed={changed} status={status} />
|
||||
</form>
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
@use '../../theme/v2Styles' as *;
|
||||
@use '../../theme/ontimeColours' as *;
|
||||
|
||||
.headerNotes {
|
||||
@mixin modal-link {
|
||||
color: $blue-500;
|
||||
transition-property: color;
|
||||
transition-duration: $transition-time-action;
|
||||
|
||||
&:hover {
|
||||
color: $ontime-color;
|
||||
}
|
||||
}
|
||||
|
||||
.headerNotes {
|
||||
font-size: $text-body-size;
|
||||
width: 100%;
|
||||
padding: 0 $section-spacing;
|
||||
@@ -10,13 +20,7 @@
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: $blue-500;
|
||||
transition-property: color;
|
||||
transition-duration: $transition-time-action;
|
||||
|
||||
&:hover {
|
||||
color: $ontime-color;
|
||||
}
|
||||
@include modal-link
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +101,33 @@
|
||||
|
||||
.showPointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.twoColumn {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.padBottom {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: inline-block;
|
||||
vertical-align: text-bottom;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.test {
|
||||
padding-top: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
|
||||
.error {
|
||||
font-size: $error-red;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
@use '../../theme/v2Styles' as *;
|
||||
@use '../../theme/ontimeColours' as *;
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
color: $blue-500;
|
||||
transition-property: color;
|
||||
transition-duration: $transition-time-action;
|
||||
|
||||
&:hover {
|
||||
color: $ontime-color;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { IoOpenOutline } from '@react-icons/all-files/io5/IoOpenOutline';
|
||||
|
||||
import style from './ModalLink.module.scss';
|
||||
|
||||
interface ModalLinkProps {
|
||||
href: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function ModalLink(props: ModalLinkProps) {
|
||||
const { href, children } = props;
|
||||
return (
|
||||
<a href={href} target='_blank' rel='noreferrer' className={style.link}>
|
||||
{children} <IoOpenOutline />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -5,10 +5,11 @@ interface ModalWrapperProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
size?: string;
|
||||
}
|
||||
|
||||
export default function ModalWrapper(props: PropsWithChildren<ModalWrapperProps>) {
|
||||
const { isOpen, onClose, title, children } = props;
|
||||
const { isOpen, onClose, title, size = 'xl', children } = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -16,7 +17,7 @@ export default function ModalWrapper(props: PropsWithChildren<ModalWrapperProps>
|
||||
isOpen={isOpen}
|
||||
closeOnOverlayClick={false}
|
||||
motionPreset='slideInBottom'
|
||||
size='xl'
|
||||
size={size}
|
||||
scrollBehavior='inside'
|
||||
preserveScrollBarGap
|
||||
variant='ontime'
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
@use '../../theme/ontimeColours' as *;
|
||||
@use '../../theme/v2Styles' as *;
|
||||
|
||||
// style file to be deprecated
|
||||
|
||||
//////////////////////////////////// main
|
||||
|
||||
.modalBody {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react';
|
||||
|
||||
import { ReactComponent as OntimeLogo } from '@/assets/images/ontime-logo.svg';
|
||||
|
||||
import { version } from '../../../../package.json';
|
||||
import { gitbookUrl, githubUrl } from '../../../externals';
|
||||
import ModalLink from '../ModalLink';
|
||||
|
||||
import UpdateChecker from './UpdateChecker';
|
||||
|
||||
import styles from '../Modal.module.scss';
|
||||
|
||||
interface AboutModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function AboutModal(props: AboutModalProps) {
|
||||
const { isOpen, onClose } = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
size='sm'
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
closeOnOverlayClick={false}
|
||||
motionPreset='slideInBottom'
|
||||
scrollBehavior='inside'
|
||||
preserveScrollBarGap
|
||||
variant='ontime-small'
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
About Ontime
|
||||
<ModalCloseButton />
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody className={styles.body}>
|
||||
<div className={styles.twoColumn}>
|
||||
<OntimeLogo className={styles.logo} />
|
||||
<div>
|
||||
<div className={styles.padBottom}>
|
||||
<span className={styles.sectionTitle}>Ontime</span>
|
||||
Free Open Source Software for managing rundowns and event timers
|
||||
<ModalLink href='www.getontime.no'>www.getontime.no</ModalLink>
|
||||
</div>
|
||||
<div className={styles.padBottom}>
|
||||
<span className={styles.sectionTitle}>Current version</span>
|
||||
|
||||
{`You are currently using Ontime ${version}`}
|
||||
</div>
|
||||
<div className={styles.padBottom}>
|
||||
<span className={styles.sectionTitle}>Docs</span>
|
||||
<ModalLink href={gitbookUrl}>Read the docs over at GitBook</ModalLink>
|
||||
</div>
|
||||
<div>
|
||||
<span className={styles.sectionTitle}>Github</span>
|
||||
<ModalLink href={githubUrl}>Follow the project on GitHub</ModalLink>
|
||||
</div>
|
||||
<UpdateChecker version={version} />
|
||||
</div>
|
||||
</div>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@chakra-ui/react';
|
||||
|
||||
import { getLatestVersion, HasUpdate } from '../../../common/api/ontimeApi';
|
||||
import ModalLink from '../ModalLink';
|
||||
|
||||
import styles from '../Modal.module.scss';
|
||||
|
||||
interface UpdateCheckerProps {
|
||||
version: string;
|
||||
}
|
||||
|
||||
type CheckFail = {
|
||||
error: string;
|
||||
};
|
||||
|
||||
type CheckIsLatest = {
|
||||
latest: true;
|
||||
};
|
||||
|
||||
type CheckRemote = CheckFail | CheckIsLatest | HasUpdate;
|
||||
|
||||
export default function UpdateChecker(props: UpdateCheckerProps) {
|
||||
const { version } = props;
|
||||
const [updateMessage, setUpdateMessage] = useState<CheckRemote | null>(null);
|
||||
const [isFetching, setIsFetching] = useState(false);
|
||||
|
||||
/**
|
||||
* Handles version comparison and returns component with message
|
||||
*/
|
||||
const versionCheck = async () => {
|
||||
setIsFetching(true);
|
||||
|
||||
try {
|
||||
const latest = await getLatestVersion();
|
||||
|
||||
if (!latest.version.includes(version)) {
|
||||
// new version, pass data to component
|
||||
setUpdateMessage(latest);
|
||||
} else {
|
||||
setUpdateMessage({ latest: true });
|
||||
}
|
||||
} catch {
|
||||
setUpdateMessage({ error: 'Error reaching server' });
|
||||
} finally {
|
||||
setIsFetching(false);
|
||||
}
|
||||
};
|
||||
|
||||
const disableButton = Boolean(updateMessage && 'version' in updateMessage);
|
||||
|
||||
return (
|
||||
<div className={styles.test}>
|
||||
<Button onClick={versionCheck} variant='ontime-filled' isLoading={isFetching} isDisabled={disableButton}>
|
||||
Check for updates
|
||||
</Button>
|
||||
<ResolveUpdateMessage updateMessage={updateMessage} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ResolveUpdateMessage(props: { updateMessage: CheckRemote | null }) {
|
||||
const { updateMessage } = props;
|
||||
|
||||
if (updateMessage && 'error' in updateMessage) {
|
||||
return <span className={styles.error}>{updateMessage.error}</span>;
|
||||
}
|
||||
if (updateMessage && 'url' in updateMessage) {
|
||||
return <ModalLink href={updateMessage?.url}>{`New version available: ${updateMessage.version}`}</ModalLink>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user