Add the status indicator for new versions

This commit is contained in:
ajnart
2022-12-20 15:21:36 +09:00
parent 11b111209a
commit 9996ff1529
4 changed files with 89 additions and 17 deletions

View File

@@ -1,9 +1,11 @@
import { import {
ActionIcon, ActionIcon,
Anchor,
Badge, Badge,
Button, Button,
createStyles, createStyles,
Group, Group,
HoverCard,
Modal, Modal,
Table, Table,
Text, Text,
@@ -17,6 +19,7 @@ import {
IconVocabulary, IconVocabulary,
IconWorldWww, IconWorldWww,
} from '@tabler/icons'; } from '@tabler/icons';
import { motion } from 'framer-motion';
import { InitOptions } from 'i18next'; import { InitOptions } from 'i18next';
import { i18n } from 'next-i18next'; import { i18n } from 'next-i18next';
import Image from 'next/image'; import Image from 'next/image';
@@ -27,12 +30,13 @@ import { usePrimaryGradient } from '../layout/useGradient';
interface AboutModalProps { interface AboutModalProps {
opened: boolean; opened: boolean;
closeModal: () => void; closeModal: () => void;
newVersionAvailable?: string;
} }
export const AboutModal = ({ opened, closeModal }: AboutModalProps) => { export const AboutModal = ({ opened, closeModal, newVersionAvailable }: AboutModalProps) => {
const { classes } = useStyles(); const { classes } = useStyles();
const colorGradiant = usePrimaryGradient(); const colorGradiant = usePrimaryGradient();
const informations = useInformationTableItems(); const informations = useInformationTableItems(newVersionAvailable);
return ( return (
<Modal <Modal
@@ -123,7 +127,8 @@ interface ExtendedInitOptions extends InitOptions {
locales: string[]; locales: string[];
} }
const useInformationTableItems = (): InformationTableItem[] => { const useInformationTableItems = (newVersionAvailable?: string): InformationTableItem[] => {
// TODO: Fix this to not request. Pass it as a prop.
const colorGradiant = usePrimaryGradient(); const colorGradiant = usePrimaryGradient();
let items: InformationTableItem[] = []; let items: InformationTableItem[] = [];
@@ -161,9 +166,41 @@ const useInformationTableItems = (): InformationTableItem[] => {
icon: <IconVersions size={20} />, icon: <IconVersions size={20} />,
label: 'Homarr version', label: 'Homarr version',
content: ( content: (
<Group position="right">
<Badge variant="gradient" gradient={colorGradiant}> <Badge variant="gradient" gradient={colorGradiant}>
{CURRENT_VERSION} {CURRENT_VERSION}
</Badge> </Badge>
{newVersionAvailable && (
<HoverCard shadow="md" position="top" withArrow>
<HoverCard.Target>
<motion.div
initial={{ scale: 1.2 }}
animate={{
scale: [0.8, 1.10, 1],
rotate: [0, 10, 0],
}}
transition={{ duration: 0.8, ease: 'easeInOut' }}
>
<Badge color="green" variant="filled">
new: {newVersionAvailable}
</Badge>
</motion.div>
</HoverCard.Target>
<HoverCard.Dropdown>
Version{' '}
<b>
<Anchor
target="_blank"
href={`https://github.com/ajnart/homarr/releases/tag/${newVersionAvailable}`}
>
{newVersionAvailable}
</Anchor>
</b>{' '}
is available ! Current version: {CURRENT_VERSION}
</HoverCard.Dropdown>
</HoverCard>
)}
</Group>
), ),
}, },
]; ];

View File

@@ -5,7 +5,7 @@ import CustomizationSettings from './Customization/CustomizationSettings';
import CommonSettings from './Common/CommonSettings'; import CommonSettings from './Common/CommonSettings';
import Credits from './Common/Credits'; import Credits from './Common/Credits';
function SettingsMenu() { function SettingsMenu({ newVersionAvailable }: { newVersionAvailable: string }) {
const { t } = useTranslation('settings/common'); const { t } = useTranslation('settings/common');
return ( return (
@@ -33,7 +33,11 @@ interface SettingsDrawerProps {
closeDrawer: () => void; closeDrawer: () => void;
} }
export function SettingsDrawer({ opened, closeDrawer }: SettingsDrawerProps) { export function SettingsDrawer({
opened,
closeDrawer,
newVersionAvailable,
}: SettingsDrawerProps & { newVersionAvailable: string }) {
const { t } = useTranslation('settings/common'); const { t } = useTranslation('settings/common');
return ( return (
@@ -45,7 +49,7 @@ export function SettingsDrawer({ opened, closeDrawer }: SettingsDrawerProps) {
opened={opened} opened={opened}
onClose={closeDrawer} onClose={closeDrawer}
> >
<SettingsMenu /> <SettingsMenu newVersionAvailable={newVersionAvailable} />
<Credits /> <Credits />
</Drawer> </Drawer>
); );

View File

@@ -1,4 +1,6 @@
import { Box, createStyles, Group, Header as MantineHeader } from '@mantine/core'; import { Box, createStyles, Group, Header as MantineHeader, Indicator } from '@mantine/core';
import { useState, useEffect } from 'react';
import { REPO_URL, CURRENT_VERSION } from '../../../../data/constants';
import { useConfigContext } from '../../../config/provider'; import { useConfigContext } from '../../../config/provider';
import { Logo } from '../Logo'; import { Logo } from '../Logo';
import { useCardStyles } from '../useCardStyles'; import { useCardStyles } from '../useCardStyles';
@@ -15,6 +17,18 @@ export function Header(props: any) {
const { config } = useConfigContext(); const { config } = useConfigContext();
const [newVersionAvailable, setNewVersionAvailable] = useState<string>('');
useEffect(() => {
// Fetch Data here when component first mounted
fetch(`https://api.github.com/repos/${REPO_URL}/releases/latest`).then((res) => {
res.json().then((data) => {
if (data.tag_name > CURRENT_VERSION) {
setNewVersionAvailable(data.tag_name);
}
});
});
}, [CURRENT_VERSION]);
return ( return (
<MantineHeader height={HeaderHeight} className={cardClasses.card}> <MantineHeader height={HeaderHeight} className={cardClasses.card}>
<Group p="xs" noWrap grow> <Group p="xs" noWrap grow>
@@ -25,7 +39,9 @@ export function Header(props: any) {
<Search /> <Search />
<AddElementAction /> <AddElementAction />
<ToggleEditModeAction /> <ToggleEditModeAction />
<SettingsMenu /> <Indicator size={15} color="blue" withBorder processing disabled={!newVersionAvailable}>
<SettingsMenu newVersionAvailable={newVersionAvailable} />
</Indicator>
</Group> </Group>
</Group> </Group>
</MantineHeader> </MantineHeader>

View File

@@ -1,4 +1,4 @@
import { ActionIcon, Menu, Tooltip } from '@mantine/core'; import { ActionIcon, Badge, Menu, Tooltip } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import { IconInfoCircle, IconMenu2, IconSettings } from '@tabler/icons'; import { IconInfoCircle, IconMenu2, IconSettings } from '@tabler/icons';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
@@ -6,7 +6,7 @@ import { AboutModal } from '../../About/AboutModal';
import { SettingsDrawer } from '../../Settings/SettingsDrawer'; import { SettingsDrawer } from '../../Settings/SettingsDrawer';
import { ColorSchemeSwitch } from './SettingsMenu/ColorSchemeSwitch'; import { ColorSchemeSwitch } from './SettingsMenu/ColorSchemeSwitch';
export const SettingsMenu = () => { export function SettingsMenu({ newVersionAvailable }: { newVersionAvailable: string }) {
const [drawerOpened, drawer] = useDisclosure(false); const [drawerOpened, drawer] = useDisclosure(false);
const { t } = useTranslation('common'); const { t } = useTranslation('common');
const [aboutModalOpened, aboutModal] = useDisclosure(false); const [aboutModalOpened, aboutModal] = useDisclosure(false);
@@ -28,15 +28,30 @@ export const SettingsMenu = () => {
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item
icon={<IconInfoCircle strokeWidth={1.2} size={18} />} icon={<IconInfoCircle strokeWidth={1.2} size={18} />}
onClick={aboutModal.open} rightSection={
newVersionAvailable && (
<Badge variant="light" color="blue">
New
</Badge>
)
}
onClick={() => aboutModal.open()}
> >
About About
</Menu.Item> </Menu.Item>
</Menu.Dropdown> </Menu.Dropdown>
</Menu> </Menu>
</Tooltip> </Tooltip>
<SettingsDrawer opened={drawerOpened} closeDrawer={drawer.close} /> <SettingsDrawer
<AboutModal opened={aboutModalOpened} closeModal={aboutModal.close} /> opened={drawerOpened}
closeDrawer={drawer.close}
newVersionAvailable={newVersionAvailable}
/>
<AboutModal
opened={aboutModalOpened}
closeModal={aboutModal.close}
newVersionAvailable={newVersionAvailable}
/>
</> </>
); );
}; }