Update hub-button-app to use a local script

Co-authored-by: Firespray-31 <147506444+Firespray-31@users.noreply.github.com>
This commit is contained in:
Massimiliano D. 2025-09-22 10:00:44 +02:00 committed by GitHub
parent 5df4c270a7
commit 2580d0f95c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 124 additions and 37 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,14 @@
import { Box, darkTheme, FaencyProvider, lightTheme } from '@traefiklabs/faency'
import { Suspense, useEffect } from 'react'
import { Helmet, HelmetProvider } from 'react-helmet-async'
import { HelmetProvider } from 'react-helmet-async'
import { HashRouter, Navigate, Route, Routes as RouterRoutes, useLocation } from 'react-router-dom'
import { SWRConfig } from 'swr'
import Page from './layout/Page'
import fetch from './libs/fetch'
import { VersionProvider } from 'contexts/version'
import { useIsDarkMode } from 'hooks/use-theme'
import useVersion from 'hooks/use-version'
import ErrorSuspenseWrapper from 'layout/ErrorSuspenseWrapper'
import { Dashboard, HTTPPages, NotFound, TCPPages, UDPPages } from 'pages'
import { DashboardSkeleton } from 'pages/dashboard/Dashboard'
@ -33,15 +33,8 @@ const ScrollToTop = () => {
}
export const Routes = () => {
const { showHubButton } = useVersion()
return (
<Suspense fallback={<PageLoader />}>
{showHubButton && (
<Helmet>
<script src="https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js"></script>
</Helmet>
)}
<RouterRoutes>
<Route
path="/"
@ -100,10 +93,12 @@ const App = () => {
fetcher: fetch,
}}
>
<HashRouter basename={import.meta.env.VITE_APP_BASE_URL || ''}>
<ScrollToTop />
<Routes />
</HashRouter>
<VersionProvider>
<HashRouter basename={import.meta.env.VITE_APP_BASE_URL || ''}>
<ScrollToTop />
<Routes />
</HashRouter>
</VersionProvider>
</SWRConfig>
</HelmetProvider>
</FaencyProvider>

View File

@ -0,0 +1,40 @@
import { createContext, ReactNode, useEffect, useState } from 'react'
type VersionContextProps = {
showHubButton: boolean
version: string
}
export const VersionContext = createContext<VersionContextProps>({
showHubButton: false,
version: '',
})
type VersionProviderProps = {
children: ReactNode
}
export const VersionProvider = ({ children }: VersionProviderProps) => {
const [showHubButton, setShowHubButton] = useState(false)
const [version, setVersion] = useState('')
useEffect(() => {
const fetchVersion = async () => {
try {
const response = await fetch('/api/version')
if (!response.ok) {
throw new Error(`Network error: ${response.status}`)
}
const data: API.Version = await response.json()
setShowHubButton(!data.disableDashboardAd)
setVersion(data.Version)
} catch (err) {
console.error(err)
}
}
fetchVersion()
}, [])
return <VersionContext.Provider value={{ showHubButton, version }}>{children}</VersionContext.Provider>
}

View File

@ -1,13 +0,0 @@
import { useMemo } from 'react'
import useSWR from 'swr'
export default function useVersion() {
const { data: version } = useSWR('/version')
const showHubButton = useMemo(() => {
if (!version) return false
return !version?.disableDashboardAd
}, [version])
return { showHubButton, version }
}

View File

@ -19,7 +19,7 @@ import {
Tooltip,
VisuallyHidden,
} from '@traefiklabs/faency'
import { useEffect, useMemo, useState } from 'react'
import { useContext, useEffect, useMemo, useState } from 'react'
import { BsChevronDoubleRight, BsChevronDoubleLeft } from 'react-icons/bs'
import { FiBookOpen, FiGithub, FiHelpCircle } from 'react-icons/fi'
import { matchPath, useHref } from 'react-router'
@ -34,9 +34,9 @@ import Logo from 'components/icons/Logo'
import { PluginsIcon } from 'components/icons/PluginsIcon'
import ThemeSwitcher from 'components/ThemeSwitcher'
import TooltipText from 'components/TooltipText'
import { VersionContext } from 'contexts/version'
import useTotals from 'hooks/use-overview-totals'
import { useIsDarkMode } from 'hooks/use-theme'
import useVersion from 'hooks/use-version'
import { Route, ROUTES } from 'routes'
export const LAPTOP_BP = 1025
@ -136,7 +136,7 @@ export const SideNav = ({
isResponsive?: boolean
}) => {
const windowSize = useWindowSize()
const { version } = useVersion()
const { version } = useContext(VersionContext)
const { http, tcp, udp } = useTotals()
@ -228,7 +228,7 @@ export const SideNav = ({
>
<Logo height={isSmallScreen ? 36 : 56} isSmallScreen={isSmallScreen} />
{!!version && !isSmallScreen && (
<TooltipText text={version.Version} css={{ maxWidth: 50, fontWeight: '$semiBold' }} isTruncated />
<TooltipText text={version} css={{ maxWidth: 50, fontWeight: '$semiBold' }} isTruncated />
)}
</Flex>
{ROUTES.map((section, index) => (
@ -289,23 +289,60 @@ export const SideNav = ({
}
export const TopNav = () => {
const { showHubButton, version } = useVersion()
const [hasHubButtonComponent, setHasHubButtonComponent] = useState(false)
const { showHubButton, version } = useContext(VersionContext)
const isDarkMode = useIsDarkMode()
const parsedVersion = useMemo(() => {
if (!version?.Version) {
if (!version) {
return 'master'
}
if (version.Version === 'dev') {
if (version === 'dev') {
return 'master'
}
const matches = version.Version.match(/^(v?\d+\.\d+)/)
const matches = version.match(/^(v?\d+\.\d+)/)
return matches ? 'v' + matches[1] : 'master'
}, [version])
useEffect(() => {
if (!showHubButton) {
setHasHubButtonComponent(false)
return
}
if (customElements.get('hub-button-app')) {
setHasHubButtonComponent(true)
return
}
const scripts: HTMLScriptElement[] = []
const createScript = (scriptSrc: string): HTMLScriptElement => {
const script = document.createElement('script')
script.src = scriptSrc
script.async = true
script.onload = () => {
setHasHubButtonComponent(customElements.get('hub-button-app') !== undefined)
}
scripts.push(script)
return script
}
// Source: https://github.com/traefik/traefiklabs-hub-button-app
document.head.appendChild(createScript('traefiklabs-hub-button-app/main-v1.js'))
return () => {
// Remove the scripts on unmount.
scripts.forEach((script) => {
if (script.parentNode) {
script.parentNode.removeChild(script)
}
})
}
}, [showHubButton])
return (
<Flex as="nav" role="navigation" justify="end" align="center" css={{ gap: '$2', mb: '$6' }}>
{showHubButton && (
{hasHubButtonComponent && (
<Box css={{ fontFamily: '$rubik', fontWeight: '500 !important' }}>
<hub-button-app
key={`dark-mode-${isDarkMode}`}

8
webui/src/types/API.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
namespace API {
type Version = {
Codename: string
Version: string
disableDashboardAd: boolean
startDate: string
}
}