38 Commits

Author SHA1 Message Date
Fine0830
4e64b9a4b1 fix: operation pop-up window (#242) 2023-02-28 16:26:33 +08:00
Fine0830
1be572a95f feat: add cpm4d + avg calculations (#241) 2023-02-28 12:50:55 +08:00
Fine0830
5cc913a332 fix: data (#240) 2023-02-24 17:46:46 +08:00
Fine0830
220525a2d9 feat: add a calculation for cpm5d (#239) 2023-02-22 09:14:23 +08:00
yswdqz
72060f8227 Add AWS DynanoDB menu (#237) 2023-02-20 20:57:52 +08:00
Fine0830
b247ed1c24 feat: optimize menus and add Windows monitoring menu (#236) 2023-02-17 13:29:42 +08:00
Fine0830
b2707e0e62 feat: add period (#235) 2023-02-15 13:37:14 +08:00
Fine0830
a1066f09e4 refactor: optimize the attached events visualization in the trace widget (#234) 2023-02-15 13:32:32 +08:00
XinweiLyu
efed817f73 Add logo for HTTPX (#232) 2023-02-13 09:57:55 +08:00
Fine0830
4613149759 fix: remove duplicate query message (#231) 2023-02-10 20:56:15 +08:00
Fine0830
1877776720 refactor: optimize side bar component to make it more friendly (#230) 2023-02-09 17:54:11 +08:00
Fine0830
2b88266d67 build: bump postcss to a non-vulnerable version (#229) 2023-02-09 15:02:26 +08:00
dependabot[bot]
17b627a5d9 build(deps): bump @sideway/formula from 3.0.0 to 3.0.1 (#228) 2023-02-09 13:56:40 +08:00
pg.yang
5b0a68fe18 Add AWS S3 menu (#227) 2023-02-08 22:43:05 +08:00
Fine0830
d93ed2c5d3 fix: reset duration for query conditions after time range changes (#226) 2023-02-08 12:08:45 +08:00
Fine0830
c73322a504 fix: clear trace ID on the Log and Trace widgets after using association (#225) 2023-02-07 21:23:13 +08:00
Fine0830
4486684183 feat: add auto fresh to widgets independent mode (#224) 2023-02-07 16:14:38 +08:00
Fine0830
1768a1641c feat: update menus for OpenFunction (#223) 2023-02-06 14:36:13 +08:00
Fine0830
224053c0f4 feat: Implement independent mode for widgets (#221) 2023-02-06 13:38:19 +08:00
dependabot[bot]
ca38366a60 build(deps): bump http-cache-semantics from 4.1.0 to 4.1.1 (#222) 2023-02-06 10:04:39 +08:00
Superskyyy
45f2985549 Add websockets icon (#220)
* Add websockets icon

* Better one

* compress png to 12k
2023-01-17 21:46:57 -05:00
wuwen
3ef790dc07 fix: Formatted display of json content type (#219) 2023-01-16 20:34:51 +08:00
Superskyyy (COVID)
70df7605cb Add missing fastapi logo (#218) 2023-01-14 07:23:49 +08:00
dependabot[bot]
4fc451f370 build(deps): bump json5 from 1.0.1 to 1.0.2 (#217) 2023-01-08 21:11:59 +08:00
Fine0830
163de5e5cf refactor: optimize graph tooltips to make them more friendly (#216) 2023-01-05 17:44:28 +08:00
Fine0830
8785817efe feat: add a iframe widget for zipkin ui (#215) 2023-01-03 16:12:45 +08:00
Fine0830
db793e6c05 docs: update (#214) 2022-12-29 17:55:44 +08:00
Fine0830
d11ceab59d fix: add ElPopconfirm (#213) 2022-12-28 19:02:44 +08:00
吴晟 Wu Sheng
1278454148 Update .gitignore (#212) 2022-12-28 10:51:39 +08:00
Fine0830
7768f6ef16 fix: drag nodes (#211) 2022-12-20 16:52:14 +08:00
Fine0830
210b9ba491 build: update vite config (#210) 2022-12-18 11:16:21 +08:00
Fine0830
969580b770 fix: Instance Relation and Endpoint Relation dashboards show up (#209) 2022-12-17 15:59:59 +08:00
Fine0830
44dcb1e7f6 build: migrate the build tool from vue-cli to vite4 (#208) 2022-12-17 14:07:03 +08:00
Mahmoud Anwer
1e0c253488 Update MySQL UI to support MariaDB (#207) 2022-12-12 10:45:07 +08:00
dependabot[bot]
141a288542 build(deps): bump decode-uri-component from 0.2.0 to 0.2.2 (#204) 2022-12-08 11:10:01 +08:00
Fine0830
154372615e update menu icons (#203) 2022-12-07 11:53:45 +08:00
pg.yang
253f5c9261 Add AWS menu for supporting AWS monitoring (#202) 2022-12-06 21:41:15 +08:00
Marcin Grzejszczak
aa11a681ce Added Micrometer icon (#201) 2022-12-02 23:57:35 +08:00
238 changed files with 28050 additions and 54498 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 }}

34
.gitignore vendored
View File

@@ -16,24 +16,40 @@
# 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
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/*

View File

@@ -1,5 +1,4 @@
Apache SkyWalking Booster UI # Apache SkyWalking Booster UI
===============
<img src="http://skywalking.apache.org/assets/logo.svg" alt="Sky Walking logo" height="90px" align="right" /> <img src="http://skywalking.apache.org/assets/logo.svg" alt="Sky Walking logo" height="90px" align="right" />
@@ -10,11 +9,12 @@ Apache SkyWalking Booster UI
This UI starts from SkyWalking OAP v9 core. This UI starts from SkyWalking OAP v9 core.
## Release ## Release
This repo wouldn't release separately. All source codes have been included in the main repo release. The tags match the [main repo](https://github.com/apache/skywalking) tags. This repo wouldn't release separately. All source codes have been included in the main repo release. The tags match the [main repo](https://github.com/apache/skywalking) tags.
## Development ## Development
The app was built with [Vue3.x + Typescript](https://github.com/vuejs/vue). The app was built with [Vue3.x + Typescript](https://github.com/vuejs/vue).
### Prepare ### Prepare
@@ -28,19 +28,21 @@ npm install
### Build ### Build
**All following builds are for dev.** **All following builds are for dev.**
``` ```
npm install npm install
npm run serve npm run dev
``` ```
The default UI address is `http://localhost:8080`. The default UI address is `http://localhost:8080`.
# Contact Us # Contact Us
* Submit an [issue](https://github.com/apache/skywalking/issues) if you face some issues. Submit a [discussion](https://github.com/apache/skywalking/discussions) if you want to propose new feature or have any question.
* Mailing list: **dev@skywalking.apache.org**. Mail to `dev-subscribe@skywalking.apache.org`, follow the reply to subscribe the mailing list. - Submit an [issue](https://github.com/apache/skywalking/issues) if you face some issues. Submit a [discussion](https://github.com/apache/skywalking/discussions) if you want to propose new feature or have any question.
* Join Slack. Send `Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in. - Mailing list: **dev@skywalking.apache.org**. Mail to `dev-subscribe@skywalking.apache.org`, follow the reply to subscribe the mailing list.
* QQ Group: 392443393, 901167865 - Join Slack. Send `Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in.
- QQ Group: 392443393, 901167865
# License # License
[Apache 2.0 License.](/LICENSE) [Apache 2.0 License.](/LICENSE)

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",
],
],
},
};

13
src/assets/icons/index.ts → cypress.config.ts Executable file → Normal file
View File

@@ -14,7 +14,12 @@
* 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); import { defineConfig } from "cypress";
const req = require.context("./", true, /\.svg$/);
requireAll(req); export default defineConfig({
e2e: {
specPattern: "cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}",
baseUrl: "http://localhost:4173",
},
});

View File

@@ -14,10 +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.
*/ */
describe("My First Test", () => { describe("My First Test", () => {
it("renders props.msg when passed", () => { it("visits the app root url", () => {
const msg = "new message"; cy.visit("/");
console.log(msg); 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,6 +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.
*/ */
module.exports = { {
presets: ["@vue/cli-plugin-babel/preset"], "name": "Using fixtures to represent data",
}; "email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -14,8 +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.
*/ */
/// <reference types="cypress" />
// *********************************************** // ***********************************************
// This example commands.js shows you how to // This example commands.ts shows you how to
// create various custom commands and overwrite // create various custom commands and overwrite
// existing commands. // existing commands.
// //
@@ -26,16 +27,29 @@
// //
// //
// -- This is a parent command -- // -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... }) // Cypress.Commands.add('login', (email, password) => { ... })
// //
// //
// -- This is a child command -- // -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
// //
// //
// -- This is a dual command -- // -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
// //
// //
// -- This is will overwrite an existing command -- // -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // 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 {};

View File

@@ -14,6 +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.
*/ */
// *********************************************************** // ***********************************************************
// This example support/index.js is processed and // This example support/index.js is processed and
// loaded automatically before your test files. // loaded automatically before your test files.

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>

50921
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,80 @@
"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}": [
"eslint --fix", "eslint . --ext .vue,.js,.jsx,.ts,.tsx --fix --ignore-path .gitignore",
"prettier --write" "prettier --write \"src/**/*.{js,tsx,css,less,scss,vue,html,md}\"",
"stylelint --cache --fix \"**/*.{vue}\" --cache --cache-location node_modules/.cache/stylelint/"
], ],
"*.vue": [ "*.{scss,less}": [
"eslint --fix", "prettier --write \"src/**/*.{js,tsx,css,less,scss,vue,html,md}\"",
"prettier --write", "stylelint --cache --fix \"**/*.{less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/"
"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: {},
},
}; };

View File

@@ -14,13 +14,13 @@
* 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: ["cypress"], printWidth: 120,
env: { semi: true,
mocha: true, vueIndentScriptAndStyle: true,
"cypress/globals": true, trailingComma: "all",
}, proseWrap: "never",
rules: { htmlWhitespaceSensitivity: "strict",
strict: "off", endOfLine: "auto",
},
}; };

View File

@@ -15,11 +15,22 @@ limitations under the License. -->
<template> <template>
<router-view /> <router-view />
</template> </template>
<script lang="ts" setup>
import { useRoute } from "vue-router";
const route = useRoute();
setTimeout(() => {
if (route.name === "ViewWidget") {
(document.querySelector("#app") as any).style.minWidth = "120px";
} else {
(document.querySelector("#app") as any).style.minWidth = "1024px";
}
}, 500);
</script>
<style> <style>
#app { #app {
color: #2c3e50; color: #2c3e50;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
min-width: 1024px; }
}
</style> </style>

View File

@@ -0,0 +1,15 @@
<!-- 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. -->
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M856.32 428.064a32 32 0 0 0-32 32v163.328H372.48c-0.896 0-1.664 0.448-2.56 0.512v-177.696h244.48a32 32 0 1 0 0-64H130.56c-0.896 0-1.664 0.448-2.56 0.512V231.68h488.16a32 32 0 1 0 0-64H96a32 32 0 0 0-32 32v701.824a32 32 0 0 0 32 32h760.32a32 32 0 0 0 32-32V460.064a32 32 0 0 0-32-32zM128 445.728c0.896 0.064 1.664 0.512 2.56 0.512h175.36v423.264H128V445.728z m241.92 423.776v-182.624c0.896 0.064 1.664 0.512 2.56 0.512h451.84v182.08h-454.4zM960 174.656h-61.376V113.28a32 32 0 1 0-64 0v61.344H752.64a32 32 0 1 0 0 64h81.984v81.984a32 32 0 1 0 64 0V238.656H960a32 32 0 1 0 0-64z" fill="#2c2c2c"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -12,6 +12,6 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
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. -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M18.984 18q1.219 0 2.109-0.891t0.891-2.109-0.891-2.109-2.109-0.891h-1.5v-0.516q0-2.297-1.594-3.891t-3.891-1.594q-1.875 0-3.328 1.125t-1.969 2.859h-0.703q-1.641 0-2.813 1.195t-1.172 2.836 1.172 2.813 2.813 1.172h12.984zM19.359 10.031q1.922 0.141 3.281 1.57t1.359 3.398q0 2.063-1.477 3.539t-3.539 1.477h-12.984q-2.484 0-4.242-1.758t-1.758-4.242q0-2.203 1.57-3.961t3.773-1.992q0.984-1.828 2.766-2.953t3.891-1.125q2.531 0 4.711 1.781t2.648 4.266z"></path> <path d="M18.984 18q1.219 0 2.109-0.891t0.891-2.109-0.891-2.109-2.109-0.891h-1.5v-0.516q0-2.297-1.594-3.891t-3.891-1.594q-1.875 0-3.328 1.125t-1.969 2.859h-0.703q-1.641 0-2.813 1.195t-1.172 2.836 1.172 2.813 2.813 1.172h12.984zM19.359 10.031q1.922 0.141 3.281 1.57t1.359 3.398q0 2.063-1.477 3.539t-3.539 1.477h-12.984q-2.484 0-4.242-1.758t-1.758-4.242q0-2.203 1.57-3.961t3.773-1.992q0.984-1.828 2.766-2.953t3.891-1.125q2.531 0 4.711 1.781t2.648 4.266z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,15 @@
<!-- 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. -->
<svg t="1670381479745" class="icon" viewBox="0 0 1280 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2930"><path d="M577.450256 639.9892c0-104.678234 33.919428-206.436516 96.018379-289.895108 10.339826-13.879766 8.89985-33.079442-4.299927-44.279253l-49.379167-41.959292c-13.999764-11.899799-35.659398-10.179828-46.759211 4.459925C492.171695 374.833675 447.99244 505.551469 447.99244 639.9892c0 134.457731 44.179254 265.175525 125.03789 371.673728 11.119812 14.639753 32.759447 16.359724 46.759211 4.459925l49.379167-41.979292c13.179778-11.219811 14.619753-30.399487 4.299927-44.279252-62.118952-83.418592-96.01838-185.196875-96.018379-289.875109zM447.99244 31.99946c0-17.679702-14.319758-31.99946-31.99946-31.99946h-95.99838C205.116539 0 111.99811 93.118429 111.99811 207.99649v127.99784H31.99946c-17.679702 0-31.99946 14.319758-31.99946 31.99946v95.99838c0 17.679702 14.319758 31.99946 31.99946 31.99946h79.99865v255.99568c0 26.399555-21.599636 47.99919-47.99919 47.99919H31.99946c-17.679702 0-31.99946 14.319758-31.99946 31.99946v95.99838c0 17.679702 14.319758 31.99946 31.99946 31.99946h31.99946c114.878061 0 207.99649-93.118429 207.99649-207.99649V495.99163h79.99865c17.679702 0 31.99946-14.319758 31.99946-31.99946v-95.99838c0-17.679702-14.319758-31.99946-31.99946-31.99946h-79.99865v-127.99784c0-26.399555 21.599636-47.99919 47.99919-47.99919h95.99838c17.679702 0 31.99946-14.319758 31.99946-31.99946V31.99946z m706.94807 236.316012c-11.119812-14.639753-32.759447-16.359724-46.759211-4.459925l-49.379166 41.959292c-13.179778 11.219811-14.619753 30.399487-4.299928 44.279253 62.098952 83.418592 96.01838 185.216874 96.01838 289.895108 0 104.678234-33.919428 206.456516-96.01838 289.895108-10.339826 13.879766-8.89985 33.079442 4.299928 44.279253l49.379166 41.979292c13.999764 11.899799 35.659398 10.179828 46.759211-4.459925C1235.799146 905.124726 1279.9784 774.426932 1279.9784 639.9892c0-134.457731-44.179254-265.175525-125.03789-371.673728z m-108.338171 463.792174L954.483893 639.9892l92.118446-92.118445c12.499789-12.499789 12.499789-32.759447 0-45.259237l-45.239237-45.239236c-12.499789-12.499789-32.759447-12.499789-45.259236 0L863.98542 549.490727l-92.118445-92.118445c-12.499789-12.499789-32.759447-12.499789-45.259237 0l-45.239236 45.239236c-12.499789 12.499789-12.499789 32.759447 0 45.259237L773.486947 639.9892l-92.118445 92.118446c-12.499789 12.499789-12.499789 32.759447 0 45.259236l45.239236 45.239237c12.499789 12.499789 32.759447 12.499789 45.259237 0L863.98542 730.487673l92.118446 92.118446c12.499789 12.499789 32.759447 12.499789 45.259236 0l45.239237-45.239237c12.499789-12.499789 12.499789-32.759447 0-45.259236z" p-id="2931"></path></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

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;
} }
}); });

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

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

@@ -15,15 +15,19 @@ limitations under the License. -->
<template> <template>
<div class="chart" ref="chartRef" :style="`height:${height};width:${width};`"> <div class="chart" ref="chartRef" :style="`height:${height};width:${width};`">
<div v-if="!available" class="no-data">No Data</div> <div v-if="!available" class="no-data">No Data</div>
<div class="menus" v-show="visMenus" ref="menus"> <div
class="menus"
v-show="visMenus"
:style="{
top: menuPos.y + 'px',
left: menuPos.x + 'px',
}"
@mouseenter="hideTooltips"
>
<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 +44,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, reactive } 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 visMenus = ref<boolean>(false);
const visMenus = ref<boolean>(false); const { setOptions, resize, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
const { setOptions, resize, getInstance } = useECharts( const currentParams = ref<Nullable<EventParams>>(null);
chartRef as Ref<HTMLDivElement> const showTrace = ref<boolean>(false);
); const traceOptions = ref<{ type: string; filters?: unknown }>({
const currentParams = ref<Nullable<EventParams>>(null);
const showTrace = ref<boolean>(false);
const traceOptions = ref<{ type: string; filters?: unknown }>({
type: "Trace", type: "Trace",
}); });
const props = defineProps({ const menuPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
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 +83,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();
@@ -112,23 +104,41 @@ function instanceEvent() {
} }
instance.on("click", (params: EventParams) => { instance.on("click", (params: EventParams) => {
currentParams.value = params; currentParams.value = params;
if (!menus.value || !chartRef.value) { if (props.option.series.type === "sankey") {
emits("select", currentParams.value);
return; return;
} }
instance.dispatchAction({
type: "hideTip",
});
visMenus.value = true; visMenus.value = true;
if (!chartRef.value) {
return;
}
const w = chartRef.value.getBoundingClientRect().width || 0; const w = chartRef.value.getBoundingClientRect().width || 0;
const h = chartRef.value.getBoundingClientRect().height || 0; const h = chartRef.value.getBoundingClientRect().height || 0;
if (w - params.event.offsetX > 120) { if (w - params.event.offsetX > 120) {
menus.value.style.left = params.event.offsetX + "px"; menuPos.x = params.event.offsetX;
} else { } else {
menus.value.style.left = params.event.offsetX - 120 + "px"; menuPos.x = params.event.offsetX - 120;
} }
if (h - params.event.offsetY < 50) { if (h - params.event.offsetY < 50) {
menus.value.style.top = params.event.offsetY - 40 + "px"; menuPos.y = params.event.offsetY - 40;
} else { } else {
menus.value.style.top = params.event.offsetY + 2 + "px"; menuPos.y = params.event.offsetY;
} }
}); });
if (props.option.series.type === "sankey") {
return;
}
instance.on("mouseover", () => {
visMenus.value = false;
});
instance.on("mouseout", () => {
instance.dispatchAction({
type: "hideTip",
});
});
document.addEventListener( document.addEventListener(
"click", "click",
() => { () => {
@@ -136,26 +146,25 @@ function instanceEvent() {
return; return;
} }
visMenus.value = false; visMenus.value = false;
instance.dispatchAction({
type: "hideTip",
});
instance.dispatchAction({ instance.dispatchAction({
type: "updateAxisPointer", type: "updateAxisPointer",
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 || { updateOptions(currentParams.value || undefined);
dataIndex: 0, }
seriesIndex: 0,
};
updateOptions({ dataIndex, seriesIndex });
}
function updateOptions(params?: { dataIndex: number; seriesIndex: number }) { function updateOptions(params?: EventParams) {
const instance = getInstance(); const instance = getInstance();
if (!instance) { if (!instance) {
return; return;
@@ -169,20 +178,14 @@ function updateOptions(params?: { dataIndex: number; seriesIndex: number }) {
setOptions(options || props.option); setOptions(options || props.option);
} else { } else {
instance.dispatchAction({ instance.dispatchAction({
type: "updateAxisPointer", type: "showTip",
dataIndex: params ? params.dataIndex : props.filters.dataIndex, dataIndex: params ? params.dataIndex : props.filters.dataIndex,
seriesIndex: params ? params.seriesIndex : 0, seriesIndex: params ? params.seriesIndex : 0,
}); });
const ids = props.option.series.map((_: unknown, index: number) => index);
instance.dispatchAction({
type: "highlight",
dataIndex: params ? params.dataIndex : props.filters.dataIndex,
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 +193,16 @@ function viewTrace() {
}; };
showTrace.value = true; showTrace.value = true;
visMenus.value = true; visMenus.value = true;
} }
watch( function hideTooltips() {
const instance = getInstance();
instance.dispatchAction({
type: "hideTip",
});
}
watch(
() => props.option, () => props.option,
(newVal, oldVal) => { (newVal, oldVal) => {
if (!available.value) { if (!available.value) {
@@ -207,21 +217,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 +240,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 +258,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 +269,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

@@ -14,11 +14,20 @@
* 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.
*/ */
// https://docs.cypress.io/api/introduction/api.html 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", () => { describe("My First Test", () => {
it("Visits the app root url", () => { it("renders props.msg when passed", () => {
cy.visit("/"); const msg = "new message";
cy.contains("h1", "Welcome to Your Vue.js + TypeScript App"); 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

@@ -30,7 +30,6 @@ export enum Calculations {
ByteToMB = "byteToMB", ByteToMB = "byteToMB",
ByteToGB = "byteToGB", ByteToGB = "byteToGB",
Apdex = "apdex", Apdex = "apdex",
Precision = "precision",
ConvertSeconds = "convertSeconds", ConvertSeconds = "convertSeconds",
ConvertMilliseconds = "convertMilliseconds", ConvertMilliseconds = "convertMilliseconds",
MsToS = "msTos", MsToS = "msTos",
@@ -39,6 +38,8 @@ export enum Calculations {
ApdexAvg = "apdexAvg", ApdexAvg = "apdexAvg",
SecondToDay = "secondToDay", SecondToDay = "secondToDay",
NanosecondToMillisecond = "nanosecondToMillisecond", NanosecondToMillisecond = "nanosecondToMillisecond",
CPM5D = "cpm5d",
CPM5DAvg = "cpm5dAvg",
} }
export enum sizeEnum { export enum sizeEnum {
XS = "XS", XS = "XS",
@@ -67,7 +68,7 @@ screenMap.set(sizeEnum.LG, screenEnum.LG);
screenMap.set(sizeEnum.XL, screenEnum.XL); screenMap.set(sizeEnum.XL, screenEnum.XL);
screenMap.set(sizeEnum.XXL, screenEnum.XXL); screenMap.set(sizeEnum.XXL, screenEnum.XXL);
export const RespFields: any = { export const RespFields: { [key: string]: string } = {
readMetricsValues: `{ readMetricsValues: `{
label label
values { values {

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,38 +91,30 @@ 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;
} }
return { eventAssociate, traceFilters }; return { eventAssociate, traceFilters };
} }

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.CPM5DAvg];
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);
@@ -348,38 +291,26 @@ 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, Calculations.CPM5DAvg].includes(
Calculations.Average, c.calculation,
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) {
@@ -389,11 +320,9 @@ export function usePodsSource(
d[key] = {}; d[key] = {};
} }
if ( if (
[ [Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg].includes(
Calculations.Average, c.calculation,
Calculations.ApdexAvg, )
Calculations.PercentageAvg,
].includes(c.calculation)
) { ) {
d[key]["avg"] = calculateExp(item.values.values, c); d[key]["avg"] = calculateExp(item.values.values, c);
} }
@@ -435,13 +364,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:
@@ -453,6 +377,13 @@ function calculateExp(
case Calculations.ApdexAvg: case Calculations.ApdexAvg:
data = [(sum / arr.length / 10000).toFixed(2)]; data = [(sum / arr.length / 10000).toFixed(2)];
break; break;
case Calculations.CPM5DAvg:
data = [
sum / arr.length / 100000 < 1 && sum / arr.length / 100000 !== 0
? (sum / arr.length / 100000).toFixed(5)
: (sum / arr.length / 100000).toFixed(2),
];
break;
default: default:
data = arr.map((d) => aggregation(d.value, config)); data = arr.map((d) => aggregation(d.value, config));
break; break;
@@ -460,10 +391,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) {
@@ -485,15 +413,15 @@ export function aggregation(
case Calculations.Apdex: case Calculations.Apdex:
data = (val / 10000).toFixed(2); data = (val / 10000).toFixed(2);
break; break;
case Calculations.CPM5D:
data = val / 100000 < 1 && val / 100000 !== 0 ? (val / 100000).toFixed(5) : (val / 100000).toFixed(2);
break;
case Calculations.ConvertSeconds: case Calculations.ConvertSeconds:
data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss"); data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
break; break;
case Calculations.ConvertMilliseconds: case Calculations.ConvertMilliseconds:
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss"); data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
break; break;
case Calculations.Precision:
data = data.toFixed(2);
break;
case Calculations.MsToS: case Calculations.MsToS:
data = (val / 1000).toFixed(2); data = (val / 1000).toFixed(2);
break; break;
@@ -503,6 +431,12 @@ export function aggregation(
case Calculations.NanosecondToMillisecond: case Calculations.NanosecondToMillisecond:
data = (val / 1000 / 1000).toFixed(2); data = (val / 1000 / 1000).toFixed(2);
break; break;
case Calculations.ApdexAvg:
data = (val / 10000).toFixed(2);
break;
case Calculations.CPM5DAvg:
data = val / 100000 < 1 && val / 100000 !== 0 ? (val / 100000).toFixed(5) : (val / 100000).toFixed(2);
break;
default: default:
data; data;
break; break;
@@ -518,11 +452,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,9 @@ 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;
} overflow: auto;
}
</style> </style>

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="nav-bar flex-h"> <div class="nav-bar flex-h">
<div class="title">{{ appStore.pageTitle || t(pageName) }}</div> <div class="title">{{ route.name === "ViewWidget" ? "" : appStore.pageTitle || t(pageName) }}</div>
<div class="app-config"> <div class="app-config">
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span> <span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
<TimePicker <TimePicker
@@ -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,33 +97,33 @@ 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;
text-align: left; text-align: left;
justify-content: space-between; justify-content: space-between;
background-color: #fafbfc; background-color: #fafbfc;
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

@@ -13,28 +13,26 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
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. -->
<template> <template>
<div class="side-bar"> <div class="side-bar" v-if="showMenu" @click="isCollapse = false" @mouseleave="closeMenu">
<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>
<div class="menu scroll_bar_dark" :style="isCollapse ? {} : { width: '220px' }">
<el-menu <el-menu
active-text-color="#448dfe" active-text-color="#448dfe"
background-color="#252a2f" background-color="#252a2f"
class="el-menu-vertical" class="el-menu-vertical"
:default-active="name" :default-active="name"
text-color="#efefef" text-color="#efefef"
:unique-opened="true"
:collapse="isCollapse" :collapse="isCollapse"
:collapse-transition="false"
:style="{ border: 'none' }" :style="{ border: 'none' }"
> >
<template v-for="(menu, index) in routes" :key="index"> <template v-for="(menu, index) in routes" :key="index">
<el-sub-menu :index="String(menu.name)" v-if="menu.meta.hasGroup"> <el-sub-menu :index="String(menu.name)" v-if="menu.meta.hasGroup" popper-class="sub-list">
<template #title> <template #title>
<router-link class="items" :to="menu.path"> <router-link class="items" :to="menu.path">
<el-icon class="menu-icons" :style="{ marginRight: '12px' }"> <el-icon class="menu-icons" :style="{ marginRight: '12px' }" @mouseover="setCollapse">
<Icon size="lg" :iconName="menu.meta.icon" /> <Icon size="lg" :iconName="menu.meta.icon" />
</el-icon> </el-icon>
<span class="title" :class="isCollapse ? 'collapse' : ''"> <span class="title" :class="isCollapse ? 'collapse' : ''">
@@ -43,141 +41,132 @@ 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)" <el-icon class="menu-icons" :style="{ marginRight: '12px' }" @mouseover="setCollapse">
@click="changePage(menu)" <router-link class="items menu-title" :to="menu.children[0].path">
v-else
>
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
<router-link class="items" :to="menu.children[0].path">
<Icon size="lg" :iconName="menu.meta.icon" /> <Icon size="lg" :iconName="menu.meta.icon" />
</router-link> </router-link>
</el-icon> </el-icon>
<template #title> <template #title>
<router-link class="items" :to="menu.children[0].path"> <router-link class="items menu-title" :to="menu.children[0].path">
<span class="title">{{ t(menu.meta.title) }}</span> <span class="title">{{ t(menu.meta.title) }}</span>
</router-link> </router-link>
</template> </template>
</el-menu-item> </el-menu-item>
</template> </template>
</el-menu> </el-menu>
<div
class="menu-control"
:class="isCollapse ? 'collapse' : ''"
:style="{
color: theme === 'light' ? '#eee' : '#252a2f',
}"
>
<Icon
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, useRoute } 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"); const route = useRoute();
const routes = ref<RouteRecordRaw[] | any>(useRouter().options.routes); const isCollapse = ref(true);
if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) { const showMenu = ref(true);
const open = ref<boolean>(false);
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); if (route.name === "ViewWidget") {
const controlMenu = () => { showMenu.value = false;
isCollapse.value = !isCollapse.value; }
}; const changePage = (menu: RouteRecordRaw) => {
const changePage = (menu: RouteRecordRaw) => { theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) ? "light" : "black";
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) };
? "light" const filterMenus = (menus: any[]) => {
: "black";
};
const filterMenus = (menus: any[]) => {
return menus.filter((d) => d.meta && !d.meta.notShow); return menus.filter((d) => d.meta && !d.meta.notShow);
}; };
function setCollapse() {
open.value = true;
setTimeout(() => {
if (open.value) {
isCollapse.value = false;
}
open.value = false;
}, 1000);
}
function closeMenu() {
isCollapse.value = true;
open.value = false;
}
</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: 180px;
}
.menu {
height: calc(100% - 30px);
overflow: hidden;
}
.menu:hover {
overflow-y: auto; overflow-y: auto;
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: 14px;
} }
.logo-icon-collapse { .logo-icon-collapse {
width: 65px; width: 65px;
margin: 15px 0 10px 0; margin: 5px 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.collapse {
position: absolute;
top: 7px;
left: 220px;
cursor: pointer;
transition: all 0.2s linear;
z-index: 99;
color: #252a2f;
}
.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 +175,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

@@ -32,7 +32,7 @@ const msg = {
dashboards: "Dashboards", dashboards: "Dashboards",
profiles: "Profiles", profiles: "Profiles",
database: "Database", database: "Database",
mySQL: "MySQL", mySQL: "MySQL/MariaDB",
serviceName: "Service Name", serviceName: "Service Name",
technologies: "Technologies", technologies: "Technologies",
generalServicePanel: "General Service Panel", generalServicePanel: "General Service Panel",
@@ -176,11 +176,16 @@ 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",
iframeWidgetTip: "Add a link to a widget",
iframeSrc: "Iframe Link",
generateLink: "Generate Link",
setDuration: "Lock Query Duration",
openFunction: "OpenFunction",
period: "Period",
windows: "Windows",
seconds: "Seconds", seconds: "Seconds",
hourTip: "Select Hour", hourTip: "Select Hour",
minuteTip: "Select Minute", minuteTip: "Select Minute",
@@ -199,7 +204,7 @@ const msg = {
topology: "Topology", topology: "Topology",
trace: "Trace", trace: "Trace",
alarm: "Alerting", alarm: "Alerting",
auto: "Auto", auto: "Auto Fresh",
reload: "Reload", reload: "Reload",
version: "Version", version: "Version",
copy: "Copy", copy: "Copy",
@@ -315,8 +320,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,10 +374,13 @@ 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",
AWSCloud: "AWS Cloud",
AWSCloudEKS: "EKS",
AWSCloudS3: "S3",
AWSCloudDynamoDB: "DynamoDB",
}; };
export default msg; export default msg;

View File

@@ -32,7 +32,7 @@ const msg = {
dashboards: "Paneles", dashboards: "Paneles",
profiles: "Perfiles", profiles: "Perfiles",
database: "Base de Datos", database: "Base de Datos",
mySQL: "MySQL", mySQL: "MySQL/MariaDB",
serviceName: "Nombre Servicio", serviceName: "Nombre Servicio",
technologies: "Tecnologías", technologies: "Tecnologías",
generalServicePanel: "Panel Servicio General", generalServicePanel: "Panel Servicio General",
@@ -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",
@@ -164,6 +162,11 @@ const msg = {
latency: "Retraso", latency: "Retraso",
metricValues: "Valor métrico", metricValues: "Valor métrico",
legendValues: "Valor de la leyenda", legendValues: "Valor de la leyenda",
iframeWidgetTip: "Añadir enlaces a los gadgets",
iframeSrc: "Enlace Iframe",
generateLink: "Generar enlaces",
setDuration: "Duración de la consulta de bloqueo",
openFunction: "OpenFunction",
seconds: "Segundos", seconds: "Segundos",
hourTip: "Seleccione Hora", hourTip: "Seleccione Hora",
minuteTip: "Seleccione Minuto", minuteTip: "Seleccione Minuto",
@@ -180,11 +183,11 @@ 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",
period: "Period",
windows: "Windows",
second: "s", second: "s",
yearSuffix: "Año", yearSuffix: "Año",
monthsHead: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic", monthsHead: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
@@ -199,7 +202,7 @@ const msg = {
topology: "Topología", topology: "Topología",
trace: "Traza", trace: "Traza",
alarm: "Recordatorio en curso", alarm: "Recordatorio en curso",
auto: "Auto", auto: "Auto Fresh",
reload: "Recargar", reload: "Recargar",
version: "Versión", version: "Versión",
copy: "Copiar", copy: "Copiar",
@@ -315,8 +318,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 +349,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,14 +370,16 @@ 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",
gateway: "Puerta", gateway: "Puerta",
virtualMQ: "MQ virtual", virtualMQ: "MQ virtual",
AWSCloud: "AWS Cloud",
AWSCloudEKS: "EKS",
AWSCloudS3: "S3",
AWSCloudDynamoDB: "DynamoDB",
}; };
export default msg; export default msg;

View File

@@ -32,7 +32,7 @@ const msg = {
dashboards: "仪表盘", dashboards: "仪表盘",
profiles: "性能剖析", profiles: "性能剖析",
database: "数据库", database: "数据库",
mySQL: "MySQL", mySQL: "MySQL/MariaDB",
serviceName: "服务名称", serviceName: "服务名称",
technologies: "技术", technologies: "技术",
health: "健康", health: "健康",
@@ -176,6 +176,13 @@ const msg = {
when4xx: "当响应代码介于400和499之间时带有跟踪的HTTP请求和响应示例", when4xx: "当响应代码介于400和499之间时带有跟踪的HTTP请求和响应示例",
when5xx: "当响应代码介于500和599之间时带有跟踪的HTTP请求和响应示例", when5xx: "当响应代码介于500和599之间时带有跟踪的HTTP请求和响应示例",
taskTitle: "HTTP请求和响应收集规则", taskTitle: "HTTP请求和响应收集规则",
iframeWidgetTip: "添加widget的链接",
iframeSrc: "Iframe链接",
generateLink: "生成链接",
setDuration: "锁定查询持续时间",
openFunction: "OpenFunction",
period: "周期",
windows: "Windows",
seconds: "秒", seconds: "秒",
hourTip: "选择小时", hourTip: "选择小时",
minuteTip: "选择分钟", minuteTip: "选择分钟",
@@ -194,7 +201,7 @@ const msg = {
trace: "追踪", trace: "追踪",
alarm: "告警", alarm: "告警",
event: "事件", event: "事件",
auto: "自动", auto: "自动更新",
reload: "刷新", reload: "刷新",
editmode: "编辑模式", editmode: "编辑模式",
version: "版本", version: "版本",
@@ -282,12 +289,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 +314,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,10 +371,13 @@ const msg = {
addKeywordsOfContent: "请输入一个内容关键词", addKeywordsOfContent: "请输入一个内容关键词",
addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词", addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词",
noticeTag: "请输入一个标签(key=value)之后回车", noticeTag: "请输入一个标签(key=value)之后回车",
conditionNotice: conditionNotice: "请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
"请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
language: "语言", language: "语言",
gateway: "网关", gateway: "网关",
virtualMQ: "虚拟消息队列", virtualMQ: "虚拟消息队列",
AWSCloud: "AWS云服务",
AWSCloudEKS: "EKS",
AWSCloudS3: "S3",
AWSCloudDynamoDB: "DynamoDB",
}; };
export default msg; export default msg;

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,30 +161,36 @@ 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",
}, },
], ],
}, },
{
path: "",
name: "Widget",
component: () => import("@/views/dashboard/Widget.vue"),
meta: {
notShow: true,
},
children: [
{
path: "/page/:layer/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:config/:duration?",
component: () => import("@/views/dashboard/Widget.vue"),
name: "ViewWidget",
},
],
},
], ],
}, },
]; ];

79
src/router/data/aws.ts Normal file
View File

@@ -0,0 +1,79 @@
/**
* 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.
*/
export default [
{
path: "",
name: "AWSCloud",
meta: {
title: "AWSCloud",
icon: "cloud_queue",
hasGroup: true,
},
redirect: "/aws-eks",
children: [
{
path: "/aws-eks",
name: "AWSCloudEKS",
meta: {
title: "AWSCloudEKS",
layer: "AWS_EKS",
},
},
{
path: "/aws-eks/tab/:activeTabIndex",
name: "EKSActiveTabIndex",
meta: {
notShow: true,
layer: "AWS_EKS",
},
},
{
path: "/aws-s3",
name: "AWSCloudS3",
meta: {
title: "AWSCloudS3",
layer: "AWS_S3",
},
},
{
path: "/aws-s3/tab/:activeTabIndex",
name: "S3ActiveTabIndex",
meta: {
notShow: true,
layer: "AWS_S3",
},
},
{
path: "/aws-dynamodb",
name: "AWSCloudDynamoDB",
meta: {
title: "AWSCloudDynamoDB",
layer: "AWS_DYNAMODB",
},
},
{
path: "/aws-dynamodb/tab/:activeTabIndex",
name: "DynamoDBActiveTabIndex",
meta: {
notShow: true,
layer: "AWS_DYNAMODB",
},
},
],
},
];

View File

@@ -58,6 +58,22 @@ export default [
layer: "POSTGRESQL", layer: "POSTGRESQL",
}, },
}, },
{
path: "/aws-dynamodb",
name: "AWSCloudDynamoDB",
meta: {
title: "AWSCloudDynamoDB",
layer: "AWS_DYNAMODB",
},
},
{
path: "/aws-dynamodb/tab/:activeTabIndex",
name: "DynamoDBActiveTabIndex",
meta: {
notShow: true,
layer: "AWS_DYNAMODB",
},
},
], ],
}, },
]; ];

View File

@@ -21,18 +21,25 @@ export default [
name: "Functions", name: "Functions",
meta: { meta: {
title: "functions", title: "functions",
icon: "cloud_queue", icon: "functions",
layer: "FAAS", hasGroup: true,
}, },
redirect: "/functions",
children: [ children: [
{ {
path: "/functions", path: "/openFunction",
name: "Functions", name: "OpenFunction",
meta: {
title: "openFunction",
layer: "FAAS",
},
}, },
{ {
path: "/functions/tab/:activeTabIndex", path: "/openFunction/tab/:activeTabIndex",
name: "FunctionsActiveTabIndex", name: "OpenFunctionActiveTabIndex",
meta: {
notShow: true,
layer: "FAAS",
},
}, },
], ],
}, },

View File

@@ -23,6 +23,7 @@ import functions from "./functions";
import browser from "./browser"; import browser from "./browser";
import k8s from "./k8s"; import k8s from "./k8s";
import gateway from "./gateway"; import gateway from "./gateway";
import aws from "./aws";
export default [ export default [
...general, ...general,
@@ -30,6 +31,7 @@ export default [
...functions, ...functions,
...k8s, ...k8s,
...infrastructure, ...infrastructure,
...aws,
...browser, ...browser,
...gateway, ...gateway,
...database, ...database,

View File

@@ -43,6 +43,23 @@ export default [
layer: "OS_LINUX", layer: "OS_LINUX",
}, },
}, },
{
path: "/windows",
name: "Windows",
meta: {
title: "windows",
layer: "OS_WINDOWS",
},
},
{
path: "/windows/tab/:activeTabIndex",
name: "WindowsActiveTabIndex",
meta: {
title: "windows",
notShow: true,
layer: "OS_WINDOWS",
},
},
], ],
}, },
]; ];

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

@@ -37,3 +37,5 @@ export const TimeRangeConfig = {
textAlign: "center", textAlign: "center",
text: "text", text: "text",
}; };
export const ControlsTypes = ["Trace", "Profile", "Log", "DemandLog", "Ebpf", "NetworkProfiling", "ThirdPartyApp"];

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, ControlsTypes } 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";
@@ -40,6 +40,7 @@ interface DashboardState {
currentDashboard: Nullable<DashboardItem>; currentDashboard: Nullable<DashboardItem>;
editMode: boolean; editMode: boolean;
currentTabIndex: number; currentTabIndex: number;
showLinkConfig: boolean;
} }
export const dashboardStore = defineStore({ export const dashboardStore = defineStore({
@@ -58,6 +59,7 @@ export const dashboardStore = defineStore({
currentDashboard: null, currentDashboard: null,
editMode: false, editMode: false,
currentTabIndex: 0, currentTabIndex: 0,
showLinkConfig: false,
}), }),
actions: { actions: {
setLayout(data: LayoutConfig[]) { setLayout(data: LayoutConfig[]) {
@@ -66,6 +68,9 @@ export const dashboardStore = defineStore({
setMode(mode: boolean) { setMode(mode: boolean) {
this.editMode = mode; this.editMode = mode;
}, },
setWidgetLink(show: boolean) {
this.showLinkConfig = show;
},
resetDashboards(list: DashboardItem[]) { resetDashboards(list: DashboardItem[]) {
this.dashboards = list; this.dashboards = list;
sessionStorage.setItem("dashboards", JSON.stringify(list)); sessionStorage.setItem("dashboards", JSON.stringify(list));
@@ -105,24 +110,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 (ControlsTypes.includes(type)) {
[
"Trace",
"Profile",
"Log",
"DemandLog",
"Ebpf",
"NetworkProfiling",
].includes(type)
) {
newItem.h = 36; newItem.h = 36;
} }
if (type === "Text") { if (type === "Text") {
@@ -156,14 +147,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 +173,7 @@ export const dashboardStore = defineStore({
showDepth: true, showDepth: true,
}; };
} }
if ( if (ControlsTypes.includes(type)) {
[
"Trace",
"Profile",
"Log",
"DemandLog",
"Ebpf",
"NetworkProfiling",
].includes(type)
) {
newItem.h = 32; newItem.h = 32;
} }
if (type === "Text") { if (type === "Text") {
@@ -211,7 +191,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 +218,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 +234,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 +261,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 +285,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 +305,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 +337,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 +362,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 +371,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 +390,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,43 +411,37 @@ 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;
if (!json.status) {
ElMessage.error(json.message);
}
} }
if (res.data.errors || res.errors) { if (res.data.errors || res.errors) {
ElMessage.error(res.data.errors); ElMessage.error(res.data.errors);
return res.data; return res.data;
} }
if (!json.status) { if (!json.status) {
ElMessage.error(json.message);
return json; return json;
} }
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 +451,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 +462,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;
@@ -219,12 +211,12 @@ export const selectorStore = defineStore({
return res.data; return res.data;
}, },
async getProcess(instanceId: string, isRelation?: boolean) { async getProcess(processId: string, isRelation?: boolean) {
if (!instanceId) { if (!processId) {
return; return;
} }
const res: AxiosResponse = await graphql.query("queryProcess").params({ const res: AxiosResponse = await graphql.query("queryProcess").params({
instanceId, processId,
}); });
if (!res.data.errors) { if (!res.data.errors) {
if (isRelation) { if (isRelation) {

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,
}); });
@@ -232,12 +191,14 @@ export const topologyStore = defineStore({
return res.data.data.topology; return res.data.data.topology;
}, },
async getInstanceTopology() { async getInstanceTopology() {
const serverServiceId = useSelectorStore().currentService.id; const { currentService, currentDestService } = useSelectorStore();
const clientServiceId = useSelectorStore().currentDestService.id; const serverServiceId = (currentService && currentService.id) || "";
const clientServiceId = (currentDestService && currentDestService.id) || "";
const duration = useAppStoreWithOut().durationTime; const duration = useAppStoreWithOut().durationTime;
const res: AxiosResponse = await graphql if (!(serverServiceId && clientServiceId)) {
.query("getInstanceTopology") return;
.params({ }
const res: AxiosResponse = await graphql.query("getInstanceTopology").params({
clientServiceId, clientServiceId,
serverServiceId, serverServiceId,
duration, duration,
@@ -250,9 +211,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 +231,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 +242,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 +312,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 +326,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 +342,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 +369,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 +389,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 +398,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

@@ -14,6 +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.
*/ */
.flex-v { .flex-v {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -102,6 +103,13 @@
.mt-0 { .mt-0 {
margin-top: 0; margin-top: 0;
} }
.mt-10 {
margin-top: 10px;
}
.mt-20 {
margin-top: 20px;
}
.mb-5 { .mb-5 {
margin-bottom: 5px; margin-bottom: 5px;
@@ -189,3 +197,21 @@
box-shadow: inset 0 0 6px #ccc; box-shadow: inset 0 0 6px #ccc;
background-color: #aaa; background-color: #aaa;
} }
.scroll_bar_dark::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color: #666;
}
.scroll_bar_dark::-webkit-scrollbar-track {
background-color: #252a2f;
border-radius: 3px;
box-shadow: inset 0 0 6px #999;
}
.scroll_bar_dark::-webkit-scrollbar-thumb {
border-radius: 3px;
box-shadow: inset 0 0 6px #888;
background-color: #999;
}

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%;
} }
@@ -205,3 +204,11 @@ div.vis-tooltip {
.vis-item.vis-selected.Normal { .vis-item.vis-selected.Normal {
color: #1a1a1a !important; color: #1a1a1a !important;
} }
.el-menu--vertical.sub-list {
display: none;
}
div:has(> a.menu-title) {
display: none;
}

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();
} }

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