build: migrate the build tool from vue-cli to vite4 (#208)

This commit is contained in:
Fine0830 2022-12-17 14:07:03 +08:00 committed by GitHub
parent 1e0c253488
commit 44dcb1e7f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
214 changed files with 27014 additions and 54234 deletions

33
.eslintignore Normal file
View File

@ -0,0 +1,33 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile

53
.eslintrc.cjs Normal file
View File

@ -0,0 +1,53 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require("@rushstack/eslint-patch/modern-module-resolution");
module.exports = {
root: true,
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
"@vue/eslint-config-prettier",
],
overrides: [
{
files: ["cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}"],
extends: ["plugin:cypress/recommended"],
},
],
parserOptions: {
ecmaVersion: "latest",
},
env: {
browser: true,
node: true,
},
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"vue/script-setup-uses-vars": "error",
"@typescript-eslint/ban-ts-ignore'": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-this-alias": "off",
"vue/multi-word-component-names": "off",
},
};

View File

@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [12.x, 14.x, 16.x] node-version: [14.x, 16.x, 18.x]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}

33
.gitignore vendored
View File

@ -16,24 +16,39 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
# #
.DS_Store
node_modules
/dist
/node
/tests/e2e/videos/
/tests/e2e/screenshots/
# local env files # local env files
.env.local .env.local
.env.*.local .env.*.local
# Log files # Logs
logs
*.log
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Editor directories and files # Editor directories and files
.idea .idea

27
.husky/commit-msg Executable file
View File

@ -0,0 +1,27 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
PATH="/usr/local/bin:$PATH"
npx --no-install commitlint --edit "$1"

27
.husky/common.sh Normal file
View File

@ -0,0 +1,27 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#!/bin/sh
command_exists () {
command -v "$1" >/dev/null 2>&1
}
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

29
.husky/pre-commit Executable file
View File

@ -0,0 +1,29 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
[ -n "$CI" ] && exit 0
PATH="/usr/local/bin:$PATH"
# Format and submit code according to lintstagedrc configuration
npm run lint:lint-staged

22
.stylelintignore Normal file
View File

@ -0,0 +1,22 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
/dist/*
/public/*
public/*

50
commitlint.config.js Normal file
View File

@ -0,0 +1,50 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = {
ignores: [(commit) => commit.includes("init")],
extends: ["@commitlint/config-conventional"],
rules: {
"body-leading-blank": [2, "always"],
"footer-leading-blank": [1, "always"],
"header-max-length": [2, "always", 108],
"subject-empty": [2, "never"],
"type-empty": [2, "never"],
"subject-case": [0],
"type-enum": [
2,
"always",
[
"feat",
"fix",
"perf",
"style",
"docs",
"test",
"refactor",
"build",
"ci",
"chore",
"revert",
"wip",
"workflow",
"types",
"release",
],
],
},
};

25
cypress.config.ts Normal file
View File

@ -0,0 +1,25 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
specPattern: "cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}",
baseUrl: "http://localhost:4173",
},
});

View File

@ -14,6 +14,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
module.exports = { describe("My First Test", () => {
presets: ["@vue/cli-plugin-babel/preset"], it("visits the app root url", () => {
}; cy.visit("/");
cy.contains("h1", "You did it!");
});
});

26
cypress/e2e/tsconfig.json Normal file
View File

@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["./**/*", "../support/**/*"],
"compilerOptions": {
"isolatedModules": false,
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
}
}

View File

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
const requireAll = (requireContext: Recordable) => {
requireContext.keys().map(requireContext); "name": "Using fixtures to represent data",
const req = require.context("./", true, /\.svg$/); "email": "hello@cypress.io",
requireAll(req); "body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,55 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
export {};

37
cypress/support/e2e.ts Normal file
View File

@ -0,0 +1,37 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import "./commands";
// Alternatively you can use CommonJS syntax:
// require('./commands')

26
env.d.ts vendored Normal file
View File

@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_SW_PROXY_TARGET: string;
readonly VITE_DROP_CONSOLE: boolean;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

View File

@ -15,17 +15,13 @@ limitations under the License. -->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <title>Apache SkyWalking</title>
<title><%= htmlWebpackPlugin.options.title %></title>
</head> </head>
<body> <body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected --> <script type="module" src="/src/main.ts"></script>
</body> </body>
</html> </html>

50727
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,20 @@
{ {
"name": "skywalking-booster-ui", "name": "skywalking-booster-ui",
"version": "9.3.0", "version": "9.4.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "dev": "vite",
"build": "vue-cli-service build", "build": "run-p type-check build-only",
"test:unit": "vue-cli-service test:unit", "preview": "vite preview",
"test:e2e": "vue-cli-service test:e2e", "test:unit": "vitest --environment jsdom --root src/",
"lint": "vue-cli-service lint" "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' :4173 'cypress open --e2e'",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged",
"prepare": "husky install"
}, },
"dependencies": { "dependencies": {
"axios": "^0.24.0", "axios": "^0.24.0",
@ -17,132 +24,76 @@
"echarts": "^5.2.2", "echarts": "^5.2.2",
"element-plus": "^2.0.2", "element-plus": "^2.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"monaco-editor": "^0.27.0", "monaco-editor": "^0.34.1",
"pinia": "^2.0.5", "pinia": "^2.0.28",
"vis-timeline": "^7.5.1", "vis-timeline": "^7.5.1",
"vue": "^3.0.0", "vue": "^3.2.45",
"vue-grid-layout": "^3.0.0-beta1", "vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.1.9", "vue-i18n": "^9.1.9",
"vue-router": "^4.0.0-0", "vue-router": "^4.1.6",
"vue-types": "^4.1.1" "vue-types": "^4.1.1"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.3.0",
"@commitlint/config-conventional": "^17.3.0",
"@rushstack/eslint-patch": "^1.1.4",
"@types/d3": "^7.1.0", "@types/d3": "^7.1.0",
"@types/d3-tip": "^3.5.5", "@types/d3-tip": "^3.5.5",
"@types/echarts": "^4.9.12", "@types/echarts": "^4.9.12",
"@types/jest": "^24.0.19", "@types/jsdom": "^20.0.1",
"@types/lodash": "^4.14.179", "@types/lodash": "^4.14.179",
"@types/node": "^18.11.12",
"@types/three": "^0.131.0", "@types/three": "^0.131.0",
"@typescript-eslint/eslint-plugin": "^4.18.0", "@vitejs/plugin-vue": "^4.0.0",
"@typescript-eslint/parser": "^4.18.0", "@vitejs/plugin-vue-jsx": "^3.0.0",
"@vue/cli-plugin-babel": "~4.5.0", "@vue/eslint-config-prettier": "^7.0.0",
"@vue/cli-plugin-e2e-cypress": "~5.0.8", "@vue/eslint-config-typescript": "^11.0.0",
"@vue/cli-plugin-eslint": "~4.5.0", "@vue/test-utils": "^2.2.6",
"@vue/cli-plugin-router": "~4.5.0", "@vue/tsconfig": "^0.1.3",
"@vue/cli-plugin-typescript": "~4.5.0", "@vueuse/core": "^9.6.0",
"@vue/cli-plugin-unit-jest": "~4.5.0", "cypress": "^12.0.2",
"@vue/cli-plugin-vuex": "~4.5.0", "eslint": "^8.22.0",
"@vue/cli-service": "~4.5.0", "eslint-plugin-cypress": "^2.12.1",
"@vue/compiler-sfc": "^3.0.0", "eslint-plugin-vue": "^9.3.0",
"@vue/eslint-config-prettier": "^6.0.0", "husky": "^8.0.2",
"@vue/eslint-config-typescript": "^7.0.0", "jsdom": "^20.0.3",
"@vue/test-utils": "^2.0.0-0",
"babel-jest": "^24.9.0",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.0.0",
"husky": "^7.0.4",
"lint-staged": "^12.1.3", "lint-staged": "^12.1.3",
"monaco-editor-webpack-plugin": "^4.1.2", "node-sass": "^8.0.0",
"node-sass": "^6.0.1", "npm-run-all": "^4.1.5",
"postcss-html": "^1.3.0", "postcss-html": "^1.3.0",
"postcss-scss": "^4.0.2", "postcss-scss": "^4.0.2",
"prettier": "^2.2.1", "prettier": "^2.7.1",
"sass-loader": "^10.2.0", "sass": "^1.56.1",
"start-server-and-test": "^1.15.2",
"stylelint": "^14.1.0", "stylelint": "^14.1.0",
"stylelint-config-html": "^1.0.0", "stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3", "stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^24.0.0", "stylelint-config-standard": "^24.0.0",
"stylelint-order": "^5.0.0", "stylelint-order": "^5.0.0",
"svg-sprite-loader": "^6.0.11", "typescript": "~4.7.4",
"typescript": "~4.4.4",
"unplugin-auto-import": "^0.7.0", "unplugin-auto-import": "^0.7.0",
"unplugin-vue-components": "^0.19.2", "unplugin-vue-components": "^0.19.2",
"vue-jest": "^5.0.0-0" "vite": "^4.0.0",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-svg-icons": "^2.0.1",
"vitest": "^0.25.6",
"vue-tsc": "^1.0.12"
}, },
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint"
],
"parserOptions": {
"ecmaVersion": 2020
},
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"vue/script-setup-uses-vars": "error",
"@typescript-eslint/ban-ts-ignore'": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-this-alias": "off"
},
"overrides": [
{
"files": [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
"env": {
"jest": true
}
}
]
},
"eslintIgnore": [
"vue.config.js"
],
"browserslist": [ "browserslist": [
"> 1%", "> 1%",
"last 2 versions", "last 2 versions",
"not dead" "not dead"
], ],
"jest": {
"preset": "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
"transform": {
"^.+\\.vue$": "vue-jest"
}
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": { "lint-staged": {
"*.{js,jsx,ts,tsx}": [ "*.{js,jsx,ts,tsx,vue,scss,less}": [
"eslint --fix", "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"prettier --write" "prettier --write \"src/**/*.{js,tsx,css,less,scss,vue,html,md}\"",
], "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/"
"*.vue": [
"eslint --fix",
"prettier --write",
"stylelint --fix --custom-syntax postcss-html"
], ],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [ "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"prettier --write--parser json"
],
"package.json": [
"prettier --write" "prettier --write"
], ],
"*.{scss,less,styl}": [ "package.json": [
"stylelint --fix",
"prettier --write" "prettier --write"
], ],
"*.md": [ "*.md": [

View File

@ -14,8 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
module.exports = { module.exports = {
plugins: {
autoprefixer: {}, autoprefixer: {},
},
}; };

26
prettier.config.js Normal file
View File

@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = {
printWidth: 120,
semi: true,
vueIndentScriptAndStyle: true,
trailingComma: "all",
proseWrap: "never",
htmlWhitespaceSensitivity: "strict",
endOfLine: "auto",
};

View File

@ -16,10 +16,10 @@ limitations under the License. -->
<router-view /> <router-view />
</template> </template>
<style> <style>
#app { #app {
color: #2c3e50; color: #2c3e50;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
min-width: 1024px; min-width: 1024px;
} }
</style> </style>

View File

@ -14,8 +14,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
const requireComponent = require.context("./technologies", false, /\.png$/); const requireComponent = import.meta.glob("./technologies/*.png", { eager: true });
const requireTool = require.context("./tools", false, /\.png$/); const requireTool = import.meta.glob("./tools/*.png", { eager: true });
const result: { [key: string]: string } = {}; const result: { [key: string]: string } = {};
const t: { [key: string]: string } = {}; const t: { [key: string]: string } = {};
@ -24,25 +24,19 @@ function capitalizeFirstLetter(str: string) {
} }
function validateFileName(str: string): string | undefined { function validateFileName(str: string): string | undefined {
if (/^\S+\.png$/.test(str)) { if (/^\S+\.png$/.test(str)) {
return str.replace(/^\S+\/(\w+)\.png$/, (rs, $1) => return str.replace(/^\S+\/(\w+)\.png$/, (rs, $1) => capitalizeFirstLetter($1));
capitalizeFirstLetter($1)
);
} }
} }
[...requireComponent.keys()].forEach((filePath: string) => { Object.keys(requireComponent).forEach((filePath: string) => {
const componentConfig = requireComponent(filePath);
const fileName = validateFileName(filePath); const fileName = validateFileName(filePath);
if (fileName) { if (fileName) {
result[fileName] = componentConfig; result[fileName] = (requireComponent as { [key: string]: any })[filePath].default;
} }
}); });
[...requireTool.keys()].forEach((filePath: string) => { Object.keys(requireTool).forEach((filePath: string) => {
const componentConfig = requireTool(filePath);
const fileName = validateFileName(filePath); const fileName = validateFileName(filePath);
if (fileName) { if (fileName) {
t[fileName] = componentConfig; t[fileName] = (requireTool as { [key: string]: any })[filePath].default;
} }
}); });

View File

