mirror of
https://github.com/traefik/traefik.git
synced 2025-10-04 04:01:15 +02:00
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:
parent
5df4c270a7
commit
2580d0f95c
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,14 +1,14 @@
|
|||||||
import { Box, darkTheme, FaencyProvider, lightTheme } from '@traefiklabs/faency'
|
import { Box, darkTheme, FaencyProvider, lightTheme } from '@traefiklabs/faency'
|
||||||
import { Suspense, useEffect } from 'react'
|
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 { HashRouter, Navigate, Route, Routes as RouterRoutes, useLocation } from 'react-router-dom'
|
||||||
import { SWRConfig } from 'swr'
|
import { SWRConfig } from 'swr'
|
||||||
|
|
||||||
import Page from './layout/Page'
|
import Page from './layout/Page'
|
||||||
import fetch from './libs/fetch'
|
import fetch from './libs/fetch'
|
||||||
|
|
||||||
|
import { VersionProvider } from 'contexts/version'
|
||||||
import { useIsDarkMode } from 'hooks/use-theme'
|
import { useIsDarkMode } from 'hooks/use-theme'
|
||||||
import useVersion from 'hooks/use-version'
|
|
||||||
import ErrorSuspenseWrapper from 'layout/ErrorSuspenseWrapper'
|
import ErrorSuspenseWrapper from 'layout/ErrorSuspenseWrapper'
|
||||||
import { Dashboard, HTTPPages, NotFound, TCPPages, UDPPages } from 'pages'
|
import { Dashboard, HTTPPages, NotFound, TCPPages, UDPPages } from 'pages'
|
||||||
import { DashboardSkeleton } from 'pages/dashboard/Dashboard'
|
import { DashboardSkeleton } from 'pages/dashboard/Dashboard'
|
||||||
@ -33,15 +33,8 @@ const ScrollToTop = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Routes = () => {
|
export const Routes = () => {
|
||||||
const { showHubButton } = useVersion()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<PageLoader />}>
|
<Suspense fallback={<PageLoader />}>
|
||||||
{showHubButton && (
|
|
||||||
<Helmet>
|
|
||||||
<script src="https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js"></script>
|
|
||||||
</Helmet>
|
|
||||||
)}
|
|
||||||
<RouterRoutes>
|
<RouterRoutes>
|
||||||
<Route
|
<Route
|
||||||
path="/"
|
path="/"
|
||||||
@ -100,10 +93,12 @@ const App = () => {
|
|||||||
fetcher: fetch,
|
fetcher: fetch,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<VersionProvider>
|
||||||
<HashRouter basename={import.meta.env.VITE_APP_BASE_URL || ''}>
|
<HashRouter basename={import.meta.env.VITE_APP_BASE_URL || ''}>
|
||||||
<ScrollToTop />
|
<ScrollToTop />
|
||||||
<Routes />
|
<Routes />
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
|
</VersionProvider>
|
||||||
</SWRConfig>
|
</SWRConfig>
|
||||||
</HelmetProvider>
|
</HelmetProvider>
|
||||||
</FaencyProvider>
|
</FaencyProvider>
|
||||||
|
40
webui/src/contexts/version.tsx
Normal file
40
webui/src/contexts/version.tsx
Normal 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>
|
||||||
|
}
|
@ -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 }
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
VisuallyHidden,
|
VisuallyHidden,
|
||||||
} from '@traefiklabs/faency'
|
} from '@traefiklabs/faency'
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import { BsChevronDoubleRight, BsChevronDoubleLeft } from 'react-icons/bs'
|
import { BsChevronDoubleRight, BsChevronDoubleLeft } from 'react-icons/bs'
|
||||||
import { FiBookOpen, FiGithub, FiHelpCircle } from 'react-icons/fi'
|
import { FiBookOpen, FiGithub, FiHelpCircle } from 'react-icons/fi'
|
||||||
import { matchPath, useHref } from 'react-router'
|
import { matchPath, useHref } from 'react-router'
|
||||||
@ -34,9 +34,9 @@ import Logo from 'components/icons/Logo'
|
|||||||
import { PluginsIcon } from 'components/icons/PluginsIcon'
|
import { PluginsIcon } from 'components/icons/PluginsIcon'
|
||||||
import ThemeSwitcher from 'components/ThemeSwitcher'
|
import ThemeSwitcher from 'components/ThemeSwitcher'
|
||||||
import TooltipText from 'components/TooltipText'
|
import TooltipText from 'components/TooltipText'
|
||||||
|
import { VersionContext } from 'contexts/version'
|
||||||
import useTotals from 'hooks/use-overview-totals'
|
import useTotals from 'hooks/use-overview-totals'
|
||||||
import { useIsDarkMode } from 'hooks/use-theme'
|
import { useIsDarkMode } from 'hooks/use-theme'
|
||||||
import useVersion from 'hooks/use-version'
|
|
||||||
import { Route, ROUTES } from 'routes'
|
import { Route, ROUTES } from 'routes'
|
||||||
|
|
||||||
export const LAPTOP_BP = 1025
|
export const LAPTOP_BP = 1025
|
||||||
@ -136,7 +136,7 @@ export const SideNav = ({
|
|||||||
isResponsive?: boolean
|
isResponsive?: boolean
|
||||||
}) => {
|
}) => {
|
||||||
const windowSize = useWindowSize()
|
const windowSize = useWindowSize()
|
||||||
const { version } = useVersion()
|
const { version } = useContext(VersionContext)
|
||||||
|
|
||||||
const { http, tcp, udp } = useTotals()
|
const { http, tcp, udp } = useTotals()
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ export const SideNav = ({
|
|||||||
>
|
>
|
||||||
<Logo height={isSmallScreen ? 36 : 56} isSmallScreen={isSmallScreen} />
|
<Logo height={isSmallScreen ? 36 : 56} isSmallScreen={isSmallScreen} />
|
||||||
{!!version && !isSmallScreen && (
|
{!!version && !isSmallScreen && (
|
||||||
<TooltipText text={version.Version} css={{ maxWidth: 50, fontWeight: '$semiBold' }} isTruncated />
|
<TooltipText text={version} css={{ maxWidth: 50, fontWeight: '$semiBold' }} isTruncated />
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
{ROUTES.map((section, index) => (
|
{ROUTES.map((section, index) => (
|
||||||
@ -289,23 +289,60 @@ export const SideNav = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TopNav = () => {
|
export const TopNav = () => {
|
||||||
const { showHubButton, version } = useVersion()
|
const [hasHubButtonComponent, setHasHubButtonComponent] = useState(false)
|
||||||
|
const { showHubButton, version } = useContext(VersionContext)
|
||||||
const isDarkMode = useIsDarkMode()
|
const isDarkMode = useIsDarkMode()
|
||||||
|
|
||||||
const parsedVersion = useMemo(() => {
|
const parsedVersion = useMemo(() => {
|
||||||
if (!version?.Version) {
|
if (!version) {
|
||||||
return 'master'
|
return 'master'
|
||||||
}
|
}
|
||||||
if (version.Version === 'dev') {
|
if (version === 'dev') {
|
||||||
return 'master'
|
return 'master'
|
||||||
}
|
}
|
||||||
const matches = version.Version.match(/^(v?\d+\.\d+)/)
|
const matches = version.match(/^(v?\d+\.\d+)/)
|
||||||
return matches ? 'v' + matches[1] : 'master'
|
return matches ? 'v' + matches[1] : 'master'
|
||||||
}, [version])
|
}, [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 (
|
return (
|
||||||
<Flex as="nav" role="navigation" justify="end" align="center" css={{ gap: '$2', mb: '$6' }}>
|
<Flex as="nav" role="navigation" justify="end" align="center" css={{ gap: '$2', mb: '$6' }}>
|
||||||
{showHubButton && (
|
{hasHubButtonComponent && (
|
||||||
<Box css={{ fontFamily: '$rubik', fontWeight: '500 !important' }}>
|
<Box css={{ fontFamily: '$rubik', fontWeight: '500 !important' }}>
|
||||||
<hub-button-app
|
<hub-button-app
|
||||||
key={`dark-mode-${isDarkMode}`}
|
key={`dark-mode-${isDarkMode}`}
|
||||||
|
8
webui/src/types/API.d.ts
vendored
Normal file
8
webui/src/types/API.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace API {
|
||||||
|
type Version = {
|
||||||
|
Codename: string
|
||||||
|
Version: string
|
||||||
|
disableDashboardAd: boolean
|
||||||
|
startDate: string
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user