4 |
5 |
6 |
7 | Apache APISIX Dashboard
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | /.pnpm-store
27 |
28 | # Playwright
29 | /test-results/
30 | /playwright-report/
31 | /blob-report/
32 | /playwright/.cache/
33 |
34 | .eslintcache
35 |
--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG VARIANT=22
2 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT}
3 |
4 | # [Optional] Uncomment this section to install additional OS packages.
5 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
6 | # && apt-get -y install --no-install-recommends
7 |
8 | # [Optional] Uncomment if you want to install an additional version of node using nvm
9 | # ARG EXTRA_NODE_VERSION=10
10 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
11 |
12 | # [Optional] Uncomment if you want to install more global node modules
13 | # RUN su node -c "npm install -g "
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Create a feature request for the Apache APISIX Dashboard
4 | labels: 'feature'
5 | ---
6 |
7 | # Feature request
8 |
9 | ## Please describe your feature
10 |
11 | A clear and concise description of what you want and what your use case is.
12 |
13 | ## Describe the solution you'd like
14 |
15 | A clear and concise description of what you want to happen.
16 |
17 | ## Describe alternatives you've considered
18 |
19 | A clear and concise description of any alternative solutions or features you've considered.
20 |
21 | ## Additional context
22 |
23 | Add any other context or screenshots about the feature request here.
24 |
--------------------------------------------------------------------------------
/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": [
4 | "es2021",
5 | "dom"
6 | ],
7 | "allowJs": true,
8 | "sourceMap": false,
9 | "target": "ESNext",
10 | "module": "ESNext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "baseUrl": ".",
14 | "allowSyntheticDefaultImports": true,
15 | "esModuleInterop": true,
16 | "skipLibCheck": true,
17 | "noImplicitAny": false,
18 | "verbatimModuleSyntax": true,
19 | "paths": {
20 | "@e2e/*": [
21 | "./*"
22 | ],
23 | "@/*": [
24 | "../src/*"
25 | ]
26 | }
27 | },
28 | "include": [
29 | "./**/*.ts",
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/.licenserc.yaml:
--------------------------------------------------------------------------------
1 | header:
2 | license:
3 | spdx-id: Apache-2.0
4 | copyright-owner: Apache Software Foundation
5 |
6 | paths-ignore:
7 | - 'dist'
8 | - 'licenses'
9 | - '**/*.md'
10 | - 'LICENSE'
11 | - 'NOTICE'
12 | - '**/*.css'
13 | - '**/*.html'
14 | - '**/*.json'
15 | - '**/*.toml'
16 | - '**/*.yaml'
17 | - 'src/assets/**'
18 | - '.actions/**'
19 | - '.devcontainer/**'
20 | - '.github/**'
21 | - '.husky/**'
22 | - '.vscode/**'
23 | - '.dockerignore'
24 | - '.gitignore'
25 | - '.gitmodules'
26 | - '.yamllint'
27 | - 'eslint.config.js'
28 | - 'src/routeTree.gen.ts'
29 |
30 | comment: on-failure
31 |
32 | dependency:
33 | files:
34 | - package.json
35 |
--------------------------------------------------------------------------------
/.github/workflows/gitleaks.yml:
--------------------------------------------------------------------------------
1 | # Scan git repos (or files) for secrets using regex and entropy 🔑
2 |
3 | name: gitLeaks
4 |
5 | on:
6 | push:
7 | branches:
8 | - master
9 | paths-ignore:
10 | - 'docs/**'
11 | pull_request:
12 | branches:
13 | - master
14 | paths-ignore:
15 | - 'docs/**'
16 |
17 | jobs:
18 | gitleaks:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - uses: actions/checkout@v6
22 | with:
23 | fetch-depth: '1'
24 | submodules: recursive
25 | - name: wget
26 | shell: bash
27 | run: |
28 | wget https://raw.githubusercontent.com/ycjcl868/gitleaks/master/.gitleaks.toml
29 | - name: gitleaks-action
30 | uses: ./.github/actions/gitleaks-action
31 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4 | "target": "ES2022",
5 | "lib": ["ES2023"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "isolatedModules": true,
13 | "moduleDetection": "force",
14 | "noEmit": true,
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true,
21 | "noUncheckedSideEffectImports": true,
22 | "types": [
23 | "node"
24 | ],
25 | },
26 | "include": ["vite.config.ts", "vite-plugin-i18n-progress.ts"]
27 | }
28 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE:
--------------------------------------------------------------------------------
1 | Please answer these questions before submitting a pull request, **or your PR will get closed**.
2 |
3 | **Why submit this pull request?**
4 |
5 | - [ ] Bugfix
6 | - [ ] New feature provided
7 | - [ ] Improve performance
8 | - [ ] Backport patches
9 |
10 | **What changes will this PR take into?**
11 |
12 | Please update this section with detailed description.
13 |
14 | **Related issues**
15 |
16 | fix/resolve #0001
17 |
18 | **Checklist:**
19 |
20 | - [ ] Did you explain what problem does this PR solve? Or what new features have been added?
21 | - [ ] Have you added corresponding test cases?
22 | - [ ] Have you modified the corresponding document?
23 | - [ ] Is this PR backward compatible? If it is not backward compatible, please discuss on the mailing list first
24 |
--------------------------------------------------------------------------------
/.actions/ASFLicenseHeader.txt:
--------------------------------------------------------------------------------
1 | Licensed to the Apache Software Foundation (ASF) under one or more
2 | contributor license agreements. See the NOTICE file distributed with
3 | this work for additional information regarding copyright ownership.
4 | The ASF licenses this file to You under the Apache License, Version 2.0
5 | (the "License"); you may not use this file except in compliance with
6 | the License. You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 |
13 | - package-ecosystem: "npm" # See documentation for possible values
14 | directory: "/" # Location of package manifests
15 | schedule:
16 | interval: "daily"
17 |
18 | - package-ecosystem: "gomod" # See documentation for possible values
19 | directory: "/" # Location of package manifests
20 | schedule:
21 | interval: "daily"
22 |
--------------------------------------------------------------------------------
/src/assets/apisix-logo.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 | "target": "ES2020",
5 | "useDefineForClassFields": true,
6 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
7 | "module": "ESNext",
8 | "skipLibCheck": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "bundler",
12 | "allowImportingTsExtensions": true,
13 | "isolatedModules": true,
14 | "moduleDetection": "force",
15 | "noEmit": true,
16 | "jsx": "react-jsx",
17 |
18 | /* Linting */
19 | "strict": true,
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | "noFallthroughCasesInSwitch": true,
23 | "noUncheckedSideEffectImports": true,
24 | "verbatimModuleSyntax": true,
25 | "paths": {
26 | "@/*": [
27 | "./src/*"
28 | ],
29 | },
30 | "types": [
31 | "unplugin-icons/types/react",
32 | ]
33 | },
34 | "include": [
35 | "src",
36 | "e2e/utils/env.ts"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.validate": [
3 | "typescriptreact",
4 | "typescript",
5 | ],
6 | "files.readonlyInclude": {
7 | "**/routeTree.gen.ts": true
8 | },
9 | "files.watcherExclude": {
10 | "**/routeTree.gen.ts": true
11 | },
12 | "search.exclude": {
13 | "**/routeTree.gen.ts": true
14 | },
15 | "cssVariables.lookupFiles": [
16 | "**/*.css",
17 | "**/*.scss",
18 | "**/*.sass",
19 | "**/*.less",
20 | "node_modules/@mantine/core/styles.css"
21 | ],
22 | "i18n-ally.sortKeys": true,
23 | "i18n-ally.localesPaths": [
24 | "src/locales",
25 | ],
26 | "i18n-ally.keystyle": "nested",
27 | "i18n-ally.enabledFrameworks": [
28 | "react-i18next"
29 | ],
30 | "i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
31 | "i18n-ally.editor.preferEditor": true,
32 | "i18n-ally.translate.saveAsCandidates": true,
33 | "typescript.tsdk": "node_modules/typescript/lib",
34 | "editor.codeActionsOnSave": {
35 | "source.fixAll.eslint": "always"
36 | },
37 | }
38 |
--------------------------------------------------------------------------------
/src/types/router.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { router } from '@/config/global';
18 |
19 | declare module '@tanstack/react-router' {
20 | interface Register {
21 | router: typeof router;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.markdownlint.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one or more
3 | # contributor license agreements. See the NOTICE file distributed with
4 | # this work for additional information regarding copyright ownership.
5 | # The ASF licenses this file to You under the Apache License, Version 2.0
6 | # (the "License"); you may not use this file except in compliance with
7 | # the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | MD001: false
19 | MD004: false
20 | MD013: false
21 | MD014: false
22 | MD024: false
23 | MD026: false
24 | MD029: false
25 | MD033: false
26 | MD034: false
27 | MD040: false
28 | MD041: false
29 |
--------------------------------------------------------------------------------
/src/types/i18next.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { defaultNS,Resources } from '@/config/i18n';
18 |
19 | declare module 'i18next' {
20 | interface CustomTypeOptions {
21 | defaultNS: typeof defaultNS;
22 | resources: Resources['en'];
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartService/schema.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import type { z } from 'zod';
18 |
19 | import { APISIXServices } from '@/types/schema/apisix/services';
20 |
21 | export const ServicePostSchema = APISIXServices.ServicePost;
22 |
23 | export type ServicePostType = z.infer;
24 |
--------------------------------------------------------------------------------
/src/routes/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { createFileRoute, redirect } from '@tanstack/react-router';
18 |
19 | import { navRoutes } from '@/config/navRoutes';
20 |
21 | export const Route = createFileRoute('/')({
22 | beforeLoad: () => {
23 | return redirect({
24 | to: navRoutes[0].to,
25 | });
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/protos.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 |
21 | const Proto = z
22 | .object({
23 | content: z.string(),
24 | })
25 | .merge(APISIXCommon.Info);
26 |
27 | export const APISIXProtos = {
28 | Proto,
29 | ProtoPost: Proto.omit({ id: true, create_time: true, update_time: true }),
30 | };
31 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/consumer_groups.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { APISIXPluginConfigs } from './plugin_configs';
18 |
19 | const ConsumerGroup = APISIXPluginConfigs.PluginConfig.omit({ name: true });
20 |
21 | export const APISIXConsumerGroups = {
22 | ConsumerGroup,
23 | ConsumerGroupPut: ConsumerGroup.omit({
24 | create_time: true,
25 | update_time: true,
26 | }),
27 | };
28 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartGlobalRules.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { t } from 'i18next';
18 |
19 | import { FormItemPlugins } from './FormItemPlugins';
20 | import { FormSection } from './FormSection';
21 |
22 | export const FormPartGlobalRules = () => {
23 | return (
24 |
25 |
26 |
27 | );
28 | };
29 |
--------------------------------------------------------------------------------
/src/stores/global.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { atom } from 'jotai';
18 | import { atomWithStorage } from 'jotai/utils';
19 |
20 | // Admin key with persistent storage
21 | export const adminKeyAtom = atomWithStorage(
22 | 'settings:adminKey',
23 | '',
24 | undefined,
25 | {
26 | getOnInit: true,
27 | }
28 | );
29 |
30 | // Settings modal visibility state
31 | export const isSettingsOpenAtom = atom(false);
32 |
--------------------------------------------------------------------------------
/src/types/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | ///
18 | ///
19 |
20 | declare module 'virtual:i18n-progress' {
21 | const progress: import('./../../vite-plugin-i18n-progress').LangProgress;
22 | export default progress;
23 | }
24 |
25 | type FilterKeys = {
26 | [K in keyof T as K extends `${string}${R}` ? K : never]: T[K];
27 | };
28 |
--------------------------------------------------------------------------------
/src/config/global.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { QueryClient } from '@tanstack/react-query';
18 | import { createRouter } from '@tanstack/react-router';
19 |
20 | import { routeTree } from '@/routeTree.gen';
21 |
22 | import { BASE_PATH } from './constant';
23 |
24 | export const router = createRouter({ routeTree, basepath: BASE_PATH });
25 |
26 | export type Router = typeof router;
27 |
28 | export const queryClient = new QueryClient({});
29 |
--------------------------------------------------------------------------------
/src/utils/useNamePrefix.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { createContext, useContext } from 'react';
18 |
19 | const NamePrefixContext = createContext('');
20 |
21 | export const useNamePrefix = () => {
22 | const prefix = useContext(NamePrefixContext) || '';
23 | return (name: T) =>
24 | (prefix ? [prefix, name].join('.') : name) as `${T}`;
25 | };
26 |
27 | export const NamePrefixProvider = NamePrefixContext.Provider;
28 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/global_rules.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 |
22 | const GlobalRule = z
23 | .object({
24 | plugins: APISIXPlugins.Plugins,
25 | })
26 | .merge(APISIXCommon.Info);
27 |
28 | export const APISIXGlobalRules = {
29 | GlobalRule,
30 | GlobalRulePut: GlobalRule.omit({
31 | create_time: true,
32 | update_time: true,
33 | }),
34 | };
35 |
--------------------------------------------------------------------------------
/src/utils/form-context.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { createContext, use } from 'react';
18 |
19 | import type { RoutePostType } from '../components/form-slice/FormPartRoute/schema';
20 |
21 | export const CommonFormContext = createContext<{
22 | readOnlyFields: (keyof RoutePostType)[];
23 | }>({
24 | readOnlyFields: [],
25 | });
26 |
27 | export const useFormReadOnlyFields = () => {
28 | const { readOnlyFields } = use(CommonFormContext);
29 | return readOnlyFields || [];
30 | };
31 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/plugin_metadata.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { APISIXCommon } from './common';
18 | import { APISIXPlugins } from './plugins';
19 |
20 | const PluginMetadata = APISIXPlugins.PluginMetadataSchema.merge(
21 | APISIXCommon.Info
22 | ).omit({
23 | id: true,
24 | });
25 |
26 | export const APISIXPluginMetadata = {
27 | PluginMetadata: PluginMetadata,
28 | PluginMetadataPut: PluginMetadata.omit({
29 | create_time: true,
30 | update_time: true,
31 | }),
32 | };
33 |
--------------------------------------------------------------------------------
/src/components/Btn.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { Button, type ButtonProps } from '@mantine/core';
18 | import { createLink } from '@tanstack/react-router';
19 | import { forwardRef } from 'react';
20 |
21 | const MantineBtnLinkComponent = forwardRef(
22 | (props, ref) => {
23 | return ;
24 | }
25 | );
26 | MantineBtnLinkComponent.displayName = 'RouteLinkBtn';
27 |
28 | export const RouteLinkBtn = createLink(MantineBtnLinkComponent);
29 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartUpstream/schema.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIX } from '@/types/schema/apisix';
20 |
21 | // We don't omit id now, as we need it for detail view
22 | export const FormPartUpstreamSchema = APISIX.Upstream.extend({
23 | __checksEnabled: z.boolean().optional().default(false),
24 | __checksPassiveEnabled: z.boolean().optional().default(false),
25 | });
26 |
27 | export type FormPartUpstreamType = z.infer;
28 |
--------------------------------------------------------------------------------
/src/routes/consumers/detail.$username.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { createFileRoute, Outlet } from '@tanstack/react-router';
18 |
19 | import { DetailCredentialsTabs } from '@/components/page-slice/consumers/DetailCredentialsTabs';
20 |
21 | function RouteComponent() {
22 | return (
23 | <>
24 |
25 |
26 | >
27 | );
28 | }
29 |
30 | export const Route = createFileRoute('/consumers/detail/$username')({
31 | component: RouteComponent,
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartPluginConfig.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { FormPartBasic, type FormPartBasicProps } from './FormPartBasic';
18 | import { FormSectionPluginsOnly } from './FormPartConsumer';
19 |
20 | export const FormPartPluginConfig = (
21 | props: {
22 | basicProps?: FormPartBasicProps;
23 | } = {}
24 | ) => {
25 | const { basicProps } = props;
26 | return (
27 | <>
28 |
29 |
30 | >
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/src/components/form/Btn.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | Button,
19 | type ButtonProps,
20 | type PolymorphicComponentProps,
21 | } from '@mantine/core';
22 | import { useFormContext, useFormState } from 'react-hook-form';
23 |
24 | export const FormSubmitBtn = (
25 | props: PolymorphicComponentProps<'button', ButtonProps>
26 | ) => {
27 | const form = useFormContext();
28 | const { isSubmitting } = useFormState(form);
29 | return ;
30 | };
31 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartStreamRoute/schema.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import type { TypeOf } from 'zod';
18 |
19 | import { APISIXCommon } from '@/types/schema/apisix/common';
20 | import { APISIXStreamRoutes } from '@/types/schema/apisix/stream_routes';
21 |
22 | export const StreamRoutePostSchema = APISIXStreamRoutes.StreamRoute.omit({
23 | create_time: true,
24 | update_time: true,
25 | id: true,
26 | }).merge(APISIXCommon.Basic);
27 |
28 | export type StreamRoutePostType = TypeOf;
29 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/plugin_configs.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 |
22 | const PluginConfig = z
23 | .object({
24 | plugins: APISIXPlugins.Plugins,
25 | })
26 | .merge(APISIXCommon.Basic)
27 | .merge(APISIXCommon.Info);
28 |
29 | export const APISIXPluginConfigs = {
30 | PluginConfig,
31 | PluginConfigPut: PluginConfig.omit({
32 | create_time: true,
33 | update_time: true,
34 | }),
35 | };
36 |
--------------------------------------------------------------------------------
/src/styles/global.css:
--------------------------------------------------------------------------------
1 | .monaco-editor,
2 | .monaco-editor .overflow-guard {
3 | border-radius: var(--mantine-radius-sm);
4 | }
5 |
6 | /* This is to fix the suggest widget offset problem */
7 | .monaco-editor .suggest-widget {
8 | width: 200px !important;
9 | left: 60px !important;
10 | }
11 |
12 | .monaco-editor {
13 | padding-bottom: 200px;
14 | }
15 |
16 | .editor-wrapper {
17 | border: 1px solid var(--mantine-color-gray-4);
18 | border-radius: var(--mantine-radius-sm);
19 | position: relative;
20 | height: 100%;
21 |
22 | &:focus-within {
23 | border-color: var(--mantine-color-blue-6);
24 | }
25 | }
26 |
27 | .editor-wrapper--disabled {
28 | background-color: var(--mantine-color-gray-0);
29 | border-color: var(--mantine-color-gray-3);
30 | cursor: not-allowed !important;
31 |
32 | &:focus-within {
33 | border-color: var(--mantine-color-gray-3);
34 | }
35 |
36 | & * {
37 | cursor: not-allowed !important;
38 | pointer-events: none !important;
39 | }
40 |
41 | .monaco-editor,
42 | .monaco-editor .monaco-editor-background,
43 | .monaco-editor .overflow-guard,
44 | .monaco-editor .margin-view-overlays {
45 | background-color: var(--mantine-color-gray-0) !important;
46 | }
47 |
48 | .monaco-editor .view-lines,
49 | .monaco-editor .view-line * {
50 | color: var(--mantine-color-gray-5) !important;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/e2e/pom/type.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import { type Locator, type Page } from '@playwright/test';
19 |
20 | export type POMLocator = {
21 | getAddBtn: (page: Page) => Locator;
22 | };
23 |
24 | export type POMAssert = {
25 | isIndexPage: (page: Page) => Promise;
26 | isAddPage: (page: Page) => Promise;
27 | isDetailPage: (page: Page) => Promise;
28 | };
29 |
30 | export type POMGoto = {
31 | toIndex: (page: Page) => void;
32 | toAdd: (page: Page) => void;
33 | };
34 |
35 | export type CommonPOM = POMLocator & POMAssert & POMGoto;
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apache APISIX Dashboard
2 |
3 | [](https://github.com/apache/apisix-dashboard/blob/master/LICENSE)
4 | [](https://apisix.apache.org/slack)
5 |
6 |
11 |
12 | - The master version should be used with Apache APISIX master version.
13 | - The project will not be released independently but will use a fixed git tag for each APISIX release.
14 |
15 | ## What's Apache APISIX Dashboard
16 |
17 | The Apache APISIX Dashboard is designed to make it as easy as possible for users to operate [Apache APISIX](https://github.com/apache/apisix) through a frontend interface.
18 |
19 | ## Development
20 |
21 | Pull requests are encouraged and always welcome. [Pick an issue](https://github.com/apache/apisix-dashboard/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) and help us out!
22 |
23 | Please refer to the [Development Guide](./docs/en/development.md).
24 |
25 | ## Contributing
26 |
27 | Please refer to the [Contribution Guide](./CONTRIBUTING.md) for a more detailed information.
28 |
29 | ## License
30 |
31 | [Apache License 2.0](./LICENSE)
32 |
--------------------------------------------------------------------------------
/src/components/Header/SettingModalBtn.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { ActionIcon } from '@mantine/core';
18 | import { useSetAtom } from 'jotai';
19 |
20 | import { isSettingsOpenAtom } from '@/stores/global';
21 | import IconSettings from '~icons/material-symbols/settings';
22 |
23 | export const SettingModalBtn = () => {
24 | const setIsSettingsOpen = useSetAtom(isSettingsOpenAtom);
25 |
26 | return (
27 | setIsSettingsOpen(true)}
29 | variant="light"
30 | size="sm"
31 | >
32 |
33 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/e2e/utils/ui/routes.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { routesPom } from '@e2e/pom/routes';
18 | import type { Page } from '@playwright/test';
19 |
20 | import { uiHasToastMsg } from '.';
21 |
22 | export async function uiDeleteRoute(page: Page) {
23 | // Delete the route for cleanup
24 | await page.getByRole('button', { name: 'Delete' }).click();
25 | await page
26 | .getByRole('dialog', { name: 'Delete Route' })
27 | .getByRole('button', { name: 'Delete' })
28 | .click();
29 | await uiHasToastMsg(page, {
30 | hasText: 'Delete Route Successfully',
31 | });
32 | await routesPom.isIndexPage(page);
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartCredential.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { useTranslation } from 'react-i18next';
18 |
19 | import { FormItemPlugins } from './FormItemPlugins';
20 | import { FormPartBasic } from './FormPartBasic';
21 | import { FormSection } from './FormSection';
22 |
23 | export const FormPartCredential = () => {
24 | const { t } = useTranslation();
25 | return (
26 | <>
27 |
28 |
29 |
30 |
31 | >
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/credentials.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 |
22 | const Credential = z
23 | .object({
24 | plugins: APISIXPlugins.Plugins.optional(),
25 | })
26 | .merge(APISIXCommon.Info)
27 | .merge(APISIXCommon.Basic.omit({ name: true }));
28 |
29 | const ConsumerCredentials = z.array(Credential);
30 |
31 | export const APISIXCredentials = {
32 | Credential,
33 | CredentialPut: Credential.omit({
34 | create_time: true,
35 | update_time: true,
36 | }),
37 | ConsumerCredentials,
38 | };
39 |
--------------------------------------------------------------------------------
/e2e/utils/env.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { config } from 'dotenv';
18 | import { parseEnv } from 'znv';
19 | import { z } from 'zod';
20 |
21 | import { BASE_PATH } from '../../src/config/constant';
22 |
23 | config({
24 | path: ['./.env', './.env.local', './.env.development.local'],
25 | });
26 |
27 | export const env = parseEnv(process.env, {
28 | E2E_TARGET_URL: z
29 | .string()
30 | .url()
31 | .default(`http://localhost:9180${BASE_PATH}/`)
32 | .describe(
33 | `If you want to access the test server from dev container playwright to host e2e server, try http://host.docker.internal:9180${BASE_PATH}/`
34 | ),
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/page-slice/stream_routes/ErrorComponent.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | ErrorComponent,
19 | type ErrorComponentProps,
20 | } from '@tanstack/react-router';
21 | import { AxiosError } from 'axios';
22 |
23 | import type { APISIXRespErr } from '@/config/req';
24 |
25 | export const StreamRoutesErrorComponent = (props: ErrorComponentProps) => {
26 | if (props.error instanceof AxiosError) {
27 | const err = props.error as AxiosError;
28 | if (err.response?.status === 400) {
29 | return {err.response?.data.error_msg};
30 | }
31 | }
32 | return ;
33 | };
34 |
--------------------------------------------------------------------------------
/src/types/schema/pageSearch.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 |
20 | export const pageSearchSchema = z
21 | .object({
22 | page: z
23 | .union([z.string(), z.number()])
24 | .optional()
25 | .default(1)
26 | .transform((val) => (val ? Number(val) : 1)),
27 | page_size: z
28 | .union([z.string(), z.number()])
29 | .optional()
30 | .default(10)
31 | .transform((val) => (val ? Number(val) : 10)),
32 | name: z.string().optional(),
33 | label: z.string().optional(),
34 | })
35 | .passthrough();
36 |
37 | export type PageSearchType = z.infer;
38 |
--------------------------------------------------------------------------------
/src/routes/plugin_metadata/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { createFileRoute } from '@tanstack/react-router';
18 | import { useTranslation } from 'react-i18next';
19 |
20 | import PageHeader from '@/components/page/PageHeader';
21 | import { PluginMetadata } from '@/components/page-slice/plugin_metadata/PluginMetadata';
22 |
23 | function RouteComponent() {
24 | const { t } = useTranslation();
25 |
26 | return (
27 | <>
28 |
29 |
30 | >
31 | );
32 | }
33 |
34 | export const Route = createFileRoute('/plugin_metadata/')({
35 | component: RouteComponent,
36 | });
37 |
--------------------------------------------------------------------------------
/.asf.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one or more
3 | # contributor license agreements. See the NOTICE file distributed with
4 | # this work for additional information regarding copyright ownership.
5 | # The ASF licenses this file to You under the Apache License, Version 2.0
6 | # (the "License"); you may not use this file except in compliance with
7 | # the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | github:
19 | description: Dashboard for Apache APISIX
20 | homepage: https://apisix.apache.org/
21 | labels:
22 | - dashboard
23 | - api
24 | - api-management
25 | - apisix
26 | - devops
27 |
28 | enabled_merge_buttons:
29 | squash: true
30 | merge: false
31 | rebase: false
32 |
33 | protected_branches:
34 | master:
35 | required_pull_request_reviews:
36 | require_code_owner_reviews: true
37 | required_approving_review_count: 2
38 |
39 | notifications:
40 | commits: notifications@apisix.apache.org
41 | issues: notifications@apisix.apache.org
42 | pullrequests: notifications@apisix.apache.org
43 |
--------------------------------------------------------------------------------
/e2e/server/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one or more
3 | # contributor license agreements. See the NOTICE file distributed with
4 | # this work for additional information regarding copyright ownership.
5 | # The ASF licenses this file to You under the Apache License, Version 2.0
6 | # (the "License"); you may not use this file except in compliance with
7 | # the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | FROM node:22-alpine AS base
19 |
20 | # install deps
21 | FROM base AS deps
22 | WORKDIR /app
23 | COPY package.json pnpm-lock.yaml* ./
24 | RUN \
25 | if [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm install; \
26 | else echo 'Lockfile not found.' && exit 1; \
27 | fi
28 |
29 | # build ui
30 | FROM base AS builder
31 | WORKDIR /app
32 | COPY --from=deps /app/node_modules ./node_modules
33 | COPY . .
34 | # we need git to get commit sha
35 | RUN apk add --no-cache git
36 | RUN corepack enable pnpm && pnpm build
37 |
38 | # embed dashboard ui into apisix
39 | FROM apache/apisix:dev
40 | COPY --from=builder /app/dist /usr/local/apisix/ui/
41 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormDisplayDate.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { InputWrapper, type InputWrapperProps,Text } from '@mantine/core';
18 | import dayjs from 'dayjs';
19 |
20 | type FormDisplayDateProps = InputWrapperProps & {
21 | date: dayjs.ConfigType;
22 | };
23 | const format = 'YYYY-MM-DD HH:mm:ss';
24 | export const FormDisplayDate = (props: FormDisplayDateProps) => {
25 | const { date, ...rest } = props;
26 | const d = typeof date === 'number' ? date * 1000 : date;
27 | return (
28 |
29 |
30 | {d ? dayjs(d).format(format) : '-'}
31 |
32 |
33 | );
34 | };
35 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartUpstream/util.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { produce } from 'immer';
18 | import { isNotEmpty } from 'rambdax';
19 |
20 | import type { APISIXType } from '@/types/schema/apisix';
21 |
22 | import type { FormPartUpstreamType } from './schema';
23 |
24 | export const produceToUpstreamForm = (
25 | upstream: Partial,
26 | /** default to upstream */
27 | base: object = upstream
28 | ) =>
29 | produce(base, (d: FormPartUpstreamType) => {
30 | d.__checksEnabled = !!upstream.checks && isNotEmpty(upstream.checks);
31 | d.__checksPassiveEnabled =
32 | !!upstream.checks?.passive && isNotEmpty(upstream.checks.passive);
33 | });
34 |
--------------------------------------------------------------------------------
/src/components/form/util.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import type { FieldValues, UseControllerProps } from 'react-hook-form';
18 |
19 | export const genControllerProps = (
20 | props: UseControllerProps & R,
21 | defaultValueFallback?: unknown
22 | ) => {
23 | const { name, control, defaultValue, rules, shouldUnregister, ...restProps } =
24 | props;
25 | const { disabled } = restProps;
26 | return {
27 | controllerProps: {
28 | name,
29 | control,
30 | defaultValue:
31 | defaultValue ??
32 | (defaultValueFallback as UseControllerProps['defaultValue']),
33 | rules,
34 | shouldUnregister,
35 | disabled,
36 | },
37 | restProps,
38 | };
39 | };
40 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartRoute/schema.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIX } from '@/types/schema/apisix';
20 |
21 | export const RoutePostSchema = APISIX.Route.omit({
22 | id: true,
23 | create_time: true,
24 | update_time: true,
25 | }).extend({
26 | // the FormItemEditor (monaco) is for editing text,
27 | // and passing the original schema of `vars` for validation
28 | // is not in line with this usage.
29 | vars: z.string().optional(),
30 | });
31 |
32 | export type RoutePostType = z.infer;
33 |
34 | export const RoutePutSchema = APISIX.Route.extend({
35 | vars: z.string().optional(),
36 | });
37 |
38 | export type RoutePutType = z.infer;
39 |
--------------------------------------------------------------------------------
/src/config/antdConfigProvider.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import '@ant-design/v5-patch-for-react-19';
18 |
19 | import { ConfigProvider } from 'antd';
20 | import enUS from 'antd/locale/en_US';
21 | import type { PropsWithChildren } from 'react';
22 | import { useTranslation } from 'react-i18next';
23 |
24 | export const AntdConfigProvider = (props: PropsWithChildren) => {
25 | const { children } = props;
26 | const { t } = useTranslation();
27 |
28 | return (
29 |
{t('noData')}
}
33 | theme={{
34 | token: {
35 | borderRadiusSM: 2,
36 | },
37 | }}
38 | >
39 | {children}
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/src/utils/monaco.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import 'monaco-editor/esm/vs/editor/editor.all.js';
18 | import 'monaco-editor/esm/vs/language/json/monaco.contribution';
19 |
20 | import { loader } from '@monaco-editor/react';
21 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
22 | import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
23 | import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
24 |
25 | export { monaco };
26 |
27 | export const setupMonacoEditor = () => {
28 | self.MonacoEnvironment = {
29 | getWorker(_, label) {
30 | if (label === 'json') return new jsonWorker();
31 | return new editorWorker();
32 | },
33 | };
34 | loader.config({ monaco });
35 | loader.init();
36 | };
37 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/consumers.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 |
22 | const Consumer = z
23 | .object({
24 | username: z
25 | .string()
26 | .min(1)
27 | // ref: https://github.com/apache/apisix/blob/a2482df74d712228a1a6644662d74d2f51a3f5e6/apisix/schema_def.lua#L713
28 | .regex(/^[a-zA-Z0-9_-]+$/),
29 | plugins: APISIXPlugins.Plugins.optional(),
30 | group_id: z.string().optional(),
31 | })
32 | .merge(APISIXCommon.Basic.omit({ name: true }))
33 | .merge(APISIXCommon.Info.omit({ id: true }));
34 |
35 | export const APISIXConsumers = {
36 | Consumer,
37 | ConsumerPut: Consumer.omit({
38 | create_time: true,
39 | update_time: true,
40 | }),
41 | };
42 |
--------------------------------------------------------------------------------
/src/components/page/PageHeader.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { Box, Group, Stack,Text, Title } from '@mantine/core';
18 | import { type FC } from 'react';
19 |
20 | type PageHeaderProps = {
21 | title: string;
22 | desc?: string;
23 | extra?: React.ReactNode;
24 | };
25 |
26 | const PageHeader: FC = (props) => {
27 | const { title, desc, extra } = props;
28 | return (
29 |
30 |
31 |
32 | {title}
33 | {desc && (
34 |
35 | {desc}
36 |
37 | )}
38 |
39 | {extra}
40 |
41 |
42 | );
43 | };
44 |
45 | export default PageHeader;
46 |
--------------------------------------------------------------------------------
/e2e/server/docker-compose.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one or more
3 | # contributor license agreements. See the NOTICE file distributed with
4 | # this work for additional information regarding copyright ownership.
5 | # The ASF licenses this file to You under the Apache License, Version 2.0
6 | # (the "License"); you may not use this file except in compliance with
7 | # the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | services:
19 | apisix:
20 | build:
21 | context: ../..
22 | dockerfile: e2e/server/Dockerfile
23 | restart: always
24 | volumes:
25 | - ./apisix_conf.yml:/usr/local/apisix/conf/config.yaml:ro
26 | ports:
27 | - '9180:9180'
28 | depends_on:
29 | - etcd
30 | networks:
31 | - apisix
32 |
33 | etcd:
34 | image: bitnamilegacy/etcd:3.5
35 |
36 | restart: always
37 | volumes:
38 | - etcd_data:/bitnami/etcd
39 | environment:
40 | ETCD_ENABLE_V2: 'true'
41 | ALLOW_NONE_AUTHENTICATION: 'yes'
42 | ETCD_ADVERTISE_CLIENT_URLS: 'http://etcd:2379'
43 | ETCD_LISTEN_CLIENT_URLS: 'http://0.0.0.0:2379'
44 | networks:
45 | - apisix
46 |
47 | networks:
48 | apisix:
49 | driver: bridge
50 |
51 | volumes:
52 | etcd_data:
53 |
--------------------------------------------------------------------------------
/e2e/server/apisix_conf.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Licensed to the Apache Software Foundation (ASF) under one or more
3 | # contributor license agreements. See the NOTICE file distributed with
4 | # this work for additional information regarding copyright ownership.
5 | # The ASF licenses this file to You under the Apache License, Version 2.0
6 | # (the "License"); you may not use this file except in compliance with
7 | # the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 |
18 | apisix:
19 | node_listen: 9080 # APISIX listening port
20 | enable_ipv6: false
21 | proxy_mode: http&stream
22 | stream_proxy:
23 | tcp:
24 | - 9100
25 | udp:
26 | - 9200
27 |
28 | deployment:
29 | admin:
30 | allow_admin: # https://nginx.org/en/docs/http/ngx_http_access_module.html#allow
31 | - 0.0.0.0/0 # We need to restrict ip access rules for security. 0.0.0.0/0 is for test.
32 |
33 | admin_key:
34 | - name: "admin"
35 | key: edd1c9f034335f136f87ad84b625c8f1
36 | role: admin # admin: manage all configuration data
37 |
38 | etcd:
39 | host: # it's possible to define multiple etcd hosts addresses of the same etcd cluster.
40 | - "http://etcd:2379" # multiple etcd address
41 | prefix: "/apisix" # apisix configurations prefix
42 | timeout: 30 # 30 seconds
43 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartSSL/schema.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { produce } from 'immer';
18 | import { isNotEmpty } from 'rambdax';
19 | import { z } from 'zod';
20 |
21 | import { APISIX, type APISIXType } from '@/types/schema/apisix';
22 |
23 | const SSLForm = z.object({
24 | __clientEnabled: z.boolean().optional(),
25 | });
26 |
27 | export const SSLPostSchema = APISIX.SSL.omit({
28 | id: true,
29 | create_time: true,
30 | update_time: true,
31 | }).merge(SSLForm);
32 |
33 | export type SSLPostType = z.infer;
34 |
35 | export const SSLPutSchema = APISIX.SSL.merge(SSLForm);
36 |
37 | export type SSLPutType = z.infer;
38 |
39 | export const produceToSSLForm = (data: APISIXType['SSL']) =>
40 | produce(data as SSLPutType, (draft) => {
41 | draft.__clientEnabled = isNotEmpty(draft.client);
42 | });
43 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartRoute/util.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { produce } from 'immer';
18 |
19 | import { produceRmUpstreamWhenHas } from '@/utils/form-producer';
20 | import { pipeProduce } from '@/utils/producer';
21 |
22 | import type { RoutePostType, RoutePutType } from './schema';
23 |
24 | export const produceVarsToForm = produce((draft: RoutePostType) => {
25 | if (draft.vars && Array.isArray(draft.vars)) {
26 | draft.vars = JSON.stringify(draft.vars);
27 | }
28 | }) as (draft: RoutePostType) => RoutePutType;
29 |
30 | export const produceVarsToAPI = produce((draft: RoutePostType) => {
31 | if (draft.vars && typeof draft.vars === 'string') {
32 | draft.vars = JSON.parse(draft.vars);
33 | }
34 | });
35 |
36 | export const produceRoute = pipeProduce(
37 | produceRmUpstreamWhenHas('service_id', 'upstream_id'),
38 | produceVarsToAPI
39 | );
40 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.base.schema.json",
3 | "name": "APISIX Dashboard Dev Environment",
4 | "dockerComposeFile": [
5 | "./docker-compose.yml"
6 | ],
7 | "service": "apisix-dashboard",
8 | "workspaceFolder": "/workspace",
9 | "shutdownAction": "stopCompose",
10 | "postCreateCommand": "pnpm i && echo '\nUse `pnpm dev` to continue'",
11 | "forwardPorts": [
12 | 9080,
13 | 9180,
14 | 9100,
15 | 9200,
16 | 5173,
17 | 5174,
18 | 4173
19 | ],
20 | "portsAttributes": {
21 | "5173": {
22 | "label": "APISIX Dashboard",
23 | "onAutoForward": "ignore"
24 | },
25 | "5174": {
26 | "label": "APISIX Dashboard HMR WS",
27 | "onAutoForward": "silent"
28 | },
29 | "9180": {
30 | "label": "APISIX Admin API Port",
31 | "onAutoForward": "notify"
32 | },
33 | "9100": {
34 | "label": "APISIX Stream Proxy TCP Port",
35 | "onAutoForward": "silent"
36 | },
37 | "9200": {
38 | "label": "APISIX Stream Proxy UDP Port",
39 | "onAutoForward": "silent"
40 | }
41 | },
42 | "customizations": {
43 | "vscode": {
44 | "extensions": [
45 | "vunguyentuan.vscode-css-variables",
46 | "dbaeumer.vscode-eslint",
47 | "drKnoxy.eslint-disable-snippets",
48 | "esbenp.prettier-vscode",
49 | "christian-kohler.path-intellisense",
50 | "lokalise.i18n-ally",
51 | "formulahendry.auto-close-tag",
52 | "formulahendry.auto-rename-tag",
53 | "github.vscode-pull-request-github",
54 | "redhat.vscode-yaml"
55 | ]
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/e2e/pom/plugin_metadata.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { uiGoto } from '@e2e/utils/ui';
18 | import { expect, type Page } from '@playwright/test';
19 |
20 | const locator = {
21 | getPluginMetadataNavBtn: (page: Page) =>
22 | page.getByRole('link', { name: 'Plugin Metadata', exact: true }),
23 | getSelectPluginsBtn: (page: Page) =>
24 | page.getByRole('button', { name: 'Select Plugins' }),
25 | };
26 |
27 | const assert = {
28 | isIndexPage: async (page: Page) => {
29 | await expect(page).toHaveURL((url) =>
30 | url.pathname.endsWith('/plugin_metadata')
31 | );
32 | const title = page.getByRole('heading', { name: 'Plugin Metadata' });
33 | await expect(title).toBeVisible();
34 | },
35 | };
36 |
37 | const goto = {
38 | toIndex: (page: Page) => uiGoto(page, '/plugin_metadata'),
39 | };
40 |
41 | export const pluginMetadataPom = {
42 | ...locator,
43 | ...assert,
44 | ...goto,
45 | };
46 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/plugins.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | const Plugin = z.record(z.unknown());
20 |
21 | const Plugins = z.record(Plugin);
22 |
23 | const PluginsQuery = z.object({
24 | subsystem: z.union([z.literal('http'), z.literal('stream')]).optional(),
25 | });
26 |
27 | const PluginConsumerSchema = z.object({});
28 | const PluginMetadataSchema = z.object({});
29 |
30 | const PluginSchema = z.object({
31 | consumer_schema: PluginConsumerSchema.optional(),
32 | metadata_schema: PluginMetadataSchema.optional(),
33 | schema: z.object({}).optional(),
34 | });
35 |
36 | const PluginSchemaKeys = z.union([
37 | z.literal('schema'),
38 | z.literal('consumer_schema'),
39 | z.literal('metadata_schema'),
40 | ]);
41 |
42 | export const APISIXPlugins = {
43 | Plugin,
44 | Plugins,
45 | PluginsQuery,
46 | PluginSchema,
47 | PluginSchemaKeys,
48 | PluginMetadataSchema,
49 | };
50 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/services.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 | import { APISIXUpstreams } from './upstreams';
22 |
23 | const Service = z
24 | .object({
25 | plugins: APISIXPlugins.Plugins.optional(),
26 | upstream: APISIXUpstreams.Upstream.omit({ id: true }).optional(),
27 | upstream_id: z.string().optional(),
28 | script: z.string().optional(),
29 | enable_websocket: z.boolean().optional(),
30 | hosts: z.array(z.string()).optional(),
31 | })
32 | .merge(APISIXCommon.Basic)
33 | .merge(APISIXCommon.Info);
34 |
35 | export const APISIXServices = {
36 | Service,
37 | ServicePost: Service.omit({
38 | id: true,
39 | create_time: true,
40 | update_time: true,
41 | }),
42 | ServicePut: Service.omit({
43 | create_time: true,
44 | update_time: true,
45 | }),
46 | };
47 |
--------------------------------------------------------------------------------
/src/apis/global_rules.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import type { AxiosInstance } from 'axios';
19 |
20 | import { API_GLOBAL_RULES } from '@/config/constant';
21 | import type { APISIXType } from '@/types/schema/apisix';
22 |
23 | export const getGlobalRuleListReq = (req: AxiosInstance) =>
24 | req
25 | .get(API_GLOBAL_RULES)
26 | .then((v) => v.data);
27 |
28 | export const getGlobalRuleReq = (req: AxiosInstance, id: string) =>
29 | req
30 | .get(
31 | `${API_GLOBAL_RULES}/${id}`
32 | )
33 | .then((v) => v.data);
34 |
35 | export const putGlobalRuleReq = (
36 | req: AxiosInstance,
37 | data: APISIXType['GlobalRulePut']
38 | ) => {
39 | const { id, ...rest } = data;
40 | return req.put<
41 | APISIXType['GlobalRulePut'],
42 | APISIXType['RespGlobalRuleDetail']
43 | >(`${API_GLOBAL_RULES}/${id}`, rest);
44 | };
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Please use this template for reporting suspected bugs.
3 | labels: [bug]
4 | body:
5 | - type: textarea
6 | id: description
7 | attributes:
8 | label: Issue description
9 | description: A clear and concise description of what the issue is.
10 | validations:
11 | required: true
12 | - type: textarea
13 | id: expected
14 | attributes:
15 | label: Expected behavior
16 | description: A clear and concise description of what you expected to happen.
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: howto
21 | attributes:
22 | label: How to Reproduce
23 | description: Describe the how we have to take to reproduce the behavior.
24 | placeholder: |
25 | 1. Go to '...'
26 | 2. Click on '....'
27 | 3. Scroll down to '....'
28 | 4. See error
29 | validations:
30 | required: true
31 | - type: textarea
32 | id: screenshots
33 | attributes:
34 | label: Screenshots
35 | description: Add screenshots to help explain your problem if applicable.
36 | - type: textarea
37 | id: environment
38 | attributes:
39 | label: Environment
40 | value: |
41 | - apisix version (cmd: `apisix version`):
42 | - OS (cmd: `uname -a`):
43 | - OpenResty / Nginx version (cmd: `nginx -V` or `openresty -V`):
44 | - etcd version, if have (cmd: run `etcd --version`):
45 | - apisix-dashboard version, if have:
46 | - Browser version, if have:
47 | - type: textarea
48 | id: additional
49 | attributes:
50 | label: Additional context
51 | description: Do you want to solve this issue? or add any other context about the problem here.
52 |
--------------------------------------------------------------------------------
/src/config/i18n.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import i18n from 'i18next';
18 | import { initReactI18next } from 'react-i18next';
19 |
20 | import de_common from '@/locales/de/common.json';
21 | import en_common from '@/locales/en/common.json';
22 | import es_common from '@/locales/es/common.json';
23 | import tr_common from '@/locales/tr/common.json';
24 | import zh_common from '@/locales/zh/common.json';
25 |
26 | export const resources = {
27 | en: {
28 | common: en_common,
29 | },
30 | de: {
31 | common: de_common,
32 | },
33 | zh: {
34 | common: zh_common,
35 | },
36 | es: {
37 | common: es_common,
38 | },
39 | tr: {
40 | common: tr_common,
41 | },
42 | } as const;
43 |
44 | export type Resources = typeof resources;
45 | export const defaultNS: keyof Resources['en'] = 'common';
46 |
47 | i18n.use(initReactI18next).init({
48 | lng: 'en',
49 | ns: ['common'],
50 | defaultNS,
51 | resources,
52 | fallbackLng: 'en',
53 | });
54 |
55 | export default i18n;
56 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartProto.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { type FieldValues,useFormContext } from 'react-hook-form';
18 | import { useTranslation } from 'react-i18next';
19 |
20 | import type { APISIXType } from '@/types/schema/apisix';
21 |
22 | import {
23 | FormItemTextareaWithUpload,
24 | type FormItemTextareaWithUploadProps,
25 | } from '../form/TextareaWithUpload';
26 |
27 | const fileTypes = '.proto,.pb';
28 | export const FormPartProto = (
29 | props: Pick, 'allowUpload'>
30 | ) => {
31 | const { t } = useTranslation();
32 | const form = useFormContext();
33 | return (
34 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/src/components/form/TextInput.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { TextInput, type TextInputProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemTextInputProps =
27 | UseControllerProps & TextInputProps;
28 |
29 | export const FormItemTextInput = (
30 | props: FormItemTextInputProps
31 | ) => {
32 | const { controllerProps, restProps } = genControllerProps(props, '');
33 | const {
34 | field: { value, onChange: fOnChange, ...restField },
35 | fieldState,
36 | } = useController(controllerProps);
37 | return (
38 | {
42 | fOnChange(e);
43 | restProps.onChange?.(e);
44 | }}
45 | {...restField}
46 | {...restProps}
47 | />
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/src/routes/services/detail.$id/routes/detail.$routeId.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | createFileRoute,
19 | useNavigate,
20 | useParams,
21 | } from '@tanstack/react-router';
22 |
23 | import { RouteDetail } from '@/routes/routes/detail.$id';
24 | import { CommonFormContext } from '@/utils/form-context';
25 |
26 | function RouteComponent() {
27 | const { id, routeId } = useParams({
28 | from: '/services/detail/$id/routes/detail/$routeId',
29 | });
30 | const navigate = useNavigate();
31 | return (
32 |
33 |
36 | navigate({
37 | to: '/services/detail/$id/routes',
38 | params: { id },
39 | })
40 | }
41 | />
42 |
43 | );
44 | }
45 |
46 | export const Route = createFileRoute(
47 | '/services/detail/$id/routes/detail/$routeId'
48 | )({
49 | component: RouteComponent,
50 | });
51 |
--------------------------------------------------------------------------------
/src/utils/form-producer.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { produce } from 'immer';
18 | import { all, isNotEmpty, map, values } from 'rambdax';
19 |
20 | import type { APISIXType } from '@/types/schema/apisix';
21 |
22 | const allFalsy = (obj: object) =>
23 | all(
24 | Boolean,
25 | map((val) => !val, values(obj))
26 | );
27 | type hasTimeout = Pick;
28 | export const produceTimeout = produce>((draft) => {
29 | if (draft.timeout && allFalsy(draft.timeout)) {
30 | delete draft.timeout;
31 | }
32 | });
33 |
34 | export const produceTime = produce>((draft) => {
35 | if (draft.create_time) delete draft.create_time;
36 | if (draft.update_time) delete draft.update_time;
37 | });
38 |
39 | export const produceRmUpstreamWhenHas = (
40 | ...idKeys: ('upstream_id' | 'service_id')[]
41 | ) =>
42 | produce((draft) => {
43 | if (idKeys.some((idKey) => draft[idKey]) && isNotEmpty(draft.upstream)) {
44 | delete draft.upstream;
45 | }
46 | });
47 |
--------------------------------------------------------------------------------
/src/components/form/TextArray.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { TagsInput, type TagsInputProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemTextArrayProps =
27 | UseControllerProps & TagsInputProps;
28 |
29 | export const FormItemTextArray = (
30 | props: FormItemTextArrayProps
31 | ) => {
32 | const { controllerProps, restProps } = genControllerProps(props, []);
33 |
34 | const {
35 | field: { value, onChange: fOnChange, ...restField },
36 | fieldState,
37 | } = useController(controllerProps);
38 | return (
39 | {
43 | fOnChange(value);
44 | restProps?.onChange?.(value);
45 | }}
46 | {...restField}
47 | {...restProps}
48 | />
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/src/apis/plugin_configs.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import type { AxiosInstance } from 'axios';
18 |
19 | import { API_PLUGIN_CONFIGS } from '@/config/constant';
20 | import type { APISIXType } from '@/types/schema/apisix';
21 | import type { PageSearchType } from '@/types/schema/pageSearch';
22 |
23 | export const getPluginConfigListReq = (req: AxiosInstance, params: PageSearchType) =>
24 | req
25 | .get(API_PLUGIN_CONFIGS, {
26 | params,
27 | })
28 | .then((v) => v.data);
29 |
30 | export const getPluginConfigReq = (req: AxiosInstance, id: string) =>
31 | req
32 | .get(
33 | `${API_PLUGIN_CONFIGS}/${id}`
34 | )
35 | .then((v) => v.data);
36 |
37 | export const putPluginConfigReq = (
38 | req: AxiosInstance,
39 | data: APISIXType['PluginConfigPut']
40 | ) => {
41 | const { id, ...rest } = data;
42 | return req.put<
43 | APISIXType['PluginConfigPut'],
44 | APISIXType['RespPluginConfigDetail']
45 | >(`${API_PLUGIN_CONFIGS}/${id}`, rest);
46 | };
47 |
--------------------------------------------------------------------------------
/e2e/utils/common.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { access, readFile } from 'node:fs/promises';
18 | import path from 'node:path';
19 |
20 | import { nanoid } from 'nanoid';
21 | import selfsigned from 'selfsigned';
22 | import { parse } from 'yaml';
23 |
24 | type APISIXConf = {
25 | deployment: { admin: { admin_key: { key: string }[] } };
26 | };
27 | export const getAPISIXConf = async () => {
28 | const currentDir = new URL('.', import.meta.url).pathname;
29 | const confPath = path.join(currentDir, '../server/apisix_conf.yml');
30 | const file = await readFile(confPath, 'utf-8');
31 | const res = parse(file) as APISIXConf;
32 | return { adminKey: res.deployment.admin.admin_key[0].key };
33 | };
34 |
35 | export const fileExists = async (filePath: string) => {
36 | try {
37 | await access(filePath);
38 | return true;
39 | } catch {
40 | return false;
41 | }
42 | };
43 |
44 | export const randomId = (info: string) => `${info}_${nanoid()}`;
45 |
46 | export const genTLS = () => {
47 | const { cert, private: key } = selfsigned.generate();
48 | return { cert, key };
49 | };
50 |
--------------------------------------------------------------------------------
/src/components/form/Switch.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { Switch, type SwitchProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemSwitchProps = Omit<
27 | UseControllerProps & SwitchProps,
28 | 'defaultValue'
29 | >;
30 |
31 | export const FormItemSwitch = (
32 | props: FormItemSwitchProps
33 | ) => {
34 | const { controllerProps, restProps } = genControllerProps(props, false);
35 | const {
36 | field: { value, onChange: fOnChange, ...restField },
37 | fieldState,
38 | } = useController(controllerProps);
39 | return (
40 | {
46 | fOnChange(e);
47 | restProps.onChange?.(e);
48 | }}
49 | {...restField}
50 | {...restProps}
51 | />
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/src/components/form/Textarea.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | Textarea as MTextarea,
19 | type TextareaProps as MTextareaProps,
20 | } from '@mantine/core';
21 | import {
22 | type FieldValues,
23 | useController,
24 | type UseControllerProps,
25 | } from 'react-hook-form';
26 |
27 | import { genControllerProps } from './util';
28 |
29 | export type FormItemTextareaProps =
30 | UseControllerProps & MTextareaProps;
31 |
32 | export const FormItemTextarea = (
33 | props: FormItemTextareaProps
34 | ) => {
35 | const { controllerProps, restProps } = genControllerProps(props, '');
36 | const {
37 | field: { value, onChange: fOnChange, ...restField },
38 | fieldState,
39 | } = useController(controllerProps);
40 | return (
41 | {
45 | fOnChange(e);
46 | restProps.onChange?.(e);
47 | }}
48 | resize="vertical"
49 | {...restField}
50 | {...restProps}
51 | />
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/common.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | const Labels = z.record(z.string());
20 |
21 | const Expr = z.array(z.unknown());
22 |
23 | const Status = z.union([z.literal(0), z.literal(1)]);
24 |
25 | const Basic = z
26 | .object({
27 | name: z.string(),
28 | desc: z.string(),
29 | labels: Labels,
30 | status: Status.optional(),
31 | })
32 | .partial();
33 |
34 | const ID = z.object({
35 | id: z.string(),
36 | });
37 |
38 | const Timestamp = z.object({
39 | create_time: z.number(),
40 | update_time: z.number(),
41 | });
42 |
43 | const Info = ID.merge(Timestamp);
44 |
45 | const HttpMethod = z.union([
46 | z.literal('GET'),
47 | z.literal('POST'),
48 | z.literal('PUT'),
49 | z.literal('DELETE'),
50 | z.literal('PATCH'),
51 | z.literal('HEAD'),
52 | z.literal('OPTIONS'),
53 | z.literal('CONNECT'),
54 | z.literal('TRACE'),
55 | z.literal('PURGE'),
56 | ]);
57 |
58 | export const APISIXCommon = {
59 | Basic,
60 | Labels,
61 | Expr,
62 | ID,
63 | Timestamp,
64 | Info,
65 | HttpMethod,
66 | Status,
67 | };
68 |
--------------------------------------------------------------------------------
/src/utils/zod.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { xor } from 'rambdax';
18 | import { type RefinementCtx, z } from 'zod';
19 | import { init } from 'zod-empty';
20 |
21 | // ref: https://github.com/colinhacks/zod/issues/61#issuecomment-1741983149
22 | export const zOneOf =
23 | <
24 | A,
25 | K1 extends Extract,
26 | K2 extends Extract,
27 | R extends A &
28 | (
29 | | (Required> & { [P in K2]: undefined })
30 | | (Required> & { [P in K1]: undefined })
31 | )
32 | >(
33 | key1: K1,
34 | key2: K2
35 | ): ((arg: A, ctx: RefinementCtx) => arg is R) =>
36 | (arg, ctx): arg is R => {
37 | if (xor(arg[key1] as boolean, arg[key2] as boolean)) {
38 | [key1, key2].forEach((key) => {
39 | ctx.addIssue({
40 | path: [key],
41 | code: z.ZodIssueCode.custom,
42 | message: `Either '${key1}' or '${key2}' must be filled, but not both`,
43 | });
44 | });
45 | return false;
46 | }
47 | return true;
48 | };
49 |
50 | export const zGetDefault = init;
51 |
--------------------------------------------------------------------------------
/docs/en/development.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Development
3 | ---
4 |
5 | Currently, APISIX Dashboard is a SPA that only supports CSR. For easier development, it is recommended to use `VS Code` and the `Dev Containers` extension. This document uses this approach as an example.
6 |
7 | We also welcome contributions to the documentation, including guides for your preferred development workflows.
8 |
9 | ## Prerequisites
10 |
11 | Please install `VS Code` and follow [Developing inside a Container](https://code.visualstudio.com/docs/devcontainers/containers) to set up your environment.
12 |
13 | `git`, `node`, `pnpm`, as well as `apisix` and `etcd` are all provided in the `.devcontainer` configuration.
14 |
15 | ## Clone then open the project
16 |
17 | ```sh
18 | $ git clone https://github.com/apache/apisix-dashboard.git
19 | $ cd apisix-dashboard
20 | $ code .
21 | ```
22 |
23 | ## Start developing
24 |
25 | ### 1. Reopen in Container
26 |
27 | Generally, after opening the project in `VS Code`, a prompt will appear in the bottom right corner. Please click `Reopen in Container`.
28 |
29 | 
30 |
31 | If there is no prompt, open the `Command Palette`, type `reopen`, and select `Dev Containers: Reopen in Container`.
32 |
33 | 
34 |
35 | ### 2. Wait for the environment to be ready
36 |
37 | After clicking, it will take some time for the environment to be built, depending on your network conditions.
38 |
39 | Once the environment is ready, similar information will be displayed in the `TERMINAL` tab.
40 |
41 | 
42 |
43 | ### 3. Develop
44 |
45 | Open a new Terminal and execute:
46 |
47 | ```sh
48 | pnpm dev
49 | ```
50 |
51 | You can then modify the code and preview the updated page in the browser in real-time.
52 |
--------------------------------------------------------------------------------
/playwright.config.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { defineConfig, devices } from '@playwright/test';
18 |
19 | import { env } from './e2e/utils/env';
20 |
21 | /**
22 | * See https://playwright.dev/docs/test-configuration.
23 | */
24 | export default defineConfig({
25 | testDir: './e2e/tests',
26 | outputDir: './test-results',
27 | fullyParallel: true,
28 | forbidOnly: !!process.env.CI,
29 | retries: process.env.CI ? 2 : 0,
30 | workers: process.env.CI ? 1 : undefined,
31 | reporter: [
32 | ['html'],
33 | ['list'],
34 | [
35 | '@estruyf/github-actions-reporter',
36 | {
37 | useDetails: true,
38 | showError: true,
39 | },
40 | ],
41 | ],
42 | use: {
43 | baseURL: env.E2E_TARGET_URL,
44 | trace: 'on-first-retry',
45 | },
46 |
47 | projects: [
48 | {
49 | name: 'chromium',
50 | use: {
51 | ...devices['Desktop Chrome'],
52 | viewport: { width: 1920, height: 1080 },
53 | permissions: ['clipboard-read'],
54 | // use chrome
55 | // channel: "chrome",
56 | },
57 | },
58 | ],
59 | });
60 |
--------------------------------------------------------------------------------
/src/utils/useSearchParams.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | getRouteApi,
19 | type RegisteredRouter,
20 | type RouteIds,
21 | useNavigate,
22 | } from '@tanstack/react-router';
23 | import { useCallback } from 'react';
24 |
25 |
26 |
27 | export type RouteTreeIds = RouteIds;
28 |
29 | export const useSearchParams = (
30 | routeId: T
31 | ) => {
32 | const { useSearch } = getRouteApi(routeId);
33 | const navigate = useNavigate();
34 | const params = useSearch() as P;
35 |
36 | const setParams = useCallback(
37 | (props: Partial
) => {
38 | return navigate({
39 | to: '.',
40 | search: (prev) => ({ ...prev, ...props }),
41 | });
42 | },
43 | [navigate]
44 | );
45 | const resetParams = useCallback(
46 | () => navigate({ to: '.', search: {}, replace: true }),
47 | [navigate]
48 | );
49 |
50 | return { params, setParams, resetParams } as const;
51 | };
52 |
53 | export type UseSearchParams<
54 | T extends RouteTreeIds,
55 | P extends object
56 | > = ReturnType>;
57 |
--------------------------------------------------------------------------------
/src/apis/protos.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import type { AxiosInstance } from 'axios';
18 |
19 | import { API_PROTOS } from '@/config/constant';
20 | import type { APISIXType } from '@/types/schema/apisix';
21 | import type { PageSearchType } from '@/types/schema/pageSearch';
22 |
23 | export const getProtoListReq = (req: AxiosInstance, params: PageSearchType) =>
24 | req
25 | .get(API_PROTOS, {
26 | params,
27 | })
28 | .then((v) => v.data);
29 |
30 | export const getProtoReq = (req: AxiosInstance, id: string) =>
31 | req
32 | .get(`${API_PROTOS}/${id}`)
33 | .then((v) => v.data);
34 |
35 | export const putProtoReq = (req: AxiosInstance, data: APISIXType['Proto']) => {
36 | const { id, ...rest } = data;
37 | return req.put(
38 | `${API_PROTOS}/${id}`,
39 | rest
40 | );
41 | };
42 |
43 | export const postProtoReq = (
44 | req: AxiosInstance,
45 | data: APISIXType['ProtoPost']
46 | ) => {
47 | return req.post(
48 | API_PROTOS,
49 | data
50 | );
51 | };
52 |
--------------------------------------------------------------------------------
/src/components/form/NumberInput.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { NumberInput, type NumberInputProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemNumberInputProps =
27 | UseControllerProps & NumberInputProps;
28 |
29 | export const FormItemNumberInput = (
30 | props: FormItemNumberInputProps
31 | ) => {
32 | const { controllerProps, restProps } = genControllerProps(props);
33 | const {
34 | field: { value, onChange: fOnChange, ...restField },
35 | fieldState,
36 | } = useController(controllerProps);
37 | return (
38 | {
42 | restProps.onChange?.(e);
43 | // Mantine's NumberInput returns a string when the value is empty
44 | const val = typeof e === 'string' ? undefined : e;
45 | fOnChange(val);
46 | }}
47 | {...restField}
48 | {...restProps}
49 | />
50 | );
51 | };
52 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/ssls.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 |
21 | const SSLType = z.union([z.literal('server'), z.literal('client')]);
22 |
23 | const SSLProtocols = z.union([
24 | z.literal('TLSv1.1'),
25 | z.literal('TLSv1.2'),
26 | z.literal('TLSv1.3'),
27 | ]);
28 |
29 | const SSLClient = z.object({
30 | ca: z.string().optional(),
31 | depth: z.number().min(0).default(1).optional(),
32 | skip_mtls_uri_regex: z.array(z.string()).optional(),
33 | });
34 |
35 | const SSL = z
36 | .object({
37 | cert: z.string(),
38 | key: z.string(),
39 | sni: z.string().optional(),
40 | snis: z.array(z.string()),
41 | certs: z.array(z.string()),
42 | keys: z.array(z.string()),
43 | client: SSLClient.optional(),
44 | type: SSLType.optional(),
45 | status: APISIXCommon.Status.optional(),
46 | ssl_protocols: z.array(SSLProtocols).optional(),
47 | })
48 | .partial()
49 | .merge(APISIXCommon.Basic)
50 | .merge(APISIXCommon.Info);
51 |
52 | export const APISIXSSLs = {
53 | SSL,
54 | SSLStatus: APISIXCommon.Status,
55 | SSLType,
56 | SSLProtocols,
57 | SSLClient,
58 | };
59 |
--------------------------------------------------------------------------------
/src/components/page/Tabs.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | Tabs as MTabs,
19 | type TabsListProps,
20 | type TabsProps as MTabsProps,
21 | } from '@mantine/core';
22 |
23 | export type TabsItem = {
24 | value: string;
25 | label: string;
26 | content?: React.ReactNode;
27 | };
28 | export type TabsProps = {
29 | defaultValue?: string;
30 | items: TabsItem[];
31 | listProps?: TabsListProps;
32 | } & MTabsProps;
33 |
34 | export const Tabs = (props: TabsProps) => {
35 | const { defaultValue, items, listProps, ...rest } = props;
36 | return (
37 |
42 |
43 | {items.map((item) => (
44 |
45 | {item.label}
46 |
47 | ))}
48 |
49 | {items.map(
50 | (item) =>
51 | item.content && (
52 |
53 | {item.content}
54 |
55 | )
56 | )}
57 |
58 | );
59 | };
60 |
--------------------------------------------------------------------------------
/src/config/constant.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | export const BASE_PATH = '/ui';
18 | export const PAGE_SIZE_MIN = 10;
19 | export const PAGE_SIZE_MAX = 500;
20 | export const API_HEADER_KEY = 'X-API-KEY';
21 | export const API_PREFIX = '/apisix/admin';
22 | export const API_ROUTES = '/routes';
23 | export const API_STREAM_ROUTES = '/stream_routes';
24 | export const API_UPSTREAMS = '/upstreams';
25 | export const API_PROTOS = '/protos';
26 | export const API_SERVICES = '/services';
27 | export const API_GLOBAL_RULES = '/global_rules';
28 | export const API_PLUGINS = '/plugins';
29 | export const API_PLUGINS_LIST = '/plugins/list';
30 | export const API_PLUGIN_METADATA = '/plugin_metadata';
31 | export const API_SECRETS = '/secrets';
32 | export const API_CONSUMERS = '/consumers';
33 | export const API_CONSUMER_GROUPS = '/consumer_groups';
34 | export const API_CREDENTIALS = (username: string) =>
35 | `${API_CONSUMERS}/${username}/credentials` as const;
36 | export const API_SSLS = '/ssls';
37 | export const API_PLUGIN_CONFIGS = '/plugin_configs';
38 |
39 | export const SKIP_INTERCEPTOR_HEADER = '__dashboard__skipInterceptor';
40 | export const APPSHELL_HEADER_HEIGHT = 60;
41 | export const APPSHELL_NAVBAR_WIDTH = 250;
42 |
--------------------------------------------------------------------------------
/src/config/navRoutes.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import type { Resources } from '@/config/i18n';
18 | import type { FileRouteTypes } from '@/routeTree.gen';
19 |
20 | export type NavRoute = {
21 | to: FileRouteTypes['to'];
22 | label: keyof Resources['en']['common']['sources'];
23 | };
24 | export const navRoutes: NavRoute[] = [
25 | {
26 | to: '/services',
27 | label: 'services',
28 | },
29 | {
30 | to: '/routes',
31 | label: 'routes',
32 | },
33 | {
34 | to: '/stream_routes',
35 | label: 'streamRoutes',
36 | },
37 | {
38 | to: '/upstreams',
39 | label: 'upstreams',
40 | },
41 | {
42 | to: '/consumers',
43 | label: 'consumers',
44 | },
45 | {
46 | to: '/consumer_groups',
47 | label: 'consumerGroups',
48 | },
49 | {
50 | to: '/ssls',
51 | label: 'ssls',
52 | },
53 | {
54 | to: '/global_rules',
55 | label: 'globalRules',
56 | },
57 | {
58 | to: '/plugin_metadata',
59 | label: 'pluginMetadata',
60 | },
61 | {
62 | to: '/plugin_configs',
63 | label: 'pluginConfigs',
64 | },
65 | {
66 | to: '/secrets',
67 | label: 'secrets',
68 | },
69 | {
70 | to: '/protos',
71 | label: 'protos',
72 | },
73 | ];
74 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/routes.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 | import { APISIXUpstreams } from './upstreams';
22 |
23 | const Route = z
24 | .object({
25 | uri: z.string(),
26 | uris: z.array(z.string()),
27 | host: z.string(),
28 | hosts: z.array(z.string()),
29 | methods: z.array(APISIXCommon.HttpMethod),
30 | remote_addr: z.string(),
31 | remote_addrs: z.array(z.string()),
32 | vars: APISIXCommon.Expr,
33 | filter_func: z.string(),
34 | script: z.string(),
35 | script_id: z.string(),
36 | plugins: APISIXPlugins.Plugins,
37 | plugin_config_id: z.string(),
38 | upstream: APISIXUpstreams.Upstream.omit({ id: true }),
39 | upstream_id: z.string(),
40 | service_id: z.string(),
41 | timeout: APISIXUpstreams.UpstreamTimeout.partial(),
42 | enable_websocket: z.boolean(),
43 | priority: z.number().default(0),
44 | status: APISIXCommon.Status,
45 | })
46 | .partial()
47 | .merge(APISIXCommon.Basic)
48 | .merge(APISIXCommon.Info);
49 |
50 | export const APISIXRoutes = {
51 | Route,
52 | RouteStatus: APISIXCommon.Status,
53 | };
54 |
--------------------------------------------------------------------------------
/src/components/form/PasswordInput.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { PasswordInput, type PasswordInputProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemPasswordInputProps =
27 | UseControllerProps & PasswordInputProps;
28 |
29 | /**
30 | * Form field component for sensitive data (passwords, tokens, keys).
31 | * Renders input with masked characters by default with an option to reveal.
32 | */
33 | export const FormItemPasswordInput = (
34 | props: FormItemPasswordInputProps
35 | ) => {
36 | const { controllerProps, restProps } = genControllerProps(props, '');
37 | const {
38 | field: { value, onChange: fOnChange, ...restField },
39 | fieldState,
40 | } = useController(controllerProps);
41 | return (
42 | {
46 | fOnChange(e);
47 | restProps.onChange?.(e);
48 | }}
49 | {...restField}
50 | {...restProps}
51 | />
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/src/routes/services/detail.$id/stream_routes/detail.$routeId.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import {
18 | createFileRoute,
19 | useNavigate,
20 | useParams,
21 | } from '@tanstack/react-router';
22 |
23 | import { StreamRoutesErrorComponent } from '@/components/page-slice/stream_routes/ErrorComponent';
24 | import { StreamRouteDetail } from '@/routes/stream_routes/detail.$id';
25 | import { CommonFormContext } from '@/utils/form-context';
26 |
27 | function RouteComponent() {
28 | const { id, routeId } = useParams({
29 | from: '/services/detail/$id/stream_routes/detail/$routeId',
30 | });
31 | const navigate = useNavigate();
32 | return (
33 |
34 |
37 | navigate({
38 | to: '/services/detail/$id/stream_routes',
39 | params: { id },
40 | })
41 | }
42 | />
43 |
44 | );
45 | }
46 |
47 | export const Route = createFileRoute(
48 | '/services/detail/$id/stream_routes/detail/$routeId'
49 | )({
50 | component: RouteComponent,
51 | errorComponent: StreamRoutesErrorComponent,
52 | });
53 |
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import '@mantine/core/styles.css';
18 | import '@mantine/notifications/styles.css';
19 | import './styles/global.css';
20 |
21 | import { createTheme, MantineProvider } from '@mantine/core';
22 | import { ModalsProvider } from '@mantine/modals';
23 | import { Notifications } from '@mantine/notifications';
24 | import { QueryClientProvider } from '@tanstack/react-query';
25 | import { RouterProvider } from '@tanstack/react-router';
26 | import { StrictMode } from 'react';
27 | import ReactDOM from 'react-dom/client';
28 |
29 | import { queryClient, router } from './config/global';
30 |
31 | const theme = createTheme({});
32 |
33 | // Render the app
34 | const rootElement = document.getElementById('root')!;
35 | if (!rootElement.innerHTML) {
36 | const root = ReactDOM.createRoot(rootElement);
37 | root.render(
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/Navbar.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { AppShellNavbar, NavLink, type NavLinkProps } from '@mantine/core';
18 | import { createLink } from '@tanstack/react-router';
19 | import type { FC } from 'react';
20 | import * as React from 'react';
21 | import { useTranslation } from 'react-i18next';
22 |
23 | import { navRoutes } from '@/config/navRoutes';
24 |
25 | const MantineLinkComponent = React.forwardRef(
26 | (props, ref) => {
27 | return ;
28 | }
29 | );
30 | MantineLinkComponent.displayName = 'MantineLinkComponent';
31 |
32 | const CreatedLinkComponent = createLink(MantineLinkComponent);
33 |
34 | interface NavbarLinkProps extends NavLinkProps {
35 | to: string;
36 | }
37 |
38 | export const NavbarLink: FC = (props) => {
39 | return ;
40 | };
41 |
42 | export const Navbar = () => {
43 | const { t } = useTranslation();
44 | return (
45 |
46 | {navRoutes.map((route) => (
47 |
52 | ))}
53 |
54 | );
55 | };
56 |
--------------------------------------------------------------------------------
/src/components/Header/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { AppShell, Burger, Group, Image } from '@mantine/core';
18 | import type { FC } from 'react';
19 | import { useTranslation } from 'react-i18next';
20 |
21 | import apisixLogo from '@/assets/apisix-logo.svg';
22 |
23 | import { LanguageMenu } from './LanguageMenu';
24 | import { SettingModalBtn } from './SettingModalBtn';
25 |
26 | const Logo = () => {
27 | const { t } = useTranslation();
28 | return (
29 |
30 | );
31 | };
32 |
33 | type HeaderProps = {
34 | opened: boolean;
35 | toggle: () => void;
36 | };
37 | export const Header: FC = (props) => {
38 | const { opened, toggle } = props;
39 | const { t } = useTranslation();
40 | return (
41 |
42 |
43 |
44 |
45 |
46 |
{t('apisix.dashboard')}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | );
55 | };
56 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { APISIXCommon } from './common';
18 | import { APISIXConsumerGroups } from './consumer_groups';
19 | import { APISIXConsumers } from './consumers';
20 | import { APISIXCredentials } from './credentials';
21 | import { APISIXGlobalRules } from './global_rules';
22 | import { APISIXPluginConfigs } from './plugin_configs';
23 | import { APISIXPluginMetadata } from './plugin_metadata';
24 | import { APISIXPlugins } from './plugins';
25 | import { APISIXProtos } from './protos';
26 | import { APISIXRoutes } from './routes';
27 | import { APISIXSecrets } from './secrets';
28 | import { APISIXServices } from './services';
29 | import { APISIXSSLs } from './ssls';
30 | import { APISIXStreamRoutes } from './stream_routes';
31 | import { APISIXUpstreams } from './upstreams';
32 |
33 | export type { APISIXType } from './type';
34 | export const APISIX = {
35 | ...APISIXCommon,
36 | ...APISIXConsumers,
37 | ...APISIXConsumerGroups,
38 | ...APISIXUpstreams,
39 | ...APISIXRoutes,
40 | ...APISIXStreamRoutes,
41 | ...APISIXProtos,
42 | ...APISIXGlobalRules,
43 | ...APISIXPlugins,
44 | ...APISIXPluginMetadata,
45 | ...APISIXSSLs,
46 | ...APISIXServices,
47 | ...APISIXSecrets,
48 | ...APISIXCredentials,
49 | ...APISIXPluginConfigs,
50 | };
51 |
--------------------------------------------------------------------------------
/src/types/schema/apisix/stream_routes.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { z } from 'zod';
18 |
19 | import { APISIXCommon } from './common';
20 | import { APISIXPlugins } from './plugins';
21 | import { APISIXUpstreams } from './upstreams';
22 |
23 | const StreamRouteProtocolLoggerItem = z.object({
24 | name: z.string(),
25 | filter: z.array(z.any()),
26 | conf: z.object({}),
27 | });
28 | const StreamRouteProtocol = z.object({
29 | name: z.string(),
30 | superior_id: z.string(),
31 | conf: z.object({}).optional(),
32 | logger: z.array(StreamRouteProtocolLoggerItem).optional(),
33 | });
34 |
35 | const StreamRoute = z
36 | .object({
37 | server_addr: z.string().optional(),
38 | server_port: z.number().int().gte(1).lte(65535).optional(),
39 | remote_addr: z.string().optional(),
40 | sni: z.string().optional(),
41 | plugins: APISIXPlugins.Plugins.optional(),
42 | upstream: APISIXUpstreams.Upstream.omit({ id: true }).optional(),
43 | upstream_id: z.string().optional(),
44 | service_id: z.string().optional(),
45 | protocol: StreamRouteProtocol.partial().optional(),
46 | })
47 | .partial()
48 | .merge(APISIXCommon.Basic.omit({ name: true, status: true }))
49 | .merge(APISIXCommon.Info);
50 |
51 | export const APISIXStreamRoutes = {
52 | StreamRoute,
53 | };
54 |
--------------------------------------------------------------------------------
/src/components/form-slice/FormPartUpstream/FormSectionDiscovery.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { useFormContext } from 'react-hook-form';
18 | import { useTranslation } from 'react-i18next';
19 |
20 | import { FormItemJsonInput } from '@/components/form/JsonInput';
21 | import { useNamePrefix } from '@/utils/useNamePrefix';
22 |
23 | import { FormItemTextInput } from '../../form/TextInput';
24 | import { FormSection } from '../FormSection';
25 | import type { FormPartUpstreamType } from './schema';
26 |
27 | export const FormSectionDiscovery = () => {
28 | const { t } = useTranslation();
29 | const { control } = useFormContext();
30 | const np = useNamePrefix();
31 | return (
32 |
33 |
38 |
43 |
49 |
50 | );
51 | };
52 |
--------------------------------------------------------------------------------
/src/components/form/TagInput.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { TagsInput, type TagsInputProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemTagsInputProps<
27 | T extends FieldValues,
28 | R
29 | > = UseControllerProps &
30 | TagsInputProps & {
31 | from?: (v: R) => string;
32 | to?: (v: string) => R;
33 | };
34 |
35 | export const FormItemTagsInput = (
36 | props: FormItemTagsInputProps
37 | ) => {
38 | const {
39 | controllerProps,
40 | restProps: { from, to, ...restProps },
41 | } = genControllerProps(props, []);
42 |
43 | const {
44 | field: { value, onChange: fOnChange, ...restField },
45 | fieldState,
46 | } = useController(controllerProps);
47 | return (
48 | {
52 | const val = to ? value.map(to) : value;
53 | fOnChange(val);
54 | restProps?.onChange?.(value);
55 | }}
56 | comboboxProps={{ shadow: 'md' }}
57 | acceptValueOnBlur
58 | {...restField}
59 | {...restProps}
60 | />
61 | );
62 | };
63 |
--------------------------------------------------------------------------------
/src/components/form/Select.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | import { Select, type SelectProps } from '@mantine/core';
18 | import {
19 | type FieldValues,
20 | useController,
21 | type UseControllerProps,
22 | } from 'react-hook-form';
23 |
24 | import { genControllerProps } from './util';
25 |
26 | export type FormItemSelectProps = UseControllerProps &
27 | Omit & {
28 | from?: (v: R) => string;
29 | to?: (v: string) => R;
30 | };
31 |
32 | export const FormItemSelect = (
33 | props: FormItemSelectProps
34 | ) => {
35 | const {
36 | controllerProps,
37 | restProps: { from, to, ...restProps },
38 | } = genControllerProps(props, []);
39 |
40 | const {
41 | field: { value, onChange: fOnChange, ...restField },
42 | fieldState,
43 | } = useController(controllerProps);
44 | return (
45 |