This commit is contained in:
typescreep
2025-05-23 07:34:48 +03:00
commit 11b8de2537
21 changed files with 12378 additions and 0 deletions

7
.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
node_modules
build
public
.dockerignore
Dockerfile
Dockerfile.prod
Dockerfile.local

17
.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[/deploy/**]
indent_style = unset
indent_size = unset
end_of_line = unset
charset = unset
trim_trailing_whitespace = unset
insert_final_newline = unset

1
.env.options.dist Normal file
View File

@@ -0,0 +1 @@
KUBE_API_URL=

5
.eslintignore Normal file
View File

@@ -0,0 +1,5 @@
**/build/*
**/public/*
**/node_modules/*
!src/
vite.config.ts

70
.eslintrc.json Normal file
View File

@@ -0,0 +1,70 @@
{
"root": true,
"extends": [
"airbnb",
"airbnb/hooks",
"plugin:prettier/recommended",
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true,
"modules": true,
"experimentalObjectRestSpread": true
},
"project": ["./tsconfig.json"]
},
"plugins": ["prettier", "react", "@typescript-eslint", "import"],
"ignorePatterns": ["dist/**", "node_modules/**", "public/**"],
"overrides": [
{
"files": ["pages/**/*"],
"rules": {
"import/no-default-export": 0
}
}
],
"rules": {
"quotes": ["off", "single"],
"semi": ["error", "never"],
"prefer-template": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/anchor-is-valid": "off",
"react/react-in-jsx-scope": 0,
"react/display-name": 0,
"react/function-component-definition": [2, { "namedComponents": "arrow-function" }],
"no-alert": "error",
"no-else-return": 1,
"no-cond-assign": "error",
"no-lonely-if": "warn",
"no-dupe-else-if": "warn",
"no-duplicate-case": "warn",
"react/jsx-filename-extension": "off",
"react/jsx-props-no-spreading": "off",
"react/jsx-key": ["warn", { "checkFragmentShorthand": true }],
"react/jsx-no-duplicate-props": "warn",
"react/no-unescaped-entities": "warn",
"react/require-default-props": "off",
"prettier/prettier": "error",
"import/prefer-default-export": "off",
"import/no-unresolved": "off",
"import/extensions": "off",
"import/no-extraneous-dependencies": "off",
"no-shadow": "off",
"max-lines-per-function": ["warn", 250],
"import/no-default-export": "warn",
"react/jsx-handler-names": ["warn"],
"no-unused-expressions": "off",
"no-unused-vars": "off",
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
"@typescript-eslint/no-unused-expressions": ["error"],
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}

18
.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.options
npm-debug.log*
yarn-debug.log*
yarn-error.log*

2
.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
build
public

8
.prettierrc Normal file
View File

@@ -0,0 +1,8 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 120,
"arrowParens": "avoid",
"trailingComma": "all",
"tabWidth": 2
}

12
.stylelintignore Normal file
View File

@@ -0,0 +1,12 @@
build/
public/
node_modules/
*.woff
*.ico
*.png
*.mdx
*.svg
*.jpg
.history
src/index.css

43
.stylelintrc Normal file
View File

@@ -0,0 +1,43 @@
{
"extends": ["stylelint-config-standard"],
"customSyntax": "postcss-styled-syntax",
"rules": {
"declaration-empty-line-before": "never",
"color-named": "always-where-possible",
"selector-no-qualifying-type": true,
"selector-max-combinators": 4,
"rule-empty-line-before": ["always-multi-line", { "except": ["first-nested"] }],
"selector-attribute-quotes": "always",
"declaration-block-no-duplicate-properties": true,
"declaration-no-important": true,
"property-no-vendor-prefix": true,
"value-no-vendor-prefix": true,
"function-url-quotes": "always",
"font-weight-notation": "numeric",
"font-family-name-quotes": "always-unless-keyword",
"comment-whitespace-inside": "always",
"at-rule-no-vendor-prefix": true,
"selector-pseudo-element-colon-notation": "single",
"selector-no-vendor-prefix": true,
"selector-type-no-unknown": null,
"media-feature-name-no-vendor-prefix": true,
"block-no-empty": null,
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["global"]
}
],
"property-no-unknown": [
true,
{
"ignoreProperties": ["composes", "compose-with"]
}
],
"value-keyword-case": null,
"selector-class-pattern": null,
"color-function-notation": null,
"alpha-value-notation": null,
"at-rule-no-unknown": null
}
}

21
Dockerfile.local Normal file
View File

@@ -0,0 +1,21 @@
FROM node:21.6.1-alpine3.19 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm i
COPY . .
RUN npm run build
FROM nginxinc/nginx-unprivileged:1.25.3
COPY --from=builder /app/build /usr/share/nginx/html/openapi-ui
COPY deploy/ /
USER root
RUN chmod g+rw -R /run /usr/share/nginx/html \
&& chown root:root /usr/share/nginx/html
USER 1001
CMD ["nginx", "-g", "daemon off;"]

1
README.md Normal file
View File

@@ -0,0 +1 @@
# openapi-ui

19
index.html Normal file
View File

@@ -0,0 +1,19 @@
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap"
rel="stylesheet"
/>
<title>OpenAPI UI</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

11939
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

83
package.json Normal file
View File

