mirror of
https://github.com/diced/zipline.git
synced 2025-05-11 10:26:05 +02:00
feat: version checking
This commit is contained in:
parent
485f106a65
commit
4a5d01c663
4 changed files with 252 additions and 18 deletions
|
@ -48,6 +48,7 @@ import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import ConfigProvider from './ConfigProvider';
|
import ConfigProvider from './ConfigProvider';
|
||||||
|
import VersionBadge from './VersionBadge';
|
||||||
|
|
||||||
type NavLinks = {
|
type NavLinks = {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -357,23 +358,27 @@ export default function Layout({ children, config }: { children: React.ReactNode
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<Divider mt='auto' />
|
<div style={{ marginTop: 'auto' }}>
|
||||||
|
<VersionBadge />
|
||||||
|
|
||||||
<ScrollArea mah='auto'>
|
<Divider />
|
||||||
<Box>
|
|
||||||
{config.website.externalLinks.map(({ name, url }, i) => (
|
<ScrollArea mah='auto'>
|
||||||
<NavLink
|
<Box>
|
||||||
key={i}
|
{config.website.externalLinks.map(({ name, url }, i) => (
|
||||||
label={name}
|
<NavLink
|
||||||
leftSection={<IconExternalLink size='1rem' />}
|
key={i}
|
||||||
variant='light'
|
label={name}
|
||||||
component={Link}
|
leftSection={<IconExternalLink size='1rem' />}
|
||||||
href={url}
|
variant='light'
|
||||||
target='_blank'
|
component={Link}
|
||||||
/>
|
href={url}
|
||||||
))}
|
target='_blank'
|
||||||
</Box>
|
/>
|
||||||
</ScrollArea>
|
))}
|
||||||
|
</Box>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
</AppShell.Navbar>
|
</AppShell.Navbar>
|
||||||
|
|
||||||
<AppShell.Main>
|
<AppShell.Main>
|
||||||
|
|
173
src/components/VersionBadge.tsx
Normal file
173
src/components/VersionBadge.tsx
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
import useVersion from '@/lib/hooks/useVersion';
|
||||||
|
import {
|
||||||
|
Anchor,
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
Indicator,
|
||||||
|
Modal,
|
||||||
|
Paper,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
|
|
||||||
|
function DataDisplay({ items }: { items: { label: string; value: string; href?: string }[] }) {
|
||||||
|
return (
|
||||||
|
<Paper withBorder p='sm'>
|
||||||
|
<Stack gap='xs'>
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<Flex justify='space-between' align='center' style={{ width: '100%' }} key={index}>
|
||||||
|
<Text c='dimmed' fw='bolder' style={{ flex: 1 }}>
|
||||||
|
{item.label}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{item.href ? (
|
||||||
|
<Anchor href={item.href} target='_blank'>
|
||||||
|
{item.value}
|
||||||
|
</Anchor>
|
||||||
|
) : (
|
||||||
|
<Text>{item.value}</Text>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function VersionButton({ text, children, href }: { href: string; text: string; children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
component='a'
|
||||||
|
href={href}
|
||||||
|
target='_blank'
|
||||||
|
variant='filled'
|
||||||
|
fullWidth
|
||||||
|
color='blue'
|
||||||
|
size='sm'
|
||||||
|
mt='xs'
|
||||||
|
leftSection={
|
||||||
|
<Text size='sm' fw='bolder'>
|
||||||
|
{text}
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function VersionBadge() {
|
||||||
|
const { version, isLoading } = useVersion();
|
||||||
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
|
|
||||||
|
if (isLoading) return null;
|
||||||
|
if (!version) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal title='Zipline Version' opened={opened} onClose={close} size='lg'>
|
||||||
|
{version.isLatest && <Text>Running the latest version of Zipline.</Text>}
|
||||||
|
{version.isUpstream && (
|
||||||
|
<Text>
|
||||||
|
You are running an <b>unstable</b> version of Zipline. Upstream versions are not fully tested and
|
||||||
|
may contain bugs.
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{!version.isLatest && !version.isUpstream && version.isRelease && (
|
||||||
|
<Text>
|
||||||
|
You are running an <b>outdated</b> version of Zipline. It is recommended to update to the{' '}
|
||||||
|
<Anchor href={version.latest?.url!}>latest version</Anchor>.
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Indicator
|
||||||
|
processing
|
||||||
|
position='middle-end'
|
||||||
|
inline
|
||||||
|
offset={-15}
|
||||||
|
color='red'
|
||||||
|
disabled={version.isLatest}
|
||||||
|
>
|
||||||
|
<Title order={3} my='sm'>
|
||||||
|
Current Version
|
||||||
|
</Title>
|
||||||
|
</Indicator>
|
||||||
|
<DataDisplay
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: 'Version',
|
||||||
|
value: version.version?.tag!,
|
||||||
|
href: `https://github.com/diced/zipline/releases/${version.version?.tag}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Commit',
|
||||||
|
value: version.version?.sha!,
|
||||||
|
href: `https://github.com/diced/zipline/commit/${version.version?.sha}`,
|
||||||
|
},
|
||||||
|
{ label: 'Upstream?', value: version.isUpstream ? 'Yes' : 'No' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!version.isLatest && version.isUpstream && (
|
||||||
|
<>
|
||||||
|
<Title order={3} mt='sm'>
|
||||||
|
Latest Commit Available
|
||||||
|
</Title>
|
||||||
|
<Text c='dimmed' size='sm' mb='sm'>
|
||||||
|
This is only visible when running an upstream version.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<DataDisplay
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: 'Commit',
|
||||||
|
value: version.latest?.commit?.sha!.slice(0, 7)!,
|
||||||
|
href: `https://github.com/diced/zipline/commit/${version.latest?.commit?.sha}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Available to update',
|
||||||
|
value: version.latest?.commit?.pull ? 'Yes' : 'No',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!version.isLatest && version.isRelease && (
|
||||||
|
<>
|
||||||
|
<Title order={3} mt='sm'>
|
||||||
|
{version.latest?.tag} is available
|
||||||
|
</Title>
|
||||||
|
|
||||||
|
<VersionButton text='Changelogs' href={version.latest?.url!}>
|
||||||
|
{version.latest?.tag}
|
||||||
|
</VersionButton>
|
||||||
|
|
||||||
|
<VersionButton text='Update' href='https://zipline.diced.sh/docs/get-started/docker#updating'>
|
||||||
|
{version.latest?.tag}
|
||||||
|
</VersionButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Tooltip label='Click to view more version information'>
|
||||||
|
<Badge
|
||||||
|
onClick={open}
|
||||||
|
style={{ cursor: 'pointer', textTransform: 'unset' }}
|
||||||
|
mx='sm'
|
||||||
|
my='xs'
|
||||||
|
color={version.isLatest ? 'green' : 'red'}
|
||||||
|
variant='dot'
|
||||||
|
size='lg'
|
||||||
|
radius='md'
|
||||||
|
>
|
||||||
|
{version.version?.tag}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
23
src/lib/hooks/useVersion.ts
Executable file
23
src/lib/hooks/useVersion.ts
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { Response } from '../api/response';
|
||||||
|
const f = async () => {
|
||||||
|
const res = await fetch('/api/version', {
|
||||||
|
cache: 'force-cache',
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error('Failed to fetch version');
|
||||||
|
const r = await res.json();
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useVersion() {
|
||||||
|
const { isLoading, data } = useSWR<Response['/api/version'], Error>('/api/version', f, {
|
||||||
|
refreshInterval: undefined,
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
revalidateIfStale: false,
|
||||||
|
refreshWhenOffline: false,
|
||||||
|
refreshWhenHidden: false,
|
||||||
|
revalidateOnReconnect: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { version: data?.data, isLoading };
|
||||||
|
}
|
|
@ -3,16 +3,49 @@ import fastifyPlugin from 'fastify-plugin';
|
||||||
import { getVersion } from '@/lib/version';
|
import { getVersion } from '@/lib/version';
|
||||||
|
|
||||||
export type ApiVersionResponse = {
|
export type ApiVersionResponse = {
|
||||||
version: string;
|
details: ReturnType<typeof getVersion>;
|
||||||
|
data: VersionAPI;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface VersionAPI {
|
||||||
|
isUpstream?: boolean;
|
||||||
|
isRelease?: boolean;
|
||||||
|
isLatest?: boolean;
|
||||||
|
version?: {
|
||||||
|
tag: string;
|
||||||
|
sha: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
latest?: {
|
||||||
|
tag: string;
|
||||||
|
url: string;
|
||||||
|
commit?: {
|
||||||
|
sha: string;
|
||||||
|
url: string;
|
||||||
|
pull: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const PATH = '/api/version';
|
export const PATH = '/api/version';
|
||||||
export default fastifyPlugin(
|
export default fastifyPlugin(
|
||||||
(server, _, done) => {
|
(server, _, done) => {
|
||||||
server.get(PATH, { preHandler: [userMiddleware] }, async (_, res) => {
|
server.get(PATH, { preHandler: [userMiddleware] }, async (_, res) => {
|
||||||
const details = getVersion();
|
const details = getVersion();
|
||||||
|
const params = new URLSearchParams([['details', JSON.stringify(details)]]);
|
||||||
|
|
||||||
return res.send(details);
|
const resp = await fetch(`https://zipline-version.diced.sh/?${params.toString()}`);
|
||||||
|
|
||||||
|
if (!resp.ok) {
|
||||||
|
return res.internalServerError('failed to fetch version details: ' + await resp.text());
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: VersionAPI = await resp.json();
|
||||||
|
|
||||||
|
return res.send({
|
||||||
|
data,
|
||||||
|
details,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue