mirror of
https://gitea.com/gitea/docs.git
synced 2026-07-22 02:37:42 +00:00
Add api page (#32)
# Changes - Added [redocusaurus](https://github.com/rohit-gohri/redocusaurus) package to display swagger api with reference to [woodpecker](https://github.com/woodpecker-ci/woodpecker/tree/master/docs) - Change `sed` for swagger.json for proper version and baseurl. - Add a dropdown for different api versions. (screenshot below) - On API pages, only API version dropdown will show(hide locale dropdown, version dropdown for doc, and doc search) - Allow build CSR API pages for development so it saves building time. # Screenshots     Search:  Reviewed-on: https://gitea.com/gitea/gitea-docusaurus/pulls/32 Co-authored-by: HesterG <hestergong@gmail.com> Co-committed-by: HesterG <hestergong@gmail.com>
This commit is contained in:
@@ -38,8 +38,7 @@ jobs:
|
|||||||
rm static/_*
|
rm static/_*
|
||||||
- name: build site
|
- name: build site
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
make build
|
||||||
npm run build
|
|
||||||
- name: aws credential configure
|
- name: aws credential configure
|
||||||
uses: https://github.com/aws-actions/configure-aws-credentials@v1
|
uses: https://github.com/aws-actions/configure-aws-credentials@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -34,5 +34,4 @@ jobs:
|
|||||||
rm static/_*
|
rm static/_*
|
||||||
- name: build site
|
- name: build site
|
||||||
run: |
|
run: |
|
||||||
npm ci
|
make build
|
||||||
npm run build
|
|
||||||
|
|||||||
29
Makefile
29
Makefile
@@ -1,8 +1,4 @@
|
|||||||
ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu)
|
export NODE_OPTIONS := "--max-old-space-size=4096"
|
||||||
SED_INPLACE := sed -i
|
|
||||||
else
|
|
||||||
SED_INPLACE := sed -i ''
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: build
|
all: build
|
||||||
@@ -36,8 +32,8 @@ prepare-latest: clone_main
|
|||||||
cp -r .tmp/upstream-docs-latest/docs/static/* static/
|
cp -r .tmp/upstream-docs-latest/docs/static/* static/
|
||||||
rsync -avz --prune-empty-dirs --include '*/' --include='*.en-us.md' --exclude '*' .tmp/upstream-docs-latest/docs/content/doc/ docs/
|
rsync -avz --prune-empty-dirs --include '*/' --include='*.en-us.md' --exclude '*' .tmp/upstream-docs-latest/docs/content/doc/ docs/
|
||||||
cp .tmp/upstream-docs-latest/docs/content/page/index.en-us.md docs/intro.md
|
cp .tmp/upstream-docs-latest/docs/content/page/index.en-us.md docs/intro.md
|
||||||
cp .tmp/upstream-docs-latest/templates/swagger/v1_json.tmpl static/latest-swagger.json
|
cp .tmp/upstream-docs-latest/templates/swagger/v1_json.tmpl static/swagger-latest.json
|
||||||
bash loop_docs.sh lastest en-us
|
bash loop_docs.sh latest en-us
|
||||||
|
|
||||||
.PHONY: prepare-latest-zh-cn
|
.PHONY: prepare-latest-zh-cn
|
||||||
prepare-latest-zh-cn:
|
prepare-latest-zh-cn:
|
||||||
@@ -46,7 +42,8 @@ prepare-latest-zh-cn:
|
|||||||
mkdir -p i18n/zh-cn/docusaurus-plugin-content-docs/current
|
mkdir -p i18n/zh-cn/docusaurus-plugin-content-docs/current
|
||||||
rsync -avz --prune-empty-dirs --include '*/' --include='*.zh-cn.md' --exclude '*' .tmp/upstream-docs-latest/docs/content/doc/ i18n/zh-cn/docusaurus-plugin-content-docs/current/
|
rsync -avz --prune-empty-dirs --include '*/' --include='*.zh-cn.md' --exclude '*' .tmp/upstream-docs-latest/docs/content/doc/ i18n/zh-cn/docusaurus-plugin-content-docs/current/
|
||||||
cp .tmp/upstream-docs-latest/docs/content/page/index.zh-cn.md i18n/zh-cn/docusaurus-plugin-content-docs/current/intro.md
|
cp .tmp/upstream-docs-latest/docs/content/page/index.zh-cn.md i18n/zh-cn/docusaurus-plugin-content-docs/current/intro.md
|
||||||
bash loop_docs.sh lastest zh-cn
|
bash loop_docs.sh latest zh-cn
|
||||||
|
rm -rf .tmp/upstream-docs-latest
|
||||||
|
|
||||||
.PHONY: clone_\#%
|
.PHONY: clone_\#%
|
||||||
clone_\#%: create_dir
|
clone_\#%: create_dir
|
||||||
@@ -61,7 +58,7 @@ prepare\#%: clone_\#%
|
|||||||
cp -r .tmp/upstream-docs-$*/docs/static/* static/
|
cp -r .tmp/upstream-docs-$*/docs/static/* static/
|
||||||
rsync -a --prune-empty-dirs --include '*/' --include='*.en-us.md' --exclude '*' .tmp/upstream-docs-$*/docs/content/doc/ versioned_docs/version-1.$*/
|
rsync -a --prune-empty-dirs --include '*/' --include='*.en-us.md' --exclude '*' .tmp/upstream-docs-$*/docs/content/doc/ versioned_docs/version-1.$*/
|
||||||
cp .tmp/upstream-docs-$*/docs/content/page/index.en-us.md versioned_docs/version-1.$*/intro.md
|
cp .tmp/upstream-docs-$*/docs/content/page/index.en-us.md versioned_docs/version-1.$*/intro.md
|
||||||
cp .tmp/upstream-docs-$*/templates/swagger/v1_json.tmpl static/$*-swagger.json
|
cp .tmp/upstream-docs-$*/templates/swagger/v1_json.tmpl static/swagger-$*.json
|
||||||
bash loop_docs.sh $* en-us
|
bash loop_docs.sh $* en-us
|
||||||
|
|
||||||
.PHONY: prepare-zh-cn\#%
|
.PHONY: prepare-zh-cn\#%
|
||||||
@@ -72,18 +69,22 @@ prepare-zh-cn\#%:
|
|||||||
rsync -avz --prune-empty-dirs --include '*/' --include='*.zh-cn.md' --exclude '*' .tmp/upstream-docs-$*/docs/content/doc/ i18n/zh-cn/docusaurus-plugin-content-docs/version-1.$*/
|
rsync -avz --prune-empty-dirs --include '*/' --include='*.zh-cn.md' --exclude '*' .tmp/upstream-docs-$*/docs/content/doc/ i18n/zh-cn/docusaurus-plugin-content-docs/version-1.$*/
|
||||||
cp .tmp/upstream-docs-$*/docs/content/page/index.zh-cn.md i18n/zh-cn/docusaurus-plugin-content-docs/version-1.$*/intro.md
|
cp .tmp/upstream-docs-$*/docs/content/page/index.zh-cn.md i18n/zh-cn/docusaurus-plugin-content-docs/version-1.$*/intro.md
|
||||||
bash loop_docs.sh $* zh-cn
|
bash loop_docs.sh $* zh-cn
|
||||||
|
rm -rf .tmp/upstream-docs-$*
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
install:
|
install:
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
|
.PHONY: prepare-docs
|
||||||
|
prepare-docs: install prepare-latest prepare\#20 prepare\#19 prepare-latest-zh-cn prepare-zh-cn\#20 prepare-zh-cn\#19 prepare-awesome-latest prepare-awesome\#19 prepare-awesome\#20
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: install prepare-latest prepare\#19 prepare\#20 prepare-latest-zh-cn prepare-zh-cn\#19 prepare-zh-cn\#20 prepare-awesome-latest prepare-awesome\#19 prepare-awesome\#20
|
build:
|
||||||
npm ci
|
npm ci
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
.PHONY: serve
|
.PHONY: serve
|
||||||
serve: install prepare-latest prepare\#19 prepare\#20 prepare-latest-zh-cn prepare-zh-cn\#19 prepare-zh-cn\#20 prepare-awesome-latest prepare-awesome\#19 prepare-awesome\#20
|
serve: prepare-docs
|
||||||
npm run start
|
npm run start
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
@@ -92,6 +93,6 @@ clean:
|
|||||||
rm -rf docs
|
rm -rf docs
|
||||||
rm -rf versioned_docs/
|
rm -rf versioned_docs/
|
||||||
rm -rf static/_*
|
rm -rf static/_*
|
||||||
rm -rf static/latest-swagger.json
|
rm -rf static/swagger-latest.json
|
||||||
rm -rf static/19-swagger.json
|
rm -rf static/swagger-19.json
|
||||||
rm -rf static/20-swagger.json
|
rm -rf static/swagger-20.json
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
make clean
|
make clean
|
||||||
|
make prepare-docs
|
||||||
make build
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ make build
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
make clean
|
make clean
|
||||||
|
make prepare-docs
|
||||||
make serve
|
make serve
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -38,3 +40,12 @@ npx docusaurus write-translations --locale zh-cn
|
|||||||
npm run build
|
npm run build
|
||||||
npm run serve
|
npm run serve
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Use CSR Api
|
||||||
|
|
||||||
|
This is for development, api pages will be CSR so this saves building time
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run start-CSRApi
|
||||||
|
npm run build-CSRApi
|
||||||
|
```
|
||||||
|
|||||||
@@ -13,6 +13,40 @@ function sortItemsByCategory(items) {
|
|||||||
return sortedItems;
|
return sortedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const includeAPI = process.env.INCLUDE_API !== 'false';
|
||||||
|
|
||||||
|
const apiConfig = [
|
||||||
|
'redocusaurus',
|
||||||
|
{
|
||||||
|
// Plugin Options for loading OpenAPI files
|
||||||
|
specs: includeAPI ? [
|
||||||
|
{
|
||||||
|
spec: 'static/swagger-latest.json',
|
||||||
|
route: '/api/next/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
route: '/api/1.20/',
|
||||||
|
spec: 'static/swagger-20.json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
route: '/api/1.19/',
|
||||||
|
spec: 'static/swagger-19.json',
|
||||||
|
},
|
||||||
|
]: [],
|
||||||
|
// Theme Options for modifying how redoc renders them
|
||||||
|
theme: {
|
||||||
|
// Change with your site colors
|
||||||
|
primaryColor: '#1890ff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const pageConfig = includeAPI ? {
|
||||||
|
exclude: [
|
||||||
|
'api/**',
|
||||||
|
],
|
||||||
|
}: {}
|
||||||
|
|
||||||
/** @type {import('@docusaurus/types').Config} */
|
/** @type {import('@docusaurus/types').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
title: 'Gitea Documentation',
|
title: 'Gitea Documentation',
|
||||||
@@ -82,8 +116,10 @@ const config = {
|
|||||||
theme: {
|
theme: {
|
||||||
customCss: require.resolve('./src/css/custom.css'),
|
customCss: require.resolve('./src/css/custom.css'),
|
||||||
},
|
},
|
||||||
|
pages: pageConfig,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
apiConfig,
|
||||||
],
|
],
|
||||||
themes: [
|
themes: [
|
||||||
[
|
[
|
||||||
@@ -119,10 +155,28 @@ const config = {
|
|||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
to: '/',
|
type: 'doc',
|
||||||
|
docId: 'intro',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
label: 'Docs',
|
label: 'Docs',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
to: '/api/1.19/',
|
||||||
|
label: 'API',
|
||||||
|
position: 'left',
|
||||||
|
activeBaseRegex: 'api/(1.19|1.20|next)/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'API Version',
|
||||||
|
position: 'right',
|
||||||
|
items: [
|
||||||
|
{to: '/api/next/', label: '1.21-dev' },
|
||||||
|
{to: '/api/1.20/', label: '1.20.0-rc0' },
|
||||||
|
{to: '/api/1.19/', label: '1.19.3' },
|
||||||
|
],
|
||||||
|
className: 'api-dropdown',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
href: 'https://github.com/go-gitea/gitea',
|
href: 'https://github.com/go-gitea/gitea',
|
||||||
label: 'Code',
|
label: 'Code',
|
||||||
|
|||||||
13
loop_docs.sh
13
loop_docs.sh
@@ -15,7 +15,7 @@ SED_INPLACE() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
version="$1"
|
version="$1"
|
||||||
if [ "$version" != "lastest" ]; then
|
if [ "$version" != "latest" ]; then
|
||||||
version="1.$1"
|
version="1.$1"
|
||||||
fi
|
fi
|
||||||
locale="$2"
|
locale="$2"
|
||||||
@@ -31,7 +31,7 @@ elif ["$version" == "1.20"]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
docs_dir="versioned_docs/version-$version"
|
docs_dir="versioned_docs/version-$version"
|
||||||
if [ "$version" == "lastest" ]; then
|
if [ "$version" == "latest" ]; then
|
||||||
if [ "$locale" == "en-us" ]; then
|
if [ "$locale" == "en-us" ]; then
|
||||||
docs_dir="docs"
|
docs_dir="docs"
|
||||||
else
|
else
|
||||||
@@ -58,13 +58,14 @@ SED_INPLACE "s/{{< min-go-version >}}/$minGoVer/" "$docs_dir/installation/from-s
|
|||||||
|
|
||||||
# TODO: improve this sed
|
# TODO: improve this sed
|
||||||
# need confirmation
|
# need confirmation
|
||||||
if [ "$version" == "lastest" ]; then
|
if [ "$version" == "latest" ]; then
|
||||||
SED_INPLACE 's/"version":.*/"version":"1.21-dev"/' static/latest-swagger.json
|
SED_INPLACE 's/"version": "{{AppVer | JSEscape | Safe}}"/"version": "1.21-dev"/' static/swagger-latest.json
|
||||||
elif [ "$version" == "1.20" ]; then
|
elif [ "$version" == "1.20" ]; then
|
||||||
SED_INPLACE 's/"version":.*/"version":"1.20.0-rc2"/' static/20-swagger.json
|
SED_INPLACE 's/"version": "{{AppVer | JSEscape | Safe}}"/"version": "1.20.0-rc2"/' static/swagger-20.json
|
||||||
elif [ "$version" == "1.19" ]; then
|
elif [ "$version" == "1.19" ]; then
|
||||||
SED_INPLACE 's/"version":.*/"version":"1.19.3"/' static/19-swagger.json
|
SED_INPLACE 's/"version": "{{AppVer | JSEscape | Safe}}"/"version": "1.19.3"/' static/swagger-19.json
|
||||||
fi
|
fi
|
||||||
|
SED_INPLACE 's/"basePath": "{{AppSubUrl | JSEscape | Safe}}/"basePath": "https:\/\/gitea.com/' static/swagger-"$1".json
|
||||||
|
|
||||||
for file in `find ./"$docs_dir" -name "*.md"`; do
|
for file in `find ./"$docs_dir" -name "*.md"`; do
|
||||||
# hide hugo toc
|
# hide hugo toc
|
||||||
|
|||||||
1914
package-lock.json
generated
1914
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"docusaurus": "docusaurus",
|
"docusaurus": "docusaurus",
|
||||||
"start": "docusaurus start",
|
"start": "docusaurus start",
|
||||||
|
"start-CSRApi": "cross-env INCLUDE_API='false' docusaurus start",
|
||||||
"build": "docusaurus build",
|
"build": "docusaurus build",
|
||||||
|
"build-CSRApi": "cross-env INCLUDE_API='false' docusaurus build",
|
||||||
"swizzle": "docusaurus swizzle",
|
"swizzle": "docusaurus swizzle",
|
||||||
"deploy": "docusaurus deploy",
|
"deploy": "docusaurus deploy",
|
||||||
"clear": "docusaurus clear",
|
"clear": "docusaurus clear",
|
||||||
@@ -21,10 +23,12 @@
|
|||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"prism-react-renderer": "^1.3.5",
|
"prism-react-renderer": "^1.3.5",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2"
|
"react-dom": "^17.0.2",
|
||||||
|
"redocusaurus": "^1.6.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "^2.3.1"
|
"@docusaurus/module-type-aliases": "^2.3.1",
|
||||||
|
"cross-env": "^7.0.3"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|||||||
12
src/components/ClientOnly.js
Normal file
12
src/components/ClientOnly.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ApiDoc from '@theme/ApiDoc';
|
||||||
|
// For csr api pages
|
||||||
|
export default function ClientOnly(props) {
|
||||||
|
return (
|
||||||
|
<ApiDoc
|
||||||
|
specProps={{
|
||||||
|
url: props.swaggerPath,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import Translate from '@docusaurus/Translate';
|
import Translate from '@docusaurus/Translate';
|
||||||
|
|
||||||
export default function Outdated(props) {
|
export default function Outdated(props) {
|
||||||
|
|||||||
@@ -58,3 +58,57 @@
|
|||||||
background-color: rgb(7, 19, 24);
|
background-color: rgb(7, 19, 24);
|
||||||
color: rgb(184, 231, 251);
|
color: rgb(184, 231, 251);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.redocusaurus .menu-content {
|
||||||
|
top: 70px !important;
|
||||||
|
height: calc(100vh - 70px) !important;
|
||||||
|
}
|
||||||
|
/* The following css is for toggling API version dropdown/menu,
|
||||||
|
selectors like :first-of-type are for browsers those do not support :has */
|
||||||
|
/* Do not show doc search on api pages */
|
||||||
|
body:has(.redocusaurus) [class*='searchBox'],
|
||||||
|
.plugin-redoc [class*='searchBox'],
|
||||||
|
.plugin-pages [class*='searchBox'] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 996px) {
|
||||||
|
/* hide api-dropdown on other pages */
|
||||||
|
.navbar__item.dropdown:not(:has(.api-dropdown)),
|
||||||
|
.navbar__item.dropdown:first-of-type {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* show api-dropdown dropdown and hide other dropdowns on api pages */
|
||||||
|
body:has(.redocusaurus) .navbar__item.dropdown:not(:has(.api-dropdown)),
|
||||||
|
.plugin-redoc .navbar__item.dropdown:not(:first-of-type),
|
||||||
|
.plugin-pages .navbar__item.dropdown:not(:first-of-type) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
body:has(.redocusaurus) .navbar__item.dropdown:has(.api-dropdown),
|
||||||
|
.plugin-redoc .navbar__item.dropdown:first-of-type,
|
||||||
|
.plugin-pages .navbar__item.dropdown:first-of-type {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 996px) {
|
||||||
|
/* need to find a way to customize the classname */
|
||||||
|
/* on mobile, dropdown becomes menu list */
|
||||||
|
/* Hide api version menu on other pages */
|
||||||
|
.menu__list-item.menu__list-item--collapsed:has(.api-dropdown),
|
||||||
|
.menu__list-item.menu__list-item--collapsed:nth-of-type(3) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* Hide collapsible menus except for API menu on API pages */
|
||||||
|
body:has(.redocusaurus) .menu__list-item.menu__list-item--collapsed:not(:has(.api-dropdown)),
|
||||||
|
.plugin-redoc .menu__list-item.menu__list-item--collapsed:not(:first-of-type),
|
||||||
|
.plugin-pages .menu__list-item.menu__list-item--collapsed:not(:first-of-type) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* Show collapsible API menu on API pages */
|
||||||
|
body:has(.redocusaurus) .menu__list-item:has(.api-dropdown),
|
||||||
|
.plugin-redoc .menu__list-item:nth-of-type(3),
|
||||||
|
.plugin-pages .menu__list-item:nth-of-type(3) {
|
||||||
|
display: list-item !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
8
src/pages/api/1.19/index.js
Normal file
8
src/pages/api/1.19/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ClientOnly from '@site/src/components/ClientOnly';
|
||||||
|
|
||||||
|
export default function Api19() {
|
||||||
|
return (
|
||||||
|
<ClientOnly swaggerPath="/swagger-19.json"/>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
src/pages/api/1.20/index.js
Normal file
8
src/pages/api/1.20/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ClientOnly from '@site/src/components/ClientOnly';
|
||||||
|
|
||||||
|
export default function Api20() {
|
||||||
|
return (
|
||||||
|
<ClientOnly swaggerPath="/swagger-20.json"/>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
src/pages/api/next/index.js
Normal file
8
src/pages/api/next/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ClientOnly from '@site/src/components/ClientOnly';
|
||||||
|
|
||||||
|
export default function ApiLatest() {
|
||||||
|
return (
|
||||||
|
<ClientOnly swaggerPath="/swagger-latest.json"/>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user