@@ -0,0 +1,83 @@
{
"name": "openapi-ui",
"type": "module",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "cross-env BASEPREFIX=/ vite --open --port 4001 --strictPort",
"build": "tsc && vite build",
"serve": "vite preview --port 4001 --strictPort",
"preview": "vite preview --port 4001 --strictPort",
"tsc": "tsc --project tsconfig.json",
"lint:css": "stylelint ./src/**/styled.{js,ts} --fix",
"lint:js": "eslint .",
"lint": "npm run lint:js && npm run lint:css && npm run tsc"
},
"dependencies": {
"@ant-design/icons": "5.6.0",
"@monaco-editor/react": "4.6.0",
"@originjs/vite-plugin-federation": "1.3.6",
"@prorobotech/openapi-k8s-toolkit": "0.0.1-alpha.16",
"@readme/openapi-parser": "2.6.0",
"@reduxjs/toolkit": "2.2.5",
"@tanstack/react-query": "5.62.2",
"@tanstack/react-query-devtools": "5.62.2",
"antd": "5.20.0",
"axios": "1.4.0",
"cross-env": "7.0.3",
"dotenv": "16.4.7",
"jsonpath": "1.1.1",
"lodash": "4.17.21",
"openapi-types": "12.1.3",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-redux": "9.1.2",
"react-router-dom": "6.25.1",
"styled-components": "6.0.7",
"typescript": "4.9.5",
"usehooks-ts": "3.1.1",
"uuid": "11.0.3",
"yaml": "2.7.0"
},
"devDependencies": {
"@stylelint/postcss-css-in-js": "0.38.0",
"@types/jsonpath": "0.2.4",
"@types/lodash": "4.17.13",
"@types/node": "20.5.4",
"@types/react": "18.2.25",
"@types/react-dom": "18.2.7",
"@types/react-router-dom": "5.3.3",
"@types/styled-components": "5.1.26",
"@typescript-eslint/eslint-plugin": "8.6.0",
"@vitejs/plugin-react-swc": "3.7.0",
"eslint": "8.57.1",
"eslint-config-airbnb": "19.0.4",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-jsx-a11y": "6.7.1",
"eslint-plugin-prettier": "5.0.0",
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "4.6.0",
"postcss": "8.5.2",
"postcss-styled-syntax": "0.7.1",
"prettier": "3.0.2",
"stylelint": "16.14.1",
"stylelint-config-standard": "37.0.0",
"vite": "5.4.6",
"vite-plugin-node-polyfills": "0.22.0",
"vite-tsconfig-paths": "5.0.1"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"homepage": "/"
}

6
src/global.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
declare global {
interface Window {
_env_: Record<string, string>
}
}
export {}

13
src/index.css Normal file
View File

@@ -0,0 +1,13 @@
html,
body {
margin: 0;
font-family: 'Roboto';
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
.ant-input-number-outlined {
width: 100%;
}

13
src/index.tsx Normal file
View File

@@ -0,0 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import { store } from 'store/store'
import './index.css'
import { App } from './App'
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(
<Provider store={store}>
<App />
</Provider>,
)

1
src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

33
tsconfig.json Normal file
View File

@@ -0,0 +1,33 @@
{
"compilerOptions": {
"baseUrl": "src",
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["vite/client"],
"paths": {
"api/*": ["./api/*"],
"components/*": ["./components/*"],
"constants/*": ["./constants/*"],
"localTypes/*": ["./localTypes/*"],
"mocks/*": ["./mocks/*"],
"pages/*": ["./pages/*"],
"store/*": ["./store/*"],
"templates/*": ["./templates/*"],
"utils/*": ["./utils/*"]
}
},
"include": ["src"]
}

66
vite.config.ts Normal file
View File

@@ -0,0 +1,66 @@
import path from 'path'
import dotenv from 'dotenv'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
const { VITE_BASEPREFIX } = process.env
const { parsed: options } = await dotenv.config({ path: './.env.options' })
// https://vitejs.dev/config/
export default defineConfig({
root: './',
base: VITE_BASEPREFIX || '/openapi-ui',
build: {
outDir: 'build',
modulePreload: false,
target: 'esnext',
minify: false,
cssCodeSplit: false,
},
publicDir: 'public',
plugins: [
react(),
nodePolyfills({
include: ['buffer', 'process'],
globals: {
Buffer: true, // can also be 'build', 'dev', or false
global: true,
process: true,
},
}),
],
resolve: {
alias: {
api: path.resolve(__dirname, './src/api'),
components: path.resolve(__dirname, './src/components'),
constants: path.resolve(__dirname, './src/constants'),
localTypes: path.resolve(__dirname, './src/localTypes'),
mocks: path.resolve(__dirname, './src/mocks'),
pages: path.resolve(__dirname, './src/pages'),
store: path.resolve(__dirname, './src/store'),
templates: path.resolve(__dirname, './src/templates'),
utils: path.resolve(__dirname, './src/utils'),
hooks: path.resolve(__dirname, './src/hooks'),
},
},
server: {
host: '0.0.0.0',
port: 4000,
proxy: {
'^/api/clusters/.*/k8s/': {
target: `${options?.KUBE_API_URL}/api/clusters`,
changeOrigin: true,
secure: false,
ws: true,
rewrite: path => path.replace(/^\/api\/clusters\//, '/'),
},
'/clusterlist': {
target: `${options?.KUBE_API_URL}/clusterlist`,
changeOrigin: true,
secure: false,
rewrite: path => path.replace(/^\/clusterlist/, ''),
},
},
},
})