@ -15,35 +15,18 @@ limitations under the License. -->
<template> <template>
<div :class="`${state.pre}`"> <div :class="`${state.pre}`">
<div :class="`${state.pre}-head`"> <div :class="`${state.pre}-head`">
<a <a :class="`${state.pre}-prev-decade-btn`" v-show="state.showYears" @click="state.year -= 10">
:class="`${state.pre}-prev-decade-btn`"
v-show="state.showYears"
@click="state.year -= 10"
>
<Icon size="sm" iconName="angle-double-left" /> <Icon size="sm" iconName="angle-double-left" />
</a> </a>
<a <a :class="`${state.pre}-prev-year-btn`" v-show="!state.showYears" @click="state.year--">
:class="`${state.pre}-prev-year-btn`"
v-show="!state.showYears"
@click="state.year--"
>
<Icon size="sm" iconName="angle-double-left" /> <Icon size="sm" iconName="angle-double-left" />
</a> </a>
<a <a :class="`${state.pre}-prev-month-btn`" v-show="!state.showYears && !state.showMonths" @click="pm">
:class="`${state.pre}-prev-month-btn`"
v-show="!state.showYears && !state.showMonths"
@click="pm"
>
<Icon size="middle" iconName="chevron-left" /> <Icon size="middle" iconName="chevron-left" />
</a> </a>
<a :class="`${state.pre}-year-select`" v-show="state.showYears">{{ <a :class="`${state.pre}-year-select`" v-show="state.showYears">{{ ys + "-" + ye }}</a>
ys + "-" + ye
}}</a>
<template v-if="local.yearSuffix"> <template v-if="local.yearSuffix">
<a <a :class="`${state.pre}-year-select`" @click="state.showYears = !state.showYears" v-show="!state.showYears"
:class="`${state.pre}-year-select`"
@click="state.showYears = !state.showYears"
v-show="!state.showYears"
>{{ state.year }}{{ local.yearSuffix }}</a >{{ state.year }}{{ local.yearSuffix }}</a
> >
<a <a
@ -60,54 +43,29 @@ limitations under the License. -->
v-show="!state.showYears && !state.showMonths" v-show="!state.showYears && !state.showMonths"
>{{ local.monthsHead[state.month] }}</a >{{ local.monthsHead[state.month] }}</a
> >
<a <a :class="`${state.pre}-year-select`" @click="state.showYears = !state.showYears" v-show="!state.showYears">{{
:class="`${state.pre}-year-select`" state.year
@click="state.showYears = !state.showYears" }}</a>
v-show="!state.showYears"
>{{ state.year }}</a
>
</template> </template>
<a <a :class="`${state.pre}-next-month-btn`" v-show="!state.showYears && !state.showMonths" @click="nm">
:class="`${state.pre}-next-month-btn`"
v-show="!state.showYears && !state.showMonths"
@click="nm"
>
<Icon size="middle" iconName="chevron-right" /> <Icon size="middle" iconName="chevron-right" />
</a> </a>
<a <a :class="`${state.pre}-next-year-btn`" v-show="!state.showYears" @click="state.year++">
:class="`${state.pre}-next-year-btn`"
v-show="!state.showYears"
@click="state.year++"
>
<Icon size="sm" iconName="angle-double-right" /> <Icon size="sm" iconName="angle-double-right" />
</a> </a>
<a <a :class="`${state.pre}-next-decade-btn`" v-show="state.showYears" @click="state.year += 10">
:class="`${state.pre}-next-decade-btn`"
v-show="state.showYears"
@click="state.year += 10"
>
<Icon size="sm" iconName="angle-double-right" /> <Icon size="sm" iconName="angle-double-right" />
</a> </a>
</div> </div>
<div :class="`${state.pre}-body`"> <div :class="`${state.pre}-body`">
<div :class="`${state.pre}-days`"> <div :class="`${state.pre}-days`">
<a :class="`${state.pre}-week`" v-for="i in local.weeks" :key="i">{{ <a :class="`${state.pre}-week`" v-for="i in local.weeks" :key="i">{{ i }}</a>
i
}}</a>
<a <a
v-for="(j, i) in days" v-for="(j, i) in days"
@click="is($event) && ((state.day = j.i), ok(j))" @click="is($event) && ((state.day = j.i), ok(j))"
:class="[ :class="[
j.p || j.n ? `${state.pre}-date-out` : '', j.p || j.n ? `${state.pre}-date-out` : '',
status( status(j.y, j.m, j.i, state.hour, state.minute, state.second, 'YYYYMMDD'),
j.y,
j.m,
j.i,
state.hour,
state.minute,
state.second,
'YYYYMMDD'
),
]" ]"
:key="i" :key="i"
>{{ j.i }}</a >{{ j.i }}</a
@ -116,23 +74,8 @@ limitations under the License. -->
<div :class="`${state.pre}-months`" v-show="state.showMonths"> <div :class="`${state.pre}-months`" v-show="state.showMonths">
<a <a
v-for="(i, j) in local.months" v-for="(i, j) in local.months"
@click=" @click="is($event) && ((state.showMonths = state.m === 'M'), (state.month = j), state.m === 'M' && ok('m'))"
is($event) && :class="[status(state.year, j, state.day, state.hour, state.minute, state.second, 'YYYYMM')]"
((state.showMonths = state.m === 'M'),
(state.month = j),
state.m === 'M' && ok('m'))
"
:class="[
status(
state.year,
j,
state.day,
state.hour,
state.minute,
state.second,
'YYYYMM'
),
]"
:key="j" :key="j"
>{{ i }}</a >{{ i }}</a
> >
@ -140,23 +83,10 @@ limitations under the License. -->
<div :class="`${state.pre}-years`" v-show="state.showYears"> <div :class="`${state.pre}-years`" v-show="state.showYears">
<a <a
v-for="(i, j) in years" v-for="(i, j) in years"
@click=" @click="is($event) && ((state.showYears = state.m === 'Y'), (state.year = i), state.m === 'Y' && ok('y'))"
is($event) &&
((state.showYears = state.m === 'Y'),
(state.year = i),
state.m === 'Y' && ok('y'))
"
:class="[ :class="[
j === 0 || j === 11 ? `${state.pre}-date-out` : '', j === 0 || j === 11 ? `${state.pre}-date-out` : '',
status( status(i, state.month, state.day, state.hour, state.minute, state.second, 'YYYY'),
i,
state.month,
state.day,
state.hour,
state.minute,
state.second,
'YYYY'
),
]" ]"
:key="j" :key="j"
>{{ i }}</a >{{ i }}</a
@ -167,21 +97,8 @@ limitations under the License. -->
<div class="scroll_hide calendar-overflow"> <div class="scroll_hide calendar-overflow">
<a <a
v-for="(j, i) in 24" v-for="(j, i) in 24"
@click=" @click="is($event) && ((state.showHours = false), (state.hour = i), ok('h'))"
is($event) && :class="[status(state.year, state.month, state.day, i, state.minute, state.second, 'YYYYMMDDHH')]"
((state.showHours = false), (state.hour = i), ok('h'))
"
:class="[
status(
state.year,
state.month,
state.day,
i,
state.minute,
state.second,
'YYYYMMDDHH'
),
]"
:key="i" :key="i"
>{{ i }}</a >{{ i }}</a
> >
@ -192,21 +109,8 @@ limitations under the License. -->
<div class="scroll_hide calendar-overflow"> <div class="scroll_hide calendar-overflow">
<a <a
v-for="(j, i) in 60" v-for="(j, i) in 60"
@click=" @click="is($event) && ((state.showMinutes = false), (state.minute = i), ok('h'))"
is($event) && :class="[status(state.year, state.month, state.day, state.hour, i, state.second, 'YYYYMMDDHHmm')]"
((state.showMinutes = false), (state.minute = i), ok('h'))
"
:class="[
status(
state.year,
state.month,
state.day,
state.hour,
i,
state.second,
'YYYYMMDDHHmm'
),
]"
:key="i" :key="i"
>{{ i }}</a >{{ i }}</a
> >
@ -217,21 +121,8 @@ limitations under the License. -->
<div class="scroll_hide calendar-overflow"> <div class="scroll_hide calendar-overflow">
<a <a
v-for="(j, i) in 60" v-for="(j, i) in 60"
@click=" @click="is($event) && ((state.showSeconds = false), (state.second = i), ok('h'))"
is($event) && :class="[status(state.year, state.month, state.day, state.hour, state.minute, i, 'YYYYMMDDHHmmss')]"
((state.showSeconds = false), (state.second = i), ok('h'))
"
:class="[
status(
state.year,
state.month,
state.day,
state.hour,
state.minute,
i,
'YYYYMMDDHHmmss'
),
]"
:key="i" :key="i"
>{{ i }}</a >{{ i }}</a
> >
@ -242,20 +133,14 @@ limitations under the License. -->
<div :class="`${state.pre}-hour`"> <div :class="`${state.pre}-hour`">
<a <a
:title="local.hourTip" :title="local.hourTip"
@click=" @click="(state.showHours = !state.showHours), (state.showMinutes = state.showSeconds = false)"
(state.showHours = !state.showHours),
(state.showMinutes = state.showSeconds = false)
"
:class="{ on: state.showHours }" :class="{ on: state.showHours }"
>{{ dd(state.hour) }}</a >{{ dd(state.hour) }}</a
> >
<span>:</span> <span>:</span>
<a <a
:title="local.minuteTip" :title="local.minuteTip"
@click=" @click="(state.showMinutes = !state.showMinutes), (state.showHours = state.showSeconds = false)"
(state.showMinutes = !state.showMinutes),
(state.showHours = state.showSeconds = false)
"
:class="{ on: state.showMinutes }" :class="{ on: state.showMinutes }"
>{{ dd(state.minute) }}</a >{{ dd(state.minute) }}</a
> >
@ -263,10 +148,7 @@ limitations under the License. -->
<span>:</span> <span>:</span>
<a <a
:title="local.secondTip" :title="local.secondTip"
@click=" @click="(state.showSeconds = !state.showSeconds), (state.showHours = state.showMinutes = false)"
(state.showSeconds = !state.showSeconds),
(state.showHours = state.showMinutes = false)
"
:class="{ on: state.showSeconds }" :class="{ on: state.showSeconds }"
>{{ dd(state.second) }}</a >{{ dd(state.second) }}</a
> >
@ -277,13 +159,13 @@ limitations under the License. -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, watch, reactive } from "vue"; import { computed, onMounted, watch, reactive } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
/*global defineProps, defineEmits */ /*global defineProps, defineEmits */
const emit = defineEmits(["input", "setDates", "ok"]); const emit = defineEmits(["input", "setDates", "ok"]);
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps({ const props = defineProps({
value: { type: Date }, value: { type: Date },
left: { type: Boolean, default: false }, left: { type: Boolean, default: false },
right: { type: Boolean, default: false }, right: { type: Boolean, default: false },
@ -293,8 +175,8 @@ const props = defineProps({
type: String, type: String,
default: "YYYY-MM-DD", default: "YYYY-MM-DD",
}, },
}); });
const state = reactive({ const state = reactive({
pre: "", pre: "",
m: "", m: "",
showYears: false, showYears: false,
@ -308,8 +190,8 @@ const state = reactive({
hour: 0, hour: 0,
minute: 0, minute: 0,
second: 0, second: 0,
}); });
const get = (time: Date): { [key: string]: any } => { const get = (time: Date): { [key: string]: any } => {
return { return {
year: time.getFullYear(), year: time.getFullYear(),
month: time.getMonth(), month: time.getMonth(),
@ -318,8 +200,8 @@ const get = (time: Date): { [key: string]: any } => {
minute: time.getMinutes(), minute: time.getMinutes(),
second: time.getSeconds(), second: time.getSeconds(),
}; };
}; };
if (props.value) { if (props.value) {
const time = get(props.value); const time = get(props.value);
state.pre = "calendar"; state.pre = "calendar";
state.m = "D"; state.m = "D";
@ -334,8 +216,8 @@ if (props.value) {
state.hour = time.hour; state.hour = time.hour;
state.minute = time.minute; state.minute = time.minute;
state.second = time.second; state.second = time.second;
} }
watch( watch(
() => props.value, () => props.value,
(val: Date | undefined) => { (val: Date | undefined) => {
if (!val) { if (!val) {
@ -348,32 +230,32 @@ watch(
state.hour = time.hour; state.hour = time.hour;
state.minute = time.minute; state.minute = time.minute;
state.second = time.second; state.second = time.second;
} },
); );
const parse = (num: number): number => { const parse = (num: number): number => {
return num / 100000; return num / 100000;
}; };
const start = computed(() => { const start = computed(() => {
return parse(Number(props.dates[0])); return parse(Number(props.dates[0]));
}); });
const end = computed(() => { const end = computed(() => {
return parse(Number(props.dates[1])); return parse(Number(props.dates[1]));
}); });
const ys = computed(() => { const ys = computed(() => {
return Math.floor(state.year / 10) * 10; return Math.floor(state.year / 10) * 10;
}); });
const ye = computed(() => { const ye = computed(() => {
return ys.value + 10; return ys.value + 10;
}); });
const years = computed(() => { const years = computed(() => {
const arr = []; const arr = [];
let start = ys.value - 1; let start = ys.value - 1;
while (arr.length < 12) { while (arr.length < 12) {
arr.push((start += 1)); arr.push((start += 1));
} }
return arr; return arr;
}); });
const local = computed(() => { const local = computed(() => {
return { return {
dow: 1, // Monday is the first day of the week dow: 1, // Monday is the first day of the week
hourTip: t("hourTip"), // tip of select hour hourTip: t("hourTip"), // tip of select hour
@ -392,8 +274,8 @@ const local = computed(() => {
weekCutTip: t("weekCutTip"), weekCutTip: t("weekCutTip"),
monthCutTip: t("monthCutTip"), monthCutTip: t("monthCutTip"),
}; };
}); });
const days = computed(() => { const days = computed(() => {
const days = []; const days = [];
const year = state.year; const year = state.year;
const month = state.month; const month = state.month;
@ -431,26 +313,19 @@ const days = computed(() => {
}); });
} }
return days; return days;
}); });
const dd = (val: number) => ("0" + val).slice(-2); const dd = (val: number) => ("0" + val).slice(-2);
const status = ( const status = (
year: number, year: number,
month: number, month: number,
day: number, day: number,
hour: number, hour: number,
minute: number, minute: number,
second: number, second: number,
format: string format: string,
) => { ) => {
const maxDay = new Date(year, month + 1, 0).getDate(); const maxDay = new Date(year, month + 1, 0).getDate();
const time: any = new Date( const time: any = new Date(year, month, day > maxDay ? maxDay : day, hour, minute, second);
year,
month,
day > maxDay ? maxDay : day,
hour,
minute,
second
);
const t = parse(time); const t = parse(time);
const tf = (time?: Date, format?: any): string => { const tf = (time?: Date, format?: any): string => {
if (!time) { if (!time) {
@ -482,10 +357,7 @@ const status = (
s: seconds, s: seconds,
S: milliseconds, S: milliseconds,
}; };
return (format || props.format).replace( return (format || props.format).replace(/Y+|M+|D+|H+|h+|m+|s+|S+/g, (str: string) => map[str]);
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
(str: string) => map[str]
);
}; };
const classObj: any = {}; const classObj: any = {};
let flag = false; let flag = false;
@ -497,33 +369,31 @@ const status = (
flag = tf(props.value, format) === tf(time, format); flag = tf(props.value, format) === tf(time, format);
} }
classObj[`${state.pre}-date`] = true; classObj[`${state.pre}-date`] = true;
classObj[`${state.pre}-date-disabled`] = classObj[`${state.pre}-date-disabled`] = (props.right && t < start.value) || props.disabledDate(time, format);
(props.right && t < start.value) || props.disabledDate(time, format); classObj[`${state.pre}-date-on`] = (props.left && t > start.value) || (props.right && t < end.value);
classObj[`${state.pre}-date-on`] =
(props.left && t > start.value) || (props.right && t < end.value);
classObj[`${state.pre}-date-selected`] = flag; classObj[`${state.pre}-date-selected`] = flag;
return classObj; return classObj;
}; };
const nm = () => { const nm = () => {
if (state.month < 11) { if (state.month < 11) {
state.month++; state.month++;
} else { } else {
state.month = 0; state.month = 0;
state.year++; state.year++;
} }
}; };
const pm = () => { const pm = () => {
if (state.month > 0) { if (state.month > 0) {
state.month--; state.month--;
} else { } else {
state.month = 11; state.month = 11;
state.year--; state.year--;
} }
}; };
const is = (e: any) => { const is = (e: any) => {
return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1; return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1;
}; };
const ok = (info: any) => { const ok = (info: any) => {
let year = ""; let year = "";
let month = ""; let month = "";
let day = ""; let day = "";
@ -544,7 +414,7 @@ const ok = (info: any) => {
day ? Number(day) : state.day, day ? Number(day) : state.day,
state.hour, state.hour,
state.minute, state.minute,
state.second state.second,
); );
if (props.left && _time.getTime() / 100000 < end.value) { if (props.left && _time.getTime() / 100000 < end.value) {
emit("setDates", _time, "left"); emit("setDates", _time, "left");
@ -556,8 +426,8 @@ const ok = (info: any) => {
emit("setDates", _time); emit("setDates", _time);
} }
emit("ok", info === "h"); emit("ok", info === "h");
}; };
onMounted(() => { onMounted(() => {
const is = (c: string) => props.format.indexOf(c) !== -1; const is = (c: string) => props.format.indexOf(c) !== -1;
if (is("s") && is("m") && (is("h") || is("H"))) { if (is("s") && is("m") && (is("h") || is("H"))) {
state.m = "H"; state.m = "H";
@ -570,30 +440,30 @@ onMounted(() => {
state.m = "Y"; state.m = "Y";
state.showYears = true; state.showYears = true;
} }
}); });
</script> </script>
<style scoped> <style scoped>
.calendar { .calendar {
float: left; float: left;
user-select: none; user-select: none;
color: #3d444f; color: #3d444f;
} }
.calendar + .calendar { .calendar + .calendar {
border-left: solid 1px #eaeaea; border-left: solid 1px #eaeaea;
margin-left: 5px; margin-left: 5px;
padding-left: 5px; padding-left: 5px;
} }
.calendar-head { .calendar-head {
line-height: 34px; line-height: 34px;
height: 34px; height: 34px;
text-align: center; text-align: center;
position: relative; position: relative;
} }
.calendar-head a { .calendar-head a {
color: #666; color: #666;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@ -601,50 +471,50 @@ onMounted(() => {
position: absolute; position: absolute;
padding: 0 5px; padding: 0 5px;
font-size: 16px; font-size: 16px;
} }
.calendar-head a:hover { .calendar-head a:hover {
color: #3f97e3; color: #3f97e3;
} }
.calendar-head .calendar-year-select, .calendar-head .calendar-year-select,
.calendar-head .calendar-month-select { .calendar-head .calendar-month-select {
font-size: 12px; font-size: 12px;
padding: 0 2px; padding: 0 2px;
position: relative; position: relative;
} }
.calendar-prev-decade-btn, .calendar-prev-decade-btn,
.calendar-prev-year-btn { .calendar-prev-year-btn {
left: 6px; left: 6px;
} }
.calendar-prev-month-btn { .calendar-prev-month-btn {
left: 24px; left: 24px;
} }
.calendar-next-decade-btn, .calendar-next-decade-btn,
.calendar-next-year-btn { .calendar-next-year-btn {
right: 6px; right: 6px;
} }
.calendar-next-month-btn { .calendar-next-month-btn {
right: 24px; right: 24px;
} }
.calendar-body { .calendar-body {
position: relative; position: relative;
width: 196px; width: 196px;
height: 196px; height: 196px;
} }
.calendar-days { .calendar-days {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.calendar-week, .calendar-week,
.calendar-date { .calendar-date {
font-weight: normal; font-weight: normal;
width: 14.28%; width: 14.28%;
height: 14.28%; height: 14.28%;
@ -652,96 +522,96 @@ onMounted(() => {
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
float: left; float: left;
} }
.calendar-week:before, .calendar-week:before,
.calendar-date:before { .calendar-date:before {
content: ""; content: "";
display: inline-block; display: inline-block;
height: 100%; height: 100%;
vertical-align: middle; vertical-align: middle;
} }
.calendar-date { .calendar-date {
cursor: pointer; cursor: pointer;
line-height: 29px; line-height: 29px;
transition: background-color 0.3s; transition: background-color 0.3s;
} }
.calendar-date-out { .calendar-date-out {
color: #ccc; color: #ccc;
} }
.calendar-date:hover, .calendar-date:hover,
.calendar-date-on { .calendar-date-on {
color: #3f97e3; color: #3f97e3;
background-color: #f8f8f8; background-color: #f8f8f8;
} }
.calendar-date-selected, .calendar-date-selected,
.calendar-date-selected:hover { .calendar-date-selected:hover {
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
border-radius: 14px; border-radius: 14px;
background: #3f97e3; background: #3f97e3;
} }
.calendar-date-disabled { .calendar-date-disabled {
cursor: not-allowed !important; cursor: not-allowed !important;
color: #ccc !important; color: #ccc !important;
background: #fff !important; background: #fff !important;
} }
.calendar-foot { .calendar-foot {
margin-top: 5px; margin-top: 5px;
} }
.calendar-hour { .calendar-hour {
display: inline-block; display: inline-block;
border: 1px solid #e6e5e5; border: 1px solid #e6e5e5;
color: #9e9e9e; color: #9e9e9e;
} }
.calendar-hour a { .calendar-hour a {
display: inline-block; display: inline-block;
padding: 2px 4px; padding: 2px 4px;
cursor: pointer; cursor: pointer;
} }
.calendar-hour a:hover, .calendar-hour a:hover,
.calendar-hour a.on { .calendar-hour a.on {
color: #3f97e3; color: #3f97e3;
} }
.calendar-years, .calendar-years,
.calendar-months, .calendar-months,
.calendar-hours, .calendar-hours,
.calendar-minutes, .calendar-minutes,
.calendar-seconds { .calendar-seconds {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
background: #fff; background: #fff;
left: 0; left: 0;
top: 0; top: 0;
} }
.calendar-months a { .calendar-months a {
width: 33.33%; width: 33.33%;
height: 25%; height: 25%;
} }
.calendar-years a { .calendar-years a {
width: 33.33%; width: 33.33%;
height: 25%; height: 25%;
} }
.calendar-overflow { .calendar-overflow {
overflow-x: scroll; overflow-x: scroll;
height: 100%; height: 100%;
} }
/* .calendar-hours a { /* .calendar-hours a {
width: 20%; width: 20%;
height: 20%; height: 20%;
} }
@ -752,12 +622,12 @@ onMounted(() => {
height: 10%; height: 10%;
} */ } */
.calendar-title { .calendar-title {
margin-top: -30px; margin-top: -30px;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
background: #fff; background: #fff;
text-align: center; text-align: center;
font-weight: bold; font-weight: bold;
} }
</style> </style>

View File

@ -19,11 +19,7 @@ limitations under the License. -->
<div class="tools" @click="associateMetrics" v-if="associate.length"> <div class="tools" @click="associateMetrics" v-if="associate.length">
{{ t("associateMetrics") }} {{ t("associateMetrics") }}
</div> </div>
<div <div class="tools" @click="viewTrace" v-if="relatedTrace && relatedTrace.enableRelate">
class="tools"
@click="viewTrace"
v-if="relatedTrace && relatedTrace.enableRelate"
>
{{ t("viewTrace") }} {{ t("viewTrace") }}
</div> </div>
</div> </div>
@ -40,39 +36,29 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { import { watch, ref, onMounted, onBeforeUnmount, unref, computed } from "vue";
watch, import type { PropType, Ref } from "vue";
ref, import { useI18n } from "vue-i18n";
Ref, import type { EventParams } from "@/types/app";
onMounted, import type { Filters, RelatedTrace } from "@/types/dashboard";
onBeforeUnmount, import { useECharts } from "@/hooks/useEcharts";
unref, import { addResizeListener, removeResizeListener } from "@/utils/event";
computed, import Trace from "@/views/dashboard/related/trace/Index.vue";
} from "vue"; import associateProcessor from "@/hooks/useAssociateProcessor";
import type { PropType } from "vue";
import { useI18n } from "vue-i18n";
import { EventParams } from "@/types/app";
import { Filters, RelatedTrace } from "@/types/dashboard";
import { useECharts } from "@/hooks/useEcharts";
import { addResizeListener, removeResizeListener } from "@/utils/event";
import Trace from "@/views/dashboard/related/trace/Index.vue";
import associateProcessor from "@/hooks/useAssociateProcessor";
/*global Nullable, defineProps, defineEmits*/ /*global Nullable, defineProps, defineEmits*/
const emits = defineEmits(["select"]); const emits = defineEmits(["select"]);
const { t } = useI18n(); const { t } = useI18n();
const chartRef = ref<Nullable<HTMLDivElement>>(null); const chartRef = ref<Nullable<HTMLDivElement>>(null);
const menus = ref<Nullable<HTMLDivElement>>(null); const menus = ref<Nullable<HTMLDivElement>>(null);
const visMenus = ref<boolean>(false); const visMenus = ref<boolean>(false);
const { setOptions, resize, getInstance } = useECharts( const { setOptions, resize, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
chartRef as Ref<HTMLDivElement> const currentParams = ref<Nullable<EventParams>>(null);
); const showTrace = ref<boolean>(false);
const currentParams = ref<Nullable<EventParams>>(null); const traceOptions = ref<{ type: string; filters?: unknown }>({
const showTrace = ref<boolean>(false);
const traceOptions = ref<{ type: string; filters?: unknown }>({
type: "Trace", type: "Trace",
}); });
const props = defineProps({ const props = defineProps({
height: { type: String, default: "100%" }, height: { type: String, default: "100%" },
width: { type: String, default: "100%" }, width: { type: String, default: "100%" },
option: { option: {
@ -89,21 +75,19 @@ const props = defineProps({
type: Array as PropType<{ widgetId: string }[]>, type: Array as PropType<{ widgetId: string }[]>,
default: () => [], default: () => [],
}, },
}); });
const available = computed( const available = computed(
() => () =>
(Array.isArray(props.option.series) && (Array.isArray(props.option.series) && props.option.series[0] && props.option.series[0].data) ||
props.option.series[0] && (Array.isArray(props.option.series.data) && props.option.series.data[0]),
props.option.series[0].data) || );
(Array.isArray(props.option.series.data) && props.option.series.data[0]) onMounted(async () => {
);
onMounted(async () => {
await setOptions(props.option); await setOptions(props.option);
chartRef.value && addResizeListener(unref(chartRef), resize); chartRef.value && addResizeListener(unref(chartRef), resize);
instanceEvent(); instanceEvent();
}); });
function instanceEvent() { function instanceEvent() {
setTimeout(() => { setTimeout(() => {
const instance = getInstance(); const instance = getInstance();
@ -141,21 +125,21 @@ function instanceEvent() {
currTrigger: "leave", currTrigger: "leave",
}); });
}, },
true true,
); );
}, 1000); }, 1000);
} }
function associateMetrics() { function associateMetrics() {
emits("select", currentParams.value); emits("select", currentParams.value);
const { dataIndex, seriesIndex } = currentParams.value || { const { dataIndex, seriesIndex } = currentParams.value || {
dataIndex: 0, dataIndex: 0,
seriesIndex: 0, seriesIndex: 0,
}; };
updateOptions({ dataIndex, seriesIndex }); updateOptions({ dataIndex, seriesIndex });
} }
function updateOptions(params?: { dataIndex: number; seriesIndex: number }) { function updateOptions(params?: { dataIndex: number; seriesIndex: number }) {
const instance = getInstance(); const instance = getInstance();
if (!instance) { if (!instance) {
return; return;
@ -180,9 +164,9 @@ function updateOptions(params?: { dataIndex: number; seriesIndex: number }) {
seriesIndex: ids, seriesIndex: ids,
}); });
} }
} }
function viewTrace() { function viewTrace() {
const item = associateProcessor(props).traceFilters(currentParams.value); const item = associateProcessor(props).traceFilters(currentParams.value);
traceOptions.value = { traceOptions.value = {
...traceOptions.value, ...traceOptions.value,
@ -190,9 +174,9 @@ function viewTrace() {
}; };
showTrace.value = true; showTrace.value = true;
visMenus.value = true; visMenus.value = true;
} }
watch( watch(
() => props.option, () => props.option,
(newVal, oldVal) => { (newVal, oldVal) => {
if (!available.value) { if (!available.value) {
@ -207,21 +191,21 @@ watch(
options = eventAssociate(); options = eventAssociate();
} }
setOptions(options || props.option); setOptions(options || props.option);
} },
); );
watch( watch(
() => props.filters, () => props.filters,
() => { () => {
updateOptions(); updateOptions();
} },
); );
onBeforeUnmount(() => { onBeforeUnmount(() => {
removeResizeListener(unref(chartRef), resize); removeResizeListener(unref(chartRef), resize);
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.no-data { .no-data {
font-size: 12px; font-size: 12px;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
@ -230,14 +214,14 @@ onBeforeUnmount(() => {
-webkit-box-pack: center; -webkit-box-pack: center;
-webkit-box-align: center; -webkit-box-align: center;
color: #666; color: #666;
} }
.chart { .chart {
overflow: hidden; overflow: hidden;
flex: 1; flex: 1;
} }
.menus { .menus {
position: absolute; position: absolute;
display: block; display: block;
white-space: nowrap; white-space: nowrap;
@ -248,9 +232,9 @@ onBeforeUnmount(() => {
border-radius: 4px; border-radius: 4px;
color: rgb(51, 51, 51); color: rgb(51, 51, 51);
padding: 5px; padding: 5px;
} }
.tools { .tools {
padding: 5px; padding: 5px;
color: #999; color: #999;
cursor: pointer; cursor: pointer;
@ -259,5 +243,5 @@ onBeforeUnmount(() => {
color: #409eff; color: #409eff;
background-color: #eee; background-color: #eee;
} }
} }
</style> </style>

View File

@ -24,21 +24,19 @@ limitations under the License. -->
loading, loading,
}" }"
> >
<use :xlink:href="`#${iconName}`"></use> <use :href="`#${iconName}`"></use>
</svg> </svg>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import "@/assets/icons/index"; /*global defineProps */
defineProps({
/*global defineProps */
defineProps({
iconName: { type: String, default: "" }, iconName: { type: String, default: "" },
size: { type: String, default: "sm" }, size: { type: String, default: "sm" },
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.icon { .icon {
width: 16px; width: 16px;
height: 16px; height: 16px;
vertical-align: middle; vertical-align: middle;
@ -72,8 +70,8 @@ defineProps({
height: 30px; height: 30px;
width: 30px; width: 30px;
} }
} }
@keyframes loading { @keyframes loading {
0% { 0% {
-webkit-transform: rotate(0deg); -webkit-transform: rotate(0deg);
transform: rotate(0deg); transform: rotate(0deg);
@ -83,5 +81,5 @@ defineProps({
-webkit-transform: rotate(1turn); -webkit-transform: rotate(1turn);
transform: rotate(1turn); transform: rotate(1turn);
} }
} }
</style> </style>

View File

@ -20,19 +20,19 @@ limitations under the License. -->
</el-radio-group> </el-radio-group>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
interface Option { /*global defineProps, defineEmits */
const emit = defineEmits(["change"]);
const props = defineProps({
options: {
type: Array as PropType<
{
label: string | number; label: string | number;
value: string | number; value: string | number;
} }[]
>,
/*global defineProps, defineEmits */
const emit = defineEmits(["change"]);
const props = defineProps({
options: {
type: Array as PropType<Option[]>,
default: () => [], default: () => [],
}, },
value: { value: {
@ -40,11 +40,11 @@ const props = defineProps({
default: "", default: "",
}, },
size: { type: null, default: "default" }, size: { type: null, default: "default" },
}); });
const selected = ref<string>(props.value); const selected = ref<string>(props.value);
function checked(opt: unknown) { function checked(opt: unknown) {
emit("change", opt); emit("change", opt);
} }
</script> </script>

View File

@ -19,9 +19,7 @@ limitations under the License. -->
{{ selected.label }} {{ selected.label }}
</span> </span>
<span class="no-data" v-else>Please select a option</span> <span class="no-data" v-else>Please select a option</span>
<span class="remove-icon" @click="removeSelected" v-if="clearable"> <span class="remove-icon" @click="removeSelected" v-if="clearable"> × </span>
×
</span>
</div> </div>
<div class="opt-wrapper" v-show="visible"> <div class="opt-wrapper" v-show="visible">
<div <div
@ -37,13 +35,13 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { Option } from "@/types/app"; import type { Option } from "@/types/app";
/*global defineProps, defineEmits*/ /*global defineProps, defineEmits*/
const emit = defineEmits(["change"]); const emit = defineEmits(["change"]);
const props = defineProps({ const props = defineProps({
options: { options: {
type: Array as PropType<Option[]>, type: Array as PropType<Option[]>,
default: () => [], default: () => [],
@ -53,38 +51,38 @@ const props = defineProps({
default: () => "", default: () => "",
}, },
clearable: { type: Boolean, default: false }, clearable: { type: Boolean, default: false },
}); });
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
const opt = props.options.find((d: Option) => props.value === d.value); const opt = props.options.find((d: Option) => props.value === d.value);
const selected = ref<Option>(opt || { label: "", value: "" }); const selected = ref<Option>(opt || { label: "", value: "" });
function handleSelect(i: Option) { function handleSelect(i: Option) {
selected.value = i; selected.value = i;
emit("change", i.value); emit("change", i.value);
} }
function removeSelected() { function removeSelected() {
selected.value = { label: "", value: "" }; selected.value = { label: "", value: "" };
emit("change", ""); emit("change", "");
} }
watch( watch(
() => props.value, () => props.value,
(data) => { (data) => {
const opt = props.options.find((d: Option) => data === d.value); const opt = props.options.find((d: Option) => data === d.value);
selected.value = opt || { label: "", value: "" }; selected.value = opt || { label: "", value: "" };
} },
); );
document.body.addEventListener("click", handleClick, false); document.body.addEventListener("click", handleClick, false);
function handleClick() { function handleClick() {
visible.value = false; visible.value = false;
} }
function setPopper(event: any) { function setPopper(event: any) {
event.stopPropagation(); event.stopPropagation();
visible.value = !visible.value; visible.value = !visible.value;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.bar-select { .bar-select {
position: relative; position: relative;
justify-content: space-between; justify-content: space-between;
border: 1px solid #ddd; border: 1px solid #ddd;
@ -103,13 +101,13 @@ function setPopper(event: any) {
border: 1px solid #e8e8e8; border: 1px solid #e8e8e8;
text-align: center; text-align: center;
} }
} }
.no-data { .no-data {
color: #c0c4cc; color: #c0c4cc;
} }
.bar-i { .bar-i {
height: 100%; height: 100%;
width: 100%; width: 100%;
padding: 2px 10px; padding: 2px 10px;
@ -122,9 +120,9 @@ function setPopper(event: any) {
display: block; display: block;
} }
} }
} }
.remove-icon { .remove-icon {
position: absolute; position: absolute;
right: 5px; right: 5px;
top: 0; top: 0;
@ -132,9 +130,9 @@ function setPopper(event: any) {
display: none; display: none;
color: #aaa; color: #aaa;
cursor: pointer; cursor: pointer;
} }
.opt-wrapper { .opt-wrapper {
color: #606266; color: #606266;
position: absolute; position: absolute;
top: 26px; top: 26px;
@ -160,9 +158,9 @@ function setPopper(event: any) {
opacity: 1; opacity: 1;
} }
} }
} }
.opt { .opt {
padding: 7px 15px; padding: 7px 15px;
&.select-disabled { &.select-disabled {
@ -173,5 +171,5 @@ function setPopper(event: any) {
&:hover { &:hover {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
} }
</style> </style>

View File

@ -27,29 +27,29 @@ limitations under the License. -->
:remote-method="remoteMethod" :remote-method="remoteMethod"
:filterable="filterable" :filterable="filterable"
> >
<el-option <el-option v-for="item in options" :key="item.value || ''" :label="item.label || ''" :value="item.value || ''">
v-for="item in options"
:key="item.value || ''"
:label="item.label || ''"
:value="item.value || ''"
>
</el-option> </el-option>
</el-select> </el-select>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
interface Option { // interface Option {
// label: string | number;
// value: string | number;
// }
/*global defineProps, defineEmits*/
const emit = defineEmits(["change", "query"]);
const props = defineProps({
options: {
type: Array as PropType<
({
label: string | number; label: string | number;
value: string | number; value: string | number;
} } & { disabled?: boolean })[]
>,
/*global defineProps, defineEmits*/
const emit = defineEmits(["change", "query"]);
const props = defineProps({
options: {
type: Array as PropType<(Option & { disabled?: boolean })[]>,
default: () => [], default: () => [],
}, },
value: { value: {
@ -67,33 +67,31 @@ const props = defineProps({
clearable: { type: Boolean, default: false }, clearable: { type: Boolean, default: false },
isRemote: { type: Boolean, default: false }, isRemote: { type: Boolean, default: false },
filterable: { type: Boolean, default: true }, filterable: { type: Boolean, default: true },
}); });
const selected = ref<string[] | string>(props.value); const selected = ref<string[] | string>(props.value);
function changeSelected() { function changeSelected() {
const options = props.options.filter((d: any) => const options = props.options.filter((d: any) =>
props.multiple props.multiple ? selected.value.includes(d.value) : selected.value === d.value,
? selected.value.includes(d.value)
: selected.value === d.value
); );
emit("change", options); emit("change", options);
} }
function remoteMethod(query: string) { function remoteMethod(query: string) {
if (props.isRemote) { if (props.isRemote) {
emit("query", query); emit("query", query);
} }
} }
watch( watch(
() => props.value, () => props.value,
(data) => { (data) => {
selected.value = data; selected.value = data;
} },
); );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.el-input__inner { .el-input__inner {
border-radius: unset !important; border-radius: unset !important;
} }
</style> </style>

View File

@ -35,56 +35,28 @@ limitations under the License. -->
<transition name="datepicker-anim"> <transition name="datepicker-anim">
<div <div
class="datepicker-popup" class="datepicker-popup"
:class="[ :class="[popupClass, { 'datepicker-inline': type === 'inline' }, position]"
popupClass,
{ 'datepicker-inline': type === 'inline' },
position,
]"
tabindex="-1" tabindex="-1"
v-if="show || type === 'inline'" v-if="show || type === 'inline'"
> >
<template v-if="range"> <template v-if="range">
<div class="datepicker-popup__sidebar"> <div class="datepicker-popup__sidebar">
<button <button type="button" class="datepicker-popup__shortcut" @click="quickPick('quarter')">
type="button"
class="datepicker-popup__shortcut"
@click="quickPick('quarter')"
>
{{ local.quarterHourCutTip }} {{ local.quarterHourCutTip }}
</button> </button>
<button <button type="button" class="datepicker-popup__shortcut" @click="quickPick('half')">
type="button"
class="datepicker-popup__shortcut"
@click="quickPick('half')"
>
{{ local.halfHourCutTip }} {{ local.halfHourCutTip }}
</button> </button>
<button <button type="button" class="datepicker-popup__shortcut" @click="quickPick('hour')">
type="button"
class="datepicker-popup__shortcut"
@click="quickPick('hour')"
>
{{ local.hourCutTip }} {{ local.hourCutTip }}
</button> </button>
<button <button type="button" class="datepicker-popup__shortcut" @click="quickPick('day')">
type="button"
class="datepicker-popup__shortcut"
@click="quickPick('day')"
>
{{ local.dayCutTip }} {{ local.dayCutTip }}
</button> </button>
<button <button type="button" class="datepicker-popup__shortcut" @click="quickPick('week')">
type="button"
class="datepicker-popup__shortcut"
@click="quickPick('week')"
>
{{ local.weekCutTip }} {{ local.weekCutTip }}
</button> </button>
<button <button type="button" class="datepicker-popup__shortcut" @click="quickPick('month')">
type="button"
class="datepicker-popup__shortcut"
@click="quickPick('month')"
>
{{ local.monthCutTip }} {{ local.monthCutTip }}
</button> </button>
</div> </div>
@ -123,16 +95,10 @@ limitations under the License. -->
/> />
</template> </template>
<div v-if="showButtons" class="datepicker__buttons"> <div v-if="showButtons" class="datepicker__buttons">
<button <button @click.prevent.stop="cancel" class="datepicker__button-cancel">
@click.prevent.stop="cancel"
class="datepicker__button-cancel"
>
{{ local.cancelTip }} {{ local.cancelTip }}
</button> </button>
<button <button @click.prevent.stop="submit" class="datepicker__button-select">
@click.prevent.stop="submit"
class="datepicker__button-select"
>
{{ local.submitTip }} {{ local.submitTip }}
</button> </button>
</div> </div>
@ -142,16 +108,16 @@ limitations under the License. -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue"; import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import DateCalendar from "./DateCalendar.vue"; import DateCalendar from "./DateCalendar.vue";
import { useTimeoutFn } from "@/hooks/useTimeout"; import { useTimeoutFn } from "@/hooks/useTimeout";
/*global defineProps, defineEmits */ /*global defineProps, defineEmits */
const datepicker = ref(null); const datepicker = ref(null);
const { t } = useI18n(); const { t } = useI18n();
const show = ref<boolean>(false); const show = ref<boolean>(false);
const dates = ref<Date | string[] | any>([]); const dates = ref<Date | string[] | any>([]);
const props = defineProps({ const props = defineProps({
position: { type: String, default: "bottom" }, position: { type: String, default: "bottom" },
name: [String], name: [String],
inputClass: [String], inputClass: [String],
@ -184,9 +150,9 @@ const props = defineProps({
default: false, default: false,
}, },
dateRangeSelect: [Function], dateRangeSelect: [Function],
}); });
const emit = defineEmits(["clear", "input", "confirm", "cancel"]); const emit = defineEmits(["clear", "input", "confirm", "cancel"]);
const local = computed(() => { const local = computed(() => {
return { return {
dow: 1, // Monday is the first day of the week dow: 1, // Monday is the first day of the week
hourTip: t("hourTip"), // tip of select hour hourTip: t("hourTip"), // tip of select hour
@ -205,8 +171,8 @@ const local = computed(() => {
weekCutTip: t("weekCutTip"), weekCutTip: t("weekCutTip"),
monthCutTip: t("monthCutTip"), monthCutTip: t("monthCutTip"),
}; };
}); });
const tf = (time: Date, format?: any): string => { const tf = (time: Date, format?: any): string => {
const year = time.getFullYear(); const year = time.getFullYear();
const month = time.getMonth(); const month = time.getMonth();
const day = time.getDate(); const day = time.getDate();
@ -234,58 +200,51 @@ const tf = (time: Date, format?: any): string => {
s: seconds, s: seconds,
S: milliseconds, S: milliseconds,
}; };
return (format || props.format).replace( return (format || props.format).replace(/Y+|M+|D+|H+|h+|m+|s+|S+/g, (str: string) => map[str]);
/Y+|M+|D+|H+|h+|m+|s+|S+/g, };
(str: string) => map[str] const range = computed(() => {
);
};
const range = computed(() => {
return dates.value.length === 2; return dates.value.length === 2;
}); });
const text = computed(() => { const text = computed(() => {
const val = props.value; const val = props.value;
const txt = dates.value const txt = dates.value.map((date: Date) => tf(date)).join(` ${props.rangeSeparator} `);
.map((date: Date) => tf(date))
.join(` ${props.rangeSeparator} `);
if (Array.isArray(val)) { if (Array.isArray(val)) {
return val.length > 1 ? txt : ""; return val.length > 1 ? txt : "";
} }
return val ? txt : ""; return val ? txt : "";
}); });
const get = () => { const get = () => {
return Array.isArray(props.value) ? dates.value : dates.value[0]; return Array.isArray(props.value) ? dates.value : dates.value[0];
}; };
const cls = () => { const cls = () => {
emit("clear"); emit("clear");
emit("input", range.value ? [] : ""); emit("input", range.value ? [] : "");
}; };
const vi = (val: any) => { const vi = (val: any) => {
if (Array.isArray(val)) { if (Array.isArray(val)) {
return val.length > 1 return val.length > 1 ? val.map((item) => new Date(item)) : [new Date(), new Date()];
? val.map((item) => new Date(item))
: [new Date(), new Date()];
} }
return val ? [new Date(val)] : [new Date()]; return val ? [new Date(val)] : [new Date()];
}; };
const ok = (leaveOpened: boolean) => { const ok = (leaveOpened: boolean) => {
emit("input", get()); emit("input", get());
!leaveOpened && !leaveOpened &&
!props.showButtons && !props.showButtons &&
useTimeoutFn(() => { useTimeoutFn(() => {
show.value = range.value; show.value = range.value;
}, 1); }, 1);
}; };
const setDates = (d: Date, pos: string) => { const setDates = (d: Date, pos: string) => {
if (pos === "right") { if (pos === "right") {
dates.value[1] = d; dates.value[1] = d;
return; return;
} }
dates.value[0] = d; dates.value[0] = d;
}; };
const dc = (e: any) => { const dc = (e: any) => {
show.value = (datepicker.value as any).contains(e.target) && !props.disabled; show.value = (datepicker.value as any).contains(e.target) && !props.disabled;
}; };
const quickPick = (type: string) => { const quickPick = (type: string) => {
const end = new Date(); const end = new Date();
const start = new Date(); const start = new Date();
switch (type) { switch (type) {
@ -312,32 +271,32 @@ const quickPick = (type: string) => {
} }
dates.value = [start, end]; dates.value = [start, end];
emit("input", get()); emit("input", get());
}; };
const submit = () => { const submit = () => {
emit("confirm", get()); emit("confirm", get());
show.value = false; show.value = false;
}; };
const cancel = () => { const cancel = () => {
emit("cancel"); emit("cancel");
show.value = false; show.value = false;
}; };
onMounted(() => { onMounted(() => {
dates.value = vi(props.value); dates.value = vi(props.value);
document.addEventListener("click", dc, true); document.addEventListener("click", dc, true);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
document.removeEventListener("click", dc, true); document.removeEventListener("click", dc, true);
}); });
watch( watch(
() => props.value, () => props.value,
(val: unknown) => { (val: unknown) => {
dates.value = vi(val); dates.value = vi(val);
} },
); );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@keyframes datepicker-anim-in { @keyframes datepicker-anim-in {
0% { 0% {
opacity: 0; opacity: 0;
transform: scaleY(0.8); transform: scaleY(0.8);
@ -347,9 +306,9 @@ watch(
opacity: 1; opacity: 1;
transform: scaleY(1); transform: scaleY(1);
} }
} }
@keyframes datepicker-anim-out { @keyframes datepicker-anim-out {
0% { 0% {
opacity: 1; opacity: 1;
transform: scaleY(1); transform: scaleY(1);
@ -359,22 +318,22 @@ watch(
opacity: 0; opacity: 0;
transform: scaleY(0.8); transform: scaleY(0.8);
} }
} }
.datepicker { .datepicker {
display: inline-block; display: inline-block;
position: relative; position: relative;
} }
.datepicker-icon { .datepicker-icon {
display: block; display: block;
position: absolute; position: absolute;
top: 8px; top: 8px;
left: 8px; left: 8px;
color: #515a6ecc; color: #515a6ecc;
} }
.datepicker-close { .datepicker-close {
display: none; display: none;
position: absolute; position: absolute;
width: 34px; width: 34px;
@ -382,9 +341,9 @@ watch(
top: 0; top: 0;
right: 0; right: 0;
cursor: pointer; cursor: pointer;
} }
.datepicker-close:before { .datepicker-close:before {
display: block; display: block;
content: ""; content: "";
position: absolute; position: absolute;
@ -400,21 +359,21 @@ watch(
background: #ccc background: #ccc
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3IDciIHdpZHRoPSI3IiBoZWlnaHQ9IjciPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01LjU4LDVsMi44LTIuODFBLjQxLjQxLDAsMSwwLDcuOCwxLjZMNSw0LjQxLDIuMiwxLjZhLjQxLjQxLDAsMCwwLS41OC41OGgwTDQuNDIsNSwxLjYyLDcuOGEuNDEuNDEsMCwwLDAsLjU4LjU4TDUsNS41OCw3LjgsOC4zOWEuNDEuNDEsMCwwLDAsLjU4LS41OGgwWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEuNSAtMS40OCkiIHN0eWxlPSJmaWxsOiNmZmYiLz48L3N2Zz4NCg==") url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3IDciIHdpZHRoPSI3IiBoZWlnaHQ9IjciPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01LjU4LDVsMi44LTIuODFBLjQxLjQxLDAsMSwwLDcuOCwxLjZMNSw0LjQxLDIuMiwxLjZhLjQxLjQxLDAsMCwwLS41OC41OGgwTDQuNDIsNSwxLjYyLDcuOGEuNDEuNDEsMCwwLDAsLjU4LjU4TDUsNS41OCw3LjgsOC4zOWEuNDEuNDEsMCwwLDAsLjU4LS41OGgwWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEuNSAtMS40OCkiIHN0eWxlPSJmaWxsOiNmZmYiLz48L3N2Zz4NCg==")
no-repeat 50% 50%; no-repeat 50% 50%;
} }
.datepicker__clearable:hover:before { .datepicker__clearable:hover:before {
display: none; display: none;
} }
.datepicker__clearable:hover .datepicker-close { .datepicker__clearable:hover .datepicker-close {
display: block; display: block;
} }
.datepicker-close:hover:before { .datepicker-close:hover:before {
background-color: #afafaf; background-color: #afafaf;
} }
.datepicker > input { .datepicker > input {
color: inherit; color: inherit;
// transition: all 200ms ease; // transition: all 200ms ease;
border-radius: 4px; border-radius: 4px;
@ -428,23 +387,23 @@ watch(
user-select: none; user-select: none;
font-family: "Monaco"; font-family: "Monaco";
letter-spacing: -0.7px; letter-spacing: -0.7px;
} }
// .datepicker > input.focus { // .datepicker > input.focus {
// border-color: #3f97e3; // border-color: #3f97e3;
// -webkit-box-shadow: 0 0 5px rgba(59, 180, 242, 0.3); // -webkit-box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
// box-shadow: 0 0 5px rgba(59, 180, 242, 0.3); // box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
// } // }
.datepicker > input:disabled { .datepicker > input:disabled {
cursor: not-allowed; cursor: not-allowed;
background-color: #ebebe4; background-color: #ebebe4;
border-color: #e5e5e5; border-color: #e5e5e5;
-webkit-box-shadow: none; -webkit-box-shadow: none;
box-shadow: none; box-shadow: none;
} }
.datepicker-popup { .datepicker-popup {
border-radius: 4px; border-radius: 4px;
position: absolute; position: absolute;
transition: all 200ms ease; transition: all 200ms ease;
@ -514,52 +473,52 @@ watch(
margin-left: 100px; margin-left: 100px;
padding-left: 5px; padding-left: 5px;
} }
} }
.datepicker-inline { .datepicker-inline {
position: relative; position: relative;
margin-top: 0; margin-top: 0;
} }
.datepicker-range { .datepicker-range {
min-width: 238px; min-width: 238px;
} }
.datepicker-range .datepicker-popup { .datepicker-range .datepicker-popup {
width: 520px; width: 520px;
} }
.datepicker-bottom { .datepicker-bottom {
float: left; float: left;
width: 100%; width: 100%;
text-align: right; text-align: right;
} }
.datepicker-btn { .datepicker-btn {
padding: 5px 10px; padding: 5px 10px;
background: #3f97e3; background: #3f97e3;
color: #fff; color: #fff;
border-radius: 2px; border-radius: 2px;
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
} }
.datepicker-anim-enter-active { .datepicker-anim-enter-active {
transform-origin: 0 0; transform-origin: 0 0;
animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1); animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1);
} }
.datepicker-anim-leave-active { .datepicker-anim-leave-active {
transform-origin: 0 0; transform-origin: 0 0;
animation: datepicker-anim-out 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06); animation: datepicker-anim-out 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06);
} }
.datepicker__buttons { .datepicker__buttons {
display: block; display: block;
text-align: right; text-align: right;
} }
.datepicker__buttons button { .datepicker__buttons button {
display: inline-block; display: inline-block;
font-size: 13px; font-size: 13px;
border: none; border: none;
@ -567,13 +526,13 @@ watch(
margin: 10px 0 0 5px; margin: 10px 0 0 5px;
padding: 5px 15px; padding: 5px 15px;
color: #ffffff; color: #ffffff;
} }
.datepicker__buttons .datepicker__button-select { .datepicker__buttons .datepicker__button-select {
background: #3f97e3; background: #3f97e3;
} }
.datepicker__buttons .datepicker__button-cancel { .datepicker__buttons .datepicker__button-cancel {
background: #666; background: #666;
} }
</style> </style>

View File

@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { describe, it } from "vitest";
// import { mount } from '@vue/test-utils'
// import HelloWorld from '../HelloWorld.vue'
// describe('HelloWorld', () => {
// it('renders properly', () => {
// const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
// expect(wrapper.text()).toContain('Hello Vitest')
// })
// })
describe("My First Test", () => {
it("renders props.msg when passed", () => {
const msg = "new message";
console.log(msg);
});
});

View File

@ -14,22 +14,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import axios, { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import axios from "axios";
import { cancelToken } from "@/utils/cancelToken"; import { cancelToken } from "@/utils/cancelToken";
async function query(param: { async function query(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
queryStr: string;
conditions: { [key: string]: unknown };
}) {
const res: AxiosResponse = await axios.post( const res: AxiosResponse = await axios.post(
"/graphql", "/graphql",
{ query: param.queryStr, variables: { ...param.conditions } }, { query: param.queryStr, variables: { ...param.conditions } },
{ cancelToken: cancelToken() } { cancelToken: cancelToken() },
); );
if (res.data.errors) { if (res.data.errors) {
res.data.errors = res.data.errors res.data.errors = res.data.errors.map((e: { message: string }) => e.message).join(" ");
.map((e: { message: string }) => e.message)
.join(" ");
} }
return res; return res;
} }

View File

@ -16,8 +16,7 @@
*/ */
export const Alarm = { export const Alarm = {
variable: variable: "$keyword: String, $scope: Scope, $duration:Duration!, $tags:[AlarmTag], $paging: Pagination!",
"$keyword: String, $scope: Scope, $duration:Duration!, $tags:[AlarmTag], $paging: Pagination!",
query: ` query: `
getAlarm(keyword: $keyword, scope: $scope, duration: $duration, paging: $paging, tags: $tags) { getAlarm(keyword: $keyword, scope: $scope, duration: $duration, paging: $paging, tags: $tags) {
items: msgs { items: msgs {

View File

@ -33,8 +33,7 @@ export const createEBPFTask = {
}`, }`,
}; };
export const queryEBPFTasks = { export const queryEBPFTasks = {
variable: variable: "$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!]",
"$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!]",
query: ` query: `
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets) { queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets) {
taskId taskId

View File

@ -53,8 +53,7 @@ export const EndpointTopology = {
}`, }`,
}; };
export const InstanceTopology = { export const InstanceTopology = {
variable: variable: "$clientServiceId: ID!, $serverServiceId: ID!, $duration: Duration!",
"$clientServiceId: ID!, $serverServiceId: ID!, $duration: Duration!",
query: ` query: `
topology: getServiceInstanceTopology(clientServiceId: $clientServiceId, topology: getServiceInstanceTopology(clientServiceId: $clientServiceId,
serverServiceId: $serverServiceId, duration: $duration) { serverServiceId: $serverServiceId, duration: $duration) {

View File

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import axios, { AxiosPromise, AxiosResponse } from "axios"; import type { AxiosPromise, AxiosResponse } from "axios";
import axios from "axios";
import { cancelToken } from "@/utils/cancelToken"; import { cancelToken } from "@/utils/cancelToken";
import * as app from "./query/app"; import * as app from "./query/app";
import * as selector from "./query/selector"; import * as selector from "./query/selector";
@ -55,13 +56,11 @@ class Graphql {
query: query[this.queryData], query: query[this.queryData],
variables: variablesData, variables: variablesData,
}, },
{ cancelToken: cancelToken() } { cancelToken: cancelToken() },
) )
.then((res: AxiosResponse) => { .then((res: AxiosResponse) => {
if (res.data.errors) { if (res.data.errors) {
res.data.errors = res.data.errors res.data.errors = res.data.errors.map((e: { message: string }) => e.message).join(" ");
.map((e: { message: string }) => e.message)
.join(" ");
} }
return res; return res;
}) })

View File

@ -14,12 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { import { InstanceTopology, EndpointTopology, ServicesTopology, ProcessTopology } from "../fragments/topology";
InstanceTopology,
EndpointTopology,
ServicesTopology,
ProcessTopology,
} from "../fragments/topology";
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`; export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`; export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;

View File

@ -15,12 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { Traces, TraceSpans, TraceTagKeys, TraceTagValues } from "../fragments/trace";
Traces,
TraceSpans,
TraceTagKeys,
TraceTagValues,
} from "../fragments/trace";
export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`; export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`;

View File

@ -17,7 +17,7 @@
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import dateFormatStep from "@/utils/dateFormat"; import dateFormatStep from "@/utils/dateFormat";
import getLocalTime from "@/utils/localtime"; import getLocalTime from "@/utils/localtime";
import { EventParams } from "@/types/app"; import type { EventParams } from "@/types/app";
export default function associateProcessor(props: any) { export default function associateProcessor(props: any) {
function eventAssociate() { function eventAssociate() {
@ -30,9 +30,7 @@ export default function associateProcessor(props: any) {
if (!props.option.series[0]) { if (!props.option.series[0]) {
return; return;
} }
const list = props.option.series[0].data.map( const list = props.option.series[0].data.map((d: (number | string)[]) => d[0]);
(d: (number | string)[]) => d[0]
);
if (!list.includes(props.filters.duration.endTime)) { if (!list.includes(props.filters.duration.endTime)) {
return; return;
} }
@ -77,16 +75,8 @@ export default function associateProcessor(props: any) {
if (start) { if (start) {
const end = start; const end = start;
duration = { duration = {
start: dateFormatStep( start: dateFormatStep(getLocalTime(appStore.utc, new Date(start)), step, true),
getLocalTime(appStore.utc, new Date(start)), end: dateFormatStep(getLocalTime(appStore.utc, new Date(end)), step, true),
step,
true
),
end: dateFormatStep(
getLocalTime(appStore.utc, new Date(end)),
step,
true
),
step, step,
}; };
} }
@ -101,36 +91,27 @@ export default function associateProcessor(props: any) {
status, status,
}; };
if (latency) { if (latency) {
const latencyList = series.map( const latencyList = series.map((d: { name: string; data: number[][] }, index: number) => {
(d: { name: string; data: number[][] }, index: number) => {
const data = [ const data = [
d.data[currentParams.dataIndex][1], d.data[currentParams.dataIndex][1],
series[index + 1] series[index + 1] ? series[index + 1].data[currentParams.dataIndex][1] : Infinity,
? series[index + 1].data[currentParams.dataIndex][1]
: Infinity,
]; ];
return { return {
label: label: d.name + "--" + (series[index + 1] ? series[index + 1].name : "Infinity"),
d.name +
"--" +
(series[index + 1] ? series[index + 1].name : "Infinity"),
value: String(index), value: String(index),
data, data,
}; };
} });
);
item.latency = latencyList; item.latency = latencyList;
} }
const value = series.map( const value = series.map((d: { name: string; data: number[][] }, index: number) => {
(d: { name: string; data: number[][] }, index: number) => {
return { return {
label: d.name, label: d.name,
value: String(index), value: String(index),
data: d.data[currentParams.dataIndex][1], data: d.data[currentParams.dataIndex][1],
date: d.data[currentParams.dataIndex][0], date: d.data[currentParams.dataIndex][0],
}; };
} });
);
item.metricValue = value; item.metricValue = value;
return item; return item;
} }

View File

@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ref, computed, ComputedRef, unref } from "vue"; import type { ComputedRef } from "vue";
import { ref, computed, unref } from "vue";
import { useEventListener } from "./useEventListener"; import { useEventListener } from "./useEventListener";
import { screenMap, sizeEnum, screenEnum } from "./data"; import { screenMap, sizeEnum, screenEnum } from "./data";
@ -40,9 +41,7 @@ export function useBreakpoint(): any {
}; };
} }
export function createBreakpointListen( export function createBreakpointListen(fn?: (opt: CreateCallbackParams) => void): any {
fn?: (opt: CreateCallbackParams) => void
): any {
const screenRef = ref<sizeEnum>(sizeEnum.XL || ""); const screenRef = ref<sizeEnum>(sizeEnum.XL || "");
const realWidthRef = ref(window.innerWidth); const realWidthRef = ref(window.innerWidth);

View File

@ -16,19 +16,15 @@
*/ */
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { LayoutConfig } from "@/types/dashboard"; import type { LayoutConfig } from "@/types/dashboard";
export default function getDashboard(param?: { export default function getDashboard(param?: { name: string; layer: string; entity: string }) {
name: string;
layer: string;
entity: string;
}) {
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const opt = param || dashboardStore.currentDashboard; const opt = param || dashboardStore.currentDashboard;
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]"); const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
const dashboard = list.find( const dashboard = list.find(
(d: { name: string; layer: string; entity: string }) => (d: { name: string; layer: string; entity: string }) =>
d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer,
); );
const all = dashboardStore.layout; const all = dashboardStore.layout;
const widgets: LayoutConfig[] = []; const widgets: LayoutConfig[] = [];

View File

@ -14,13 +14,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { import type { BarSeriesOption, LineSeriesOption, HeatmapSeriesOption, SankeySeriesOption } from "echarts/charts";
BarSeriesOption, import type {
LineSeriesOption,
HeatmapSeriesOption,
SankeySeriesOption,
} from "echarts/charts";
import {
TitleComponentOption, TitleComponentOption,
TooltipComponentOption, TooltipComponentOption,
GridComponentOption, GridComponentOption,
@ -48,10 +43,7 @@ export type ECOption = echarts.ComposeOption<
| SankeySeriesOption | SankeySeriesOption
>; >;
export function useECharts( export function useECharts(elRef: Ref<HTMLDivElement>, theme: "light" | "dark" | "default" = "default"): any {
elRef: Ref<HTMLDivElement>,
theme: "light" | "dark" | "default" = "default"
): any {
const getDarkMode = computed(() => { const getDarkMode = computed(() => {
return theme === "default" ? "light" : theme; return theme === "default" ? "light" : theme;
}); });
@ -131,7 +123,7 @@ export function useECharts(
initCharts(theme as "default"); initCharts(theme as "default");
setOptions(cacheOptions.value); setOptions(cacheOptions.value);
} }
} },
); );
tryOnUnmounted(() => { tryOnUnmounted(() => {

View File

@ -43,16 +43,13 @@ export function useEventListener({
if (el) { if (el) {
const element = ref(el as Element) as Ref<Element>; const element = ref(el as Element) as Ref<Element>;
const handler = isDebounce const handler = isDebounce ? useDebounceFn(listener, wait) : useThrottleFn(listener, wait);
? useDebounceFn(listener, wait)
: useThrottleFn(listener, wait);
const realHandler = wait ? handler : listener; const realHandler = wait ? handler : listener;
const removeEventListener = (e: Element) => { const removeEventListener = (e: Element) => {
isAddRef.value = true; isAddRef.value = true;
e.removeEventListener(name, realHandler, options); e.removeEventListener(name, realHandler, options);
}; };
const addEventListener = (e: Element) => const addEventListener = (e: Element) => e.addEventListener(name, realHandler, options);
e.addEventListener(name, realHandler, options);
const removeWatch = watch( const removeWatch = watch(
element, element,
@ -64,7 +61,7 @@ export function useEventListener({
}); });
} }
}, },
{ immediate: true } { immediate: true },
); );
remove = () => { remove = () => {

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { LegendOptions } from "@/types/dashboard"; import type { LegendOptions } from "@/types/dashboard";
import { isDef } from "@/utils/is"; import { isDef } from "@/utils/is";
export default function useLegendProcess(legend?: LegendOptions) { export default function useLegendProcess(legend?: LegendOptions) {
@ -37,14 +37,9 @@ export default function useLegendProcess(legend?: LegendOptions) {
} }
return true; return true;
} }
function aggregations( function aggregations(data: { [key: string]: number[] }, intervalTime: string[]) {
data: { [key: string]: number[] },
intervalTime: string[]
) {
const source: { [key: string]: unknown }[] = []; const source: { [key: string]: unknown }[] = [];
const keys = Object.keys(data || {}).filter( const keys = Object.keys(data || {}).filter((i: any) => Array.isArray(data[i]) && data[i].length);
(i: any) => Array.isArray(data[i]) && data[i].length
);
const headers = []; const headers = [];
for (const [key, value] of keys.entries()) { for (const [key, value] of keys.entries()) {
@ -58,12 +53,7 @@ export default function useLegendProcess(legend?: LegendOptions) {
value: d, value: d,
}; };
}) })
.sort( .sort((a: { key: string; value: number }, b: { key: string; value: number }) => b.value - a.value)
(
a: { key: string; value: number },
b: { key: string; value: number }
) => b.value - a.value
)
.filter((_: unknown, index: number) => index < 10), .filter((_: unknown, index: number) => index < 10),
}; };
if (legend) { if (legend) {

View File

@ -17,25 +17,14 @@
import { MetricQueryTypes, Calculations } from "./data"; import { MetricQueryTypes, Calculations } from "./data";
export function useListConfig(config: any, index: string) { export function useListConfig(config: any, index: string) {
const i = Number(index); const i = Number(index);
const types = [ const types = [Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg];
Calculations.Average, const calculation = config.metricConfig && config.metricConfig[i] && config.metricConfig[i].calculation;
Calculations.ApdexAvg,
Calculations.PercentageAvg,
];
const calculation =
config.metricConfig &&
config.metricConfig[i] &&
config.metricConfig[i].calculation;
const isLinear = const isLinear =
[ [MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
MetricQueryTypes.ReadMetricsValues, !types.includes(calculation);
MetricQueryTypes.ReadLabeledMetricsValues,
].includes(config.metricTypes[i]) && !types.includes(calculation);
const isAvg = const isAvg =
[ [MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
MetricQueryTypes.ReadMetricsValues, types.includes(calculation);
MetricQueryTypes.ReadLabeledMetricsValues,
].includes(config.metricTypes[i]) && types.includes(calculation);
return { return {
isLinear, isLinear,
isAvg, isAvg,

View File

@ -20,8 +20,8 @@ import { ElMessage } from "element-plus";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { Instance, Endpoint, Service } from "@/types/selector"; import type { Instance, Endpoint, Service } from "@/types/selector";
import { MetricConfigOpt } from "@/types/dashboard"; import type { MetricConfigOpt } from "@/types/dashboard";
import { MetricCatalog } from "@/views/dashboard/data"; import { MetricCatalog } from "@/views/dashboard/data";
export function useQueryProcessor(config: any) { export function useQueryProcessor(config: any) {
@ -42,33 +42,21 @@ export function useQueryProcessor(config: any) {
duration: appStore.durationTime, duration: appStore.durationTime,
}; };
const variables: string[] = [`$duration: Duration!`]; const variables: string[] = [`$duration: Duration!`];
const isRelation = [ const isRelation = ["ServiceRelation", "ServiceInstanceRelation", "EndpointRelation", "ProcessRelation"].includes(
"ServiceRelation", dashboardStore.entity,
"ServiceInstanceRelation", );
"EndpointRelation",
"ProcessRelation",
].includes(dashboardStore.entity);
if (isRelation && !selectorStore.currentDestService) { if (isRelation && !selectorStore.currentDestService) {
return; return;
} }
const fragment = config.metrics.map((name: string, index: number) => { const fragment = config.metrics.map((name: string, index: number) => {
const metricType = config.metricTypes[index] || ""; const metricType = config.metricTypes[index] || "";
const c = (config.metricConfig && config.metricConfig[index]) || {}; const c = (config.metricConfig && config.metricConfig[index]) || {};
if ( if ([MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics].includes(metricType)) {
[
MetricQueryTypes.ReadSampledRecords,
MetricQueryTypes.SortMetrics,
].includes(metricType)
) {
variables.push(`$condition${index}: TopNCondition!`); variables.push(`$condition${index}: TopNCondition!`);
conditions[`condition${index}`] = { conditions[`condition${index}`] = {
name, name,
parentService: ["All"].includes(dashboardStore.entity) parentService: ["All"].includes(dashboardStore.entity) ? null : selectorStore.currentService.value,
? null normal: selectorStore.currentService ? selectorStore.currentService.normal : true,
: selectorStore.currentService.value,
normal: selectorStore.currentService
? selectorStore.currentService.normal
: true,
scope: config.catalog, scope: config.catalog,
topN: c.topN || 10, topN: c.topN || 10,
order: c.sortOrder || "DES", order: c.sortOrder || "DES",
@ -76,19 +64,11 @@ export function useQueryProcessor(config: any) {
} else { } else {
const entity = { const entity = {
scope: config.catalog, scope: config.catalog,
serviceName: serviceName: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.value,
dashboardStore.entity === "All" normal: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.normal,
? undefined serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", "ProcessRelation"].includes(
: selectorStore.currentService.value, dashboardStore.entity,
normal: )
dashboardStore.entity === "All"
? undefined
: selectorStore.currentService.normal,
serviceInstanceName: [
"ServiceInstance",
"ServiceInstanceRelation",
"ProcessRelation",
].includes(dashboardStore.entity)
? selectorStore.currentPod && selectorStore.currentPod.value ? selectorStore.currentPod && selectorStore.currentPod.value
: undefined, : undefined,
endpointName: dashboardStore.entity.includes("Endpoint") endpointName: dashboardStore.entity.includes("Endpoint")
@ -97,16 +77,9 @@ export function useQueryProcessor(config: any) {
processName: dashboardStore.entity.includes("Process") processName: dashboardStore.entity.includes("Process")
? selectorStore.currentProcess && selectorStore.currentProcess.value ? selectorStore.currentProcess && selectorStore.currentProcess.value
: undefined, : undefined,
destNormal: isRelation destNormal: isRelation ? selectorStore.currentDestService.normal : undefined,
? selectorStore.currentDestService.normal destServiceName: isRelation ? selectorStore.currentDestService.value : undefined,
: undefined, destServiceInstanceName: ["ServiceInstanceRelation", "ProcessRelation"].includes(dashboardStore.entity)
destServiceName: isRelation
? selectorStore.currentDestService.value
: undefined,
destServiceInstanceName: [
"ServiceInstanceRelation",
"ProcessRelation",
].includes(dashboardStore.entity)
? selectorStore.currentDestPod && selectorStore.currentDestPod.value ? selectorStore.currentDestPod && selectorStore.currentDestPod.value
: undefined, : undefined,
destEndpointName: destEndpointName:
@ -114,8 +87,7 @@ export function useQueryProcessor(config: any) {
? selectorStore.currentDestPod && selectorStore.currentDestPod.value ? selectorStore.currentDestPod && selectorStore.currentDestPod.value
: undefined, : undefined,
destProcessName: dashboardStore.entity.includes("ProcessRelation") destProcessName: dashboardStore.entity.includes("ProcessRelation")
? selectorStore.currentDestProcess && ? selectorStore.currentDestProcess && selectorStore.currentDestProcess.value
selectorStore.currentDestProcess.value
: undefined, : undefined,
}; };
if ([MetricQueryTypes.ReadRecords].includes(metricType)) { if ([MetricQueryTypes.ReadRecords].includes(metricType)) {
@ -129,9 +101,7 @@ export function useQueryProcessor(config: any) {
} else { } else {
entity.scope = dashboardStore.entity; entity.scope = dashboardStore.entity;
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) { if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
const labels = (c.labelsIndex || "") const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
.split(",")
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
variables.push(`$labels${index}: [String!]!`); variables.push(`$labels${index}: [String!]!`);
conditions[`labels${index}`] = labels; conditions[`labels${index}`] = labels;
} }
@ -161,7 +131,7 @@ export function useSourceProcessor(
metrics: string[]; metrics: string[];
metricTypes: string[]; metricTypes: string[];
metricConfig: MetricConfigOpt[]; metricConfig: MetricConfigOpt[];
} },
) { ) {
if (resp.errors) { if (resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
@ -179,23 +149,14 @@ export function useSourceProcessor(
const c = (config.metricConfig && config.metricConfig[index]) || {}; const c = (config.metricConfig && config.metricConfig[index]) || {};
if (type === MetricQueryTypes.ReadMetricsValues) { if (type === MetricQueryTypes.ReadMetricsValues) {
source[c.label || m] = source[c.label || m] = (resp.data[keys[index]] && calculateExp(resp.data[keys[index]].values.values, c)) || [];
(resp.data[keys[index]] &&
calculateExp(resp.data[keys[index]].values.values, c)) ||
[];
} }
if (type === MetricQueryTypes.ReadLabeledMetricsValues) { if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
const resVal = Object.values(resp.data)[0] || []; const resVal = Object.values(resp.data)[0] || [];
const labels = (c.label || "") const labels = (c.label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
.split(",") const labelsIdx = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
const labelsIdx = (c.labelsIndex || "")
.split(",")
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
for (const item of resVal) { for (const item of resVal) {
const values = item.values.values.map((d: { value: number }) => const values = item.values.values.map((d: { value: number }) => aggregation(Number(d.value), c));
aggregation(Number(d.value), c)
);
const indexNum = labelsIdx.findIndex((d: string) => d === item.label); const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
if (labels[indexNum] && indexNum > -1) { if (labels[indexNum] && indexNum > -1) {
source[labels[indexNum]] = values; source[labels[indexNum]] = values;
@ -209,20 +170,14 @@ export function useSourceProcessor(
} }
if ( if (
( (
[ [MetricQueryTypes.ReadRecords, MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics] as string[]
MetricQueryTypes.ReadRecords,
MetricQueryTypes.ReadSampledRecords,
MetricQueryTypes.SortMetrics,
] as string[]
).includes(type) ).includes(type)
) { ) {
source[m] = (Object.values(resp.data)[0] || []).map( source[m] = (Object.values(resp.data)[0] || []).map((d: { value: unknown; name: string }) => {
(d: { value: unknown; name: string }) => {
d.value = aggregation(Number(d.value), c); d.value = aggregation(Number(d.value), c);
return d; return d;
} });
);
} }
if (type === MetricQueryTypes.READHEATMAP) { if (type === MetricQueryTypes.READHEATMAP) {
const resVal = Object.values(resp.data)[0] || {}; const resVal = Object.values(resp.data)[0] || {};
@ -238,12 +193,7 @@ export function useSourceProcessor(
}); });
let buckets = [] as any; let buckets = [] as any;
if (resVal.buckets.length) { if (resVal.buckets.length) {
buckets = [ buckets = [resVal.buckets[0].min, ...resVal.buckets.map((item: { min: string; max: string }) => item.max)];
resVal.buckets[0].min,
...resVal.buckets.map(
(item: { min: string; max: string }) => item.max
),
];
} }
source[m] = { nodes, buckets }; // nodes: number[][] source[m] = { nodes, buckets }; // nodes: number[][]
@ -260,7 +210,7 @@ export function useQueryPodsMetrics(
metricTypes: string[]; metricTypes: string[];
metricConfig: MetricConfigOpt[]; metricConfig: MetricConfigOpt[];
}, },
scope: string scope: string,
) { ) {
const metricTypes = (config.metricTypes || []).filter((m: string) => m); const metricTypes = (config.metricTypes || []).filter((m: string) => m);
if (!metricTypes.length) { if (!metricTypes.length) {
@ -277,11 +227,7 @@ export function useQueryPodsMetrics(
}; };
const variables: string[] = [`$duration: Duration!`]; const variables: string[] = [`$duration: Duration!`];
const currentService = selectorStore.currentService || {}; const currentService = selectorStore.currentService || {};
const fragmentList = pods.map( const fragmentList = pods.map((d: (Instance | Endpoint | Service) & { normal: boolean }, index: number) => {
(
d: (Instance | Endpoint | Service) & { normal: boolean },
index: number
) => {
const param = { const param = {
scope, scope,
serviceName: scope === "Service" ? d.label : currentService.label, serviceName: scope === "Service" ? d.label : currentService.label,
@ -301,16 +247,13 @@ export function useQueryPodsMetrics(
const c = config.metricConfig[idx] || {}; const c = config.metricConfig[idx] || {};
variables.push(`$labels${index}${idx}: [String!]!`); variables.push(`$labels${index}${idx}: [String!]!`);
labelStr = `labels: $labels${index}${idx}, `; labelStr = `labels: $labels${index}${idx}, `;
const labels = (c.labelsIndex || "") const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
.split(",")
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
conditions[`labels${index}${idx}`] = labels; conditions[`labels${index}${idx}`] = labels;
} }
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[metricType]}`; return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[metricType]}`;
}); });
return f; return f;
} });
);
const fragment = fragmentList.flat(1).join(" "); const fragment = fragmentList.flat(1).join(" ");
const queryStr = `query queryData(${variables}) {${fragment}}`; const queryStr = `query queryData(${variables}) {${fragment}}`;
@ -324,7 +267,7 @@ export function usePodsSource(
metrics: string[]; metrics: string[];
metricTypes: string[]; metricTypes: string[];
metricConfig: MetricConfigOpt[]; metricConfig: MetricConfigOpt[];
} },
): any { ): any {
if (resp.errors) { if (resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
@ -347,39 +290,23 @@ export function usePodsSource(
} }
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) { if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
d[name] = {}; d[name] = {};
if ( if ([Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg].includes(c.calculation)) {
[
Calculations.Average,
Calculations.ApdexAvg,
Calculations.PercentageAvg,
].includes(c.calculation)
) {
d[name]["avg"] = calculateExp(resp.data[key].values.values, c); d[name]["avg"] = calculateExp(resp.data[key].values.values, c);
} }
d[name]["values"] = resp.data[key].values.values.map( d[name]["values"] = resp.data[key].values.values.map((val: { value: number }) => aggregation(val.value, c));
(val: { value: number }) => aggregation(val.value, c)
);
if (idx === 0) { if (idx === 0) {
names.push(name); names.push(name);
metricConfigArr.push(c); metricConfigArr.push(c);
metricTypesArr.push(config.metricTypes[index]); metricTypesArr.push(config.metricTypes[index]);
} }
} }
if ( if (config.metricTypes[index] === MetricQueryTypes.ReadLabeledMetricsValues) {
config.metricTypes[index] === MetricQueryTypes.ReadLabeledMetricsValues
) {
const resVal = resp.data[key] || []; const resVal = resp.data[key] || [];
const labels = (c.label || "") const labels = (c.label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
.split(",") const labelsIdx = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
const labelsIdx = (c.labelsIndex || "")
.split(",")
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
for (let i = 0; i < resVal.length; i++) { for (let i = 0; i < resVal.length; i++) {
const item = resVal[i]; const item = resVal[i];
const values = item.values.values.map((d: { value: number }) => const values = item.values.values.map((d: { value: number }) => aggregation(Number(d.value), c));
aggregation(Number(d.value), c)
);
const indexNum = labelsIdx.findIndex((d: string) => d === item.label); const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
let key = item.label; let key = item.label;
if (labels[indexNum] && indexNum > -1) { if (labels[indexNum] && indexNum > -1) {
@ -388,13 +315,7 @@ export function usePodsSource(
if (!d[key]) { if (!d[key]) {
d[key] = {}; d[key] = {};
} }
if ( if ([Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg].includes(c.calculation)) {
[
Calculations.Average,
Calculations.ApdexAvg,
Calculations.PercentageAvg,
].includes(c.calculation)
) {
d[key]["avg"] = calculateExp(item.values.values, c); d[key]["avg"] = calculateExp(item.values.values, c);
} }
d[key]["values"] = values; d[key]["values"] = values;
@ -435,13 +356,8 @@ export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
return { queryStr, conditions }; return { queryStr, conditions };
} }
function calculateExp( function calculateExp(arr: { value: number }[], config: { calculation?: string }): (number | string)[] {
arr: { value: number }[], const sum = arr.map((d: { value: number }) => d.value).reduce((a, b) => a + b);
config: { calculation?: string }
): (number | string)[] {
const sum = arr
.map((d: { value: number }) => d.value)
.reduce((a, b) => a + b);
let data: (number | string)[] = []; let data: (number | string)[] = [];
switch (config.calculation) { switch (config.calculation) {
case Calculations.Average: case Calculations.Average:
@ -460,10 +376,7 @@ function calculateExp(
return data; return data;
} }
export function aggregation( export function aggregation(val: number, config: { calculation?: string }): number | string {
val: number,
config: { calculation?: string }
): number | string {
let data: number | string = Number(val); let data: number | string = Number(val);
switch (config.calculation) { switch (config.calculation) {
@ -518,11 +431,9 @@ export async function useGetMetricEntity(metric: string, metricType: any) {
let catalog = ""; let catalog = "";
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
if ( if (
[ [MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics, MetricQueryTypes.ReadRecords].includes(
MetricQueryTypes.ReadSampledRecords, metricType,
MetricQueryTypes.SortMetrics, )
MetricQueryTypes.ReadRecords,
].includes(metricType)
) { ) {
const res = await dashboardStore.fetchMetricList(metric); const res = await dashboardStore.fetchMetricList(metric);
if (res.errors) { if (res.errors) {

View File

@ -18,11 +18,7 @@ import { ref, watch } from "vue";
import { tryOnUnmounted } from "@vueuse/core"; import { tryOnUnmounted } from "@vueuse/core";
import { isFunction } from "@/utils/is"; import { isFunction } from "@/utils/is";
export function useTimeoutFn( export function useTimeoutFn(handle: Fn<any>, wait: number, native = false): any {
handle: Fn<any>,
wait: number,
native = false
): any {
if (!isFunction(handle)) { if (!isFunction(handle)) {
throw new Error("handle is not Function!"); throw new Error("handle is not Function!");
} }
@ -36,7 +32,7 @@ export function useTimeoutFn(
(maturity) => { (maturity) => {
maturity && handle(); maturity && handle();
}, },
{ immediate: false } { immediate: false },
); );
} }
return { readyRef, stop, start }; return { readyRef, stop, start };

View File

@ -22,15 +22,15 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { AppMain, SideBar, NavBar } from "./components"; import { AppMain, SideBar, NavBar } from "./components";
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.app-wrapper { .app-wrapper {
height: 100%; height: 100%;
} }
.main-container { .main-container {
flex-grow: 2; flex-grow: 2;
height: 100%; height: 100%;
} }
</style> </style>

View File

@ -22,8 +22,8 @@ limitations under the License. -->
</section> </section>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.app-main { .app-main {
height: calc(100% - 40px); height: calc(100% - 40px);
background: #f7f9fa; background: #f7f9fa;
} }
</style> </style>

View File

@ -23,21 +23,12 @@ limitations under the License. -->
format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm"
@input="changeTimeRange" @input="changeTimeRange"
/> />
<span> <span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
UTC{{ appStore.utcHour >= 0 ? "+" : ""
}}{{ `${appStore.utcHour}:${appStore.utcMin}` }}
</span>
<span title="refresh" class="ghost ml-5 cp" @click="handleReload"> <span title="refresh" class="ghost ml-5 cp" @click="handleReload">
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" /> <Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
</span> </span>
<span class="version ml-5 cp"> <span class="version ml-5 cp">
<el-popover <el-popover trigger="hover" width="250" placement="bottom" effect="light" :content="appStore.version">
trigger="hover"
width="250"
placement="bottom"
effect="light"
:content="appStore.version"
>
<template #reference> <template #reference>
<span> <span>
<Icon iconName="info_outline" size="middle" /> <Icon iconName="info_outline" size="middle" />
@ -49,54 +40,52 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import timeFormat from "@/utils/timeFormat"; import timeFormat from "@/utils/timeFormat";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const route = useRoute(); const route = useRoute();
const pageName = ref<string>(""); const pageName = ref<string>("");
const timeRange = ref<number>(0); const timeRange = ref<number>(0);
resetDuration(); resetDuration();
getVersion(); getVersion();
const setConfig = (value: string) => { const setConfig = (value: string) => {
pageName.value = value || ""; pageName.value = value || "";
}; };
function handleReload() { function handleReload() {
const gap = const gap = appStore.duration.end.getTime() - appStore.duration.start.getTime();
appStore.duration.end.getTime() - appStore.duration.start.getTime();
const dates: Date[] = [new Date(new Date().getTime() - gap), new Date()]; const dates: Date[] = [new Date(new Date().getTime() - gap), new Date()];
appStore.setDuration(timeFormat(dates)); appStore.setDuration(timeFormat(dates));
} }
function changeTimeRange(val: Date[] | any) { function changeTimeRange(val: Date[] | any) {
timeRange.value = timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
if (timeRange.value) { if (timeRange.value) {
return; return;
} }
appStore.setDuration(timeFormat(val)); appStore.setDuration(timeFormat(val));
} }
setConfig(String(route.meta.title)); setConfig(String(route.meta.title));
watch( watch(
() => route.meta.title, () => route.meta.title,
(title: unknown) => { (title: unknown) => {
setConfig(String(title)); setConfig(String(title));
} },
); );
async function getVersion() { async function getVersion() {
const res = await appStore.fetchVersion(); const res = await appStore.fetchVersion();
if (res.errors) { if (res.errors) {
ElMessage.error(res.errors); ElMessage.error(res.errors);
} }
} }
function resetDuration() { function resetDuration() {
const { duration }: any = route.params; const { duration }: any = route.params;
if (duration) { if (duration) {
const d = JSON.parse(duration); const d = JSON.parse(duration);
@ -108,10 +97,10 @@ function resetDuration() {
}); });
appStore.updateUTC(d.utc); appStore.updateUTC(d.utc);
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.nav-bar { .nav-bar {
padding: 5px 10px 5px 28px; padding: 5px 10px 5px 28px;
text-align: left; text-align: left;
justify-content: space-between; justify-content: space-between;
@ -119,22 +108,22 @@ function resetDuration() {
border-bottom: 1px solid #dfe4e8; border-bottom: 1px solid #dfe4e8;
color: #222; color: #222;
font-size: 12px; font-size: 12px;
} }
.nav-bar.dark { .nav-bar.dark {
background-color: #333840; background-color: #333840;
border-bottom: 1px solid #252a2f; border-bottom: 1px solid #252a2f;
color: #fafbfc; color: #fafbfc;
} }
.title { .title {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
height: 28px; height: 28px;
line-height: 28px; line-height: 28px;
} }
.nav-tabs { .nav-tabs {
padding: 10px; padding: 10px;
} }
</style> </style>

View File

@ -15,10 +15,7 @@ limitations under the License. -->
<template> <template>
<div class="side-bar"> <div class="side-bar">
<div :class="isCollapse ? 'logo-icon-collapse' : 'logo-icon'"> <div :class="isCollapse ? 'logo-icon-collapse' : 'logo-icon'">
<Icon <Icon :size="isCollapse ? 'xl' : 'logo'" :iconName="isCollapse ? 'logo' : 'logo-sw'" />
:size="isCollapse ? 'xl' : 'logo'"
:iconName="isCollapse ? 'logo' : 'logo-sw'"
/>
</div> </div>
<el-menu <el-menu
active-text-color="#448dfe" active-text-color="#448dfe"
@ -43,22 +40,14 @@ limitations under the License. -->
</router-link> </router-link>
</template> </template>
<el-menu-item-group> <el-menu-item-group>
<el-menu-item <el-menu-item v-for="(m, idx) in filterMenus(menu.children)" :index="m.name" :key="idx">
v-for="(m, idx) in filterMenus(menu.children)"
:index="m.name"
:key="idx"
>
<router-link class="items" :to="m.path"> <router-link class="items" :to="m.path">
<span class="title">{{ m.meta && t(m.meta.title) }}</span> <span class="title">{{ m.meta && t(m.meta.title) }}</span>
</router-link> </router-link>
</el-menu-item> </el-menu-item>
</el-menu-item-group> </el-menu-item-group>
</el-sub-menu> </el-sub-menu>
<el-menu-item <el-menu-item :index="String(menu.name)" @click="changePage(menu)" v-else>
:index="String(menu.name)"
@click="changePage(menu)"
v-else
>
<el-icon class="menu-icons" :style="{ marginRight: '12px' }"> <el-icon class="menu-icons" :style="{ marginRight: '12px' }">
<router-link class="items" :to="menu.children[0].path"> <router-link class="items" :to="menu.children[0].path">
<Icon size="lg" :iconName="menu.meta.icon" /> <Icon size="lg" :iconName="menu.meta.icon" />
@ -79,82 +68,75 @@ limitations under the License. -->
color: theme === 'light' ? '#eee' : '#252a2f', color: theme === 'light' ? '#eee' : '#252a2f',
}" }"
> >
<Icon <Icon size="middle" iconName="format_indent_decrease" @click="controlMenu" />
size="middle"
iconName="format_indent_decrease"
@click="controlMenu"
/>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { useRouter, RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { useI18n } from "vue-i18n"; import { useRouter } from "vue-router";
import Icon from "@/components/Icon.vue"; import { useI18n } from "vue-i18n";
import { useAppStoreWithOut } from "@/store/modules/app"; import Icon from "@/components/Icon.vue";
import { useAppStoreWithOut } from "@/store/modules/app";
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const { t } = useI18n(); const { t } = useI18n();
const name = ref<string>(String(useRouter().currentRoute.value.name)); const name = ref<string>(String(useRouter().currentRoute.value.name));
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "") const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "") ? ref("light") : ref("black");
? ref("light") const routes = ref<RouteRecordRaw[] | any>(useRouter().options.routes);
: ref("black"); if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
const routes = ref<RouteRecordRaw[] | any>(useRouter().options.routes);
if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
appStore.setIsMobile(true); appStore.setIsMobile(true);
} else { } else {
appStore.setIsMobile(false); appStore.setIsMobile(false);
} }
const isCollapse = ref(false); const isCollapse = ref(false);
const controlMenu = () => { const controlMenu = () => {
isCollapse.value = !isCollapse.value; isCollapse.value = !isCollapse.value;
}; };
const changePage = (menu: RouteRecordRaw) => { const changePage = (menu: RouteRecordRaw) => {
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) ? "light" : "black";
? "light" };
: "black"; const filterMenus = (menus: any[]) => {
};
const filterMenus = (menus: any[]) => {
return menus.filter((d) => d.meta && !d.meta.notShow); return menus.filter((d) => d.meta && !d.meta.notShow);
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.side-bar { .side-bar {
background: #252a2f; background: #252a2f;
height: 100%; height: 100%;
margin-bottom: 100px; margin-bottom: 100px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.el-menu-vertical:not(.el-menu--collapse) { .el-menu-vertical:not(.el-menu--collapse) {
width: 220px; width: 220px;
font-size: 16px; font-size: 16px;
} }
.logo-icon-collapse { .logo-icon-collapse {
width: 65px; width: 65px;
margin: 15px 0 10px 0; margin: 15px 0 10px 0;
text-align: center; text-align: center;
} }
span.collapse { span.collapse {
height: 0; height: 0;
width: 0; width: 0;
overflow: hidden; overflow: hidden;
visibility: hidden; visibility: hidden;
display: inline-block; display: inline-block;
} }
.logo-icon { .logo-icon {
margin: 15px 0 10px 20px; margin: 15px 0 10px 20px;
width: 110px; width: 110px;
} }
.menu-control { .menu-control {
position: absolute; position: absolute;
top: 7px; top: 7px;
left: 220px; left: 220px;
@ -162,22 +144,22 @@ span.collapse {
transition: all 0.2s linear; transition: all 0.2s linear;
z-index: 99; z-index: 99;
color: #252a2f; color: #252a2f;
} }
.menu-control.collapse { .menu-control.collapse {
left: 70px; left: 70px;
} }
.el-icon.el-sub-menu__icon-arrow { .el-icon.el-sub-menu__icon-arrow {
height: 12px; height: 12px;
} }
.items { .items {
display: inline-block; display: inline-block;
width: 100%; width: 100%;
} }
.version { .version {
color: #eee; color: #eee;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
@ -186,17 +168,17 @@ span.collapse {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 10px; left: 10px;
} }
.empty { .empty {
width: 100%; width: 100%;
height: 60px; height: 60px;
} }
.title { .title {
display: inline-block; display: inline-block;
max-width: 110px; max-width: 110px;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
} }
</style> </style>

View File

@ -32,6 +32,7 @@ if (!savedLanguage) {
} }
language = savedLanguage ? savedLanguage : language; language = savedLanguage ? savedLanguage : language;
const i18n = createI18n({ const i18n = createI18n({
legacy: false,
locale: language, locale: language,
messages, messages,
}); });

View File

@ -176,10 +176,8 @@ const msg = {
toTheRight: "To The Right", toTheRight: "To The Right",
legendValues: "Legend Values", legendValues: "Legend Values",
minDuration: "Minimal Request Duration", minDuration: "Minimal Request Duration",
when4xx: when4xx: "Sample HTTP requests and responses with tracing when response code between 400 and 499",
"Sample HTTP requests and responses with tracing when response code between 400 and 499", when5xx: "Sample HTTP requests and responses with tracing when response code between 500 and 599",
when5xx:
"Sample HTTP requests and responses with tracing when response code between 500 and 599",
taskTitle: "HTTP request and response collecting rules", taskTitle: "HTTP request and response collecting rules",
seconds: "Seconds", seconds: "Seconds",
hourTip: "Select Hour", hourTip: "Select Hour",
@ -315,8 +313,7 @@ const msg = {
viewLogs: "View Logs", viewLogs: "View Logs",
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable. logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
Check more details on the Configuration Vocabulary page`, Check more details on the Configuration Vocabulary page`,
keywordsOfContentLogTips: keywordsOfContentLogTips: "Current storage of SkyWalking OAP server does not support this.",
"Current storage of SkyWalking OAP server does not support this.",
setEvent: "Set Event", setEvent: "Set Event",
viewAttributes: "View", viewAttributes: "View",
serviceEvents: "Service Events", serviceEvents: "Service Events",
@ -370,8 +367,7 @@ const msg = {
addKeywordsOfContent: "Please input a keyword of content", addKeywordsOfContent: "Please input a keyword of content",
addExcludingKeywordsOfContent: "Please input a keyword of excluding content", addExcludingKeywordsOfContent: "Please input a keyword of excluding content",
noticeTag: "Please press Enter after inputting a tag(key=value).", noticeTag: "Please press Enter after inputting a tag(key=value).",
conditionNotice: conditionNotice: "Notice: Please press Enter after inputting a key of content, exclude key of content(key=value).",
"Notice: Please press Enter after inputting a key of content, exclude key of content(key=value).",
language: "Language", language: "Language",
gateway: "Gateway", gateway: "Gateway",
virtualMQ: "Virtual MQ", virtualMQ: "Virtual MQ",

View File

@ -77,10 +77,8 @@ const msg = {
editGraph: "Editar Opciones", editGraph: "Editar Opciones",
dashboardName: "Selecciona Nombre del Panel", dashboardName: "Selecciona Nombre del Panel",
linkDashboard: "Nombre del panel relacionado con llamadas de la topología", linkDashboard: "Nombre del panel relacionado con llamadas de la topología",
linkServerMetrics: linkServerMetrics: "Métricas de servidor relacionadas con llamadas de la topología",
"Métricas de servidor relacionadas con llamadas de la topología", linkClientMetrics: "Métricas de cliente relacionadas con llamadas de la topología",
linkClientMetrics:
"Métricas de cliente relacionadas con llamadas de la topología",
nodeDashboard: "Nombre del panel relacionado con nodos de la topología", nodeDashboard: "Nombre del panel relacionado con nodos de la topología",
nodeMetrics: "Mêtricas relacionas con nodos de la topología", nodeMetrics: "Mêtricas relacionas con nodos de la topología",
instanceDashboard: "Nombre del panel relacionado con instancias de servicio", instanceDashboard: "Nombre del panel relacionado con instancias de servicio",
@ -180,10 +178,8 @@ const msg = {
asTable: "Como tabla", asTable: "Como tabla",
toTheRight: "Derecha", toTheRight: "Derecha",
minDuration: "Duración mínima de la solicitud", minDuration: "Duración mínima de la solicitud",
when4xx: when4xx: "Ejemplo de solicitud y respuesta http con seguimiento cuando el Código de respuesta está entre 400 y 499",
"Ejemplo de solicitud y respuesta http con seguimiento cuando el Código de respuesta está entre 400 y 499", when5xx: "Ejemplo de solicitud y respuesta http con seguimiento cuando el Código de respuesta está entre 500 y 599",
when5xx:
"Ejemplo de solicitud y respuesta http con seguimiento cuando el Código de respuesta está entre 500 y 599",
taskTitle: "Reglas de recolección de peticiones y respuestas HTTP", taskTitle: "Reglas de recolección de peticiones y respuestas HTTP",
second: "s", second: "s",
yearSuffix: "Año", yearSuffix: "Año",
@ -315,8 +311,7 @@ const msg = {
viewLogs: "Ver Registro de Datos", viewLogs: "Ver Registro de Datos",
logsTagsTip: `Solamente etiquetas definidas en core/default/searchableLogsTags pueden ser buscadas. logsTagsTip: `Solamente etiquetas definidas en core/default/searchableLogsTags pueden ser buscadas.
Más información en la página de Vocabulario de Configuración`, Más información en la página de Vocabulario de Configuración`,
keywordsOfContentLogTips: keywordsOfContentLogTips: "El almacenamiento actual del servidor SkyWalking OAP no lo soporta.",
"El almacenamiento actual del servidor SkyWalking OAP no lo soporta.",
setEvent: "Establecer Evento", setEvent: "Establecer Evento",
viewAttributes: "Ver", viewAttributes: "Ver",
serviceEvents: "Eventos Servico", serviceEvents: "Eventos Servico",
@ -347,8 +342,7 @@ const msg = {
destEndpoint: "Endpoint Destinación", destEndpoint: "Endpoint Destinación",
eventSource: "Fuente Envento", eventSource: "Fuente Envento",
modalTitle: "Inspección", modalTitle: "Inspección",
selectRedirectPage: selectRedirectPage: "Quiere inspeccionar las Trazas or Registros de datos del servicio %s?",
"Quiere inspeccionar las Trazas or Registros de datos del servicio %s?",
logAnalysis: "Lenguaje de Análisis de Registro de Datos", logAnalysis: "Lenguaje de Análisis de Registro de Datos",
logDataBody: "Contenido del Registro de Datos", logDataBody: "Contenido del Registro de Datos",
addType: "Por favor introduzca un tipo", addType: "Por favor introduzca un tipo",
@ -369,10 +363,8 @@ const msg = {
addTraceID: "Por favor introduzca el ID de la traza", addTraceID: "Por favor introduzca el ID de la traza",
addTags: "Por favor introduzaca una etiqueta", addTags: "Por favor introduzaca una etiqueta",
addKeywordsOfContent: "Por favor introduzca una clave de contenido", addKeywordsOfContent: "Por favor introduzca una clave de contenido",
addExcludingKeywordsOfContent: addExcludingKeywordsOfContent: "Por favor introduzca una clave excluyente de contenido",
"Por favor introduzca una clave excluyente de contenido", noticeTag: "Por favor presione Intro después de introducir una etiqueta(clave=valor).",
noticeTag:
"Por favor presione Intro después de introducir una etiqueta(clave=valor).",
conditionNotice: conditionNotice:
"Aviso: Por favor presione Intro después de introducir una clave de contenido, excluir clave de contenido(clave=valor).", "Aviso: Por favor presione Intro después de introducir una clave de contenido, excluir clave de contenido(clave=valor).",
language: "Lenguaje", language: "Lenguaje",

View File

@ -282,12 +282,9 @@ const msg = {
chartType: "图表类型", chartType: "图表类型",
currentDepth: "当前深度", currentDepth: "当前深度",
defaultDepth: "默认深度", defaultDepth: "默认深度",
traceTagsTip: traceTagsTip: "只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。", logTagsTip: "只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
logTagsTip: alarmTagsTip: "只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
alarmTagsTip:
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
tagsLink: "配置词汇页", tagsLink: "配置词汇页",
addTag: "请添加标签", addTag: "请添加标签",
logCategory: "日志类别", logCategory: "日志类别",
@ -310,8 +307,7 @@ const msg = {
contentType: "内容类型", contentType: "内容类型",
content: "内容", content: "内容",
viewLogs: "查看日志", viewLogs: "查看日志",
logsTagsTip: logsTagsTip: "只有core/default/searchableLogsTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
"只有core/default/searchableLogsTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
keywordsOfContentLogTips: "SkyWalking OAP服务器的当前存储不支持此操作", keywordsOfContentLogTips: "SkyWalking OAP服务器的当前存储不支持此操作",
setEvent: "设置事件", setEvent: "设置事件",
viewAttributes: "查看", viewAttributes: "查看",
@ -368,8 +364,7 @@ const msg = {
addKeywordsOfContent: "请输入一个内容关键词", addKeywordsOfContent: "请输入一个内容关键词",
addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词", addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词",
noticeTag: "请输入一个标签(key=value)之后回车", noticeTag: "请输入一个标签(key=value)之后回车",
conditionNotice: conditionNotice: "请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
"请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
language: "语言", language: "语言",
gateway: "网关", gateway: "网关",
virtualMQ: "虚拟消息队列", virtualMQ: "虚拟消息队列",

View File

@ -22,6 +22,7 @@ import components from "@/components";
import i18n from "./locales"; import i18n from "./locales";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import "./styles/index.ts"; import "./styles/index.ts";
import "virtual:svg-icons-register";
const app = createApp(App); const app = createApp(App);
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import Layout from "@/layout/Index.vue"; import Layout from "@/layout/Index.vue";
export const routesAlarm: Array<RouteRecordRaw> = [ export const routesAlarm: Array<RouteRecordRaw> = [
@ -31,8 +31,7 @@ export const routesAlarm: Array<RouteRecordRaw> = [
{ {
path: "/alerting", path: "/alerting",
name: "Alarm", name: "Alarm",
component: () => component: () => import("@/views/Alarm.vue"),
import(/* webpackChunkName: "alerting" */ "@/views/Alarm.vue"),
}, },
], ],
}, },

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import Layout from "@/layout/Index.vue"; import Layout from "@/layout/Index.vue";
export const routesDashboard: Array<RouteRecordRaw> = [ export const routesDashboard: Array<RouteRecordRaw> = [
@ -30,10 +30,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
children: [ children: [
{ {
path: "/dashboard/list", path: "/dashboard/list",
component: () => component: () => import("@/views/dashboard/List.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/List.vue"
),
name: "List", name: "List",
meta: { meta: {
title: "dashboardList", title: "dashboardList",
@ -41,10 +38,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
}, },
{ {
path: "/dashboard/new", path: "/dashboard/new",
component: () => component: () => import("@/views/dashboard/New.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/New.vue"
),
name: "New", name: "New",
meta: { meta: {
title: "dashboardNew", title: "dashboardNew",
@ -54,38 +48,26 @@ export const routesDashboard: Array<RouteRecordRaw> = [
path: "", path: "",
redirect: "/dashboard/:layerId/:entity/:name", redirect: "/dashboard/:layerId/:entity/:name",
name: "Create", name: "Create",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
meta: { meta: {
notShow: true, notShow: true,
}, },
children: [ children: [
{ {
path: "/dashboard/:layerId/:entity/:name", path: "/dashboard/:layerId/:entity/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "CreateChild", name: "CreateChild",
}, },
{ {
path: "/dashboard/:layerId/:entity/:name/tab/:activeTabIndex", path: "/dashboard/:layerId/:entity/:name/tab/:activeTabIndex",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "CreateActiveTabIndex", name: "CreateActiveTabIndex",
}, },
], ],
}, },
{ {
path: "", path: "",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "View", name: "View",
redirect: "/dashboard/:layerId/:entity/:serviceId/:name", redirect: "/dashboard/:layerId/:entity/:serviceId/:name",
meta: { meta: {
@ -94,30 +76,20 @@ export const routesDashboard: Array<RouteRecordRaw> = [
children: [ children: [
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:name", path: "/dashboard/:layerId/:entity/:serviceId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewChild", name: "ViewChild",
}, },
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:name/tab/:activeTabIndex", path: "/dashboard/:layerId/:entity/:serviceId/:name/tab/:activeTabIndex",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewActiveTabIndex", name: "ViewActiveTabIndex",
}, },
], ],
}, },
{ {
path: "", path: "",
redirect: redirect: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
"/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name", component: () => import("@/views/dashboard/Edit.vue"),
component: () =>
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewServiceRelation", name: "ViewServiceRelation",
meta: { meta: {
notShow: true, notShow: true,
@ -125,18 +97,12 @@ export const routesDashboard: Array<RouteRecordRaw> = [
children: [ children: [
{ {
path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name", path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewServiceRelation", name: "ViewServiceRelation",
}, },
{ {
path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name/tab/:activeTabIndex", path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name/tab/:activeTabIndex",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewServiceRelationActiveTabIndex", name: "ViewServiceRelationActiveTabIndex",
}, },
], ],
@ -144,10 +110,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
{ {
path: "", path: "",
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:name", redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewPod", name: "ViewPod",
meta: { meta: {
notShow: true, notShow: true,
@ -155,30 +118,20 @@ export const routesDashboard: Array<RouteRecordRaw> = [
children: [ children: [
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewPod", name: "ViewPod",
}, },
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name/tab/:activeTabIndex", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name/tab/:activeTabIndex",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewPodActiveTabIndex", name: "ViewPodActiveTabIndex",
}, },
], ],
}, },
{ {
path: "", path: "",
redirect: redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
"/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name", component: () => import("@/views/dashboard/Edit.vue"),
component: () =>
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "PodRelation", name: "PodRelation",
meta: { meta: {
notShow: true, notShow: true,
@ -186,18 +139,12 @@ export const routesDashboard: Array<RouteRecordRaw> = [
children: [ children: [
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewPodRelation", name: "ViewPodRelation",
}, },
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name/tab/:activeTabIndex", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name/tab/:activeTabIndex",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewPodRelationActiveTabIndex", name: "ViewPodRelationActiveTabIndex",
}, },
], ],
@ -206,10 +153,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
path: "", path: "",
redirect: redirect:
"/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name", "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ProcessRelation", name: "ProcessRelation",
meta: { meta: {
notShow: true, notShow: true,
@ -217,26 +161,17 @@ export const routesDashboard: Array<RouteRecordRaw> = [
children: [ children: [
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewProcessRelation", name: "ViewProcessRelation",
}, },
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name/tab/:activeTabIndex", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name/tab/:activeTabIndex",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewProcessRelationActiveTabIndex", name: "ViewProcessRelationActiveTabIndex",
}, },
{ {
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name/duration/:duration", path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name/duration/:duration",
component: () => component: () => import("@/views/dashboard/Edit.vue"),
import(
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
),
name: "ViewProcessRelationDuration", name: "ViewProcessRelationDuration",
}, },
], ],

View File

@ -14,21 +14,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { createRouter, createWebHistory } from "vue-router";
import { routesDashboard } from "./dashboard"; import { routesDashboard } from "./dashboard";
import { routesSetting } from "./setting"; import { routesSetting } from "./setting";
import { routesAlarm } from "./alarm"; import { routesAlarm } from "./alarm";
import routesLayers from "./layer"; import routesLayers from "./layer";
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [...routesLayers, ...routesDashboard, ...routesAlarm, ...routesSetting];
...routesLayers,
...routesDashboard,
...routesAlarm,
...routesSetting,
];
const router = createRouter({ const router = createRouter({
history: createWebHistory(process.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes, routes,
}); });

View File

@ -22,8 +22,7 @@ function layerDashboards() {
item.component = Layout; item.component = Layout;
if (item.children) { if (item.children) {
item.children = item.children.map((d: any) => { item.children = item.children.map((d: any) => {
d.component = () => d.component = () => import("@/views/Layer.vue");
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue");
return d; return d;
}); });
} }

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import Layout from "@/layout/Index.vue"; import Layout from "@/layout/Index.vue";
export const routesSetting: Array<RouteRecordRaw> = [ export const routesSetting: Array<RouteRecordRaw> = [
@ -36,8 +36,7 @@ export const routesSetting: Array<RouteRecordRaw> = [
icon: "settings", icon: "settings",
hasGroup: false, hasGroup: false,
}, },
component: () => component: () => import("@/views/Settings.vue"),
import(/* webpackChunkName: "settings" */ "@/views/Settings.vue"),
}, },
], ],
}, },

View File

@ -17,8 +17,8 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { Alarm } from "@/types/alarm"; import type { Alarm } from "@/types/alarm";
interface AlarmState { interface AlarmState {
loading: boolean; loading: boolean;
@ -35,9 +35,7 @@ export const alarmStore = defineStore({
}), }),
actions: { actions: {
async getAlarms(params: any) { async getAlarms(params: any) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryAlarms").params(params);
.query("queryAlarms")
.params(params);
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }

View File

@ -17,9 +17,9 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { Duration, DurationTime } from "@/types/app"; import type { Duration, DurationTime } from "@/types/app";
import getLocalTime from "@/utils/localtime"; import getLocalTime from "@/utils/localtime";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat"; import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
import { TimeType } from "@/constants/data"; import { TimeType } from "@/constants/data";
/*global Nullable*/ /*global Nullable*/
@ -92,9 +92,7 @@ export const appStore = defineStore({
this.duration.start.getMonth()); this.duration.start.getMonth());
break; break;
} }
const utcSpace = const utcSpace = (this.utcHour + new Date().getTimezoneOffset() / 60) * 3600000 + this.utcMin * 60000;
(this.utcHour + new Date().getTimezoneOffset() / 60) * 3600000 +
this.utcMin * 60000;
const startUnix: number = this.duration.start.getTime(); const startUnix: number = this.duration.start.getTime();
const endUnix: number = this.duration.end.getTime(); const endUnix: number = this.duration.end.getTime();
const timeIntervals: number[] = []; const timeIntervals: number[] = [];
@ -157,13 +155,11 @@ export const appStore = defineStore({
this.eventStack.forEach((event: any) => { this.eventStack.forEach((event: any) => {
setTimeout(event(), 0); setTimeout(event(), 0);
}), }),
500 500,
); );
}, },
async queryOAPTimeInfo() { async queryOAPTimeInfo() {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryOAPTimeInfo").params({});
.query("queryOAPTimeInfo")
.params({});
if (res.data.errors) { if (res.data.errors) {
this.utc = -(new Date().getTimezoneOffset() / 60) + ":0"; this.utc = -(new Date().getTimezoneOffset() / 60) + ":0";
} else { } else {
@ -176,9 +172,7 @@ export const appStore = defineStore({
return res.data; return res.data;
}, },
async fetchVersion(): Promise<void> { async fetchVersion(): Promise<void> {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryOAPVersion").params({});
.query("queryOAPVersion")
.params({});
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }

View File

@ -16,13 +16,13 @@
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import { LayoutConfig } from "@/types/dashboard"; import type { LayoutConfig } from "@/types/dashboard";
import graphql from "@/graphql"; import graphql from "@/graphql";
import query from "@/graphql/fetch"; import query from "@/graphql/fetch";
import { DashboardItem } from "@/types/dashboard"; import type { DashboardItem } from "@/types/dashboard";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { NewControl, TextConfig, TimeRangeConfig } from "../data"; import { NewControl, TextConfig, TimeRangeConfig } from "../data";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { EntityType } from "@/views/dashboard/data"; import { EntityType } from "@/views/dashboard/data";
@ -105,24 +105,10 @@ export const dashboardStore = defineStore({
newItem.h = 36; newItem.h = 36;
newItem.graph = { newItem.graph = {
showDepth: true, showDepth: true,
depth: depth: this.entity === EntityType[1].value ? 1 : this.entity === EntityType[0].value ? 2 : 3,
this.entity === EntityType[1].value
? 1
: this.entity === EntityType[0].value
? 2
: 3,
}; };
} }
if ( if (["Trace", "Profile", "Log", "DemandLog", "Ebpf", "NetworkProfiling"].includes(type)) {
[
"Trace",
"Profile",
"Log",
"DemandLog",
"Ebpf",
"NetworkProfiling",
].includes(type)
) {
newItem.h = 36; newItem.h = 36;
} }
if (type === "Text") { if (type === "Text") {
@ -156,14 +142,12 @@ export const dashboardStore = defineStore({
}, },
addTabControls(type: string) { addTabControls(type: string) {
const activedGridItem = this.activedGridItem.split("-")[0]; const activedGridItem = this.activedGridItem.split("-")[0];
const idx = this.layout.findIndex( const idx = this.layout.findIndex((d: LayoutConfig) => d.i === activedGridItem);
(d: LayoutConfig) => d.i === activedGridItem
);
if (idx < 0) { if (idx < 0) {
return; return;
} }
const tabIndex = this.layout[idx].activedTabIndex || 0; const tabIndex = this.layout[idx].activedTabIndex || 0;
const { children } = this.layout[idx].children[tabIndex]; const { children } = (this.layout[idx].children || [])[tabIndex];
const arr = children.map((d: any) => Number(d.i)); const arr = children.map((d: any) => Number(d.i));
let index = String(Math.max(...arr) + 1); let index = String(Math.max(...arr) + 1);
if (!children.length) { if (!children.length) {
@ -184,16 +168,7 @@ export const dashboardStore = defineStore({
showDepth: true, showDepth: true,
}; };
} }
if ( if (["Trace", "Profile", "Log", "DemandLog", "Ebpf", "NetworkProfiling"].includes(type)) {
[
"Trace",
"Profile",
"Log",
"DemandLog",
"Ebpf",
"NetworkProfiling",
].includes(type)
) {
newItem.h = 32; newItem.h = 32;
} }
if (type === "Text") { if (type === "Text") {
@ -211,7 +186,7 @@ export const dashboardStore = defineStore({
return d; return d;
}); });
items.push(newItem); items.push(newItem);
this.layout[idx].children[tabIndex].children = items; (this.layout[idx].children || [])[tabIndex].children = items;
this.currentTabItems = items; this.currentTabItems = items;
} }
}, },
@ -238,19 +213,15 @@ export const dashboardStore = defineStore({
}, },
removeControls(item: LayoutConfig) { removeControls(item: LayoutConfig) {
const actived = this.activedGridItem.split("-"); const actived = this.activedGridItem.split("-");
const index = this.layout.findIndex( const index = this.layout.findIndex((d: LayoutConfig) => actived[0] === d.i);
(d: LayoutConfig) => actived[0] === d.i
);
if (this.selectedGrid && this.selectedGrid.i === item.i) { if (this.selectedGrid && this.selectedGrid.i === item.i) {
this.selectedGrid = null; this.selectedGrid = null;
} }
if (actived.length === 3) { if (actived.length === 3) {
const tabIndex = Number(actived[1]); const tabIndex = Number(actived[1]);
this.currentTabItems = this.currentTabItems.filter( this.currentTabItems = this.currentTabItems.filter((d: LayoutConfig) => actived[2] !== d.i);
(d: LayoutConfig) => actived[2] !== d.i (this.layout[index].children || [])[tabIndex].children = this.currentTabItems;
);
this.layout[index].children[tabIndex].children = this.currentTabItems;
return; return;
} }
this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i); this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i);
@ -258,8 +229,8 @@ export const dashboardStore = defineStore({
removeTabItem(item: LayoutConfig, index: number) { removeTabItem(item: LayoutConfig, index: number) {
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i); const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i);
if (this.selectedGrid) { if (this.selectedGrid) {
for (const item of this.layout[idx].children[index].children) { for (const item of (this.layout[idx].children || [])[index].children) {
if (this.selectedGrid.i === item.i) { if (this.selectedGrid?.i === item.i) {
this.selectedGrid = null; this.selectedGrid = null;
} }
} }
@ -285,22 +256,19 @@ export const dashboardStore = defineStore({
}, },
setConfigs(param: { [key: string]: unknown }) { setConfigs(param: { [key: string]: unknown }) {
const actived = this.activedGridItem.split("-"); const actived = this.activedGridItem.split("-");
const index = this.layout.findIndex( const index = this.layout.findIndex((d: LayoutConfig) => actived[0] === d.i);
(d: LayoutConfig) => actived[0] === d.i
);
if (actived.length === 3) { if (actived.length === 3) {
const tabIndex = Number(actived[1]); const tabIndex = Number(actived[1]);
const itemIndex = this.layout[index].children[ const itemIndex = (this.layout[index].children || [])[tabIndex].children.findIndex(
tabIndex (d: LayoutConfig) => actived[2] === d.i,
].children.findIndex((d: LayoutConfig) => actived[2] === d.i); );
this.layout[index].children[tabIndex].children[itemIndex] = { (this.layout[index].children || [])[tabIndex].children[itemIndex] = {
...this.layout[index].children[tabIndex].children[itemIndex], ...(this.layout[index].children || [])[tabIndex].children[itemIndex],
...param, ...param,
}; };
this.selectedGrid = this.selectedGrid = (this.layout[index].children || [])[tabIndex].children[itemIndex];
this.layout[index].children[tabIndex].children[itemIndex]; this.setCurrentTabItems((this.layout[index].children || [])[tabIndex].children);
this.setCurrentTabItems(this.layout[index].children[tabIndex].children);
return; return;
} }
this.layout[index] = { this.layout[index] = {
@ -312,8 +280,8 @@ export const dashboardStore = defineStore({
setWidget(param: LayoutConfig) { setWidget(param: LayoutConfig) {
for (let i = 0; i < this.layout.length; i++) { for (let i = 0; i < this.layout.length; i++) {
if (this.layout[i].type === "Tab") { if (this.layout[i].type === "Tab") {
if (this.layout[i].children && this.layout[i].children.length) { if ((this.layout[i].children || []).length) {
for (const child of this.layout[i].children) { for (const child of this.layout[i].children || []) {
if (child.children && child.children.length) { if (child.children && child.children.length) {
for (let c = 0; c < child.children.length; c++) { for (let c = 0; c < child.children.length; c++) {
if (child.children[c].id === param.id) { if (child.children[c].id === param.id) {
@ -332,23 +300,16 @@ export const dashboardStore = defineStore({
} }
}, },
async fetchMetricType(item: string) { async fetchMetricType(item: string) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryTypeOfMetrics").params({ name: item });
.query("queryTypeOfMetrics")
.params({ name: item });
return res.data; return res.data;
}, },
async fetchMetricList(regex: string) { async fetchMetricList(regex: string) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryMetrics").params({ regex });
.query("queryMetrics")
.params({ regex });
return res.data; return res.data;
}, },
async fetchMetricValue(param: { async fetchMetricValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
queryStr: string;
conditions: { [key: string]: unknown };
}) {
const res: AxiosResponse = await query(param); const res: AxiosResponse = await query(param);
return res.data; return res.data;
}, },
@ -371,10 +332,7 @@ export const dashboardStore = defineStore({
name: c.name, name: c.name,
isRoot: c.isRoot, isRoot: c.isRoot,
}); });
sessionStorage.setItem( sessionStorage.setItem(key, JSON.stringify({ id: t.id, configuration: c }));
key,
JSON.stringify({ id: t.id, configuration: c })
);
} }
list = list.sort((a, b) => { list = list.sort((a, b) => {
const nameA = a.name.toUpperCase(); const nameA = a.name.toUpperCase();
@ -399,9 +357,7 @@ export const dashboardStore = defineStore({
return; return;
} }
} }
this.dashboards = JSON.parse( this.dashboards = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
sessionStorage.getItem("dashboards") || "[]"
);
}, },
async resetTemplates() { async resetTemplates() {
const res = await this.fetchTemplates(); const res = await this.fetchTemplates();
@ -410,9 +366,7 @@ export const dashboardStore = defineStore({
ElMessage.error(res.errors); ElMessage.error(res.errors);
return; return;
} }
this.dashboards = JSON.parse( this.dashboards = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
sessionStorage.getItem("dashboards") || "[]"
);
}, },
async updateDashboard(setting: { id: string; configuration: string }) { async updateDashboard(setting: { id: string; configuration: string }) {
const res: AxiosResponse = await graphql.query("updateTemplate").params({ const res: AxiosResponse = await graphql.query("updateTemplate").params({
@ -431,7 +385,7 @@ export const dashboardStore = defineStore({
return res.data; return res.data;
}, },
async saveDashboard() { async saveDashboard() {
if (!this.currentDashboard.name) { if (!this.currentDashboard?.name) {
ElMessage.error("The dashboard name is needed."); ElMessage.error("The dashboard name is needed.");
return; return;
} }
@ -452,18 +406,16 @@ export const dashboardStore = defineStore({
c.isRoot = false; c.isRoot = false;
const index = this.dashboards.findIndex( const index = this.dashboards.findIndex(
(d: DashboardItem) => (d: DashboardItem) =>
d.name === this.currentDashboard.name && d.name === this.currentDashboard?.name &&
d.entity === this.currentDashboard.entity && d.entity === this.currentDashboard.entity &&
d.layer === this.currentDashboard.layerId d.layer === this.currentDashboard?.layer,
); );
if (index > -1) { if (index > -1) {
const { t } = useI18n(); const { t } = useI18n();
ElMessage.error(t("nameError")); ElMessage.error(t("nameError"));
return; return;
} }
res = await graphql res = await graphql.query("addNewTemplate").params({ setting: { configuration: JSON.stringify(c) } });
.query("addNewTemplate")
.params({ setting: { configuration: JSON.stringify(c) } });
json = res.data.data.addTemplate; json = res.data.data.addTemplate;
} }
@ -478,17 +430,11 @@ export const dashboardStore = defineStore({
if (!this.currentDashboard.id) { if (!this.currentDashboard.id) {
ElMessage.success("Saved successfully"); ElMessage.success("Saved successfully");
} }
const key = [ const key = [this.currentDashboard.layer, this.currentDashboard.entity, this.currentDashboard.name].join("_");
this.currentDashboard.layer,
this.currentDashboard.entity,
this.currentDashboard.name,
].join("_");
this.currentDashboard.id = json.id; this.currentDashboard.id = json.id;
if (this.currentDashboard.id) { if (this.currentDashboard.id) {
sessionStorage.removeItem(key); sessionStorage.removeItem(key);
this.dashboards = this.dashboards.filter( this.dashboards = this.dashboards.filter((d: DashboardItem) => d.id !== this.currentDashboard?.id);
(d: DashboardItem) => d.id !== this.currentDashboard.id
);
} }
this.dashboards.push(this.currentDashboard); this.dashboards.push(this.currentDashboard);
const l = { id: json.id, configuration: c }; const l = { id: json.id, configuration: c };
@ -498,9 +444,7 @@ export const dashboardStore = defineStore({
return json; return json;
}, },
async deleteDashboard() { async deleteDashboard() {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("removeTemplate").params({ id: this.currentDashboard?.id });
.query("removeTemplate")
.params({ id: this.currentDashboard.id });
if (res.data.errors) { if (res.data.errors) {
ElMessage.error(res.data.errors); ElMessage.error(res.data.errors);
@ -511,14 +455,8 @@ export const dashboardStore = defineStore({
ElMessage.error(json.message); ElMessage.error(json.message);
return res.data; return res.data;
} }
this.dashboards = this.dashboards.filter( this.dashboards = this.dashboards.filter((d: any) => d.id !== this.currentDashboard?.id);
(d: any) => d.id !== this.currentDashboard.id const key = [this.currentDashboard?.layer, this.currentDashboard?.entity, this.currentDashboard?.name].join("_");
);
const key = [
this.currentDashboard.layer,
this.currentDashboard.entity,
this.currentDashboard.name,
].join("_");
sessionStorage.removeItem(key); sessionStorage.removeItem(key);
}, },
}, },

View File

@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { Instance } from "@/types/selector"; import type { Instance } from "@/types/selector";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { Conditions, Log } from "@/types/demand-log"; import type { Conditions, Log } from "@/types/demand-log";
interface DemandLogState { interface DemandLogState {
containers: Instance[]; containers: Instance[];
@ -59,9 +59,7 @@ export const demandLogStore = defineStore({
this.message = message || ""; this.message = message || "";
}, },
async getInstances(id: string) { async getInstances(id: string) {
const serviceId = this.selectorStore.currentService const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({ const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId, serviceId,
duration: useAppStoreWithOut().durationTime, duration: useAppStoreWithOut().durationTime,
@ -75,16 +73,12 @@ export const demandLogStore = defineStore({
}, },
async getContainers(serviceInstanceId: string) { async getContainers(serviceInstanceId: string) {
if (!serviceInstanceId) { if (!serviceInstanceId) {
return new Promise((resolve) => return new Promise((resolve) => resolve({ errors: "No service instance" }));
resolve({ errors: "No service instance" })
);
} }
const condition = { const condition = {
serviceInstanceId, serviceInstanceId,
}; };
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("fetchContainers").params({ condition });
.query("fetchContainers")
.params({ condition });
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -100,21 +94,17 @@ export const demandLogStore = defineStore({
}, },
async getDemandLogs() { async getDemandLogs() {
this.loadLogs = true; this.loadLogs = true;
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("fetchDemandPodLogs").params({ condition: this.conditions });
.query("fetchDemandPodLogs")
.params({ condition: this.conditions });
this.loadLogs = false; this.loadLogs = false;
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
if (res.data.data.logs.errorReason) { if (res.data.data.logs.errorReason) {
this.setLogs("", res.data.data.logs.errorReason); this.setLogs([], res.data.data.logs.errorReason);
return res.data; return res.data;
} }
this.total = res.data.data.logs.logs.length; this.total = res.data.data.logs.logs.length;
const logs = res.data.data.logs.logs const logs = res.data.data.logs.logs.map((d: Log) => d.content).join("\n");
.map((d: Log) => d.content)
.join("\n");
this.setLogs(logs); this.setLogs(logs);
return res.data; return res.data;
}, },

View File

@ -15,18 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { Option } from "@/types/app"; import type { Option } from "@/types/app";
import { import type { EBPFTaskCreationRequest, EBPFProfilingSchedule, EBPFTaskList, AnalyzationTrees } from "@/types/ebpf";
EBPFTaskCreationRequest,
EBPFProfilingSchedule,
EBPFTaskList,
AnalyzationTrees,
} from "@/types/ebpf";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
interface EbpfState { interface EbpfState {
taskList: EBPFTaskList[]; taskList: Array<Recordable<EBPFTaskList>>;
eBPFSchedules: EBPFProfilingSchedule[]; eBPFSchedules: EBPFProfilingSchedule[];
currentSchedule: EBPFProfilingSchedule | Record<string, never>; currentSchedule: EBPFProfilingSchedule | Record<string, never>;
analyzeTrees: AnalyzationTrees[]; analyzeTrees: AnalyzationTrees[];
@ -51,7 +46,7 @@ export const ebpfStore = defineStore({
aggregateType: "COUNT", aggregateType: "COUNT",
}), }),
actions: { actions: {
setSelectedTask(task: EBPFTaskList) { setSelectedTask(task: Recordable<EBPFTaskList>) {
this.selectedTask = task || {}; this.selectedTask = task || {};
}, },
setCurrentSchedule(s: EBPFProfilingSchedule) { setCurrentSchedule(s: EBPFProfilingSchedule) {
@ -61,9 +56,7 @@ export const ebpfStore = defineStore({
this.analyzeTrees = tree; this.analyzeTrees = tree;
}, },
async getCreateTaskData(serviceId: string) { async getCreateTaskData(serviceId: string) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getCreateTaskData").params({ serviceId });
.query("getCreateTaskData")
.params({ serviceId });
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -76,9 +69,7 @@ export const ebpfStore = defineStore({
return res.data; return res.data;
}, },
async createTask(param: EBPFTaskCreationRequest) { async createTask(param: EBPFTaskCreationRequest) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("saveEBPFTask").params({ request: param });
.query("saveEBPFTask")
.params({ request: param });
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -89,17 +80,11 @@ export const ebpfStore = defineStore({
}); });
return res.data; return res.data;
}, },
async getTaskList(params: { async getTaskList(params: { serviceId: string; targets: string[] }) {
serviceId: string;
serviceInstanceId: string;
targets: string[];
}) {
if (!params.serviceId) { if (!params.serviceId) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
.query("getEBPFTasks")
.params(params);
this.tip = ""; this.tip = "";
if (res.data.errors) { if (res.data.errors) {
@ -111,16 +96,14 @@ export const ebpfStore = defineStore({
if (!this.taskList.length) { if (!this.taskList.length) {
return res.data; return res.data;
} }
this.getEBPFSchedules({ taskId: this.taskList[0].taskId }); this.getEBPFSchedules({ taskId: String(this.taskList[0].taskId) });
return res.data; return res.data;
}, },
async getEBPFSchedules(params: { taskId: string }) { async getEBPFSchedules(params: { taskId: string }) {
if (!params.taskId) { if (!params.taskId) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getEBPFSchedules").params({ ...params });
.query("getEBPFSchedules")
.params({ ...params });
if (res.data.errors) { if (res.data.errors) {
this.eBPFSchedules = []; this.eBPFSchedules = [];
@ -148,9 +131,7 @@ export const ebpfStore = defineStore({
if (!params.timeRanges.length) { if (!params.timeRanges.length) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getEBPFResult").params(params);
.query("getEBPFResult")
.params(params);
if (res.data.errors) { if (res.data.errors) {
this.analyzeTrees = []; this.analyzeTrees = [];

View File

@ -17,9 +17,9 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { Event, QueryEventCondition } from "@/types/events"; import type { Event, QueryEventCondition } from "@/types/events";
import { Instance, Endpoint } from "@/types/selector"; import type { Instance, Endpoint } from "@/types/selector";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
@ -45,9 +45,7 @@ export const eventStore = defineStore({
this.condition = data; this.condition = data;
}, },
async getInstances() { async getInstances() {
const serviceId = useSelectorStore().currentService const serviceId = useSelectorStore().currentService ? useSelectorStore().currentService.id : "";
? useSelectorStore().currentService.id
: "";
const res: AxiosResponse = await graphql.query("queryInstances").params({ const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId, serviceId,
duration: useAppStoreWithOut().durationTime, duration: useAppStoreWithOut().durationTime,
@ -56,15 +54,11 @@ export const eventStore = defineStore({
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
this.instances = [{ value: "", label: "All" }, ...res.data.data.pods] || [ this.instances = [{ value: "", label: "All" }, ...res.data.data.pods] || [{ value: "", label: "All" }];
{ value: "", label: "All" },
];
return res.data; return res.data;
}, },
async getEndpoints() { async getEndpoints() {
const serviceId = useSelectorStore().currentService const serviceId = useSelectorStore().currentService ? useSelectorStore().currentService.id : "";
? useSelectorStore().currentService.id
: "";
if (!serviceId) { if (!serviceId) {
return; return;
} }
@ -76,9 +70,7 @@ export const eventStore = defineStore({
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods] || [ this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods] || [{ value: "", label: "All" }];
{ value: "", label: "All" },
];
return res.data; return res.data;
}, },
async getEvents() { async getEvents() {
@ -94,8 +86,7 @@ export const eventStore = defineStore({
return res.data; return res.data;
} }
if (res.data.data.fetchEvents) { if (res.data.data.fetchEvents) {
this.events = (res.data.data.fetchEvents.events || []).map( this.events = (res.data.data.fetchEvents.events || []).map((item: Event) => {
(item: Event) => {
let scope = "Service"; let scope = "Service";
if (item.source.serviceInstance) { if (item.source.serviceInstance) {
scope = "ServiceInstance"; scope = "ServiceInstance";
@ -108,8 +99,7 @@ export const eventStore = defineStore({
item.endTime = Number(item.startTime) + 60000; item.endTime = Number(item.startTime) + 60000;
} }
return item; return item;
} });
);
} }
return res.data; return res.data;
}, },

View File

@ -15,10 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { Instance, Endpoint, Service } from "@/types/selector"; import type { Instance, Endpoint, Service } from "@/types/selector";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
@ -71,9 +71,7 @@ export const logStore = defineStore({
return res.data; return res.data;
}, },
async getInstances(id: string) { async getInstances(id: string) {
const serviceId = this.selectorStore.currentService const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({ const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId, serviceId,
duration: useAppStoreWithOut().durationTime, duration: useAppStoreWithOut().durationTime,
@ -82,16 +80,11 @@ export const logStore = defineStore({
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
this.instances = [ this.instances = [{ value: "0", label: "All" }, ...res.data.data.pods] || [{ value: " 0", label: "All" }];
{ value: "0", label: "All" },
...res.data.data.pods,
] || [{ value: " 0", label: "All" }];
return res.data; return res.data;
}, },
async getEndpoints(id: string, keyword?: string) { async getEndpoints(id: string, keyword?: string) {
const serviceId = this.selectorStore.currentService const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryEndpoints").params({ const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId, serviceId,
duration: useAppStoreWithOut().durationTime, duration: useAppStoreWithOut().durationTime,
@ -100,16 +93,11 @@ export const logStore = defineStore({
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
this.endpoints = [ this.endpoints = [{ value: "0", label: "All" }, ...res.data.data.pods] || [{ value: "0", label: "All" }];
{ value: "0", label: "All" },
...res.data.data.pods,
] || [{ value: "0", label: "All" }];
return res.data; return res.data;
}, },
async getLogsByKeywords() { async getLogsByKeywords() {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryLogsByKeywords").params({});
.query("queryLogsByKeywords")
.params({});
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -127,9 +115,7 @@ export const logStore = defineStore({
}, },
async getServiceLogs() { async getServiceLogs() {
this.loadLogs = true; this.loadLogs = true;
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryServiceLogs").params({ condition: this.conditions });
.query("queryServiceLogs")
.params({ condition: this.conditions });
this.loadLogs = false; this.loadLogs = false;
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -140,9 +126,7 @@ export const logStore = defineStore({
}, },
async getBrowserLogs() { async getBrowserLogs() {
this.loadLogs = true; this.loadLogs = true;
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryBrowserErrorLogs").params({ condition: this.conditions });
.query("queryBrowserErrorLogs")
.params({ condition: this.conditions });
this.loadLogs = false; this.loadLogs = false;
if (res.data.errors) { if (res.data.errors) {

View File

@ -15,16 +15,16 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { EBPFTaskList, ProcessNode } from "@/types/ebpf"; import type { EBPFTaskList, ProcessNode } from "@/types/ebpf";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { Call } from "@/types/topology"; import type { Call } from "@/types/topology";
import { LayoutConfig } from "@/types/dashboard"; import type { LayoutConfig } from "@/types/dashboard";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
interface NetworkProfilingState { interface NetworkProfilingState {
networkTasks: EBPFTaskList[]; networkTasks: Array<Recordable<EBPFTaskList>>;
networkTip: string; networkTip: string;
selectedNetworkTask: Recordable<EBPFTaskList>; selectedNetworkTask: Recordable<EBPFTaskList>;
nodes: ProcessNode[]; nodes: ProcessNode[];
@ -55,10 +55,10 @@ export const networkProfilingStore = defineStore({
loadNodes: false, loadNodes: false,
}), }),
actions: { actions: {
setSelectedNetworkTask(task: EBPFTaskList) { setSelectedNetworkTask(task: Recordable<EBPFTaskList>) {
this.selectedNetworkTask = task || {}; this.selectedNetworkTask = task || {};
}, },
setNode(node: Node) { setNode(node: Nullable<ProcessNode>) {
this.node = node; this.node = node;
}, },
setLink(link: Call) { setLink(link: Call) {
@ -117,11 +117,9 @@ export const networkProfilingStore = defineStore({
when4xx: string; when4xx: string;
when5xx: string; when5xx: string;
minDuration: number; minDuration: number;
}[] }[],
) { ) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("newNetworkProfiling").params({
.query("newNetworkProfiling")
.params({
request: { request: {
instanceId, instanceId,
samplings: params, samplings: params,
@ -133,17 +131,11 @@ export const networkProfilingStore = defineStore({
} }
return res.data; return res.data;
}, },
async getTaskList(params: { async getTaskList(params: { serviceId: string; serviceInstanceId: string; targets: string[] }) {
serviceId: string;
serviceInstanceId: string;
targets: string[];
}) {
if (!params.serviceId) { if (!params.serviceId) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
.query("getEBPFTasks")
.params(params);
this.networkTip = ""; this.networkTip = "";
if (res.data.errors) { if (res.data.errors) {
@ -162,11 +154,8 @@ export const networkProfilingStore = defineStore({
if (!taskId) { if (!taskId) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("aliveNetworkProfiling").params({ taskId });
.query("aliveNetworkProfiling")
.params({ taskId });
this.aliveMessage = "";
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
@ -176,14 +165,9 @@ export const networkProfilingStore = defineStore({
} }
return res.data; return res.data;
}, },
async getProcessTopology(params: { async getProcessTopology(params: { duration: any; serviceInstanceId: string }) {
duration: any;
serviceInstanceId: string;
}) {
this.loadNodes = true; this.loadNodes = true;
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getProcessTopology").params(params);
.query("getProcessTopology")
.params(params);
this.loadNodes = false; this.loadNodes = false;
if (res.data.errors) { if (res.data.errors) {
this.nodes = []; this.nodes = [];

View File

@ -15,18 +15,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { Endpoint } from "@/types/selector"; import type { Endpoint } from "@/types/selector";
import { import type {
TaskListItem, TaskListItem,
SegmentSpan, SegmentSpan,
ProfileAnalyzationTrees, ProfileAnalyzationTrees,
TaskLog, TaskLog,
ProfileTaskCreationRequest, ProfileTaskCreationRequest,
} from "@/types/profile"; } from "@/types/profile";
import { Trace, Span } from "@/types/trace"; import type { Trace } from "@/types/trace";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
interface ProfileState { interface ProfileState {
@ -35,9 +35,9 @@ interface ProfileState {
condition: { serviceId: string; endpointName: string }; condition: { serviceId: string; endpointName: string };
taskList: TaskListItem[]; taskList: TaskListItem[];
segmentList: Trace[]; segmentList: Trace[];
currentSegment: Trace | Record<string, never>; currentSegment: Recordable<Trace>;
segmentSpans: SegmentSpan[]; segmentSpans: Array<Recordable<SegmentSpan>>;
currentSpan: SegmentSpan | Record<string, never>; currentSpan: Recordable<SegmentSpan>;
analyzeTrees: ProfileAnalyzationTrees; analyzeTrees: ProfileAnalyzationTrees;
taskLogs: TaskLog[]; taskLogs: TaskLog[];
highlightTop: boolean; highlightTop: boolean;
@ -65,10 +65,10 @@ export const profileStore = defineStore({
...data, ...data,
}; };
}, },
setCurrentSpan(span: Span) { setCurrentSpan(span: Recordable<SegmentSpan>) {
this.currentSpan = span; this.currentSpan = span;
}, },
setCurrentSegment(s: Trace) { setCurrentSegment(s: Recordable<Trace>) {
this.currentSegment = s; this.currentSegment = s;
}, },
setHighlightTop() { setHighlightTop() {
@ -99,9 +99,7 @@ export const profileStore = defineStore({
return res.data; return res.data;
}, },
async getTaskList() { async getTaskList() {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getProfileTaskList").params(this.condition);
.query("getProfileTaskList")
.params(this.condition);
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -122,9 +120,7 @@ export const profileStore = defineStore({
if (!params.taskID) { if (!params.taskID) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getProfileTaskSegmentList").params(params);
.query("getProfileTaskSegmentList")
.params(params);
if (res.data.errors) { if (res.data.errors) {
this.segmentList = []; this.segmentList = [];
@ -143,7 +139,7 @@ export const profileStore = defineStore({
this.currentSegment = segmentList[0]; this.currentSegment = segmentList[0];
this.getSegmentSpans({ segmentId: segmentList[0].segmentId }); this.getSegmentSpans({ segmentId: segmentList[0].segmentId });
} else { } else {
this.currentSegment = null; this.currentSegment = {};
} }
return res.data; return res.data;
}, },
@ -151,9 +147,7 @@ export const profileStore = defineStore({
if (!params.segmentId) { if (!params.segmentId) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryProfileSegment").params(params);
.query("queryProfileSegment")
.params(params);
if (res.data.errors) { if (res.data.errors) {
this.segmentSpans = []; this.segmentSpans = [];
return res.data; return res.data;
@ -167,8 +161,8 @@ export const profileStore = defineStore({
this.segmentSpans = segment.spans.map((d: SegmentSpan) => { this.segmentSpans = segment.spans.map((d: SegmentSpan) => {
return { return {
...d, ...d,
segmentId: this.currentSegment.segmentId, segmentId: this.currentSegment?.segmentId,
traceId: this.currentSegment.traceIds[0], traceId: (this.currentSegment.traceIds as any)[0],
}; };
}); });
if (!(segment.spans && segment.spans.length)) { if (!(segment.spans && segment.spans.length)) {
@ -179,19 +173,14 @@ export const profileStore = defineStore({
this.currentSpan = segment.spans[index]; this.currentSpan = segment.spans[index];
return res.data; return res.data;
}, },
async getProfileAnalyze(params: { async getProfileAnalyze(params: { segmentId: string; timeRanges: Array<{ start: number; end: number }> }) {
segmentId: string;
timeRanges: Array<{ start: number; end: number }>;
}) {
if (!params.segmentId) { if (!params.segmentId) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
if (!params.timeRanges.length) { if (!params.timeRanges.length) {
return new Promise((resolve) => resolve({})); return new Promise((resolve) => resolve({}));
} }
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getProfileAnalyze").params(params);
.query("getProfileAnalyze")
.params(params);
if (res.data.errors) { if (res.data.errors) {
this.analyzeTrees = []; this.analyzeTrees = [];
@ -211,9 +200,7 @@ export const profileStore = defineStore({
return res.data; return res.data;
}, },
async createTask(param: ProfileTaskCreationRequest) { async createTask(param: ProfileTaskCreationRequest) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("saveProfileTask").params({ creationRequest: param });
.query("saveProfileTask")
.params({ creationRequest: param });
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
@ -222,9 +209,7 @@ export const profileStore = defineStore({
return res.data; return res.data;
}, },
async getTaskLogs(param: { taskID: string }) { async getTaskLogs(param: { taskID: string }) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getProfileTaskLogs").params(param);
.query("getProfileTaskLogs")
.params(param);
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;

View File

@ -15,10 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { Service, Instance, Endpoint, Process } from "@/types/selector"; import type { Service, Instance, Endpoint, Process } from "@/types/selector";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
interface SelectorState { interface SelectorState {
services: Service[]; services: Service[];
@ -82,9 +82,7 @@ export const selectorStore = defineStore({
return res.data || {}; return res.data || {};
}, },
async fetchServices(layer: string): Promise<AxiosResponse> { async fetchServices(layer: string): Promise<AxiosResponse> {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryServices").params({ layer });
.query("queryServices")
.params({ layer });
if (!res.data.errors) { if (!res.data.errors) {
this.services = res.data.data.services || []; this.services = res.data.data.services || [];
@ -92,10 +90,7 @@ export const selectorStore = defineStore({
} }
return res.data; return res.data;
}, },
async getServiceInstances(param?: { async getServiceInstances(param?: { serviceId: string; isRelation: boolean }): Promise<Nullable<AxiosResponse>> {
serviceId: string;
isRelation: boolean;
}): Promise<Nullable<AxiosResponse>> {
const serviceId = param ? param.serviceId : this.currentService?.id; const serviceId = param ? param.serviceId : this.currentService?.id;
if (!serviceId) { if (!serviceId) {
return null; return null;
@ -113,10 +108,7 @@ export const selectorStore = defineStore({
} }
return res.data; return res.data;
}, },
async getProcesses(param?: { async getProcesses(param?: { instanceId: string; isRelation: boolean }): Promise<Nullable<AxiosResponse>> {
instanceId: string;
isRelation: boolean;
}): Promise<Nullable<AxiosResponse>> {
const instanceId = param ? param.instanceId : this.currentPod?.id; const instanceId = param ? param.instanceId : this.currentPod?.id;
if (!instanceId) { if (!instanceId) {
return null; return null;

View File

@ -16,12 +16,12 @@
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { store } from "@/store"; import { store } from "@/store";
import { Service } from "@/types/selector"; import type { Service } from "@/types/selector";
import { Node, Call } from "@/types/topology"; import type { Node, Call } from "@/types/topology";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import query from "@/graphql/fetch"; import query from "@/graphql/fetch";
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor"; import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
@ -105,21 +105,19 @@ export const topologyStore = defineStore({
this.calls = calls; this.calls = calls;
this.nodes = nodes; this.nodes = nodes;
}, },
setNodeMetricValue(m: { id: string; value: unknown }[]) { setNodeMetricValue(m: MetricVal) {
this.nodeMetricValue = m; this.nodeMetricValue = m;
}, },
setLinkServerMetrics(m: { id: string; value: unknown }[]) { setLinkServerMetrics(m: MetricVal) {
this.linkServerMetrics = m; this.linkServerMetrics = m;
}, },
setLinkClientMetrics(m: { id: string; value: unknown }[]) { setLinkClientMetrics(m: MetricVal) {
this.linkClientMetrics = m; this.linkClientMetrics = m;
}, },
async getDepthServiceTopology(serviceIds: string[], depth: number) { async getDepthServiceTopology(serviceIds: string[], depth: number) {
const res = await this.getServicesTopology(serviceIds); const res = await this.getServicesTopology(serviceIds);
if (depth > 1) { if (depth > 1) {
const ids = (res.nodes || []) const ids = (res.nodes || []).map((item: Node) => item.id).filter((d: string) => !serviceIds.includes(d));
.map((item: Node) => item.id)
.filter((d: string) => !serviceIds.includes(d));
if (!ids.length) { if (!ids.length) {
this.setTopology(res); this.setTopology(res);
return; return;
@ -139,9 +137,7 @@ export const topologyStore = defineStore({
if (depth > 3) { if (depth > 3) {
const services = topo.nodes const services = topo.nodes
.map((item: Node) => item.id) .map((item: Node) => item.id)
.filter( .filter((d: string) => ![...ids, ...pods, ...serviceIds].includes(d));
(d: string) => ![...ids, ...pods, ...serviceIds].includes(d)
);
if (!services.length) { if (!services.length) {
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes]; const nodes = [...res.nodes, ...json.nodes, ...topo.nodes];
const calls = [...res.calls, ...json.calls, ...topo.calls]; const calls = [...res.calls, ...json.calls, ...topo.calls];
@ -152,55 +148,20 @@ export const topologyStore = defineStore({
if (depth > 4) { if (depth > 4) {
const nodeIds = data.nodes const nodeIds = data.nodes
.map((item: Node) => item.id) .map((item: Node) => item.id)
.filter( .filter((d: string) => ![...services, ...ids, ...pods, ...serviceIds].includes(d));
(d: string) =>
![...services, ...ids, ...pods, ...serviceIds].includes(d)
);
if (!nodeIds.length) { if (!nodeIds.length) {
const nodes = [ const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes];
...res.nodes, const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls];
...json.nodes,
...topo.nodes,
...data.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
];
this.setTopology({ nodes, calls }); this.setTopology({ nodes, calls });
return; return;
} }
const toposObj = await this.getServicesTopology(nodeIds); const toposObj = await this.getServicesTopology(nodeIds);
const nodes = [ const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes, ...toposObj.nodes];
...res.nodes, const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls, ...toposObj.calls];
...json.nodes,
...topo.nodes,
...data.nodes,
...toposObj.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
...toposObj.calls,
];
this.setTopology({ nodes, calls }); this.setTopology({ nodes, calls });
} else { } else {
const nodes = [ const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes];
...res.nodes, const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls];
...json.nodes,
...topo.nodes,
...data.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
];
this.setTopology({ nodes, calls }); this.setTopology({ nodes, calls });
} }
} else { } else {
@ -220,9 +181,7 @@ export const topologyStore = defineStore({
}, },
async getServicesTopology(serviceIds: string[]) { async getServicesTopology(serviceIds: string[]) {
const duration = useAppStoreWithOut().durationTime; const duration = useAppStoreWithOut().durationTime;
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getServicesTopology").params({
.query("getServicesTopology")
.params({
serviceIds, serviceIds,
duration, duration,
}); });
@ -235,9 +194,7 @@ export const topologyStore = defineStore({
const serverServiceId = useSelectorStore().currentService.id; const serverServiceId = useSelectorStore().currentService.id;
const clientServiceId = useSelectorStore().currentDestService.id; const clientServiceId = useSelectorStore().currentDestService.id;
const duration = useAppStoreWithOut().durationTime; const duration = useAppStoreWithOut().durationTime;
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("getInstanceTopology").params({
.query("getInstanceTopology")
.params({
clientServiceId, clientServiceId,
serverServiceId, serverServiceId,
duration, duration,
@ -250,9 +207,7 @@ export const topologyStore = defineStore({
async updateEndpointTopology(endpointIds: string[], depth: number) { async updateEndpointTopology(endpointIds: string[], depth: number) {
const res = await this.getEndpointTopology(endpointIds); const res = await this.getEndpointTopology(endpointIds);
if (depth > 1) { if (depth > 1) {
const ids = res.nodes const ids = res.nodes.map((item: Node) => item.id).filter((d: string) => !endpointIds.includes(d));
.map((item: Node) => item.id)
.filter((d: string) => !endpointIds.includes(d));
if (!ids.length) { if (!ids.length) {
this.setTopology(res); this.setTopology(res);
return; return;
@ -272,9 +227,7 @@ export const topologyStore = defineStore({
if (depth > 3) { if (depth > 3) {
const endpoints = topo.nodes const endpoints = topo.nodes
.map((item: Node) => item.id) .map((item: Node) => item.id)
.filter( .filter((d: string) => ![...ids, ...pods, ...endpointIds].includes(d));
(d: string) => ![...ids, ...pods, ...endpointIds].includes(d)
);
if (!endpoints.length) { if (!endpoints.length) {
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes]; const nodes = [...res.nodes, ...json.nodes, ...topo.nodes];
const calls = [...res.calls, ...json.calls, ...topo.calls]; const calls = [...res.calls, ...json.calls, ...topo.calls];
@ -285,55 +238,20 @@ export const topologyStore = defineStore({
if (depth > 4) { if (depth > 4) {
const nodeIds = data.nodes const nodeIds = data.nodes
.map((item: Node) => item.id) .map((item: Node) => item.id)
.filter( .filter((d: string) => ![...endpoints, ...ids, ...pods, ...endpointIds].includes(d));
(d: string) =>
![...endpoints, ...ids, ...pods, ...endpointIds].includes(d)
);
if (!nodeIds.length) { if (!nodeIds.length) {
const nodes = [ const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes];
...res.nodes, const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls];
...json.nodes,
...topo.nodes,
...data.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
];
this.setTopology({ nodes, calls }); this.setTopology({ nodes, calls });
return; return;
} }
const toposObj = await this.getEndpointTopology(nodeIds); const toposObj = await this.getEndpointTopology(nodeIds);
const nodes = [ const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes, ...toposObj.nodes];
...res.nodes, const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls, ...toposObj.calls];
...json.nodes,
...topo.nodes,
...data.nodes,
...toposObj.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
...toposObj.calls,
];
this.setTopology({ nodes, calls }); this.setTopology({ nodes, calls });
} else { } else {
const nodes = [ const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes];
...res.nodes, const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls];
...json.nodes,
...topo.nodes,
...data.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
];
this.setTopology({ nodes, calls }); this.setTopology({ nodes, calls });
} }
} else { } else {
@ -390,10 +308,7 @@ export const topologyStore = defineStore({
return { calls, nodes }; return { calls, nodes };
}, },
async getNodeMetricValue(param: { async getNodeMetricValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
queryStr: string;
conditions: { [key: string]: unknown };
}) {
const res: AxiosResponse = await query(param); const res: AxiosResponse = await query(param);
if (res.data.errors) { if (res.data.errors) {
@ -407,9 +322,7 @@ export const topologyStore = defineStore({
this.setLinkClientMetrics({}); this.setLinkClientMetrics({});
return; return;
} }
const idsC = this.calls const idsC = this.calls.filter((i: Call) => i.detectPoints.includes("CLIENT")).map((b: Call) => b.id);
.filter((i: Call) => i.detectPoints.includes("CLIENT"))
.map((b: Call) => b.id);
if (!idsC.length) { if (!idsC.length) {
return; return;
} }
@ -425,9 +338,7 @@ export const topologyStore = defineStore({
this.setLinkServerMetrics({}); this.setLinkServerMetrics({});
return; return;
} }
const idsS = this.calls const idsS = this.calls.filter((i: Call) => i.detectPoints.includes("SERVER")).map((b: Call) => b.id);
.filter((i: Call) => i.detectPoints.includes("SERVER"))
.map((b: Call) => b.id);
if (!idsS.length) { if (!idsS.length) {
return; return;
} }
@ -454,10 +365,7 @@ export const topologyStore = defineStore({
ElMessage.error(res.errors); ElMessage.error(res.errors);
} }
}, },
async getLegendMetrics(param: { async getLegendMetrics(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
queryStr: string;
conditions: { [key: string]: unknown };
}) {
const res: AxiosResponse = await query(param); const res: AxiosResponse = await query(param);
if (res.data.errors) { if (res.data.errors) {
@ -477,10 +385,7 @@ export const topologyStore = defineStore({
}); });
return res.data; return res.data;
}, },
async getCallServerMetrics(param: { async getCallServerMetrics(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
queryStr: string;
conditions: { [key: string]: unknown };
}) {
const res: AxiosResponse = await query(param); const res: AxiosResponse = await query(param);
if (res.data.errors) { if (res.data.errors) {
@ -489,10 +394,7 @@ export const topologyStore = defineStore({
this.setLinkServerMetrics(res.data.data); this.setLinkServerMetrics(res.data.data);
return res.data; return res.data;
}, },
async getCallClientMetrics(param: { async getCallClientMetrics(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
queryStr: string;
conditions: { [key: string]: unknown };
}) {
const res: AxiosResponse = await query(param); const res: AxiosResponse = await query(param);
if (res.data.errors) { if (res.data.errors) {

View File

@ -15,11 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { Instance, Endpoint, Service } from "@/types/selector"; import type { Instance, Endpoint, Service } from "@/types/selector";
import { Trace, Span } from "@/types/trace"; import type { Trace, Span } from "@/types/trace";
import { store } from "@/store"; import { store } from "@/store";
import graphql from "@/graphql"; import graphql from "@/graphql";
import { AxiosResponse } from "axios"; import type { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { QueryOrders } from "@/views/dashboard/data"; import { QueryOrders } from "@/views/dashboard/data";
@ -30,7 +30,7 @@ interface TraceState {
endpoints: Endpoint[]; endpoints: Endpoint[];
traceList: Trace[]; traceList: Trace[];
traceSpans: Span[]; traceSpans: Span[];
currentTrace: Trace | any; currentTrace: Recordable<Trace>;
conditions: any; conditions: any;
traceSpanLogs: any[]; traceSpanLogs: any[];
selectorStore: any; selectorStore: any;
@ -58,10 +58,10 @@ export const traceStore = defineStore({
setTraceCondition(data: any) { setTraceCondition(data: any) {
this.conditions = { ...this.conditions, ...data }; this.conditions = { ...this.conditions, ...data };
}, },
setCurrentTrace(trace: Trace) { setCurrentTrace(trace: Recordable<Trace>) {
this.currentTrace = trace; this.currentTrace = trace;
}, },
setTraceSpans(spans: Span) { setTraceSpans(spans: Span[]) {
this.traceSpans = spans; this.traceSpans = spans;
}, },
resetState() { resetState() {
@ -116,9 +116,7 @@ export const traceStore = defineStore({
return res.data; return res.data;
}, },
async getInstances(id: string) { async getInstances(id: string) {
const serviceId = this.selectorStore.currentService const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryInstances").params({ const res: AxiosResponse = await graphql.query("queryInstances").params({
serviceId: serviceId, serviceId: serviceId,
duration: useAppStoreWithOut().durationTime, duration: useAppStoreWithOut().durationTime,
@ -131,9 +129,7 @@ export const traceStore = defineStore({
return res.data; return res.data;
}, },
async getEndpoints(id: string, keyword?: string) { async getEndpoints(id: string, keyword?: string) {
const serviceId = this.selectorStore.currentService const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
? this.selectorStore.currentService.id
: id;
const res: AxiosResponse = await graphql.query("queryEndpoints").params({ const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId, serviceId,
duration: useAppStoreWithOut().durationTime, duration: useAppStoreWithOut().durationTime,
@ -146,9 +142,7 @@ export const traceStore = defineStore({
return res.data; return res.data;
}, },
async getTraces() { async getTraces() {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryTraces").params({ condition: this.conditions });
.query("queryTraces")
.params({ condition: this.conditions });
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
@ -169,9 +163,7 @@ export const traceStore = defineStore({
return res.data; return res.data;
}, },
async getTraceSpans(params: { traceId: string }) { async getTraceSpans(params: { traceId: string }) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryTrace").params(params);
.query("queryTrace")
.params(params);
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }
@ -180,9 +172,7 @@ export const traceStore = defineStore({
return res.data; return res.data;
}, },
async getSpanLogs(params: any) { async getSpanLogs(params: any) {
const res: AxiosResponse = await graphql const res: AxiosResponse = await graphql.query("queryServiceLogs").params(params);
.query("queryServiceLogs")
.params(params);
if (res.data.errors) { if (res.data.errors) {
this.traceSpanLogs = []; this.traceSpanLogs = [];
return res.data; return res.data;

View File

@ -20,9 +20,8 @@ body {
line-height: 1.5; line-height: 1.5;
font-size: 14px; font-size: 14px;
color: #3d444f; color: #3d444f;
font-family: Helvetica, Arial, "Source Han Sans CN", "Microsoft YaHei", font-family: Helvetica, Arial, "Source Han Sans CN", "Microsoft YaHei", sans-serif;
sans-serif; text-rendering: optimizelegibility;
text-rendering: optimizeLegibility;
text-size-adjust: 100%; text-size-adjust: 100%;
} }

View File

@ -1,6 +1,7 @@
// generated by unplugin-vue-components // generated by unplugin-vue-components
// We suggest you to commit this file into source control // We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
@ -46,4 +47,4 @@ declare module '@vue/runtime-core' {
} }
} }
export { } export {}

View File

@ -1,4 +1,3 @@
import { DurationTime } from "@/types/app";
/** /**
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { DurationTime } from "./app"; import type { DurationTime } from "./app";
export interface Conditions { export interface Conditions {
container: string; container: string;

2
src/types/ebpf.d.ts vendored
View File

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Process } from "./selector"; import type { Process } from "./selector";
export interface EBPFTaskCreationRequest { export interface EBPFTaskCreationRequest {
serviceId: string; serviceId: string;
processLabels: string[]; processLabels: string[];

View File

@ -110,7 +110,5 @@ declare global {
} }
declare module "vue" { declare module "vue" {
export type JSXComponent<Props = any> = export type JSXComponent<Props = any> = { new (): ComponentPublicInstance<Props> } | FunctionalComponent<Props>;
| { new (): ComponentPublicInstance<Props> }
| FunctionalComponent<Props>;
} }

View File

@ -38,7 +38,6 @@ declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> {
$el: T; $el: T;
} }
declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null;
ComponentElRef<T> | null;
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>; declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>;

View File

@ -15,3 +15,4 @@
* limitations under the License. * limitations under the License.
*/ */
declare module "monaco-editor"; declare module "monaco-editor";
export {};

View File

@ -29,6 +29,7 @@ export type Instance = {
language?: string; language?: string;
instanceUUID?: string; instanceUUID?: string;
attributes?: { name: string; value: string }[]; attributes?: { name: string; value: string }[];
id?: string;
}; };
export type Endpoint = { export type Endpoint = {

View File

@ -15,11 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import dayjs from "dayjs"; import dayjs from "dayjs";
export default function dateFormatStep( export default function dateFormatStep(date: Date, step: string, monthDayDiff?: boolean): string {
date: Date,
step: string,
monthDayDiff?: boolean
): string {
const year = date.getFullYear(); const year = date.getFullYear();
const monthTemp = date.getMonth() + 1; const monthTemp = date.getMonth() + 1;
let month = `${monthTemp}`; let month = `${monthTemp}`;
@ -101,5 +97,4 @@ export const dateFormatTime = (date: Date, step: string): string => {
return ""; return "";
}; };
export const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") => export const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") => dayjs(new Date(date)).format(pattern);
dayjs(new Date(date)).format(pattern);

View File

@ -39,10 +39,7 @@ export function addResizeListener(element: any, fn: () => unknown): void {
export function removeResizeListener(element: any, fn: () => unknown): void { export function removeResizeListener(element: any, fn: () => unknown): void {
if (!element || !element.__resizeListeners__) return; if (!element || !element.__resizeListeners__) return;
element.__resizeListeners__.splice( element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
element.__resizeListeners__.indexOf(fn),
1
);
if (!element.__resizeListeners__.length) { if (!element.__resizeListeners__.length) {
element.__ro__.disconnect(); element.__ro__.disconnect();
} }

View File

@ -53,12 +53,7 @@ export function isNumber(val: unknown): val is number {
} }
export function isPromise<T = any>(val: unknown): val is Promise<T> { export function isPromise<T = any>(val: unknown): val is Promise<T> {
return ( return is(val, "Promise") && isObject(val) && isFunction(val.then) && isFunction(val.catch);
is(val, "Promise") &&
isObject(val) &&
isFunction(val.then) &&
isFunction(val.catch)
);
} }
export function isString(val: unknown): val is string { export function isString(val: unknown): val is string {

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Duration } from "@/types/app"; import type { Duration } from "@/types/app";
import { TimeType } from "@/constants/data"; import { TimeType } from "@/constants/data";
const timeFormat = (time: Date[]): Duration => { const timeFormat = (time: Date[]): Duration => {

View File

@ -17,11 +17,7 @@
class Vec2 extends Float32Array { class Vec2 extends Float32Array {
constructor(v?: unknown, y?: unknown) { constructor(v?: unknown, y?: unknown) {
super(2); super(2);
if ( if (v instanceof Vec2 || v instanceof Float32Array || (v instanceof Array && v.length == 2)) {
v instanceof Vec2 ||
v instanceof Float32Array ||
(v instanceof Array && v.length == 2)
) {
this[0] = v[0]; this[0] = v[0];
this[1] = v[1]; this[1] = v[1];
} else if (typeof v === "number" && typeof y === "number") { } else if (typeof v === "number" && typeof y === "number") {

View File

@ -17,19 +17,11 @@
class Vec3 extends Float32Array { class Vec3 extends Float32Array {
constructor(v?: unknown, y?: unknown, z?: unknown) { constructor(v?: unknown, y?: unknown, z?: unknown) {
super(3); super(3);
if ( if (v instanceof Vec3 || v instanceof Float32Array || (v instanceof Array && v.length == 3)) {
v instanceof Vec3 ||
v instanceof Float32Array ||
(v instanceof Array && v.length == 3)
) {
this[0] = v[0]; this[0] = v[0];
this[1] = v[1]; this[1] = v[1];
this[2] = v[2]; this[2] = v[2];
} else if ( } else if (typeof v === "number" && typeof y === "number" && typeof z === "number") {
typeof v === "number" &&
typeof y === "number" &&
typeof z === "number"
) {
this[0] = v; this[0] = v;
this[1] = y; this[1] = y;
this[2] = z; this[2] = z;
@ -158,17 +150,9 @@ class Vec3 extends Float32Array {
} }
static norm(x: unknown, y: unknown, z: unknown): Vec3 { static norm(x: unknown, y: unknown, z: unknown): Vec3 {
const rtn = new Vec3(); const rtn = new Vec3();
if ( if (x instanceof Vec3 || x instanceof Float32Array || (x instanceof Array && x.length == 3)) {
x instanceof Vec3 ||
x instanceof Float32Array ||
(x instanceof Array && x.length == 3)
) {
rtn.copy(x); rtn.copy(x);
} else if ( } else if (typeof x === "number" && typeof y === "number" && typeof z === "number") {
typeof x === "number" &&
typeof y === "number" &&
typeof z === "number"
) {
rtn.xyz(x, y, z); rtn.xyz(x, y, z);
} }
return rtn.norm(); return rtn.norm();

View File

@ -19,17 +19,17 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import Header from "./alarm/Header.vue"; import Header from "./alarm/Header.vue";
import Content from "./alarm/Content.vue"; import Content from "./alarm/Content.vue";
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
appStore.setPageTitle("Alerting"); appStore.setPageTitle("Alerting");
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.alarm { .alarm {
flex-grow: 1; flex-grow: 1;
height: 100%; height: 100%;
font-size: 12px; font-size: 12px;
} }
</style> </style>

View File

@ -19,18 +19,18 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import Header from "./event/Header.vue"; import Header from "./event/Header.vue";
import Content from "./event/Content.vue"; import Content from "./event/Content.vue";
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
appStore.setPageTitle("Events"); appStore.setPageTitle("Events");
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.event { .event {
flex-grow: 1; flex-grow: 1;
height: 100%; height: 100%;
font-size: 12px; font-size: 12px;
} }
</style> </style>

View File

@ -14,38 +14,34 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<Dashboard v-if="dashboardStore.currentDashboard" /> <Dashboard v-if="dashboardStore.currentDashboard" />
<div v-else class="no-root"> <div v-else class="no-root"> {{ t("noRoot") }} {{ dashboardStore.layerId }} </div>
{{ t("noRoot") }} {{ dashboardStore.layerId }}
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { EntityType } from "./dashboard/data"; import { EntityType } from "./dashboard/data";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import Dashboard from "./dashboard/Edit.vue"; import Dashboard from "./dashboard/Edit.vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const layer = ref<string>("GENERAL"); const layer = ref<string>("GENERAL");
getDashboard(); getDashboard();
async function getDashboard() { async function getDashboard() {
layer.value = String(route.meta.layer); layer.value = String(route.meta.layer);
dashboardStore.setLayer(layer.value); dashboardStore.setLayer(layer.value);
dashboardStore.setMode(false); dashboardStore.setMode(false);
await dashboardStore.setDashboards(); await dashboardStore.setDashboards();
const item = dashboardStore.dashboards.find( const item = dashboardStore.dashboards.find(
(d: { name: string; isRoot: boolean; layer: string; entity: string }) => (d: { name: string; isRoot: boolean; layer: string; entity: string }) =>
d.layer === dashboardStore.layerId && d.layer === dashboardStore.layerId && [EntityType[0].value, EntityType[1].value].includes(d.entity) && d.isRoot,
[EntityType[0].value, EntityType[1].value].includes(d.entity) &&
d.isRoot
); );
if (!item) { if (!item) {
appStore.setPageTitle(dashboardStore.layer); appStore.setPageTitle(dashboardStore.layer);
@ -55,13 +51,13 @@ async function getDashboard() {
} }
dashboardStore.setEntity(item.entity); dashboardStore.setEntity(item.entity);
dashboardStore.setCurrentDashboard(item); dashboardStore.setCurrentDashboard(item);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.no-root { .no-root {
padding: 15px; padding: 15px;
width: 100%; width: 100%;
text-align: center; text-align: center;
color: #888; color: #888;
} }
</style> </style>

View File

@ -30,24 +30,10 @@ limitations under the License. -->
<div> <div>
<span>UTC</span> <span>UTC</span>
<span class="ml-5 mr-5">{{ utcHour >= 0 ? "+" : "" }}</span> <span class="ml-5 mr-5">{{ utcHour >= 0 ? "+" : "" }}</span>
<input <input type="number" v-model="utcHour" min="-12" max="14" class="utc-input" @change="setUTCHour" />
type="number"
v-model="utcHour"
min="-12"
max="14"
class="utc-input"
@change="setUTCHour"
/>
<span class="ml-5 mr-5">:</span> <span class="ml-5 mr-5">:</span>
<span class="utc-min">{{ utcMin > 9 || utcMin === 0 ? null : 0 }}</span> <span class="utc-min">{{ utcMin > 9 || utcMin === 0 ? null : 0 }}</span>
<input <input type="number" v-model="utcMin" min="0" max="59" class="utc-input" @change="setUTCMin" />
type="number"
v-model="utcMin"
min="0"
max="59"
class="utc-input"
@change="setUTCMin"
/>
</div> </div>
</div> </div>
<div class="flex-h item"> <div class="flex-h item">
@ -55,12 +41,7 @@ limitations under the License. -->
<el-switch v-model="auto" @change="handleAuto" style="height: 25px" /> <el-switch v-model="auto" @change="handleAuto" style="height: 25px" />
<div class="auto-time ml-5"> <div class="auto-time ml-5">
<span class="auto-select"> <span class="auto-select">
<input <input type="number" v-model="autoTime" @change="changeAutoTime" min="1" />
type="number"
v-model="autoTime"
@change="changeAutoTime"
min="1"
/>
</span> </span>
{{ t("second") }} {{ t("second") }}
<i class="ml-10">{{ t("timeReload") }}</i> <i class="ml-10">{{ t("timeReload") }}</i>
@ -69,33 +50,32 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import timeFormat from "@/utils/timeFormat"; import timeFormat from "@/utils/timeFormat";
import { Languages } from "@/constants/data"; import { Languages } from "@/constants/data";
import Selector from "@/components/Selector.vue"; import Selector from "@/components/Selector.vue";
import getLocalTime from "@/utils/localtime"; import getLocalTime from "@/utils/localtime";
const { t, locale } = useI18n(); const { t, locale } = useI18n();
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const lang = ref<string>(locale.value || "en"); const lang = ref<string>(locale.value || "en");
const autoTime = ref<number>(6); const autoTime = ref<number>(6);
const auto = ref<boolean>(appStore.autoRefresh || false); const auto = ref<boolean>(appStore.autoRefresh || false);
const utcHour = ref<number>(appStore.utcHour); const utcHour = ref<number>(appStore.utcHour);
const utcMin = ref<number>(appStore.utcMin); const utcMin = ref<number>(appStore.utcMin);
appStore.setPageTitle("Setting"); appStore.setPageTitle("Setting");
const handleReload = () => { const handleReload = () => {
const gap = const gap = appStore.duration.end.getTime() - appStore.duration.start.getTime();
appStore.duration.end.getTime() - appStore.duration.start.getTime();
const dates: Date[] = [ const dates: Date[] = [
getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)), getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)),
getLocalTime(appStore.utc, new Date()), getLocalTime(appStore.utc, new Date()),
]; ];
appStore.setDuration(timeFormat(dates)); appStore.setDuration(timeFormat(dates));
}; };
const handleAuto = () => { const handleAuto = () => {
if (autoTime.value < 1) { if (autoTime.value < 1) {
return; return;
} }
@ -108,8 +88,8 @@ const handleAuto = () => {
clearInterval(appStore.reloadTimer); clearInterval(appStore.reloadTimer);
} }
} }
}; };
const changeAutoTime = () => { const changeAutoTime = () => {
if (autoTime.value < 1) { if (autoTime.value < 1) {
return; return;
} }
@ -120,12 +100,12 @@ const changeAutoTime = () => {
handleReload(); handleReload();
appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000)); appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000));
} }
}; };
const setLang = (): void => { const setLang = (): void => {
locale.value = lang.value; locale.value = lang.value;
window.localStorage.setItem("language", lang.value); window.localStorage.setItem("language", lang.value);
}; };
const setUTCHour = () => { const setUTCHour = () => {
if (utcHour.value < -12) { if (utcHour.value < -12) {
utcHour.value = -12; utcHour.value = -12;
} }
@ -136,8 +116,8 @@ const setUTCHour = () => {
utcHour.value = 0; utcHour.value = 0;
} }
appStore.setUTC(utcHour.value, utcMin.value); appStore.setUTC(utcHour.value, utcMin.value);
}; };
const setUTCMin = () => { const setUTCMin = () => {
if (utcMin.value < 0) { if (utcMin.value < 0) {
utcMin.value = 0; utcMin.value = 0;
} }
@ -148,23 +128,23 @@ const setUTCMin = () => {
utcMin.value = 0; utcMin.value = 0;
} }
appStore.setUTC(utcHour.value, utcMin.value); appStore.setUTC(utcHour.value, utcMin.value);
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.utc-input { .utc-input {
color: inherit; color: inherit;
background: 0; background: 0;
border: 0; border: 0;
outline: none; outline: none;
padding-bottom: 0; padding-bottom: 0;
} }
.utc-min { .utc-min {
display: inline-block; display: inline-block;
padding-top: 2px; padding-top: 2px;
} }
.auto-select { .auto-select {
border-radius: 3px; border-radius: 3px;
background-color: #fff; background-color: #fff;
padding: 1px; padding: 1px;
@ -174,9 +154,9 @@ const setUTCMin = () => {
border-style: unset; border-style: unset;
outline: 0; outline: 0;
} }
} }
.settings { .settings {
color: #606266; color: #606266;
font-size: 13px; font-size: 13px;
padding: 20px; padding: 20px;
@ -201,5 +181,5 @@ const setUTCMin = () => {
color: #000; color: #000;
line-height: 25px; line-height: 25px;
} }
} }
</style> </style>

View File

@ -14,11 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="timeline-table clear"> <div class="timeline-table clear">
<div <div v-for="(i, index) in alarmStore.alarms" :key="index" class="clear timeline-item">
v-for="(i, index) in alarmStore.alarms"
:key="index"
class="clear timeline-item"
>
<div class="g-sm-3 grey sm hide-xs time-line tr"> <div class="g-sm-3 grey sm hide-xs time-line tr">
{{ dateFormat(parseInt(i.startTime)) }} {{ dateFormat(parseInt(i.startTime)) }}
</div> </div>
@ -50,11 +46,7 @@ limitations under the License. -->
:destroy-on-close="true" :destroy-on-close="true"
@closed="isShowDetails = false" @closed="isShowDetails = false"
> >
<div <div class="mb-10 clear alarm-detail" v-for="(item, index) in AlarmDetailCol" :key="index">
class="mb-10 clear alarm-detail"
v-for="(item, index) in AlarmDetailCol"
:key="index"
>
<span class="g-sm-2 grey">{{ t(item.value) }}:</span> <span class="g-sm-2 grey">{{ t(item.value) }}:</span>
<span v-if="item.label === 'startTime'"> <span v-if="item.label === 'startTime'">
{{ dateFormat(currentDetail[item.label]) }} {{ dateFormat(currentDetail[item.label]) }}
@ -66,24 +58,12 @@ limitations under the License. -->
<div> <div>
<ul> <ul>
<li> <li>
<span <span v-for="(i, index) of EventsDetailHeaders" :class="i.class" :key="i.class + index">
v-for="(i, index) of EventsDetailHeaders"
:class="i.class"
:key="i.class + index"
>
{{ t(i.text) }} {{ t(i.text) }}
</span> </span>
</li> </li>
<li <li v-for="event in currentEvents" :key="event.uuid" @click="viewEventDetail(event)">
v-for="event in currentEvents" <span v-for="(d, index) of EventsDetailHeaders" :class="d.class" :key="event.uuid + index">
:key="event.uuid"
@click="viewEventDetail(event)"
>
<span
v-for="(d, index) of EventsDetailHeaders"
:class="d.class"
:key="event.uuid + index"
>
<span v-if="d.class === 'startTime' || d.class === 'endTime'"> <span v-if="d.class === 'startTime' || d.class === 'endTime'">
{{ dateFormat(event[d.class]) }} {{ dateFormat(event[d.class]) }}
</span> </span>
@ -106,29 +86,16 @@ limitations under the License. -->
@closed="showEventDetails = false" @closed="showEventDetails = false"
> >
<div class="event-detail"> <div class="event-detail">
<div <div class="mb-10" v-for="(eventKey, index) in EventsDetailKeys" :key="index">
class="mb-10"
v-for="(eventKey, index) in EventsDetailKeys"
:key="index"
>
<span class="keys">{{ t(eventKey.text) }}</span> <span class="keys">{{ t(eventKey.text) }}</span>
<span v-if="eventKey.class === 'parameters'"> <span v-if="eventKey.class === 'parameters'">
<span v-for="(d, index) of currentEvent[eventKey.class]" :key="index"> <span v-for="(d, index) of currentEvent[eventKey.class]" :key="index"> {{ d.key }}={{ d.value }}; </span>
{{ d.key }}={{ d.value }};
</span> </span>
</span> <span v-else-if="eventKey.class === 'startTime' || eventKey.class === 'endTime'">
<span
v-else-if="
eventKey.class === 'startTime' || eventKey.class === 'endTime'
"
>
{{ dateFormat(currentEvent[eventKey.class]) }} {{ dateFormat(currentEvent[eventKey.class]) }}
</span> </span>
<span v-else-if="eventKey.class === 'source'" class="source"> <span v-else-if="eventKey.class === 'source'" class="source">
<span <span>{{ t("service") }}: {{ currentEvent[eventKey.class].service }}</span>
>{{ t("service") }}:
{{ currentEvent[eventKey.class].service }}</span
>
<div v-show="currentEvent[eventKey.class].endpoint"> <div v-show="currentEvent[eventKey.class].endpoint">
{{ t("endpoint") }}: {{ t("endpoint") }}:
{{ currentEvent[eventKey.class].endpoint }} {{ currentEvent[eventKey.class].endpoint }}
@ -144,45 +111,43 @@ limitations under the License. -->
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { Alarm, Event } from "@/types/alarm"; import type { Alarm, Event } from "@/types/alarm";
import { useAlarmStore } from "@/store/modules/alarm"; import { useAlarmStore } from "@/store/modules/alarm";
import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data"; import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data";
import { dateFormat } from "@/utils/dateFormat"; import { dateFormat } from "@/utils/dateFormat";
const { t } = useI18n(); const { t } = useI18n();
const alarmStore = useAlarmStore(); const alarmStore = useAlarmStore();
const isShowDetails = ref<boolean>(false); const isShowDetails = ref<boolean>(false);
const showEventDetails = ref<boolean>(false); const showEventDetails = ref<boolean>(false);
const currentDetail = ref<Alarm | any>({}); const currentDetail = ref<Alarm | any>({});
const alarmTags = ref<string[]>([]); const alarmTags = ref<string[]>([]);
const currentEvents = ref<any[]>([]); const currentEvents = ref<any[]>([]);
const currentEvent = ref<Event | any>({}); const currentEvent = ref<Event | any>({});
function showDetails(item: Alarm) { function showDetails(item: Alarm) {
isShowDetails.value = true; isShowDetails.value = true;
currentDetail.value = item; currentDetail.value = item;
currentEvents.value = item.events; currentEvents.value = item.events;
alarmTags.value = currentDetail.value.tags.map( alarmTags.value = currentDetail.value.tags.map((d: { key: string; value: string }) => {
(d: { key: string; value: string }) => {
return `${d.key} = ${d.value}`; return `${d.key} = ${d.value}`;
});
} }
);
}
function viewEventDetail(event: Event) { function viewEventDetail(event: Event) {
currentEvent.value = event; currentEvent.value = event;
showEventDetails.value = true; showEventDetails.value = true;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../components/style.scss"; @import "../components/style.scss";
.tips { .tips {
width: 100%; width: 100%;
margin: 20px 0; margin: 20px 0;
text-align: center; text-align: center;
font-size: 14px; font-size: 14px;
} }
</style> </style>

View File

@ -28,12 +28,7 @@ limitations under the License. -->
</div> </div>
<div class="mr-10 ml-10"> <div class="mr-10 ml-10">
<span class="grey">{{ t("searchKeyword") }}: </span> <span class="grey">{{ t("searchKeyword") }}: </span>
<el-input <el-input size="small" v-model="keyword" class="alarm-tool-input" @change="refreshAlarms({ pageNum: 1 })" />
size="small"
v-model="keyword"
class="alarm-tool-input"
@change="refreshAlarms({ pageNum: 1 })"
/>
</div> </div>
<div class="pagination"> <div class="pagination">
<el-pagination <el-pagination
@ -48,37 +43,32 @@ limitations under the License. -->
/> />
</div> </div>
</div> </div>
<ConditionTags <ConditionTags :type="'ALARM'" @update="(data) => refreshAlarms({ pageNum: 1, tagsMap: data.tagsMap })" />
:type="'ALARM'"
@update="(data) => refreshAlarms({ pageNum: 1, tagsMap: data.tagsMap })"
/>
</nav> </nav>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed } from "vue"; import { ref, computed } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import ConditionTags from "@/views/components/ConditionTags.vue"; import ConditionTags from "@/views/components/ConditionTags.vue";
import { AlarmOptions } from "./data"; import { AlarmOptions } from "./data";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useAlarmStore } from "@/store/modules/alarm"; import { useAlarmStore } from "@/store/modules/alarm";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const alarmStore = useAlarmStore(); const alarmStore = useAlarmStore();
const { t } = useI18n(); const { t } = useI18n();
const pageSize = 20; const pageSize = 20;
const entity = ref<string>(""); const entity = ref<string>("");
const keyword = ref<string>(""); const keyword = ref<string>("");
const pageNum = ref<number>(1); const pageNum = ref<number>(1);
const total = computed(() => const total = computed(() =>
alarmStore.alarms.length === pageSize alarmStore.alarms.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value,
? pageSize * pageNum.value + 1 );
: pageSize * pageNum.value
);
refreshAlarms({ pageNum: 1 }); refreshAlarms({ pageNum: 1 });
async function refreshAlarms(param: { pageNum: number; tagsMap?: any }) { async function refreshAlarms(param: { pageNum: number; tagsMap?: any }) {
const params: any = { const params: any = {
duration: appStore.durationTime, duration: appStore.durationTime,
paging: { paging: {
@ -94,38 +84,38 @@ async function refreshAlarms(param: { pageNum: number; tagsMap?: any }) {
if (res.errors) { if (res.errors) {
ElMessage.error(res.errors); ElMessage.error(res.errors);
} }
} }
function changeEntity(param: any) { function changeEntity(param: any) {
entity.value = param[0].value; entity.value = param[0].value;
refreshAlarms({ pageNum: 1 }); refreshAlarms({ pageNum: 1 });
} }
function changePage(p: number) { function changePage(p: number) {
pageNum.value = p; pageNum.value = p;
refreshAlarms({ pageNum: p }); refreshAlarms({ pageNum: p });
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.alarm-tool { .alarm-tool {
font-size: 12px; font-size: 12px;
border-bottom: 1px solid #c1c5ca41; border-bottom: 1px solid #c1c5ca41;
background-color: #f0f2f5; background-color: #f0f2f5;
padding: 10px; padding: 10px;
position: relative; position: relative;
} }
.alarm-tool-input { .alarm-tool-input {
border-style: unset; border-style: unset;
outline: 0; outline: 0;
padding: 2px 5px; padding: 2px 5px;
width: 250px; width: 250px;
border-radius: 3px; border-radius: 3px;
} }
.pagination { .pagination {
position: absolute; position: absolute;
top: 10px; top: 10px;
right: 5px; right: 5px;
} }
</style> </style>

View File

@ -42,20 +42,12 @@ limitations under the License. -->
/> />
</template> </template>
<div class="content"> <div class="content">
<span <span v-for="(item, index) in tagList" :key="index" @click="selectTag(item)" class="tag-item">
v-for="(item, index) in tagList"
:key="index"
@click="selectTag(item)"
class="tag-item"
>
{{ item }} {{ item }}
</span> </span>
</div> </div>
</el-popover> </el-popover>
<span <span class="tags-tip" :class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''">
class="tags-tip"
:class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''"
>
<a <a
target="blank" target="blank"
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md" href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
@ -72,50 +64,50 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useTraceStore } from "@/store/modules/trace"; import { useTraceStore } from "@/store/modules/trace";
import { useLogStore } from "@/store/modules/log"; import { useLogStore } from "@/store/modules/log";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
/*global defineEmits, defineProps */ /*global defineEmits, defineProps */
const emit = defineEmits(["update"]); const emit = defineEmits(["update"]);
const props = defineProps({ const props = defineProps({
type: { type: String, default: "TRACE" }, type: { type: String, default: "TRACE" },
}); });
const traceStore = useTraceStore(); const traceStore = useTraceStore();
const logStore = useLogStore(); const logStore = useLogStore();
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const { t } = useI18n(); const { t } = useI18n();
const tags = ref<string>(""); const tags = ref<string>("");
const tagsList = ref<string[]>([]); const tagsList = ref<string[]>([]);
const tagArr = ref<string[]>([]); const tagArr = ref<string[]>([]);
const tagList = ref<string[]>([]); const tagList = ref<string[]>([]);
const tagKeys = ref<string[]>([]); const tagKeys = ref<string[]>([]);
const keysList = ref<string[]>([]); const keysList = ref<string[]>([]);
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
const tipsMap = { const tipsMap = {
LOG: "logTagsTip", LOG: "logTagsTip",
TRACE: "traceTagsTip", TRACE: "traceTagsTip",
ALARM: "alarmTagsTip", ALARM: "alarmTagsTip",
}; };
fetchTagKeys(); fetchTagKeys();
function removeTags(index: number) { function removeTags(index: number) {
tagsList.value.splice(index, 1); tagsList.value.splice(index, 1);
updateTags(); updateTags();
} }
function addLabels() { function addLabels() {
if (!tags.value) { if (!tags.value) {
return; return;
} }
tagsList.value.push(tags.value); tagsList.value.push(tags.value);
tags.value = ""; tags.value = "";
updateTags(); updateTags();
} }
function updateTags() { function updateTags() {
const tagsMap = tagsList.value.map((item: string) => { const tagsMap = tagsList.value.map((item: string) => {
const key = item.substring(0, item.indexOf("=")); const key = item.substring(0, item.indexOf("="));
return { return {
@ -124,8 +116,8 @@ function updateTags() {
}; };
}); });
emit("update", { tagsMap, tagsList: tagsList.value }); emit("update", { tagsMap, tagsList: tagsList.value });
} }
async function fetchTagKeys() { async function fetchTagKeys() {
let resp: any = {}; let resp: any = {};
if (props.type === "TRACE") { if (props.type === "TRACE") {
resp = await traceStore.getTagKeys(); resp = await traceStore.getTagKeys();
@ -141,9 +133,9 @@ async function fetchTagKeys() {
tagKeys.value = resp.data.tagKeys; tagKeys.value = resp.data.tagKeys;
keysList.value = resp.data.tagKeys; keysList.value = resp.data.tagKeys;
searchTags(); searchTags();
} }
async function fetchTagValues() { async function fetchTagValues() {
const param = tags.value.split("=")[0]; const param = tags.value.split("=")[0];
let resp: any = {}; let resp: any = {};
if (props.type === "TRACE") { if (props.type === "TRACE") {
@ -158,9 +150,9 @@ async function fetchTagValues() {
} }
tagArr.value = resp.data.tagValues; tagArr.value = resp.data.tagValues;
searchTags(); searchTags();
} }
function inputTags() { function inputTags() {
if (!tags.value) { if (!tags.value) {
tagArr.value = keysList.value; tagArr.value = keysList.value;
tagKeys.value = keysList.value; tagKeys.value = keysList.value;
@ -175,18 +167,18 @@ function inputTags() {
search = tags.value; search = tags.value;
} }
tagList.value = tagArr.value.filter((d: string) => d.includes(search)); tagList.value = tagArr.value.filter((d: string) => d.includes(search));
} }
function addTags() { function addTags() {
if (!tags.value.includes("=")) { if (!tags.value.includes("=")) {
return; return;
} }
addLabels(); addLabels();
tagArr.value = tagKeys.value; tagArr.value = tagKeys.value;
searchTags(); searchTags();
} }
function selectTag(item: string) { function selectTag(item: string) {
if (tags.value.includes("=")) { if (tags.value.includes("=")) {
const key = tags.value.split("=")[0]; const key = tags.value.split("=")[0];
tags.value = key + "=" + item; tags.value = key + "=" + item;
@ -195,9 +187,9 @@ function selectTag(item: string) {
} }
tags.value = item + "="; tags.value = item + "=";
fetchTagValues(); fetchTagValues();
} }
function searchTags() { function searchTags() {
let search = ""; let search = "";
if (tags.value.includes("=")) { if (tags.value.includes("=")) {
search = tags.value.split("=")[1]; search = tags.value.split("=")[1];
@ -205,25 +197,25 @@ function searchTags() {
search = tags.value; search = tags.value;
} }
tagList.value = tagArr.value.filter((d: string) => d.includes(search)); tagList.value = tagArr.value.filter((d: string) => d.includes(search));
} }
watch( watch(
() => appStore.durationTime, () => appStore.durationTime,
() => { () => {
fetchTagKeys(); fetchTagKeys();
} },
); );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.trace-tags { .trace-tags {
padding: 1px 5px 0 0; padding: 1px 5px 0 0;
border-radius: 3px; border-radius: 3px;
height: 24px; height: 24px;
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
} }
.selected { .selected {
display: inline-block; display: inline-block;
padding: 0 3px; padding: 0 3px;
border-radius: 3px; border-radius: 3px;
@ -231,23 +223,23 @@ watch(
border: 1px dashed #aaa; border: 1px dashed #aaa;
font-size: 12px; font-size: 12px;
margin: 3px 2px 0 2px; margin: 3px 2px 0 2px;
} }
.trace-new-tag { .trace-new-tag {
border-style: unset; border-style: unset;
outline: 0; outline: 0;
padding: 2px 5px; padding: 2px 5px;
border-radius: 3px; border-radius: 3px;
width: 250px; width: 250px;
} }
.remove-icon { .remove-icon {
display: inline-block; display: inline-block;
margin-left: 3px; margin-left: 3px;
cursor: pointer; cursor: pointer;
} }
.tag-item { .tag-item {
display: inline-block; display: inline-block;
min-width: 210px; min-width: 210px;
cursor: pointer; cursor: pointer;
@ -256,17 +248,17 @@ watch(
&:hover { &:hover {
color: #409eff; color: #409eff;
} }
} }
.tags-tip { .tags-tip {
color: #a7aebb; color: #a7aebb;
} }
.link-tips { .link-tips {
display: inline-block; display: inline-block;
} }
.light { .light {
color: #3d444f; color: #3d444f;
input { input {
@ -276,15 +268,15 @@ watch(
.selected { .selected {
color: #3d444f; color: #3d444f;
} }
} }
.icon-help { .icon-help {
cursor: pointer; cursor: pointer;
} }
.content { .content {
width: 300px; width: 300px;
max-height: 400px; max-height: 400px;
overflow: auto; overflow: auto;
} }
</style> </style>

View File

@ -33,17 +33,17 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, defineComponent } from "vue"; import { ref, defineComponent } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import GridLayout from "./panel/Layout.vue"; import GridLayout from "./panel/Layout.vue";
import Tool from "./panel/Tool.vue"; import Tool from "./panel/Tool.vue";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import Configuration from "./configuration"; import Configuration from "./configuration";
import { LayoutConfig } from "@/types/dashboard"; import type { LayoutConfig } from "@/types/dashboard";
export default defineComponent({ export default defineComponent({
name: "Dashboard", name: "Dashboard",
components: { ...Configuration, GridLayout, Tool }, components: { ...Configuration, GridLayout, Tool },
setup() { setup() {
@ -63,9 +63,7 @@ export default defineComponent({
const { layer, entity, name } = dashboardStore.currentDashboard; const { layer, entity, name } = dashboardStore.currentDashboard;
layoutKey.value = `${layer}_${entity}_${name}`; layoutKey.value = `${layer}_${entity}_${name}`;
} }
const c: { configuration: string; id: string } = JSON.parse( const c: { configuration: string; id: string } = JSON.parse(sessionStorage.getItem(layoutKey.value) || "{}");
sessionStorage.getItem(layoutKey.value) || "{}"
);
const layout: any = c.configuration || {}; const layout: any = c.configuration || {};
dashboardStore.setLayout(setWidgetsID(layout.children || [])); dashboardStore.setLayout(setWidgetsID(layout.children || []));
@ -112,10 +110,10 @@ export default defineComponent({
dashboardStore, dashboardStore,
}; };
}, },
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ds-main { .ds-main {
overflow: auto; overflow: auto;
} }
</style> </style>

View File

@ -33,9 +33,7 @@ limitations under the License. -->
{{ t("reloadDashboards") }} {{ t("reloadDashboards") }}
</el-button> </el-button>
<router-link to="/dashboard/new"> <router-link to="/dashboard/new">
<el-button size="small" type="primary"> <el-button size="small" type="primary"> + {{ t("newDashboard") }} </el-button>
+ {{ t("newDashboard") }}
</el-button>
</router-link> </router-link>
</div> </div>
<div class="table"> <div class="table">
@ -74,10 +72,7 @@ limitations under the License. -->
<el-button size="small" @click="handleRename(scope.row)"> <el-button size="small" @click="handleRename(scope.row)">
{{ t("rename") }} {{ t("rename") }}
</el-button> </el-button>
<el-popconfirm <el-popconfirm :title="t('deleteTitle')" @confirm="handleDelete(scope.row)">
:title="t('deleteTitle')"
@confirm="handleDelete(scope.row)"
>
<template #reference> <template #reference>
<el-button size="small" type="danger"> <el-button size="small" type="danger">
{{ t("delete") }} {{ t("delete") }}
@ -87,11 +82,7 @@ limitations under the License. -->
<el-popconfirm <el-popconfirm
:title="t('rootTitle')" :title="t('rootTitle')"
@confirm="setRoot(scope.row)" @confirm="setRoot(scope.row)"
v-if=" v-if="[EntityType[0].value, EntityType[1].value].includes(scope.row.entity)"
[EntityType[0].value, EntityType[1].value].includes(
scope.row.entity
)
"
> >
<template #reference> <template #reference>
<el-button size="small" style="width: 110px" type="danger"> <el-button size="small" style="width: 110px" type="danger">
@ -140,48 +131,47 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ElMessageBox, ElMessage } from "element-plus"; import { ElMessageBox, ElMessage } from "element-plus";
import type { ElTable } from "element-plus"; import { ElTable } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import router from "@/router"; import router from "@/router";
import { DashboardItem, LayoutConfig } from "@/types/dashboard"; import type { DashboardItem, LayoutConfig } from "@/types/dashboard";
import { saveFile, readFile } from "@/utils/file"; import { saveFile, readFile } from "@/utils/file";
import { EntityType } from "./data"; import { EntityType } from "./data";
import { isEmptyObject } from "@/utils/is"; import { isEmptyObject } from "@/utils/is";
/*global Nullable*/ /*global Nullable*/
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const pageSize = 20; const pageSize = 20;
const dashboards = ref<DashboardItem[]>([]); const dashboards = ref<DashboardItem[]>([]);
const searchText = ref<string>(""); const searchText = ref<string>("");
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const currentPage = ref<number>(1); const currentPage = ref<number>(1);
const total = ref<number>(0); const total = ref<number>(0);
const multipleTableRef = ref<InstanceType<typeof ElTable>>(); const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const multipleSelection = ref<DashboardItem[]>([]); const multipleSelection = ref<DashboardItem[]>([]);
const dashboardFile = ref<Nullable<HTMLDivElement>>(null); const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
appStore.setPageTitle("Dashboard List"); appStore.setPageTitle("Dashboard List");
const handleSelectionChange = (val: DashboardItem[]) => { const handleSelectionChange = (val: DashboardItem[]) => {
multipleSelection.value = val; multipleSelection.value = val;
}; };
setList(); setList();
async function setList() { async function setList() {
await dashboardStore.setDashboards(); await dashboardStore.setDashboards();
searchDashboards(1); searchDashboards(1);
} }
async function importTemplates(event: any) { async function importTemplates(event: any) {
const arr: any = await readFile(event); const arr: any = await readFile(event);
for (const item of arr) { for (const item of arr) {
const { layer, name, entity } = item.configuration; const { layer, name, entity } = item.configuration;
const index = dashboardStore.dashboards.findIndex( const index = dashboardStore.dashboards.findIndex(
(d: DashboardItem) => (d: DashboardItem) => d.name === name && d.entity === entity && d.layer === layer && !item.id,
d.name === name && d.entity === entity && d.layer === layer && !item.id
); );
if (index > -1) { if (index > -1) {
return ElMessage.error(t("nameError")); return ElMessage.error(t("nameError"));
@ -190,9 +180,7 @@ async function importTemplates(event: any) {
loading.value = true; loading.value = true;
for (const item of arr) { for (const item of arr) {
const { layer, name, entity, isRoot, children } = item.configuration; const { layer, name, entity, isRoot, children } = item.configuration;
const index = dashboardStore.dashboards.findIndex( const index = dashboardStore.dashboards.findIndex((d: DashboardItem) => d.id === item.id);
(d: DashboardItem) => d.id === item.id
);
const p: DashboardItem = { const p: DashboardItem = {
name: name.split(" ").join("-"), name: name.split(" ").join("-"),
layer: layer, layer: layer,
@ -210,16 +198,14 @@ async function importTemplates(event: any) {
dashboards.value = dashboardStore.dashboards; dashboards.value = dashboardStore.dashboards;
loading.value = false; loading.value = false;
dashboardFile.value = null; dashboardFile.value = null;
} }
function exportTemplates() { function exportTemplates() {
if (!multipleSelection.value.length) { if (!multipleSelection.value.length) {
return; return;
} }
const arr = multipleSelection.value.sort( const arr = multipleSelection.value.sort((a: DashboardItem, b: DashboardItem) => {
(a: DashboardItem, b: DashboardItem) => {
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
} });
);
const templates = arr.map((d: DashboardItem) => { const templates = arr.map((d: DashboardItem) => {
const key = [d.layer, d.entity, d.name].join("_"); const key = [d.layer, d.entity, d.name].join("_");
const layout = JSON.parse(sessionStorage.getItem(key) || "{}"); const layout = JSON.parse(sessionStorage.getItem(key) || "{}");
@ -233,15 +219,15 @@ function exportTemplates() {
setTimeout(() => { setTimeout(() => {
multipleTableRef.value!.clearSelection(); multipleTableRef.value!.clearSelection();
}, 2000); }, 2000);
} }
function optimizeTemplate( function optimizeTemplate(
children: (LayoutConfig & { children: (LayoutConfig & {
moved?: boolean; moved?: boolean;
standard?: unknown; standard?: unknown;
label?: string; label?: string;
value?: string; value?: string;
})[] })[],
) { ) {
for (const child of children || []) { for (const child of children || []) {
delete child.moved; delete child.moved;
delete child.activedTabIndex; delete child.activedTabIndex;
@ -266,9 +252,7 @@ function optimizeTemplate(
if (!(child.metrics && child.metrics.length && child.metrics[0])) { if (!(child.metrics && child.metrics.length && child.metrics[0])) {
delete child.metrics; delete child.metrics;
} }
if ( if (!(child.metricTypes && child.metricTypes.length && child.metricTypes[0])) {
!(child.metricTypes && child.metricTypes.length && child.metricTypes[0])
) {
delete child.metricTypes; delete child.metricTypes;
} }
if (child.metricConfig && child.metricConfig.length) { if (child.metricConfig && child.metricConfig.length) {
@ -295,32 +279,28 @@ function optimizeTemplate(
optimizeTemplate(item.children); optimizeTemplate(item.children);
} }
} }
if ( if (["Trace", "Topology", "Tab", "Profile", "Ebpf", "Log"].includes(child.type)) {
["Trace", "Topology", "Tab", "Profile", "Ebpf", "Log"].includes(
child.type
)
) {
delete child.widget; delete child.widget;
} }
} }
} }
function handleEdit(row: DashboardItem) { function handleEdit(row: DashboardItem) {
dashboardStore.setMode(true); dashboardStore.setMode(true);
dashboardStore.setEntity(row.entity); dashboardStore.setEntity(row.entity);
dashboardStore.setLayer(row.layer); dashboardStore.setLayer(row.layer);
dashboardStore.setCurrentDashboard(row); dashboardStore.setCurrentDashboard(row);
router.push(`/dashboard/${row.layer}/${row.entity}/${row.name}`); router.push(`/dashboard/${row.layer}/${row.entity}/${row.name}`);
} }
function handleView(row: DashboardItem) { function handleView(row: DashboardItem) {
dashboardStore.setMode(false); dashboardStore.setMode(false);
dashboardStore.setEntity(row.entity); dashboardStore.setEntity(row.entity);
dashboardStore.setLayer(row.layer); dashboardStore.setLayer(row.layer);
dashboardStore.setCurrentDashboard(row); dashboardStore.setCurrentDashboard(row);
router.push(`/dashboard/${row.layer}/${row.entity}/${row.name}`); router.push(`/dashboard/${row.layer}/${row.entity}/${row.name}`);
} }
async function setRoot(row: DashboardItem) { async function setRoot(row: DashboardItem) {
const items: DashboardItem[] = []; const items: DashboardItem[] = [];
loading.value = true; loading.value = true;
for (const d of dashboardStore.dashboards) { for (const d of dashboardStore.dashboards) {
@ -345,7 +325,7 @@ async function setRoot(row: DashboardItem) {
JSON.stringify({ JSON.stringify({
id: d.id, id: d.id,
configuration: c, configuration: c,
}) }),
); );
} }
} else { } else {
@ -373,7 +353,7 @@ async function setRoot(row: DashboardItem) {
JSON.stringify({ JSON.stringify({
id: d.id, id: d.id,
configuration: c, configuration: c,
}) }),
); );
} }
} }
@ -383,8 +363,8 @@ async function setRoot(row: DashboardItem) {
dashboardStore.resetDashboards(items); dashboardStore.resetDashboards(items);
searchDashboards(1); searchDashboards(1);
loading.value = false; loading.value = false;
} }
function handleRename(row: DashboardItem) { function handleRename(row: DashboardItem) {
ElMessageBox.prompt("Please input dashboard name", "Edit", { ElMessageBox.prompt("Please input dashboard name", "Edit", {
confirmButtonText: "OK", confirmButtonText: "OK",
cancelButtonText: "Cancel", cancelButtonText: "Cancel",
@ -399,8 +379,8 @@ function handleRename(row: DashboardItem) {
message: "Input canceled", message: "Input canceled",
}); });
}); });
} }
async function updateName(d: DashboardItem, value: string) { async function updateName(d: DashboardItem, value: string) {
if (new RegExp(/\s/).test(value)) { if (new RegExp(/\s/).test(value)) {
ElMessage.error("The name cannot contain spaces, carriage returns, etc"); ElMessage.error("The name cannot contain spaces, carriage returns, etc");
return; return;
@ -447,11 +427,11 @@ async function updateName(d: DashboardItem, value: string) {
JSON.stringify({ JSON.stringify({
id: d.id, id: d.id,
configuration: c, configuration: c,
}) }),
); );
searchText.value = ""; searchText.value = "";
} }
async function handleDelete(row: DashboardItem) { async function handleDelete(row: DashboardItem) {
dashboardStore.setCurrentDashboard(row); dashboardStore.setCurrentDashboard(row);
loading.value = true; loading.value = true;
await dashboardStore.deleteDashboard(); await dashboardStore.deleteDashboard();
@ -459,47 +439,44 @@ async function handleDelete(row: DashboardItem) {
loading.value = false; loading.value = false;
sessionStorage.setItem("dashboards", JSON.stringify(dashboards.value)); sessionStorage.setItem("dashboards", JSON.stringify(dashboards.value));
sessionStorage.removeItem(`${row.layer}_${row.entity}_${row.name}`); sessionStorage.removeItem(`${row.layer}_${row.entity}_${row.name}`);
} }
function searchDashboards(pageIndex?: any) { function searchDashboards(pageIndex?: any) {
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]"); const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
const arr = list.filter((d: { name: string }) => const arr = list.filter((d: { name: string }) => d.name.includes(searchText.value));
d.name.includes(searchText.value)
);
total.value = arr.length; total.value = arr.length;
dashboards.value = arr.filter( dashboards.value = arr.filter(
(d: { name: string }, index: number) => (d: { name: string }, index: number) => index < pageIndex * pageSize && index >= (pageIndex - 1) * pageSize,
index < pageIndex * pageSize && index >= (pageIndex - 1) * pageSize
); );
currentPage.value = pageIndex; currentPage.value = pageIndex;
} }
async function reloadTemplates() { async function reloadTemplates() {
loading.value = true; loading.value = true;
await dashboardStore.resetTemplates(); await dashboardStore.resetTemplates();
loading.value = false; loading.value = false;
} }
function changePage(pageIndex: number) { function changePage(pageIndex: number) {
currentPage.value = pageIndex; currentPage.value = pageIndex;
searchDashboards(pageIndex); searchDashboards(pageIndex);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header { .header {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.dashboard-list { .dashboard-list {
padding: 20px; padding: 20px;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
} }
.input-with-search { .input-with-search {
width: 250px; width: 250px;
} }
.table { .table {
padding: 20px 10px; padding: 20px 10px;
background-color: #fff; background-color: #fff;
box-shadow: 0px 1px 4px 0px #00000029; box-shadow: 0px 1px 4px 0px #00000029;
@ -507,43 +484,43 @@ function changePage(pageIndex: number) {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: auto; overflow: auto;
} }
.toggle-selection { .toggle-selection {
margin-top: 20px; margin-top: 20px;
background-color: #fff; background-color: #fff;
} }
.pagination { .pagination {
float: right; float: right;
} }
.btn { .btn {
width: 220px; width: 220px;
font-size: 13px; font-size: 13px;
} }
.import-template { .import-template {
display: none; display: none;
} }
.input-label { .input-label {
line-height: 30px; line-height: 30px;
height: 30px; height: 30px;
width: 220px; width: 220px;
cursor: pointer; cursor: pointer;
} }
.name { .name {
color: #409eff; color: #409eff;
} }
.reload { .reload {
margin-right: 3px; margin-right: 3px;
} }
.reload-btn { .reload-btn {
display: inline-block; display: inline-block;
margin-left: 10px; margin-left: 10px;
} }
</style> </style>

View File

@ -17,11 +17,7 @@ limitations under the License. -->
<div class="title">{{ t("newDashboard") }}</div> <div class="title">{{ t("newDashboard") }}</div>
<div class="item"> <div class="item">
<div class="label">{{ t("name") }}</div> <div class="label">{{ t("name") }}</div>
<el-input <el-input size="default" v-model="states.name" placeholder="Please input name" />
size="default"
v-model="states.name"
placeholder="Please input name"
/>
</div> </div>
<div class="item"> <div class="item">
<div class="label">{{ t("layer") }}</div> <div class="label">{{ t("layer") }}</div>
@ -51,35 +47,33 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive } from "vue"; import { reactive } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import router from "@/router"; import router from "@/router";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { EntityType } from "./data"; import { EntityType } from "./data";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
appStore.setPageTitle("Dashboard New"); appStore.setPageTitle("Dashboard New");
const { t } = useI18n(); const { t } = useI18n();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
const states = reactive({ const states = reactive({
name: "", name: "",
selectedLayer: "", selectedLayer: "",
entity: EntityType[0].value, entity: EntityType[0].value,
layers: [], layers: [],
}); });
setLayers(); setLayers();
dashboardStore.setDashboards(); dashboardStore.setDashboards();
const onCreate = () => { const onCreate = () => {
const index = dashboardStore.dashboards.findIndex( const index = dashboardStore.dashboards.findIndex(
(d: { name: string; entity: string; layer: string }) => (d: { name: string; entity: string; layer: string }) =>
d.name === states.name && d.name === states.name && states.entity === d.entity && states.selectedLayer === d.layer,
states.entity === d.entity &&
states.selectedLayer === d.layer
); );
if (!states.name) { if (!states.name) {
ElMessage.error(t("nameEmptyError")); ElMessage.error(t("nameEmptyError"));
@ -97,8 +91,8 @@ const onCreate = () => {
const name = states.name; const name = states.name;
const path = `/dashboard/${states.selectedLayer}/${states.entity}/${name}`; const path = `/dashboard/${states.selectedLayer}/${states.entity}/${name}`;
router.push(path); router.push(path);
}; };
async function setLayers() { async function setLayers() {
const resp = await selectorStore.fetchLayers(); const resp = await selectorStore.fetchLayers();
if (resp.errors) { if (resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
@ -107,39 +101,39 @@ async function setLayers() {
states.layers = resp.data.layers.map((d: string) => { states.layers = resp.data.layers.map((d: string) => {
return { label: d, value: d }; return { label: d, value: d };
}); });
} }
function changeLayer(opt: { label: string; value: string }[] | any) { function changeLayer(opt: { label: string; value: string }[] | any) {
states.selectedLayer = opt[0].value; states.selectedLayer = opt[0].value;
} }
function changeEntity(opt: { label: string; value: string }[] | any) { function changeEntity(opt: { label: string; value: string }[] | any) {
states.entity = opt[0].value; states.entity = opt[0].value;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.title { .title {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
padding-top: 20px; padding-top: 20px;
} }
.new-dashboard { .new-dashboard {
margin: 0 auto; margin: 0 auto;
} }
.item { .item {
margin-top: 20px; margin-top: 20px;
} }
.new-dashboard, .new-dashboard,
.selectors { .selectors {
width: 600px; width: 600px;
} }
.create { .create {
width: 600px; width: 600px;
} }
.btn { .btn {
margin-top: 40px; margin-top: 40px;
} }
</style> </style>

View File

@ -13,12 +13,7 @@ limitations under the License. -->
<template> <template>
<div> <div>
<span class="label">{{ t("enableAssociate") }}</span> <span class="label">{{ t("enableAssociate") }}</span>
<el-switch <el-switch v-model="eventAssociate" active-text="Yes" inactive-text="No" @change="updateConfig" />
v-model="eventAssociate"
active-text="Yes"
inactive-text="No"
@change="updateConfig"
/>
</div> </div>
<div class="footer"> <div class="footer">
<el-button size="small" @click="cancelConfig"> <el-button size="small" @click="cancelConfig">
@ -30,46 +25,46 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ref } from "vue"; import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
const { t } = useI18n(); const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid; const originConfig = dashboardStore.selectedGrid;
const eventAssociate = ref(dashboardStore.selectedGrid.eventAssociate || false); const eventAssociate = ref(dashboardStore.selectedGrid.eventAssociate || false);
function updateConfig() { function updateConfig() {
dashboardStore.selectedGrid = { dashboardStore.selectedGrid = {
...dashboardStore.selectedGrid, ...dashboardStore.selectedGrid,
eventAssociate, eventAssociate,
}; };
dashboardStore.selectWidget(dashboardStore.selectedGrid); dashboardStore.selectWidget(dashboardStore.selectedGrid);
} }
function applyConfig() { function applyConfig() {
dashboardStore.setConfigPanel(false); dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid); dashboardStore.setConfigs(dashboardStore.selectedGrid);
} }
function cancelConfig() { function cancelConfig() {
dashboardStore.selectWidget(originConfig); dashboardStore.selectWidget(originConfig);
dashboardStore.setConfigPanel(false); dashboardStore.setConfigPanel(false);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.label { .label {
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
} }
.item { .item {
margin: 10px 0; margin: 10px 0;
} }
.footer { .footer {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
right: 0; right: 0;
@ -78,5 +73,5 @@ function cancelConfig() {
text-align: right; text-align: right;
width: 100%; width: 100%;
background-color: #fff; background-color: #fff;
} }
</style> </style>

View File

@ -13,21 +13,11 @@ limitations under the License. -->
<template> <template>
<div class="item"> <div class="item">
<span class="label">{{ t("textUrl") }}</span> <span class="label">{{ t("textUrl") }}</span>
<el-input <el-input class="input" v-model="url" size="small" @change="changeConfig({ url })" />
class="input"
v-model="url"
size="small"
@change="changeConfig({ url })"
/>
</div> </div>
<div class="item"> <div class="item">
<span class="label">{{ t("content") }}</span> <span class="label">{{ t("content") }}</span>
<el-input <el-input class="input" v-model="content" size="small" @change="changeConfig({ content })" />
class="input"
v-model="content"
size="small"
@change="changeConfig({ content })"
/>
</div> </div>
<div class="item"> <div class="item">
<span class="label">{{ t("textAlign") }}</span> <span class="label">{{ t("textAlign") }}</span>
@ -85,20 +75,20 @@ limitations under the License. -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ref } from "vue"; import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
const { t } = useI18n(); const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid; const originConfig = dashboardStore.selectedGrid;
const graph = originConfig.graph || {}; const graph = originConfig.graph || {};
const url = ref(graph.url || ""); const url = ref(graph.url || "");
const backgroundColor = ref(graph.backgroundColor || "green"); const backgroundColor = ref(graph.backgroundColor || "green");
const fontColor = ref(graph.fontColor || "white"); const fontColor = ref(graph.fontColor || "white");
const content = ref<string>(graph.content || ""); const content = ref<string>(graph.content || "");
const fontSize = ref<number>(graph.fontSize || 12); const fontSize = ref<number>(graph.fontSize || 12);
const textAlign = ref(graph.textAlign || "left"); const textAlign = ref(graph.textAlign || "left");
const Colors = [ const Colors = [
{ {
label: "Green", label: "Green",
value: "green", value: "green",
@ -109,55 +99,55 @@ const Colors = [
{ label: "White", value: "white" }, { label: "White", value: "white" },
{ label: "Black", value: "black" }, { label: "Black", value: "black" },
{ label: "Orange", value: "orange" }, { label: "Orange", value: "orange" },
]; ];
const AlignStyle = [ const AlignStyle = [
{ {
label: "Left", label: "Left",
value: "left", value: "left",
}, },
{ label: "Center", value: "center" }, { label: "Center", value: "center" },
{ label: "Right", value: "right" }, { label: "Right", value: "right" },
]; ];
function changeConfig(param: { [key: string]: unknown }) { function changeConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore; const { selectedGrid } = dashboardStore;
const graph = { const graph = {
...selectedGrid.graph, ...selectedGrid.graph,
...param, ...param,
}; };
dashboardStore.selectWidget({ ...selectedGrid, graph }); dashboardStore.selectWidget({ ...selectedGrid, graph });
} }
function applyConfig() { function applyConfig() {
dashboardStore.setConfigPanel(false); dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid); dashboardStore.setConfigs(dashboardStore.selectedGrid);
} }
function cancelConfig() { function cancelConfig() {
dashboardStore.selectWidget(originConfig); dashboardStore.selectWidget(originConfig);
dashboardStore.setConfigPanel(false); dashboardStore.setConfigPanel(false);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.slider { .slider {
width: 500px; width: 500px;
margin-top: -3px; margin-top: -3px;
} }
.label { .label {
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
} }
.input { .input {
width: 500px; width: 500px;
} }
.item { .item {
margin-bottom: 10px; margin-bottom: 10px;
} }
.footer { .footer {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
right: 0; right: 0;
@ -166,5 +156,5 @@ function cancelConfig() {
text-align: right; text-align: right;
width: 100%; width: 100%;
background-color: #fff; background-color: #fff;
} }
</style> </style>

Some files were not shown because too many files have changed in this diff Show More