diff --git a/docs/apis/delivery-service.mdx b/docs/apis/delivery-service.mdx index 209b72a22ae6047ecad69c52318842f5d5ef51ef..64db5e32a43fcaa7165ab8c7fa2bdbe686b5c9a9 100644 --- a/docs/apis/delivery-service.mdx +++ b/docs/apis/delivery-service.mdx @@ -4,8 +4,5 @@ hide_table_of_contents: true --- import ApiSpec from '@site/src/components/ApiSpec' -import VersionDisplay from '@site/src/components/VersionDisplay' -Die aktuell ausgewählte Version der API ist <VersionDisplay artifact={"zustelldienst.yml"}/>. - -<ApiSpec specUrl="https://fitko.uber.space/0.9.0/zustelldienst.yml"/> +<ApiSpec artifact={"zustelldienst.yml"} /> diff --git a/package.json b/package.json index f64a4c230deaf89112157c732a898fce17cdf7d4..567469c134d87e7689e8257cbd6939453aac0725 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@docusaurus/preset-classic": "2.0.0-beta.0", "@mdx-js/react": "^1.6.21", "@svgr/webpack": "^5.5.0", + "axios": "^0.21.1", "clsx": "^1.1.1", "file-loader": "^6.2.0", "mermaid": "^8.10.2", @@ -22,6 +23,7 @@ "react": "^17.0.1", "react-dom": "^17.0.1", "remark-collapse": "^0.1.2", + "semver": "^7.3.5", "url-loader": "^4.1.1" }, "browserslist": { diff --git a/src/components/ApiSpec.js b/src/components/ApiSpec.js index 59465b0f0b852926b1d41fe71c5cd946a8d4d10b..17cf5b51aa31fb07a7337324beb62f9bfba9a72e 100644 --- a/src/components/ApiSpec.js +++ b/src/components/ApiSpec.js @@ -1,28 +1,80 @@ -import React from 'react' +import React, {useEffect} from 'react' +import axios from 'axios' +import semver from 'semver' +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment' +import useDocusaurusContext from '@docusaurus/useDocusaurusContext' import BrowserOnly from '@docusaurus/BrowserOnly' +import useAsync from '@site/src/hooks/useAsync' + +const SCHEMA_BASE_URL = 'https://docs.fitko.de' + +const getLatestVersion = async (siteVersion) => { + return axios.get('https://git.fitko.de/api/v4/projects/1/repository/tags') + .catch((error) => { + throw `Fetching of latest tags failed with ${error.response.status}` + }) + .then(async ({ data }) => { + if (siteVersion === 'next') { + return data[0].name + } else { + const versionRange = `~${siteVersion}` + const suitableVersions = await data + .filter(({ name }) => semver.satisfies(name, versionRange)) + .map(({ name }) => name) + .sort() + .reverse() + console.log('suitableVersions', suitableVersions, suitableVersions[0]) + return suitableVersions[0] + } + }) +} + +const DownloadLabel = ({ version, artifact }) => { + return <a href={`${SCHEMA_BASE_URL}/${version}/${artifact}`} download> + (herunterladen) + </a> +} + export default function ApiSpec(props) { + const isInBrowser = ExecutionEnvironment.canUseDOM + const { siteVersion = 'next' } = useDocusaurusContext().siteMetadata + + const { execute, status, error, value: latestVersion } = useAsync(getLatestVersion, [siteVersion], false) + + if (isInBrowser) { + useEffect(() => { + execute() + }, []) + } + return ( <BrowserOnly fallback={<div>Lädt...</div>}> {() => { import('rapidoc') return ( - <rapi-doc - render-style="view" - layout="column" - spec-url={props.specUrl} - theme="light" - show-info="false" - show-header="false" - show-components="false" - allow-spec-file-load="false" - info-description-headings-in-navbar="false" - allow-try="false" - primary-color="#11171a" - allow-server-selection="false" - server-url="" - /> + <div> + <p>Die aktuell angezeigte Version der API ist {status === 'success' && <code>{latestVersion}</code>} {status === 'success' && <DownloadLabel version={latestVersion} artifact={props.artifact} />}.</p> + + { status === 'success' && latestVersion && <rapi-doc + render-style="view" + layout="column" + spec-url={`${SCHEMA_BASE_URL}/${latestVersion}/${props.artifact}`} + theme="light" + show-info="false" + show-header="false" + show-components="false" + allow-spec-file-load="false" + info-description-headings-in-navbar="false" + allow-try="false" + primary-color="#11171a" + allow-server-selection="false" + server-url="" + />} + + {status === 'error' && <p>Die API-Spezifikation konnte leider nicht geladen werden.</p>} + </div> ) }} </BrowserOnly> diff --git a/src/components/VersionDisplay.js b/src/components/VersionDisplay.js deleted file mode 100644 index b6a0e42327910845df5410f2e74f7c3fc01a9ff1..0000000000000000000000000000000000000000 --- a/src/components/VersionDisplay.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react' -import useDocusaurusContext from '@docusaurus/useDocusaurusContext' - -const DownloadLabel = ({ version, artifact }) => { - return <a href={`https://fitko.uber.space/${version}/${artifact}`} download> - herunterladen - </a> -} - -export default function ({ artifact }) { - const { siteMetadata } = useDocusaurusContext() - - return ( - <span> - <code>{siteMetadata.siteVersion || 'next'}</code> - {siteMetadata.siteVersion ? ( - <DownloadLabel version={siteMetadata.siteVersion} artifact={artifact} /> - ) : undefined } - </span> - ) - -} diff --git a/src/hooks/useAsync.js b/src/hooks/useAsync.js new file mode 100644 index 0000000000000000000000000000000000000000..91ad5c5a75d3f93a20b662c57a0b62528dcd6060 --- /dev/null +++ b/src/hooks/useAsync.js @@ -0,0 +1,42 @@ +import {useCallback, useEffect, useRef, useState} from "react"; + +const useAsync = (fn, params = [], immediate = true) => { + const [status, setStatus] = useState("idle") + const [value, setValue] = useState(null) + const [error, setError] = useState(null) + const mountedRef = useRef(true) + + + const execute = useCallback(() => { + setStatus("pending") + setValue(null) + setError(null) + + return fn(...params) + .then((val) => { + if (!mountedRef.current) return null + setValue(val) + setStatus("success") + }) + .catch((error) => { + if (!mountedRef.current) return null + setError(error) + setStatus("error") + throw err + }) + }, [fn]) + + useEffect(async () => { + if (immediate){ + execute() + } + + return () => { + mountedRef.current = false + } + }, [execute, immediate]) + + return { execute, status, value, error } +} + +export default useAsync