Compare commits
171 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4e64b9a4b1 | ||
![]() |
1be572a95f | ||
![]() |
5cc913a332 | ||
![]() |
220525a2d9 | ||
![]() |
72060f8227 | ||
![]() |
b247ed1c24 | ||
![]() |
b2707e0e62 | ||
![]() |
a1066f09e4 | ||
![]() |
efed817f73 | ||
![]() |
4613149759 | ||
![]() |
1877776720 | ||
![]() |
2b88266d67 | ||
![]() |
17b627a5d9 | ||
![]() |
5b0a68fe18 | ||
![]() |
d93ed2c5d3 | ||
![]() |
c73322a504 | ||
![]() |
4486684183 | ||
![]() |
1768a1641c | ||
![]() |
224053c0f4 | ||
![]() |
ca38366a60 | ||
![]() |
45f2985549 | ||
![]() |
3ef790dc07 | ||
![]() |
70df7605cb | ||
![]() |
4fc451f370 | ||
![]() |
163de5e5cf | ||
![]() |
8785817efe | ||
![]() |
db793e6c05 | ||
![]() |
d11ceab59d | ||
![]() |
1278454148 | ||
![]() |
7768f6ef16 | ||
![]() |
210b9ba491 | ||
![]() |
969580b770 | ||
![]() |
44dcb1e7f6 | ||
![]() |
1e0c253488 | ||
![]() |
141a288542 | ||
![]() |
154372615e | ||
![]() |
253f5c9261 | ||
![]() |
aa11a681ce | ||
![]() |
1f98619a5b | ||
![]() |
aab44626da | ||
![]() |
0ff5d4d6bb | ||
![]() |
611731d6d0 | ||
![]() |
221751f034 | ||
![]() |
d4dde7e73b | ||
![]() |
5be106fc4f | ||
![]() |
d8f91bbdf3 | ||
![]() |
23e9742946 | ||
![]() |
7a1c83b5fb | ||
![]() |
7d802d490e | ||
![]() |
da1db8def6 | ||
![]() |
2230d05508 | ||
![]() |
e8d909792d | ||
![]() |
dc842609ba | ||
![]() |
670bef1d69 | ||
![]() |
882828b04a | ||
![]() |
ed6fb0448b | ||
![]() |
a0fc879eb1 | ||
![]() |
b37d65eaac | ||
![]() |
fd46211a37 | ||
![]() |
ae0b8c056d | ||
![]() |
4b88d8bbb3 | ||
![]() |
09051e916b | ||
![]() |
e597f91448 | ||
![]() |
4232161d36 | ||
![]() |
eda44db0cd | ||
![]() |
78f0096c00 | ||
![]() |
5e161f17c2 | ||
![]() |
77d189cdfb | ||
![]() |
9f57e35119 | ||
![]() |
2bf90d6a6d | ||
![]() |
0f4319499a | ||
![]() |
5bb58a00cd | ||
![]() |
d50e9fc261 | ||
![]() |
b235929c77 | ||
![]() |
4561e2e374 | ||
![]() |
214b34ddfd | ||
![]() |
26817e9f92 | ||
![]() |
9ed0121fd0 | ||
![]() |
0d63d538c3 | ||
![]() |
5da441ff9a | ||
![]() |
49bc349064 | ||
![]() |
61a4d2f759 | ||
![]() |
0b4e738699 | ||
![]() |
b88356ba46 | ||
![]() |
d8889f1787 | ||
![]() |
1a989a1434 | ||
![]() |
82b348a766 | ||
![]() |
42b20660e4 | ||
![]() |
cb3aa940b3 | ||
![]() |
87a5553e6d | ||
![]() |
e17562a766 | ||
![]() |
fdfdaab47b | ||
![]() |
a4fc5192ac | ||
![]() |
ffabc7c7a7 | ||
![]() |
2fd5fb9b1e | ||
![]() |
adb457d660 | ||
![]() |
9c0bb988e6 | ||
![]() |
973b51e9ca | ||
![]() |
f5bcd5da2e | ||
![]() |
732b834749 | ||
![]() |
4b43196bc2 | ||
![]() |
b01565b2b8 | ||
![]() |
3b3e790dd9 | ||
![]() |
dc8e4bf273 | ||
![]() |
2ba3c67d31 | ||
![]() |
673b1a41a8 | ||
![]() |
c7079ea17c | ||
![]() |
017f5bf709 | ||
![]() |
bec86e80fd | ||
![]() |
ec7a8bbfa9 | ||
![]() |
4e022ff29a | ||
![]() |
42ead4a572 | ||
![]() |
e144b43267 | ||
![]() |
b5c07e023b | ||
![]() |
04d109d0e3 | ||
![]() |
024cd1195d | ||
![]() |
7fbd6170de | ||
![]() |
3ff3d5d1cd | ||
![]() |
2230702d97 | ||
![]() |
9ad9362935 | ||
![]() |
2be0a84d48 | ||
![]() |
4c762a2458 | ||
![]() |
7813c92673 | ||
![]() |
f12d7899e4 | ||
![]() |
b697fe4713 | ||
![]() |
0828f8a7aa | ||
![]() |
f9aa6600a7 | ||
![]() |
3c37d7c197 | ||
![]() |
c875c95c20 | ||
![]() |
30069ce825 | ||
![]() |
0a746a125b | ||
![]() |
4d26728eb5 | ||
![]() |
74cb089271 | ||
![]() |
b34c0b0c72 | ||
![]() |
45f896bf36 | ||
![]() |
f334985cf0 | ||
![]() |
f2e75f2b9f | ||
![]() |
b544decbbb | ||
![]() |
b953904c71 | ||
![]() |
7e0d716111 | ||
![]() |
21523b8cb5 | ||
![]() |
8c7fee4d86 | ||
![]() |
7f474984c4 | ||
![]() |
918791f7ed | ||
![]() |
784c2e97b8 | ||
![]() |
b492787027 | ||
![]() |
0e0f2704b3 | ||
![]() |
ca14a7d2c2 | ||
![]() |
49c4c96a6a | ||
![]() |
a0b57d0a5a | ||
![]() |
024a0fe44c | ||
![]() |
918b0551ad | ||
![]() |
d93a7cead2 | ||
![]() |
2a2500a28d | ||
![]() |
7d1bb43adb | ||
![]() |
4c1884d552 | ||
![]() |
f40e9633df | ||
![]() |
02f5c4b976 | ||
![]() |
8a07b1d804 | ||
![]() |
393885324b | ||
![]() |
6bfb7915bb | ||
![]() |
be60d5c770 | ||
![]() |
3c68a4a327 | ||
![]() |
f22208395a | ||
![]() |
26db1ec23e | ||
![]() |
69a9c6de13 | ||
![]() |
2dd9df19d7 | ||
![]() |
5dfbbacd14 | ||
![]() |
deb59705ae | ||
![]() |
3b4c3cc4ea | ||
![]() |
1d83e14f22 |
33
.eslintignore
Normal 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
@@ -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",
|
||||
},
|
||||
};
|
6
.github/workflows/nodejs.yml
vendored
@@ -37,16 +37,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
node-version: [14.x, 16.x, 18.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: npm install, lint, build, and test
|
||||
- name: npm ci, lint, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm ci
|
||||
npm run lint
|
||||
npm run build --if-present
|
||||
npm run test:unit
|
||||
|
34
.gitignore
vendored
@@ -16,24 +16,40 @@
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
/node
|
||||
|
||||
/tests/e2e/videos/
|
||||
/tests/e2e/screenshots/
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.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
|
||||
.idea
|
||||
|
27
.husky/commit-msg
Executable 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
@@ -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
@@ -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
|
@@ -28,6 +28,8 @@ header:
|
||||
- '.gitignore'
|
||||
- '.prettierrc'
|
||||
- '.browserslistrc'
|
||||
- 'src/types/auto-imports.d.ts'
|
||||
- 'src/types/components.d.ts'
|
||||
- '**/*.md'
|
||||
- '**/*.json'
|
||||
|
||||
|
21
.prettierignore
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
/src/types/auto-imports.d.ts
|
||||
/src/types/components.d.ts
|
22
.stylelintignore
Normal 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/*
|
20
README.md
@@ -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" />
|
||||
|
||||
@@ -10,11 +9,12 @@ Apache SkyWalking Booster UI
|
||||
This UI starts from SkyWalking OAP v9 core.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
|
||||
@@ -28,19 +28,21 @@ npm install
|
||||
### Build
|
||||
|
||||
**All following builds are for dev.**
|
||||
|
||||
```
|
||||
npm install
|
||||
npm run serve
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The default UI address is `http://localhost:8080`.
|
||||
|
||||
|
||||
# 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.
|
||||
* 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
|
||||
|
||||
- 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.
|
||||
- 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
|
||||
|
||||
[Apache 2.0 License.](/LICENSE)
|
||||
|
@@ -14,32 +14,37 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesDatabase: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Database",
|
||||
meta: {
|
||||
title: "database",
|
||||
icon: "storage",
|
||||
hasGroup: true,
|
||||
},
|
||||
redirect: "/database",
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/database",
|
||||
name: "Database",
|
||||
meta: {
|
||||
title: "virtualDatabase",
|
||||
headPath: "/database",
|
||||
exact: true,
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
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
@@ -14,7 +14,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const requireAll = (requireContext: Recordable) =>
|
||||
requireContext.keys().map(requireContext);
|
||||
const req = require.context("./", true, /\.svg$/);
|
||||
requireAll(req);
|
||||
|
||||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
specPattern: "cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}",
|
||||
baseUrl: "http://localhost:4173",
|
||||
},
|
||||
});
|
@@ -14,10 +14,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
describe("My First Test", () => {
|
||||
it("renders props.msg when passed", () => {
|
||||
const msg = "new message";
|
||||
console.log(msg);
|
||||
it("visits the app root url", () => {
|
||||
cy.visit("/");
|
||||
cy.contains("h1", "You did it!");
|
||||
});
|
||||
});
|
26
cypress/e2e/tsconfig.json
Normal 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"]
|
||||
}
|
||||
}
|
@@ -14,6 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@import "./grid.scss";
|
||||
@import "./lib.scss";
|
||||
@import "./reset.scss";
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@@ -14,8 +14,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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
|
||||
// existing commands.
|
||||
//
|
||||
@@ -26,16 +27,29 @@
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- 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 --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
export {};
|
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
26
env.d.ts
vendored
Normal 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;
|
||||
}
|
@@ -13,19 +13,15 @@ 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. -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Apache SkyWalking</title>
|
||||
</head>
|
||||
<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>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
50229
package-lock.json
generated
155
package.json
@@ -1,140 +1,103 @@
|
||||
{
|
||||
"name": "skywalking-booster-ui",
|
||||
"version": "0.1.0",
|
||||
"version": "9.4.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"lint": "vue-cli-service lint"
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check build-only",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "vitest --environment jsdom --root src/",
|
||||
"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": {
|
||||
"axios": "^0.24.0",
|
||||
"d3": "^7.3.0",
|
||||
"d3-flame-graph": "^4.1.3",
|
||||
"d3-tip": "^0.9.1",
|
||||
"echarts": "^5.2.2",
|
||||
"element-plus": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"pinia": "^2.0.5",
|
||||
"vue": "^3.0.0",
|
||||
"monaco-editor": "^0.34.1",
|
||||
"pinia": "^2.0.28",
|
||||
"vis-timeline": "^7.5.1",
|
||||
"vue": "^3.2.45",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vue-types": "^4.1.1",
|
||||
"vuex": "^4.0.0-0"
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-types": "^4.1.1"
|
||||
},
|
||||
"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-tip": "^3.5.5",
|
||||
"@types/echarts": "^4.9.12",
|
||||
"@types/jest": "^24.0.19",
|
||||
"@types/jsdom": "^20.0.1",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@types/node": "^18.11.12",
|
||||
"@types/three": "^0.131.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-e2e-cypress": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||
"@vue/cli-plugin-unit-jest": "~4.5.0",
|
||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^7.0.0",
|
||||
"@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",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.0",
|
||||
"@vue/test-utils": "^2.2.6",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"cypress": "^12.0.2",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-vue": "^9.3.0",
|
||||
"husky": "^8.0.2",
|
||||
"jsdom": "^20.0.3",
|
||||
"lint-staged": "^12.1.3",
|
||||
"node-sass": "^6.0.1",
|
||||
"node-sass": "^8.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-html": "^1.3.0",
|
||||
"postcss-scss": "^4.0.2",
|
||||
"prettier": "^2.2.1",
|
||||
"sass-loader": "^10.2.0",
|
||||
"prettier": "^2.7.1",
|
||||
"sass": "^1.56.1",
|
||||
"start-server-and-test": "^1.15.2",
|
||||
"stylelint": "^14.1.0",
|
||||
"stylelint-config-html": "^1.0.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-standard": "^24.0.0",
|
||||
"stylelint-order": "^5.0.0",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
"typescript": "~4.4.4",
|
||||
"vue-jest": "^5.0.0-0"
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
]
|
||||
"typescript": "~4.7.4",
|
||||
"unplugin-auto-import": "^0.7.0",
|
||||
"unplugin-vue-components": "^0.19.2",
|
||||
"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"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
],
|
||||
"jest": {
|
||||
"preset": "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
|
||||
"transform": {
|
||||
"^.+\\.vue$": "vue-jest"
|
||||
}
|
||||
},
|
||||
"gitHooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
"*.{js,jsx,ts,tsx,vue}": [
|
||||
"eslint . --ext .vue,.js,.jsx,.ts,.tsx --fix --ignore-path .gitignore",
|
||||
"prettier --write \"src/**/*.{js,tsx,css,less,scss,vue,html,md}\"",
|
||||
"stylelint --cache --fix \"**/*.{vue}\" --cache --cache-location node_modules/.cache/stylelint/"
|
||||
],
|
||||
"*.vue": [
|
||||
"eslint --fix",
|
||||
"prettier --write",
|
||||
"stylelint --fix --custom-syntax postcss-html"
|
||||
"*.{scss,less}": [
|
||||
"prettier --write \"src/**/*.{js,tsx,css,less,scss,vue,html,md}\"",
|
||||
"stylelint --cache --fix \"**/*.{less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/"
|
||||
],
|
||||
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
|
||||
"prettier --write--parser json"
|
||||
],
|
||||
"package.json": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{scss,less,styl,html}": [
|
||||
"stylelint --fix",
|
||||
"package.json": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.md": [
|
||||
|
@@ -14,8 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
@@ -14,13 +14,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
plugins: ["cypress"],
|
||||
env: {
|
||||
mocha: true,
|
||||
"cypress/globals": true,
|
||||
},
|
||||
rules: {
|
||||
strict: "off",
|
||||
},
|
||||
printWidth: 120,
|
||||
semi: true,
|
||||
vueIndentScriptAndStyle: true,
|
||||
trailingComma: "all",
|
||||
proseWrap: "never",
|
||||
htmlWhitespaceSensitivity: "strict",
|
||||
endOfLine: "auto",
|
||||
};
|
19
src/App.vue
@@ -13,11 +13,24 @@ 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. -->
|
||||
<template>
|
||||
<router-view :key="$route.fullPath" />
|
||||
<router-view />
|
||||
</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>
|
||||
#app {
|
||||
#app {
|
||||
color: #2c3e50;
|
||||
height: 100%;
|
||||
}
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
15
src/assets/icons/add_fill.svg
Normal 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="1655799536378" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9286" width="48" height="48"><path d="M563.2 614.4v51.2c0 30.72-20.48 51.2-51.2 51.2s-51.2-20.48-51.2-51.2v-51.2H409.6c-30.72 0-51.2-20.48-51.2-51.2s20.48-51.2 51.2-51.2h51.2V460.8c0-30.72 20.48-51.2 51.2-51.2s51.2 20.48 51.2 51.2v51.2h51.2c30.72 0 51.2 20.48 51.2 51.2s-20.48 51.2-51.2 51.2h-51.2z m51.2-563.2c158.72 15.36 281.6 143.36 281.6 307.2v512c0 56.32-46.08 102.4-102.4 102.4h-563.2c-56.32 0-102.4-46.08-102.4-102.4V153.6c0-56.32 46.08-102.4 102.4-102.4H614.4z m163.84 230.4c-25.6-61.44-76.8-107.52-138.24-122.88v71.68c0 30.72 20.48 51.2 51.2 51.2h87.04zM537.6 153.6h-256c-30.72 0-51.2 20.48-51.2 51.2v614.4c0 30.72 20.48 51.2 51.2 51.2h460.8c30.72 0 51.2-20.48 51.2-51.2V384h-153.6c-56.32 0-102.4-46.08-102.4-102.4V153.6z" fill="#707070" p-id="9287"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
15
src/assets/icons/add_iframe.svg
Normal 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 |
16
src/assets/icons/arrow-down.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- 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 xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path id="a" d="m10.472352 7.28232367c.3431062-.36783247.904419-.36783247 1.2592596-.00644059.3578153.36442148.3578153.95850784.0002156 1.28561559l-3.10532264 3.16826253c-.17025689.1734002-.39845625.2702388-.62654793.2702388-.24380864 0-.45151514-.0919745-.62697852-.2706782l-3.09835734-3.16693764c-.36405333-.352236-.36405333-.94614513-.01248284-1.28566765.34310619-.36783247.90441901-.36783247 1.25901327-.0066912l2.48658215 2.52737493z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
15
src/assets/icons/circle.svg
Normal 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="1667899293763" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4705" width="16" height="16"><path d="M512 512m-368 0a368 368 0 1 0 736 0 368 368 0 1 0-736 0Z" p-id="4706"></path></svg>
|
After Width: | Height: | Size: 1001 B |
@@ -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.
|
||||
See the License for the specific language governing permissions and
|
||||
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>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
16
src/assets/icons/conditions.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<!-- 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="1666624449554" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2649" width="48" height="48"><path d="M381.482667 673.877333a90.389333 90.389333 0 0 1 85.226666 60.245334H853.333333v64H465.28a90.389333 90.389333 0 0 1-167.573333 0H170.666667v-64h125.610666a90.389333 90.389333 0 0 1 85.205334-60.245334z m0 64a26.346667 26.346667 0 1 0 0 52.693334 26.346667 26.346667 0 0 0 0-52.693334z m261.034666-304.938666a90.389333 90.389333 0 0 1 85.205334 60.245333H853.333333v64h-127.04a90.389333 90.389333 0 0 1-167.573333 0H170.666667v-64h386.624a90.389333 90.389333 0 0 1 85.226666-60.245333z m0 64a26.346667 26.346667 0 1 0 0 52.693333 26.346667 26.346667 0 0 0 0-52.693333zM381.482667 192a90.389333 90.389333 0 0 1 85.226666 60.224H853.333333v64H465.28a90.389333 90.389333 0 0 1-167.573333 0H170.666667v-64h125.610666A90.389333 90.389333 0 0 1 381.482667 192z m0 64a26.346667 26.346667 0 1 0 0 52.693333 26.346667 26.346667 0 0 0 0-52.693333z" p-id="2650"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
@@ -12,4 +12,4 @@ 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="1648717513168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15451" width="48" height="48"><path d="M810.666667 213.333333v597.333334H213.333333V213.333333h597.333334m85.333333-85.333333H128v768h768V128z m-512 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m-170.666667 170.666666h-85.333333v85.333334h85.333333z m170.666667 0h-85.333334v85.333334h85.333334z m-170.666667 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m170.666666-341.333333h-85.333333v85.333333h85.333333z m0 170.666666h-85.333333v85.333334h85.333333z m0 170.666667h-85.333333v85.333333h85.333333z" p-id="15452" fill="#515151"></path></svg>
|
||||
<svg t="1648717513168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15451" width="48" height="48"><path d="M810.666667 213.333333v597.333334H213.333333V213.333333h597.333334m85.333333-85.333333H128v768h768V128z m-512 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m-170.666667 170.666666h-85.333333v85.333334h85.333333z m170.666667 0h-85.333334v85.333334h85.333334z m-170.666667 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m170.666666-341.333333h-85.333333v85.333333h85.333333z m0 170.666666h-85.333333v85.333334h85.333333z m0 170.666667h-85.333333v85.333333h85.333333z" p-id="15452"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
15
src/assets/icons/copy.svg
Normal 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="1664265269855" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4109" width="48" height="48"><path d="M866.461538 39.384615H354.461538c-43.323077 0-78.769231 35.446154-78.76923 78.769231v39.384616h472.615384c43.323077 0 78.769231 35.446154 78.769231 78.76923v551.384616h39.384615c43.323077 0 78.769231-35.446154 78.769231-78.769231V118.153846c0-43.323077-35.446154-78.769231-78.769231-78.769231z m-118.153846 275.692308c0-43.323077-35.446154-78.769231-78.76923-78.769231H157.538462c-43.323077 0-78.769231 35.446154-78.769231 78.769231v590.769231c0 43.323077 35.446154 78.769231 78.769231 78.769231h512c43.323077 0 78.769231-35.446154 78.76923-78.769231V315.076923z m-354.461538 137.846154c0 11.815385-7.876923 19.692308-19.692308 19.692308h-157.538461c-11.815385 0-19.692308-7.876923-19.692308-19.692308v-39.384615c0-11.815385 7.876923-19.692308 19.692308-19.692308h157.538461c11.815385 0 19.692308 7.876923 19.692308 19.692308v39.384615z m157.538461 315.076923c0 11.815385-7.876923 19.692308-19.692307 19.692308H216.615385c-11.815385 0-19.692308-7.876923-19.692308-19.692308v-39.384615c0-11.815385 7.876923-19.692308 19.692308-19.692308h315.076923c11.815385 0 19.692308 7.876923 19.692307 19.692308v39.384615z m78.769231-157.538462c0 11.815385-7.876923 19.692308-19.692308 19.692308H216.615385c-11.815385 0-19.692308-7.876923-19.692308-19.692308v-39.384615c0-11.815385 7.876923-19.692308 19.692308-19.692308h393.846153c11.815385 0 19.692308 7.876923 19.692308 19.692308v39.384615z" p-id="4110"></path></svg>
|
After Width: | Height: | Size: 2.3 KiB |
16
src/assets/icons/demand.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<!-- 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="1654161407133" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1721" width="16" height="16"><path d="M804.224 86.144c0-19.264-15.616-34.944-34.944-34.944l-734.336 0c-19.264 0-34.944 15.68-34.944 34.944l0 82.048 804.224 0 0-82.048zM738.88 602.432c0 47.072-38.176 85.248-85.248 85.248s-85.248-38.176-85.248-85.248c0-47.072 38.176-85.248 85.248-85.248s85.248 38.176 85.248 85.248zM804.992 264.64l0-62.976-804.224 0 0 665.408c0 18.56 14.656 33.472 32.96 34.56l402.24 0c61.12 44.544 136.192 71.168 217.664 71.168 204.544 0 370.368-165.824 370.368-370.368 0-150.592-89.984-279.936-219.008-337.792zM412.096 298.24l30.528 0c-10.624 7.36-20.8 15.36-30.528 23.744l0-23.744zM63.04 298.24l153.024 0 0 153.024-153.024 0 0-153.024zM216.064 805.056l-153.024 0 0-153.024 153.024 0 0 153.024zM219.136 631.232l-153.024 0 0-153.024 153.024 0 0 153.024zM237.568 805.056l0-153.024 49.408 0c7.488 55.936 27.264 107.904 56.832 153.024l-106.24 0zM284.672 631.232l-44.032 0 0-153.024 64.384 0c-13.824 38.848-21.824 80.576-21.824 124.224 0 9.728 0.768 19.264 1.472 28.8zM390.592 341.76c-31.168 31.424-56.512 68.544-74.88 109.44l-78.144 0 0-152.96 153.024 0 0 43.52zM899.136 638.4l-63.36 12.864c-4.288 16.064-10.688 31.296-18.816 45.376l35.712 53.888-50.944 50.944-53.888-35.712c-14.08 8.128-29.312 14.528-45.376 18.816l-12.864 63.36-72 0-12.864-63.36c-16.064-4.288-31.296-10.688-45.376-18.816l-53.888 35.712-50.944-50.944 35.712-53.888c-8.128-14.08-14.528-29.312-18.816-45.376l-63.36-12.864 0-72 63.36-12.864c4.352-16.064 10.688-31.296 18.816-45.312l-35.712-53.952 50.944-50.944 53.888 35.776c14.08-8.128 29.312-14.464 45.376-18.816l12.864-63.36 72 0 12.864 63.36c16.064 4.288 31.296 10.688 45.376 18.816l53.888-35.712 50.944 50.944-35.712 53.824c8.128 14.08 14.528 29.312 18.816 45.376l63.36 12.864 0 72z" p-id="1722" fill="#707070"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
15
src/assets/icons/event.svg
Normal 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="1655695739627" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2218" width="48" height="48"><path d="M173.292308 177.230769C86.646154 265.846154 39.384615 382.030769 39.384615 504.123077 39.384615 531.692308 61.046154 551.384615 86.646154 551.384615s47.261538-21.661538 47.261538-47.261538c-1.969231-96.492308 37.415385-189.046154 106.338462-257.969231s163.446154-106.338462 257.969231-106.338461c27.569231 0 47.261538-21.661538 47.261538-47.261539 0-27.569231-21.661538-47.261538-47.261538-47.261538C378.092308 43.323077 259.938462 90.584615 173.292308 177.230769z m57.107692 326.892308c0 27.569231 19.692308 47.261538 47.261538 47.261538s47.261538-21.661538 47.261539-47.261538c0-45.292308 17.723077-90.584615 51.2-122.092308 33.476923-33.476923 76.8-49.230769 122.092308-51.2 27.569231 0 47.261538-21.661538 47.261538-47.261538 0-27.569231-19.692308-47.261538-47.261538-47.261539-70.892308 0-139.815385 27.569231-191.015385 76.8-7.876923 9.846154-80.738462 82.707692-76.8 191.015385z m665.6-204.8c-17.723077-23.630769-41.353846-51.2-45.292308-55.138462-5.907692-3.938462-13.784615-7.876923-21.661538-7.876923-7.876923 0-15.753846 1.969231-19.692308 7.876923L610.461538 441.107692c-47.261538-39.384615-118.153846-37.415385-163.446153 7.876923-45.292308 45.292308-47.261538 116.184615-7.876923 163.446154l-191.015385 191.015385c-5.907692 5.907692-9.846154 13.784615-9.846154 21.661538 0 9.846154 3.938462 19.692308 11.815385 25.6l53.16923 39.384616c72.861538 57.107692 163.446154 88.615385 259.938462 88.615384 232.369231 0 421.415385-189.046154 421.415385-421.415384 0-94.523077-33.476923-185.107692-88.615385-257.969231z" p-id="2219" fill="#707070"></path></svg>
|
After Width: | Height: | Size: 2.4 KiB |
15
src/assets/icons/functions.svg
Normal 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 |
15
src/assets/icons/gateway.svg
Normal 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="1664244255409" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2266" width="48" height="48"><path d="M523.776 430.592l-153.088 88.576 153.088 88.576 152.576-88.576-152.576-88.576z m-165.888 108.544l0.512 177.152 153.6 87.552-1.024-176.64-153.088-88.064z m330.24 0l-153.6 87.552-1.024 176.64 153.6-87.552 1.024-176.64z m131.072 205.824l-68.096-40.96 39.936-8.704-5.632-26.112-67.072 14.848-13.824 23.04 101.376 60.928 13.312-23.04z m-142.848 7.68l68.096 40.96-39.936 8.704 5.632 26.112 67.072-14.848 13.824-23.04-101.888-60.928-12.8 23.04zM481.28 424.96h26.624V306.176H481.28v79.36l-27.648-29.696-19.456 18.432L481.28 424.96z m53.76-118.784V424.96h26.624V345.088l27.648 29.696 19.456-18.432-47.104-50.176h-26.624z m-190.464 401.92l-13.312-23.04-68.608 40.448 11.264-38.912-25.6-7.168-18.944 66.048 13.312 23.04 101.888-60.416z m-89.088 82.944l13.312 23.04 68.608-39.936-11.264 38.912 25.6 7.168 19.456-66.048-13.312-23.04-102.4 59.904z m622.08-45.056c-45.568 0-82.432 36.864-82.432 82.432 0 45.568 36.864 82.432 82.432 82.432 45.568 0 82.432-36.864 82.432-82.432 0-45.568-36.864-82.432-82.432-82.432z m0 122.88c-22.528 0-40.448-17.92-40.448-40.448s17.92-40.448 40.448-40.448 40.448 17.92 40.448 40.448-17.92 40.448-40.448 40.448zM521.728 292.864c45.568 0 82.432-36.864 82.432-82.432 0-45.568-36.864-82.432-82.432-82.432-45.568 0-82.432 36.864-82.432 82.432 0 45.568 36.864 82.432 82.432 82.432z m0-122.88c22.528 0 40.448 17.92 40.448 40.448s-17.92 40.448-40.448 40.448-40.448-17.92-40.448-40.448 18.432-40.448 40.448-40.448zM167.936 749.056c-45.568 0-82.432 36.864-82.432 82.432 0 45.568 36.864 82.432 82.432 82.432 45.568 0 82.432-36.864 82.432-82.432 0-45.568-36.864-82.432-82.432-82.432z m0 122.88c-22.528 0-40.448-17.92-40.448-40.448s17.92-40.448 40.448-40.448 40.448 17.92 40.448 40.448-18.432 40.448-40.448 40.448z" p-id="2267"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
@@ -13,6 +13,5 @@ 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>info_outline</title>
|
||||
<path d="M11.016 9v-2.016h1.969v2.016h-1.969zM12 20.016q3.281 0 5.648-2.367t2.367-5.648-2.367-5.648-5.648-2.367-5.648 2.367-2.367 5.648 2.367 5.648 5.648 2.367zM12 2.016q4.125 0 7.055 2.93t2.93 7.055-2.93 7.055-7.055 2.93-7.055-2.93-2.93-7.055 2.93-7.055 7.055-2.93zM11.016 17.016v-6h1.969v6h-1.969z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
17
src/assets/icons/insert_chart.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M17.016 17.016v-4.031h-2.016v4.031h2.016zM12.984 17.016v-10.031h-1.969v10.031h1.969zM9 17.016v-7.031h-2.016v7.031h2.016zM18.984 3q0.797 0 1.406 0.609t0.609 1.406v13.969q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-13.969q0-0.797 0.609-1.406t1.406-0.609h13.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
17
src/assets/icons/keyboard_arrow_down.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M7.406 8.578l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 946 B |
17
src/assets/icons/keyboard_arrow_up.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M7.406 15.422l-1.406-1.406 6-6 6 6-1.406 1.406-4.594-4.594z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 948 B |
17
src/assets/icons/library_add.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M18.984 11.016v-2.016h-3.984v-3.984h-2.016v3.984h-3.984v2.016h3.984v3.984h2.016v-3.984h3.984zM20.016 2.016q0.797 0 1.383 0.586t0.586 1.383v12q0 0.797-0.586 1.406t-1.383 0.609h-12q-0.797 0-1.406-0.609t-0.609-1.406v-12q0-0.797 0.609-1.383t1.406-0.586h12zM3.984 6v14.016h14.016v1.969h-14.016q-0.797 0-1.383-0.586t-0.586-1.383v-14.016h1.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
15
src/assets/icons/operation.svg
Normal 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="1664266918236" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" width="48" height="48"><path d="M571.178667 643.328a144 144 0 0 1-189.098667-193.450667l77.781333 77.866667a48 48 0 1 0 67.882667-67.84l-77.824-77.909333a144 144 0 0 1 193.450667 189.141333l226.517333 207.061333a64.896 64.896 0 1 1-91.690667 91.690667l-207.018666-226.56z m51.498666 134.656a288.298667 288.298667 0 0 1-38.656 12.928v95.488c0 5.290667-4.309333 9.6-9.642666 9.6h-124.757334a9.6 9.6 0 0 1-9.6-9.6v-95.488a286.293333 286.293333 0 0 1-74.325333-30.805333l-67.541333 67.541333a9.6 9.6 0 0 1-13.568 0L196.352 739.413333a9.6 9.6 0 0 1 0-13.568l67.541333-67.541333a286.293333 286.293333 0 0 1-30.805333-74.325333H137.6A9.6 9.6 0 0 1 128 574.378667v-124.757334c0-5.290667 4.309333-9.6 9.6-9.6h95.488c6.826667-26.453333 17.28-51.370667 30.805333-74.325333L196.352 298.154667a9.6 9.6 0 0 1 0-13.568L284.586667 196.352a9.6 9.6 0 0 1 13.568 0l67.541333 67.498667a287.146667 287.146667 0 0 1 74.325333-30.848V137.6c0-5.290667 4.266667-9.6 9.6-9.6h124.8c5.248 0 9.6 4.309333 9.6 9.6v95.488c26.368 6.826667 51.328 17.28 74.282667 30.805333l67.541333-67.541333a9.6 9.6 0 0 1 13.568 0l88.234667 88.234667a9.6 9.6 0 0 1 0 13.568l-67.498667 67.541333a287.146667 287.146667 0 0 1 30.848 74.282667h95.402667c5.290667 0 9.6 4.352 9.6 9.642666v124.757334c0 5.333333-4.266667 9.6-9.6 9.6h-95.488c-4.693333 18.133333-11.178667 35.754667-19.328 52.650666a9.6 9.6 0 0 1-15.018667 2.986667l-10.112-9.173333-38.314666-34.261334-12.16-10.88a9.6 9.6 0 0 1-2.688-10.24A192.298667 192.298667 0 0 0 512 320a192 192 0 1 0 63.018667 373.333333 9.6 9.6 0 0 1 10.24 2.645334l10.837333 12.074666 35.285333 39.338667 8.149334 9.130667a9.6 9.6 0 0 1-2.901334 15.061333 283.306667 283.306667 0 0 1-13.952 6.4z" p-id="5379"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
16
src/assets/icons/setting_empty.svg
Normal file
After Width: | Height: | Size: 5.7 KiB |
19
src/assets/icons/time_range.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- 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="1660976558460" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="813" width="48" height="48">
|
||||
<path d="M498.596 482.29H345.42v57.308h210.478V274.197h-57.301V482.29z m0 0M577.685 644.985h379.88v57.302h-379.88v-57.302z m0 0M577.685 773.765h379.88v57.307h-379.88v-57.307z m0 0M577.685 902.55h379.88v57.307h-379.88V902.55z m0 0" p-id="814"></path>
|
||||
<path d="M102.523 382.29a28.668 28.668 0 0 0 23.367 2.56l190.81-61.886c15.053-4.883 23.298-21.04 18.415-36.09-4.882-15.052-21.04-23.297-36.093-18.415l-123.346 40c15.994-26.117 35.17-50.538 57.37-72.745 73.768-73.767 171.847-114.388 276.169-114.388 104.32 0 202.395 40.622 276.161 114.388S899.77 407.56 899.77 511.882c0 26.428-2.616 52.45-7.71 77.78h58.303c4.465-25.499 6.709-51.47 6.709-77.78 0-60.45-11.846-119.102-35.205-174.336-22.56-53.335-54.85-101.227-95.969-142.35-41.122-41.122-89.017-73.408-142.348-95.968-55.233-23.361-113.89-35.207-174.334-35.207-60.45 0-119.107 11.846-174.337 35.208-53.335 22.56-101.23 54.846-142.35 95.969-23.98 23.98-44.933 50.278-62.727 78.6l-20.738-105.654c-3.043-15.528-18.105-25.642-33.632-22.6-15.528 3.048-25.643 18.105-22.6 33.637l36.103 183.932a28.666 28.666 0 0 0 13.588 19.178z m0 0M126.02 587.942H67.768c5.76 33.679 15.368 66.544 28.79 98.278 22.56 53.334 54.85 101.225 95.972 142.348 41.123 41.123 89.014 73.409 142.349 95.969 54.112 22.888 111.518 34.711 170.668 35.182v-57.324c-102.95-0.941-199.595-41.446-272.5-114.349-55.501-55.502-92.237-124.77-107.027-200.104z m0 0" p-id="815">
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
@@ -13,6 +13,5 @@ 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>timeline</title>
|
||||
<path d="M23.016 8.016q0 0.797-0.609 1.383t-1.406 0.586h-0.047q-0.328 0-0.469-0.047l-3.563 3.563q0.094 0.281 0.094 0.516 0 0.797-0.609 1.383t-1.406 0.586-1.406-0.586-0.609-1.383q0-0.234 0.094-0.516l-2.578-2.578q-0.281 0.094-0.516 0.094t-0.516-0.094l-4.547 4.547q0.094 0.281 0.094 0.516 0 0.797-0.609 1.406t-1.406 0.609-1.406-0.609-0.609-1.406 0.609-1.383 1.406-0.586q0.375 0 0.516 0.047l4.547-4.547q-0.047-0.141-0.047-0.516 0-0.797 0.586-1.406t1.383-0.609 1.406 0.609 0.609 1.406q0 0.375-0.047 0.516l2.531 2.531q0.141-0.047 0.516-0.047t0.516 0.047l3.563-3.516q-0.094-0.281-0.094-0.516 0-0.797 0.609-1.406t1.406-0.609 1.406 0.609 0.609 1.406z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
15
src/assets/icons/view.svg
Normal 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="1650287922642" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3055" width="48" height="48"><path d="M277.333333 325.333333m5.333334 0l325.333333 0q5.333333 0 5.333333 5.333334l0 64q0 5.333333-5.333333 5.333333l-325.333333 0q-5.333333 0-5.333334-5.333333l0-64q0-5.333333 5.333334-5.333334Z" p-id="3056" fill="#707070"></path><path d="M277.333333 474.666667m5.333334 0l325.333333 0q5.333333 0 5.333333 5.333333l0 64q0 5.333333-5.333333 5.333333l-325.333333 0q-5.333333 0-5.333334-5.333333l0-64q0-5.333333 5.333334-5.333333Z" p-id="3057" fill="#707070"></path><path d="M277.333333 624m5.333334 0l247.36 0q5.333333 0 5.333333 5.333333l0 64q0 5.333333-5.333333 5.333334l-247.36 0q-5.333333 0-5.333334-5.333334l0-64q0-5.333333 5.333334-5.333333Z" p-id="3058" fill="#707070"></path><path d="M565.333333 842.666667H186.666667a5.333333 5.333333 0 0 1-5.333334-5.333334V186.666667a5.333333 5.333333 0 0 1 5.333334-5.333334h522.666666v346.24a5.333333 5.333333 0 0 0 5.333334 5.333334h64a5.333333 5.333333 0 0 0 5.333333-5.333334V106.666667H112a5.333333 5.333333 0 0 0-5.333333 5.333333v800a5.333333 5.333333 0 0 0 5.333333 5.333333h453.333333a5.333333 5.333333 0 0 0 5.333334-5.333333v-64a5.333333 5.333333 0 0 0-5.333334-5.333333z" p-id="3059" fill="#707070"></path><path d="M868.426667 723.786667a144.64 144.64 0 1 0-144.64 144.64 144.64 144.64 0 0 0 144.64-144.64z m-144.64 69.973333a69.973333 69.973333 0 1 1 69.973333-69.973333 70.026667 70.026667 0 0 1-69.973333 69.973333z" p-id="3060" fill="#707070"></path><path d="M811.758007 864.533065m3.771237-3.771236l45.254834-45.254834q3.771236-3.771236 7.542472 0l45.254834 45.254834q3.771236 3.771236 0 7.542472l-45.254834 45.254834q-3.771236 3.771236-7.542472 0l-45.254834-45.254834q-3.771236-3.771236 0-7.542472Z" p-id="3061" fill="#707070"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
@@ -14,8 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const requireComponent = require.context("./technologies", false, /\.png$/);
|
||||
const requireTool = require.context("./tools", false, /\.png$/);
|
||||
const requireComponent = import.meta.glob("./technologies/*.png", { eager: true });
|
||||
const requireTool = import.meta.glob("./tools/*.png", { eager: true });
|
||||
const result: { [key: string]: string } = {};
|
||||
const t: { [key: string]: string } = {};
|
||||
|
||||
@@ -24,25 +24,19 @@ function capitalizeFirstLetter(str: string) {
|
||||
}
|
||||
function validateFileName(str: string): string | undefined {
|
||||
if (/^\S+\.png$/.test(str)) {
|
||||
return str.replace(/^\S+\/(\w+)\.png$/, (rs, $1) =>
|
||||
capitalizeFirstLetter($1)
|
||||
);
|
||||
return str.replace(/^\S+\/(\w+)\.png$/, (rs, $1) => capitalizeFirstLetter($1));
|
||||
}
|
||||
}
|
||||
[...requireComponent.keys()].forEach((filePath: string) => {
|
||||
const componentConfig = requireComponent(filePath);
|
||||
|
||||
Object.keys(requireComponent).forEach((filePath: string) => {
|
||||
const fileName = validateFileName(filePath);
|
||||
if (fileName) {
|
||||
result[fileName] = componentConfig;
|
||||
result[fileName] = (requireComponent as { [key: string]: any })[filePath].default;
|
||||
}
|
||||
});
|
||||
[...requireTool.keys()].forEach((filePath: string) => {
|
||||
const componentConfig = requireTool(filePath);
|
||||
|
||||
Object.keys(requireTool).forEach((filePath: string) => {
|
||||
const fileName = validateFileName(filePath);
|
||||
if (fileName) {
|
||||
t[fileName] = componentConfig;
|
||||
t[fileName] = (requireTool as { [key: string]: any })[filePath].default;
|
||||
}
|
||||
});
|
||||
|
||||
|
BIN
src/assets/img/technologies/APACHESHENYU.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/img/technologies/BOTTLE.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
src/assets/img/technologies/EVENTMESH.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/assets/img/technologies/FASTAPI.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/img/technologies/HTTPDARK.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/img/technologies/HTTPS.png
Normal file
After Width: | Height: | Size: 895 B |
BIN
src/assets/img/technologies/HTTPX.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
src/assets/img/technologies/IMPALA.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/assets/img/technologies/MICROMETER.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
src/assets/img/technologies/MICRONAUT.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/img/technologies/NATS.png
Normal file
After Width: | Height: | Size: 626 B |
BIN
src/assets/img/technologies/WEBSOCKETS.png
Normal file
After Width: | Height: | Size: 12 KiB |
@@ -15,35 +15,18 @@ limitations under the License. -->
|
||||
<template>
|
||||
<div :class="`${state.pre}`">
|
||||
<div :class="`${state.pre}-head`">
|
||||
<a
|
||||
:class="`${state.pre}-prev-decade-btn`"
|
||||
v-show="state.showYears"
|
||||
@click="state.year -= 10"
|
||||
>
|
||||
<a :class="`${state.pre}-prev-decade-btn`" v-show="state.showYears" @click="state.year -= 10">
|
||||
<Icon size="sm" iconName="angle-double-left" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-prev-year-btn`"
|
||||
v-show="!state.showYears"
|
||||
@click="state.year--"
|
||||
>
|
||||
<a :class="`${state.pre}-prev-year-btn`" v-show="!state.showYears" @click="state.year--">
|
||||
<Icon size="sm" iconName="angle-double-left" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-prev-month-btn`"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
@click="pm"
|
||||
>
|
||||
<a :class="`${state.pre}-prev-month-btn`" v-show="!state.showYears && !state.showMonths" @click="pm">
|
||||
<Icon size="middle" iconName="chevron-left" />
|
||||
</a>
|
||||
<a :class="`${state.pre}-year-select`" v-show="state.showYears">{{
|
||||
ys + "-" + ye
|
||||
}}</a>
|
||||
<a :class="`${state.pre}-year-select`" v-show="state.showYears">{{ ys + "-" + ye }}</a>
|
||||
<template v-if="local.yearSuffix">
|
||||
<a
|
||||
:class="`${state.pre}-year-select`"
|
||||
@click="state.showYears = !state.showYears"
|
||||
v-show="!state.showYears"
|
||||
<a :class="`${state.pre}-year-select`" @click="state.showYears = !state.showYears" v-show="!state.showYears"
|
||||
>{{ state.year }}{{ local.yearSuffix }}</a
|
||||
>
|
||||
<a
|
||||
@@ -60,54 +43,29 @@ limitations under the License. -->
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
>{{ local.monthsHead[state.month] }}</a
|
||||
>
|
||||
<a
|
||||
:class="`${state.pre}-year-select`"
|
||||
@click="state.showYears = !state.showYears"
|
||||
v-show="!state.showYears"
|
||||
>{{ state.year }}</a
|
||||
>
|
||||
<a :class="`${state.pre}-year-select`" @click="state.showYears = !state.showYears" v-show="!state.showYears">{{
|
||||
state.year
|
||||
}}</a>
|
||||
</template>
|
||||
<a
|
||||
:class="`${state.pre}-next-month-btn`"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
@click="nm"
|
||||
>
|
||||
<a :class="`${state.pre}-next-month-btn`" v-show="!state.showYears && !state.showMonths" @click="nm">
|
||||
<Icon size="middle" iconName="chevron-right" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-next-year-btn`"
|
||||
v-show="!state.showYears"
|
||||
@click="state.year++"
|
||||
>
|
||||
<a :class="`${state.pre}-next-year-btn`" v-show="!state.showYears" @click="state.year++">
|
||||
<Icon size="sm" iconName="angle-double-right" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-next-decade-btn`"
|
||||
v-show="state.showYears"
|
||||
@click="state.year += 10"
|
||||
>
|
||||
<a :class="`${state.pre}-next-decade-btn`" v-show="state.showYears" @click="state.year += 10">
|
||||
<Icon size="sm" iconName="angle-double-right" />
|
||||
</a>
|
||||
</div>
|
||||
<div :class="`${state.pre}-body`">
|
||||
<div :class="`${state.pre}-days`">
|
||||
<a :class="`${state.pre}-week`" v-for="i in local.weeks" :key="i">{{
|
||||
i
|
||||
}}</a>
|
||||
<a :class="`${state.pre}-week`" v-for="i in local.weeks" :key="i">{{ i }}</a>
|
||||
<a
|
||||
v-for="(j, i) in days"
|
||||
@click="is($event) && ((state.day = j.i), ok(j))"
|
||||
:class="[
|
||||
j.p || j.n ? `${state.pre}-date-out` : '',
|
||||
status(
|
||||
j.y,
|
||||
j.m,
|
||||
j.i,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMMDD'
|
||||
),
|
||||
status(j.y, j.m, j.i, state.hour, state.minute, state.second, 'YYYYMMDD'),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ j.i }}</a
|
||||
@@ -116,23 +74,8 @@ limitations under the License. -->
|
||||
<div :class="`${state.pre}-months`" v-show="state.showMonths">
|
||||
<a
|
||||
v-for="(i, j) in local.months"
|
||||
@click="
|
||||
is($event) &&
|
||||
((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'
|
||||
),
|
||||
]"
|
||||
@click="is($event) && ((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"
|
||||
>{{ i }}</a
|
||||
>
|
||||
@@ -140,23 +83,10 @@ limitations under the License. -->
|
||||
<div :class="`${state.pre}-years`" v-show="state.showYears">
|
||||
<a
|
||||
v-for="(i, j) in years"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showYears = state.m === 'Y'),
|
||||
(state.year = i),
|
||||
state.m === 'Y' && ok('y'))
|
||||
"
|
||||
@click="is($event) && ((state.showYears = state.m === 'Y'), (state.year = i), state.m === 'Y' && ok('y'))"
|
||||
:class="[
|
||||
j === 0 || j === 11 ? `${state.pre}-date-out` : '',
|
||||
status(
|
||||
i,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYY'
|
||||
),
|
||||
status(i, state.month, state.day, state.hour, state.minute, state.second, 'YYYY'),
|
||||
]"
|
||||
:key="j"
|
||||
>{{ i }}</a
|
||||
@@ -167,21 +97,8 @@ limitations under the License. -->
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 24"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showHours = false), (state.hour = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
i,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMMDDHH'
|
||||
),
|
||||
]"
|
||||
@click="is($event) && ((state.showHours = false), (state.hour = i), ok('h'))"
|
||||
:class="[status(state.year, state.month, state.day, i, state.minute, state.second, 'YYYYMMDDHH')]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
@@ -192,21 +109,8 @@ limitations under the License. -->
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 60"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showMinutes = false), (state.minute = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
i,
|
||||
state.second,
|
||||
'YYYYMMDDHHmm'
|
||||
),
|
||||
]"
|
||||
@click="is($event) && ((state.showMinutes = false), (state.minute = i), ok('h'))"
|
||||
:class="[status(state.year, state.month, state.day, state.hour, i, state.second, 'YYYYMMDDHHmm')]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
@@ -217,21 +121,8 @@ limitations under the License. -->
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 60"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showSeconds = false), (state.second = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
i,
|
||||
'YYYYMMDDHHmmss'
|
||||
),
|
||||
]"
|
||||
@click="is($event) && ((state.showSeconds = false), (state.second = i), ok('h'))"
|
||||
:class="[status(state.year, state.month, state.day, state.hour, state.minute, i, 'YYYYMMDDHHmmss')]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
@@ -242,33 +133,24 @@ limitations under the License. -->
|
||||
<div :class="`${state.pre}-hour`">
|
||||
<a
|
||||
:title="local.hourTip"
|
||||
@click="
|
||||
(state.showHours = !state.showHours),
|
||||
(state.showMinutes = state.showSeconds = false)
|
||||
"
|
||||
@click="(state.showHours = !state.showHours), (state.showMinutes = state.showSeconds = false)"
|
||||
:class="{ on: state.showHours }"
|
||||
>{{ state.hour || dd }}</a
|
||||
>{{ dd(state.hour) }}</a
|
||||
>
|
||||
<span>:</span>
|
||||
<a
|
||||
:title="local.minuteTip"
|
||||
@click="
|
||||
(state.showMinutes = !state.showMinutes),
|
||||
(state.showHours = state.showSeconds = false)
|
||||
"
|
||||
@click="(state.showMinutes = !state.showMinutes), (state.showHours = state.showSeconds = false)"
|
||||
:class="{ on: state.showMinutes }"
|
||||
>{{ state.minute || dd }}</a
|
||||
>{{ dd(state.minute) }}</a
|
||||
>
|
||||
<span v-show="state.m !== 'D'">
|
||||
<span>:</span>
|
||||
<a
|
||||
:title="local.secondTip"
|
||||
@click="
|
||||
(state.showSeconds = !state.showSeconds),
|
||||
(state.showHours = state.showMinutes = false)
|
||||
"
|
||||
@click="(state.showSeconds = !state.showSeconds), (state.showHours = state.showMinutes = false)"
|
||||
:class="{ on: state.showSeconds }"
|
||||
>{{ state.second || dd }}</a
|
||||
>{{ dd(state.second) }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
@@ -277,13 +159,13 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, watch, reactive } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
/*global defineProps, defineEmits */
|
||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
import { computed, onMounted, watch, reactive } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
/*global defineProps, defineEmits */
|
||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
value: { type: Date },
|
||||
left: { type: Boolean, default: false },
|
||||
right: { type: Boolean, default: false },
|
||||
@@ -293,8 +175,8 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: "YYYY-MM-DD",
|
||||
},
|
||||
});
|
||||
const state = reactive({
|
||||
});
|
||||
const state = reactive({
|
||||
pre: "",
|
||||
m: "",
|
||||
showYears: false,
|
||||
@@ -308,8 +190,8 @@ const state = reactive({
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
});
|
||||
const get = (time: Date): { [key: string]: any } => {
|
||||
});
|
||||
const get = (time: Date): { [key: string]: any } => {
|
||||
return {
|
||||
year: time.getFullYear(),
|
||||
month: time.getMonth(),
|
||||
@@ -318,8 +200,8 @@ const get = (time: Date): { [key: string]: any } => {
|
||||
minute: time.getMinutes(),
|
||||
second: time.getSeconds(),
|
||||
};
|
||||
};
|
||||
if (props.value) {
|
||||
};
|
||||
if (props.value) {
|
||||
const time = get(props.value);
|
||||
state.pre = "calendar";
|
||||
state.m = "D";
|
||||
@@ -334,8 +216,8 @@ if (props.value) {
|
||||
state.hour = time.hour;
|
||||
state.minute = time.minute;
|
||||
state.second = time.second;
|
||||
}
|
||||
watch(
|
||||
}
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: Date | undefined) => {
|
||||
if (!val) {
|
||||
@@ -348,32 +230,32 @@ watch(
|
||||
state.hour = time.hour;
|
||||
state.minute = time.minute;
|
||||
state.second = time.second;
|
||||
}
|
||||
);
|
||||
const parse = (num: number): number => {
|
||||
},
|
||||
);
|
||||
const parse = (num: number): number => {
|
||||
return num / 100000;
|
||||
};
|
||||
const start = computed(() => {
|
||||
};
|
||||
const start = computed(() => {
|
||||
return parse(Number(props.dates[0]));
|
||||
});
|
||||
const end = computed(() => {
|
||||
});
|
||||
const end = computed(() => {
|
||||
return parse(Number(props.dates[1]));
|
||||
});
|
||||
const ys = computed(() => {
|
||||
});
|
||||
const ys = computed(() => {
|
||||
return Math.floor(state.year / 10) * 10;
|
||||
});
|
||||
const ye = computed(() => {
|
||||
});
|
||||
const ye = computed(() => {
|
||||
return ys.value + 10;
|
||||
});
|
||||
const years = computed(() => {
|
||||
});
|
||||
const years = computed(() => {
|
||||
const arr = [];
|
||||
let start = ys.value - 1;
|
||||
while (arr.length < 12) {
|
||||
arr.push((start += 1));
|
||||
}
|
||||
return arr;
|
||||
});
|
||||
const local = computed(() => {
|
||||
});
|
||||
const local = computed(() => {
|
||||
return {
|
||||
dow: 1, // Monday is the first day of the week
|
||||
hourTip: t("hourTip"), // tip of select hour
|
||||
@@ -392,8 +274,8 @@ const local = computed(() => {
|
||||
weekCutTip: t("weekCutTip"),
|
||||
monthCutTip: t("monthCutTip"),
|
||||
};
|
||||
});
|
||||
const days = computed(() => {
|
||||
});
|
||||
const days = computed(() => {
|
||||
const days = [];
|
||||
const year = state.year;
|
||||
const month = state.month;
|
||||
@@ -431,26 +313,19 @@ const days = computed(() => {
|
||||
});
|
||||
}
|
||||
return days;
|
||||
});
|
||||
const dd = (val: number) => ("0" + val).slice(-2);
|
||||
const status = (
|
||||
});
|
||||
const dd = (val: number) => ("0" + val).slice(-2);
|
||||
const status = (
|
||||
year: number,
|
||||
month: number,
|
||||
day: number,
|
||||
hour: number,
|
||||
minute: number,
|
||||
second: number,
|
||||
format: string
|
||||
) => {
|
||||
format: string,
|
||||
) => {
|
||||
const maxDay = new Date(year, month + 1, 0).getDate();
|
||||
const time: any = new Date(
|
||||
year,
|
||||
month,
|
||||
day > maxDay ? maxDay : day,
|
||||
hour,
|
||||
minute,
|
||||
second
|
||||
);
|
||||
const time: any = new Date(year, month, day > maxDay ? maxDay : day, hour, minute, second);
|
||||
const t = parse(time);
|
||||
const tf = (time?: Date, format?: any): string => {
|
||||
if (!time) {
|
||||
@@ -464,7 +339,6 @@ const status = (
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
const milliseconds = time.getMilliseconds();
|
||||
const dd = (t: number) => `0${t}`.slice(-2);
|
||||
const map: { [key: string]: string | number } = {
|
||||
YYYY: year,
|
||||
MM: dd(month + 1),
|
||||
@@ -483,10 +357,7 @@ const status = (
|
||||
s: seconds,
|
||||
S: milliseconds,
|
||||
};
|
||||
return (format || props.format).replace(
|
||||
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
|
||||
(str: string) => map[str]
|
||||
);
|
||||
return (format || props.format).replace(/Y+|M+|D+|H+|h+|m+|s+|S+/g, (str: string) => map[str]);
|
||||
};
|
||||
const classObj: any = {};
|
||||
let flag = false;
|
||||
@@ -498,33 +369,31 @@ const status = (
|
||||
flag = tf(props.value, format) === tf(time, format);
|
||||
}
|
||||
classObj[`${state.pre}-date`] = true;
|
||||
classObj[`${state.pre}-date-disabled`] =
|
||||
(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-disabled`] = (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-selected`] = flag;
|
||||
return classObj;
|
||||
};
|
||||
const nm = () => {
|
||||
};
|
||||
const nm = () => {
|
||||
if (state.month < 11) {
|
||||
state.month++;
|
||||
} else {
|
||||
state.month = 0;
|
||||
state.year++;
|
||||
}
|
||||
};
|
||||
const pm = () => {
|
||||
};
|
||||
const pm = () => {
|
||||
if (state.month > 0) {
|
||||
state.month--;
|
||||
} else {
|
||||
state.month = 11;
|
||||
state.year--;
|
||||
}
|
||||
};
|
||||
const is = (e: any) => {
|
||||
};
|
||||
const is = (e: any) => {
|
||||
return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1;
|
||||
};
|
||||
const ok = (info: any) => {
|
||||
};
|
||||
const ok = (info: any) => {
|
||||
let year = "";
|
||||
let month = "";
|
||||
let day = "";
|
||||
@@ -545,7 +414,7 @@ const ok = (info: any) => {
|
||||
day ? Number(day) : state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second
|
||||
state.second,
|
||||
);
|
||||
if (props.left && _time.getTime() / 100000 < end.value) {
|
||||
emit("setDates", _time, "left");
|
||||
@@ -553,12 +422,12 @@ const ok = (info: any) => {
|
||||
if (props.right && _time.getTime() / 100000 > start.value) {
|
||||
emit("setDates", _time, "right");
|
||||
}
|
||||
if (!(props.left && props.right)) {
|
||||
if (!(props.left || props.right)) {
|
||||
emit("setDates", _time);
|
||||
}
|
||||
emit("ok", info === "h");
|
||||
};
|
||||
onMounted(() => {
|
||||
};
|
||||
onMounted(() => {
|
||||
const is = (c: string) => props.format.indexOf(c) !== -1;
|
||||
if (is("s") && is("m") && (is("h") || is("H"))) {
|
||||
state.m = "H";
|
||||
@@ -571,30 +440,30 @@ onMounted(() => {
|
||||
state.m = "Y";
|
||||
state.showYears = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.calendar {
|
||||
.calendar {
|
||||
float: left;
|
||||
user-select: none;
|
||||
color: #3d444f;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar + .calendar {
|
||||
.calendar + .calendar {
|
||||
border-left: solid 1px #eaeaea;
|
||||
margin-left: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-head {
|
||||
.calendar-head {
|
||||
line-height: 34px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-head a {
|
||||
.calendar-head a {
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
@@ -602,55 +471,50 @@ onMounted(() => {
|
||||
position: absolute;
|
||||
padding: 0 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-head a:hover {
|
||||
.calendar-head a:hover {
|
||||
color: #3f97e3;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-head .calendar-year-select,
|
||||
.calendar-head .calendar-month-select {
|
||||
.calendar-head .calendar-year-select,
|
||||
.calendar-head .calendar-month-select {
|
||||
font-size: 12px;
|
||||
padding: 0 2px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-prev-decade-btn,
|
||||
.calendar-prev-year-btn {
|
||||
.calendar-prev-decade-btn,
|
||||
.calendar-prev-year-btn {
|
||||
left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-prev-month-btn {
|
||||
.calendar-prev-month-btn {
|
||||
left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-next-decade-btn,
|
||||
.calendar-next-year-btn {
|
||||
.calendar-next-decade-btn,
|
||||
.calendar-next-year-btn {
|
||||
right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-next-month-btn {
|
||||
.calendar-next-month-btn {
|
||||
right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-next-month-btn .middle,
|
||||
.calendar-prev-month-btn .middle {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.calendar-body {
|
||||
.calendar-body {
|
||||
position: relative;
|
||||
width: 196px;
|
||||
height: 196px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-days {
|
||||
.calendar-days {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-week,
|
||||
.calendar-date {
|
||||
.calendar-week,
|
||||
.calendar-date {
|
||||
font-weight: normal;
|
||||
width: 14.28%;
|
||||
height: 14.28%;
|
||||
@@ -658,96 +522,96 @@ onMounted(() => {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-week:before,
|
||||
.calendar-date:before {
|
||||
.calendar-week:before,
|
||||
.calendar-date:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-date {
|
||||
.calendar-date {
|
||||
cursor: pointer;
|
||||
line-height: 29px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-date-out {
|
||||
.calendar-date-out {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-date:hover,
|
||||
.calendar-date-on {
|
||||
.calendar-date:hover,
|
||||
.calendar-date-on {
|
||||
color: #3f97e3;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-date-selected,
|
||||
.calendar-date-selected:hover {
|
||||
.calendar-date-selected,
|
||||
.calendar-date-selected:hover {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
border-radius: 14px;
|
||||
background: #3f97e3;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-date-disabled {
|
||||
.calendar-date-disabled {
|
||||
cursor: not-allowed !important;
|
||||
color: #ccc !important;
|
||||
background: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-foot {
|
||||
.calendar-foot {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-hour {
|
||||
.calendar-hour {
|
||||
display: inline-block;
|
||||
border: 1px solid #e6e5e5;
|
||||
color: #9e9e9e;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-hour a {
|
||||
.calendar-hour a {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-hour a:hover,
|
||||
.calendar-hour a.on {
|
||||
.calendar-hour a:hover,
|
||||
.calendar-hour a.on {
|
||||
color: #3f97e3;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-years,
|
||||
.calendar-months,
|
||||
.calendar-hours,
|
||||
.calendar-minutes,
|
||||
.calendar-seconds {
|
||||
.calendar-years,
|
||||
.calendar-months,
|
||||
.calendar-hours,
|
||||
.calendar-minutes,
|
||||
.calendar-seconds {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-months a {
|
||||
.calendar-months a {
|
||||
width: 33.33%;
|
||||
height: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-years a {
|
||||
.calendar-years a {
|
||||
width: 33.33%;
|
||||
height: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-overflow {
|
||||
.calendar-overflow {
|
||||
overflow-x: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* .calendar-hours a {
|
||||
/* .calendar-hours a {
|
||||
width: 20%;
|
||||
height: 20%;
|
||||
}
|
||||
@@ -758,12 +622,12 @@ onMounted(() => {
|
||||
height: 10%;
|
||||
} */
|
||||
|
||||
.calendar-title {
|
||||
.calendar-title {
|
||||
margin-top: -30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -15,62 +15,194 @@ limitations under the License. -->
|
||||
<template>
|
||||
<div class="chart" ref="chartRef" :style="`height:${height};width:${width};`">
|
||||
<div v-if="!available" class="no-data">No Data</div>
|
||||
<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">
|
||||
{{ t("associateMetrics") }}
|
||||
</div>
|
||||
<div class="tools" @click="viewTrace" v-if="relatedTrace && relatedTrace.enableRelate">
|
||||
{{ t("viewTrace") }}
|
||||
</div>
|
||||
</div>
|
||||
<el-drawer
|
||||
v-model="showTrace"
|
||||
size="100%"
|
||||
:destroy-on-close="true"
|
||||
:before-close="() => (showTrace = false)"
|
||||
:append-to-body="true"
|
||||
title="The Related Traces"
|
||||
>
|
||||
<Trace :data="traceOptions" />
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
watch,
|
||||
ref,
|
||||
Ref,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
unref,
|
||||
computed,
|
||||
} from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useECharts } from "@/hooks/useEcharts";
|
||||
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
||||
import { watch, ref, onMounted, onBeforeUnmount, unref, computed, reactive } from "vue";
|
||||
import type { PropType, Ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import type { EventParams } from "@/types/app";
|
||||
import type { 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*/
|
||||
const emits = defineEmits(["select"]);
|
||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const { setOptions, resize, getInstance } = useECharts(
|
||||
chartRef as Ref<HTMLDivElement>
|
||||
);
|
||||
const props = defineProps({
|
||||
/*global Nullable, defineProps, defineEmits*/
|
||||
const emits = defineEmits(["select"]);
|
||||
const { t } = useI18n();
|
||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const visMenus = ref<boolean>(false);
|
||||
const { setOptions, resize, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const currentParams = ref<Nullable<EventParams>>(null);
|
||||
const showTrace = ref<boolean>(false);
|
||||
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
||||
type: "Trace",
|
||||
});
|
||||
const menuPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
||||
const props = defineProps({
|
||||
height: { type: String, default: "100%" },
|
||||
width: { type: String, default: "100%" },
|
||||
option: {
|
||||
type: Object as PropType<{ [key: string]: any }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const available = computed(
|
||||
filters: {
|
||||
type: Object as PropType<Filters>,
|
||||
},
|
||||
relatedTrace: {
|
||||
type: Object as PropType<RelatedTrace>,
|
||||
},
|
||||
associate: {
|
||||
type: Array as PropType<{ widgetId: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
const available = computed(
|
||||
() =>
|
||||
(Array.isArray(props.option.series) &&
|
||||
props.option.series[0] &&
|
||||
props.option.series[0].data) ||
|
||||
(Array.isArray(props.option.series.data) && props.option.series.data[0])
|
||||
);
|
||||
onMounted(async () => {
|
||||
if (!available.value) {
|
||||
return;
|
||||
}
|
||||
(Array.isArray(props.option.series) && props.option.series[0] && props.option.series[0].data) ||
|
||||
(Array.isArray(props.option.series.data) && props.option.series.data[0]),
|
||||
);
|
||||
onMounted(async () => {
|
||||
await setOptions(props.option);
|
||||
chartRef.value && addResizeListener(unref(chartRef), resize);
|
||||
instanceEvent();
|
||||
});
|
||||
|
||||
function instanceEvent() {
|
||||
setTimeout(() => {
|
||||
const instance = getInstance();
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
instance.on("click", (params: any) => {
|
||||
emits("select", params);
|
||||
instance.on("click", (params: EventParams) => {
|
||||
currentParams.value = params;
|
||||
if (props.option.series.type === "sankey") {
|
||||
emits("select", currentParams.value);
|
||||
return;
|
||||
}
|
||||
instance.dispatchAction({
|
||||
type: "hideTip",
|
||||
});
|
||||
visMenus.value = true;
|
||||
if (!chartRef.value) {
|
||||
return;
|
||||
}
|
||||
const w = chartRef.value.getBoundingClientRect().width || 0;
|
||||
const h = chartRef.value.getBoundingClientRect().height || 0;
|
||||
if (w - params.event.offsetX > 120) {
|
||||
menuPos.x = params.event.offsetX;
|
||||
} else {
|
||||
menuPos.x = params.event.offsetX - 120;
|
||||
}
|
||||
if (h - params.event.offsetY < 50) {
|
||||
menuPos.y = params.event.offsetY - 40;
|
||||
} else {
|
||||
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(
|
||||
"click",
|
||||
() => {
|
||||
if (instance.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
visMenus.value = false;
|
||||
instance.dispatchAction({
|
||||
type: "hideTip",
|
||||
});
|
||||
instance.dispatchAction({
|
||||
type: "updateAxisPointer",
|
||||
currTrigger: "leave",
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
function associateMetrics() {
|
||||
emits("select", currentParams.value);
|
||||
updateOptions(currentParams.value || undefined);
|
||||
}
|
||||
|
||||
function updateOptions(params?: EventParams) {
|
||||
const instance = getInstance();
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
if (!props.filters) {
|
||||
return;
|
||||
}
|
||||
if (props.filters.isRange) {
|
||||
const { eventAssociate } = associateProcessor(props);
|
||||
const options = eventAssociate();
|
||||
setOptions(options || props.option);
|
||||
} else {
|
||||
instance.dispatchAction({
|
||||
type: "showTip",
|
||||
dataIndex: params ? params.dataIndex : props.filters.dataIndex,
|
||||
seriesIndex: params ? params.seriesIndex : 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function viewTrace() {
|
||||
const item = associateProcessor(props).traceFilters(currentParams.value);
|
||||
traceOptions.value = {
|
||||
...traceOptions.value,
|
||||
filters: item,
|
||||
};
|
||||
showTrace.value = true;
|
||||
visMenus.value = true;
|
||||
}
|
||||
|
||||
function hideTooltips() {
|
||||
const instance = getInstance();
|
||||
instance.dispatchAction({
|
||||
type: "hideTip",
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.option,
|
||||
(newVal, oldVal) => {
|
||||
if (!available.value) {
|
||||
@@ -79,16 +211,27 @@ watch(
|
||||
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
||||
return;
|
||||
}
|
||||
setOptions(newVal);
|
||||
let options;
|
||||
if (props.filters && props.filters.isRange) {
|
||||
const { eventAssociate } = associateProcessor(props);
|
||||
options = eventAssociate();
|
||||
}
|
||||
);
|
||||
setOptions(options || props.option);
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => props.filters,
|
||||
() => {
|
||||
updateOptions();
|
||||
},
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
onBeforeUnmount(() => {
|
||||
removeResizeListener(unref(chartRef), resize);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.no-data {
|
||||
.no-data {
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
@@ -97,9 +240,34 @@ onBeforeUnmount(() => {
|
||||
-webkit-box-pack: center;
|
||||
-webkit-box-align: center;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.chart {
|
||||
.chart {
|
||||
overflow: hidden;
|
||||
}
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.menus {
|
||||
position: absolute;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
z-index: 9999999;
|
||||
box-shadow: #ddd 1px 2px 10px;
|
||||
transition: all cubic-bezier(0.075, 0.82, 0.165, 1) linear;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 4px;
|
||||
color: rgb(51, 51, 51);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
padding: 5px;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -24,21 +24,19 @@ limitations under the License. -->
|
||||
loading,
|
||||
}"
|
||||
>
|
||||
<use :xlink:href="`#${iconName}`"></use>
|
||||
<use :href="`#${iconName}`"></use>
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import "@/assets/icons/index";
|
||||
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
/*global defineProps */
|
||||
defineProps({
|
||||
iconName: { type: String, default: "" },
|
||||
size: { type: String, default: "sm" },
|
||||
loading: { type: Boolean, default: false },
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.icon {
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
@@ -72,8 +70,8 @@ defineProps({
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
@keyframes loading {
|
||||
}
|
||||
@keyframes loading {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
@@ -83,5 +81,5 @@ defineProps({
|
||||
-webkit-transform: rotate(1turn);
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -20,19 +20,19 @@ limitations under the License. -->
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { ref } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
interface Option {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/*global defineProps, defineEmits */
|
||||
const emit = defineEmits(["change"]);
|
||||
const props = defineProps({
|
||||
/*global defineProps, defineEmits */
|
||||
const emit = defineEmits(["change"]);
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<(Option & { disabled: boolean })[]>,
|
||||
type: Array as PropType<
|
||||
{
|
||||
label: string | number;
|
||||
value: string | number;
|
||||
}[]
|
||||
>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
@@ -40,11 +40,11 @@ const props = defineProps({
|
||||
default: "",
|
||||
},
|
||||
size: { type: null, default: "default" },
|
||||
});
|
||||
});
|
||||
|
||||
const selected = ref<string>(props.value);
|
||||
const selected = ref<string>(props.value);
|
||||
|
||||
function checked(opt: string) {
|
||||
function checked(opt: unknown) {
|
||||
emit("change", opt);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -19,9 +19,7 @@ limitations under the License. -->
|
||||
{{ selected.label }}
|
||||
</span>
|
||||
<span class="no-data" v-else>Please select a option</span>
|
||||
<span class="remove-icon" @click="removeSelected" v-if="clearable">
|
||||
×
|
||||
</span>
|
||||
<span class="remove-icon" @click="removeSelected" v-if="clearable"> × </span>
|
||||
</div>
|
||||
<div class="opt-wrapper" v-show="visible">
|
||||
<div
|
||||
@@ -37,15 +35,15 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { Option } from "@/types/app";
|
||||
import { ref, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import type { Option } from "@/types/app";
|
||||
|
||||
/*global defineProps, defineEmits*/
|
||||
const emit = defineEmits(["change"]);
|
||||
const props = defineProps({
|
||||
/*global defineProps, defineEmits*/
|
||||
const emit = defineEmits(["change"]);
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<(Option & { disabled: boolean })[]>,
|
||||
type: Array as PropType<Option[]>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
@@ -53,38 +51,38 @@ const props = defineProps({
|
||||
default: () => "",
|
||||
},
|
||||
clearable: { type: Boolean, default: false },
|
||||
});
|
||||
const visible = ref<boolean>(false);
|
||||
const opt = props.options.find((d: Option) => props.value === d.value);
|
||||
const selected = ref<Option>(opt || { label: "", value: "" });
|
||||
});
|
||||
const visible = ref<boolean>(false);
|
||||
const opt = props.options.find((d: Option) => props.value === d.value);
|
||||
const selected = ref<Option>(opt || { label: "", value: "" });
|
||||
|
||||
function handleSelect(i: Option) {
|
||||
function handleSelect(i: Option) {
|
||||
selected.value = i;
|
||||
emit("change", i.value);
|
||||
}
|
||||
function removeSelected() {
|
||||
}
|
||||
function removeSelected() {
|
||||
selected.value = { label: "", value: "" };
|
||||
emit("change", "");
|
||||
}
|
||||
watch(
|
||||
}
|
||||
watch(
|
||||
() => props.value,
|
||||
(data) => {
|
||||
const opt = props.options.find((d: Option) => data === d.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;
|
||||
}
|
||||
function setPopper(event: any) {
|
||||
}
|
||||
function setPopper(event: any) {
|
||||
event.stopPropagation();
|
||||
visible.value = !visible.value;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.bar-select {
|
||||
.bar-select {
|
||||
position: relative;
|
||||
justify-content: space-between;
|
||||
border: 1px solid #ddd;
|
||||
@@ -103,13 +101,13 @@ function setPopper(event: any) {
|
||||
border: 1px solid #e8e8e8;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
.no-data {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
|
||||
.bar-i {
|
||||
.bar-i {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 2px 10px;
|
||||
@@ -122,9 +120,9 @@ function setPopper(event: any) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remove-icon {
|
||||
.remove-icon {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
@@ -132,9 +130,9 @@ function setPopper(event: any) {
|
||||
display: none;
|
||||
color: #aaa;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.opt-wrapper {
|
||||
.opt-wrapper {
|
||||
color: #606266;
|
||||
position: absolute;
|
||||
top: 26px;
|
||||
@@ -160,9 +158,9 @@ function setPopper(event: any) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.opt {
|
||||
.opt {
|
||||
padding: 7px 15px;
|
||||
|
||||
&.select-disabled {
|
||||
@@ -173,5 +171,5 @@ function setPopper(event: any) {
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -18,7 +18,6 @@ limitations under the License. -->
|
||||
v-model="selected"
|
||||
:placeholder="placeholder"
|
||||
@change="changeSelected"
|
||||
filterable
|
||||
:multiple="multiple"
|
||||
:disabled="disabled"
|
||||
:style="{ borderRadius }"
|
||||
@@ -26,30 +25,31 @@ limitations under the License. -->
|
||||
:remote="isRemote"
|
||||
:reserve-keyword="isRemote"
|
||||
:remote-method="remoteMethod"
|
||||
:filterable="filterable"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.value || ''" :label="item.label || ''" :value="item.value || ''">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { ref, watch } 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;
|
||||
value: string | number;
|
||||
}
|
||||
|
||||
/*global defineProps, defineEmits*/
|
||||
const emit = defineEmits(["change", "query"]);
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<(Option & { disabled?: boolean })[]>,
|
||||
} & { disabled?: boolean })[]
|
||||
>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
@@ -58,7 +58,7 @@ const props = defineProps({
|
||||
},
|
||||
size: { type: null, default: "default" },
|
||||
placeholder: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
type: [String, undefined] as PropType<string>,
|
||||
default: "Select a option",
|
||||
},
|
||||
borderRadius: { type: Number, default: 3 },
|
||||
@@ -66,33 +66,32 @@ const props = defineProps({
|
||||
disabled: { type: Boolean, default: false },
|
||||
clearable: { type: Boolean, default: false },
|
||||
isRemote: { type: Boolean, default: false },
|
||||
});
|
||||
filterable: { type: Boolean, default: true },
|
||||
});
|
||||
|
||||
const selected = ref<string[] | string>(props.value);
|
||||
function changeSelected() {
|
||||
const selected = ref<string[] | string>(props.value);
|
||||
function changeSelected() {
|
||||
const options = props.options.filter((d: any) =>
|
||||
props.multiple
|
||||
? selected.value.includes(d.value)
|
||||
: selected.value === d.value
|
||||
props.multiple ? selected.value.includes(d.value) : selected.value === d.value,
|
||||
);
|
||||
emit("change", options);
|
||||
}
|
||||
}
|
||||
|
||||
function remoteMethod(query: string) {
|
||||
function remoteMethod(query: string) {
|
||||
if (props.isRemote) {
|
||||
emit("query", query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
watch(
|
||||
() => props.value,
|
||||
(data) => {
|
||||
selected.value = data;
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-input__inner {
|
||||
.el-input__inner {
|
||||
border-radius: unset !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -35,56 +35,28 @@ limitations under the License. -->
|
||||
<transition name="datepicker-anim">
|
||||
<div
|
||||
class="datepicker-popup"
|
||||
:class="[
|
||||
popupClass,
|
||||
{ 'datepicker-inline': type === 'inline' },
|
||||
position,
|
||||
]"
|
||||
:class="[popupClass, { 'datepicker-inline': type === 'inline' }, position]"
|
||||
tabindex="-1"
|
||||
v-if="show || type === 'inline'"
|
||||
>
|
||||
<template v-if="range">
|
||||
<div class="datepicker-popup__sidebar">
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('quarter')"
|
||||
>
|
||||
<button type="button" class="datepicker-popup__shortcut" @click="quickPick('quarter')">
|
||||
{{ local.quarterHourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('half')"
|
||||
>
|
||||
<button type="button" class="datepicker-popup__shortcut" @click="quickPick('half')">
|
||||
{{ local.halfHourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('hour')"
|
||||
>
|
||||
<button type="button" class="datepicker-popup__shortcut" @click="quickPick('hour')">
|
||||
{{ local.hourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('day')"
|
||||
>
|
||||
<button type="button" class="datepicker-popup__shortcut" @click="quickPick('day')">
|
||||
{{ local.dayCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('week')"
|
||||
>
|
||||
<button type="button" class="datepicker-popup__shortcut" @click="quickPick('week')">
|
||||
{{ local.weekCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('month')"
|
||||
>
|
||||
<button type="button" class="datepicker-popup__shortcut" @click="quickPick('month')">
|
||||
{{ local.monthCutTip }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -123,16 +95,10 @@ limitations under the License. -->
|
||||
/>
|
||||
</template>
|
||||
<div v-if="showButtons" class="datepicker__buttons">
|
||||
<button
|
||||
@click.prevent.stop="cancel"
|
||||
class="datepicker__button-cancel"
|
||||
>
|
||||
<button @click.prevent.stop="cancel" class="datepicker__button-cancel">
|
||||
{{ local.cancelTip }}
|
||||
</button>
|
||||
<button
|
||||
@click.prevent.stop="submit"
|
||||
class="datepicker__button-select"
|
||||
>
|
||||
<button @click.prevent.stop="submit" class="datepicker__button-select">
|
||||
{{ local.submitTip }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -142,16 +108,16 @@ limitations under the License. -->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DateCalendar from "./DateCalendar.vue";
|
||||
import { useTimeoutFn } from "@/hooks/useTimeout";
|
||||
/*global defineProps, defineEmits */
|
||||
const datepicker = ref(null);
|
||||
const { t } = useI18n();
|
||||
const show = ref<boolean>(false);
|
||||
const dates = ref<Date | string[] | any>([]);
|
||||
const props = defineProps({
|
||||
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DateCalendar from "./DateCalendar.vue";
|
||||
import { useTimeoutFn } from "@/hooks/useTimeout";
|
||||
/*global defineProps, defineEmits */
|
||||
const datepicker = ref(null);
|
||||
const { t } = useI18n();
|
||||
const show = ref<boolean>(false);
|
||||
const dates = ref<Date | string[] | any>([]);
|
||||
const props = defineProps({
|
||||
position: { type: String, default: "bottom" },
|
||||
name: [String],
|
||||
inputClass: [String],
|
||||
@@ -184,9 +150,9 @@ const props = defineProps({
|
||||
default: false,
|
||||
},
|
||||
dateRangeSelect: [Function],
|
||||
});
|
||||
const emit = defineEmits(["clear", "input", "confirm", "cancel"]);
|
||||
const local = computed(() => {
|
||||
});
|
||||
const emit = defineEmits(["clear", "input", "confirm", "cancel"]);
|
||||
const local = computed(() => {
|
||||
return {
|
||||
dow: 1, // Monday is the first day of the week
|
||||
hourTip: t("hourTip"), // tip of select hour
|
||||
@@ -205,8 +171,8 @@ const local = computed(() => {
|
||||
weekCutTip: t("weekCutTip"),
|
||||
monthCutTip: t("monthCutTip"),
|
||||
};
|
||||
});
|
||||
const tf = (time: Date, format?: any): string => {
|
||||
});
|
||||
const tf = (time: Date, format?: any): string => {
|
||||
const year = time.getFullYear();
|
||||
const month = time.getMonth();
|
||||
const day = time.getDate();
|
||||
@@ -234,58 +200,51 @@ const tf = (time: Date, format?: any): string => {
|
||||
s: seconds,
|
||||
S: milliseconds,
|
||||
};
|
||||
return (format || props.format).replace(
|
||||
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
|
||||
(str: string) => map[str]
|
||||
);
|
||||
};
|
||||
const range = computed(() => {
|
||||
return (format || props.format).replace(/Y+|M+|D+|H+|h+|m+|s+|S+/g, (str: string) => map[str]);
|
||||
};
|
||||
const range = computed(() => {
|
||||
return dates.value.length === 2;
|
||||
});
|
||||
const text = computed(() => {
|
||||
});
|
||||
const text = computed(() => {
|
||||
const val = props.value;
|
||||
const txt = dates.value
|
||||
.map((date: Date) => tf(date))
|
||||
.join(` ${props.rangeSeparator} `);
|
||||
const txt = dates.value.map((date: Date) => tf(date)).join(` ${props.rangeSeparator} `);
|
||||
if (Array.isArray(val)) {
|
||||
return val.length > 1 ? txt : "";
|
||||
}
|
||||
return val ? txt : "";
|
||||
});
|
||||
const get = () => {
|
||||
});
|
||||
const get = () => {
|
||||
return Array.isArray(props.value) ? dates.value : dates.value[0];
|
||||
};
|
||||
const cls = () => {
|
||||
};
|
||||
const cls = () => {
|
||||
emit("clear");
|
||||
emit("input", range.value ? [] : "");
|
||||
};
|
||||
const vi = (val: any) => {
|
||||
};
|
||||
const vi = (val: any) => {
|
||||
if (Array.isArray(val)) {
|
||||
return val.length > 1
|
||||
? val.map((item) => new Date(item))
|
||||
: [new Date(), new Date()];
|
||||
return val.length > 1 ? val.map((item) => new Date(item)) : [new Date(), new Date()];
|
||||
}
|
||||
return val ? [new Date(val)] : [new Date()];
|
||||
};
|
||||
const ok = (leaveOpened: boolean) => {
|
||||
};
|
||||
const ok = (leaveOpened: boolean) => {
|
||||
emit("input", get());
|
||||
!leaveOpened &&
|
||||
!props.showButtons &&
|
||||
useTimeoutFn(() => {
|
||||
show.value = range.value;
|
||||
}, 1);
|
||||
};
|
||||
const setDates = (d: Date, pos: string) => {
|
||||
};
|
||||
const setDates = (d: Date, pos: string) => {
|
||||
if (pos === "right") {
|
||||
dates.value[1] = d;
|
||||
return;
|
||||
}
|
||||
dates.value[0] = d;
|
||||
};
|
||||
const dc = (e: any) => {
|
||||
};
|
||||
const dc = (e: any) => {
|
||||
show.value = (datepicker.value as any).contains(e.target) && !props.disabled;
|
||||
};
|
||||
const quickPick = (type: string) => {
|
||||
};
|
||||
const quickPick = (type: string) => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
switch (type) {
|
||||
@@ -312,32 +271,32 @@ const quickPick = (type: string) => {
|
||||
}
|
||||
dates.value = [start, end];
|
||||
emit("input", get());
|
||||
};
|
||||
const submit = () => {
|
||||
};
|
||||
const submit = () => {
|
||||
emit("confirm", get());
|
||||
show.value = false;
|
||||
};
|
||||
const cancel = () => {
|
||||
};
|
||||
const cancel = () => {
|
||||
emit("cancel");
|
||||
show.value = false;
|
||||
};
|
||||
onMounted(() => {
|
||||
};
|
||||
onMounted(() => {
|
||||
dates.value = vi(props.value);
|
||||
document.addEventListener("click", dc, true);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("click", dc, true);
|
||||
});
|
||||
watch(
|
||||
});
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: unknown) => {
|
||||
dates.value = vi(val);
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@keyframes datepicker-anim-in {
|
||||
@keyframes datepicker-anim-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
@@ -347,9 +306,9 @@ watch(
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-out {
|
||||
@keyframes datepicker-anim-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
@@ -359,22 +318,22 @@ watch(
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker {
|
||||
.datepicker {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-icon {
|
||||
.datepicker-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
color: #515a6ecc;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-close {
|
||||
.datepicker-close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 34px;
|
||||
@@ -382,9 +341,9 @@ watch(
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-close:before {
|
||||
.datepicker-close:before {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
@@ -400,21 +359,21 @@ watch(
|
||||
background: #ccc
|
||||
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3IDciIHdpZHRoPSI3IiBoZWlnaHQ9IjciPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01LjU4LDVsMi44LTIuODFBLjQxLjQxLDAsMSwwLDcuOCwxLjZMNSw0LjQxLDIuMiwxLjZhLjQxLjQxLDAsMCwwLS41OC41OGgwTDQuNDIsNSwxLjYyLDcuOGEuNDEuNDEsMCwwLDAsLjU4LjU4TDUsNS41OCw3LjgsOC4zOWEuNDEuNDEsMCwwLDAsLjU4LS41OGgwWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEuNSAtMS40OCkiIHN0eWxlPSJmaWxsOiNmZmYiLz48L3N2Zz4NCg==")
|
||||
no-repeat 50% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker__clearable:hover:before {
|
||||
.datepicker__clearable:hover:before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker__clearable:hover .datepicker-close {
|
||||
.datepicker__clearable:hover .datepicker-close {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-close:hover:before {
|
||||
.datepicker-close:hover:before {
|
||||
background-color: #afafaf;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker > input {
|
||||
.datepicker > input {
|
||||
color: inherit;
|
||||
// transition: all 200ms ease;
|
||||
border-radius: 4px;
|
||||
@@ -428,23 +387,23 @@ watch(
|
||||
user-select: none;
|
||||
font-family: "Monaco";
|
||||
letter-spacing: -0.7px;
|
||||
}
|
||||
}
|
||||
|
||||
// .datepicker > input.focus {
|
||||
// border-color: #3f97e3;
|
||||
// -webkit-box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
|
||||
// box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
|
||||
// }
|
||||
// .datepicker > input.focus {
|
||||
// border-color: #3f97e3;
|
||||
// -webkit-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;
|
||||
background-color: #ebebe4;
|
||||
border-color: #e5e5e5;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-popup {
|
||||
.datepicker-popup {
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
transition: all 200ms ease;
|
||||
@@ -514,52 +473,52 @@ watch(
|
||||
margin-left: 100px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-inline {
|
||||
.datepicker-inline {
|
||||
position: relative;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-range {
|
||||
.datepicker-range {
|
||||
min-width: 238px;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-range .datepicker-popup {
|
||||
.datepicker-range .datepicker-popup {
|
||||
width: 520px;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-bottom {
|
||||
.datepicker-bottom {
|
||||
float: left;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-btn {
|
||||
.datepicker-btn {
|
||||
padding: 5px 10px;
|
||||
background: #3f97e3;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-anim-enter-active {
|
||||
.datepicker-anim-enter-active {
|
||||
transform-origin: 0 0;
|
||||
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;
|
||||
animation: datepicker-anim-out 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker__buttons {
|
||||
.datepicker__buttons {
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker__buttons button {
|
||||
.datepicker__buttons button {
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
border: none;
|
||||
@@ -567,13 +526,13 @@ watch(
|
||||
margin: 10px 0 0 5px;
|
||||
padding: 5px 15px;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker__buttons .datepicker__button-select {
|
||||
.datepicker__buttons .datepicker__button-select {
|
||||
background: #3f97e3;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker__buttons .datepicker__button-cancel {
|
||||
.datepicker__buttons .datepicker__button-cancel {
|
||||
background: #666;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
33
src/components/__tests__/HelloWorld.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { describe, it } from "vitest";
|
||||
|
||||
// import { mount } from '@vue/test-utils'
|
||||
// import HelloWorld from '../HelloWorld.vue'
|
||||
|
||||
// describe('HelloWorld', () => {
|
||||
// it('renders properly', () => {
|
||||
// const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
|
||||
// expect(wrapper.text()).toContain('Hello Vitest')
|
||||
// })
|
||||
// })
|
||||
describe("My First Test", () => {
|
||||
it("renders props.msg when passed", () => {
|
||||
const msg = "new message";
|
||||
console.log(msg);
|
||||
});
|
||||
});
|
@@ -14,13 +14,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { App } from "vue";
|
||||
import Icon from "./Icon.vue";
|
||||
import TimePicker from "./TimePicker.vue";
|
||||
import Selector from "./Selector.vue";
|
||||
import Graph from "./Graph.vue";
|
||||
import Radio from "./Radio.vue";
|
||||
import SelectSingle from "./SelectSingle.vue";
|
||||
import type { App } from "vue";
|
||||
import VueGridLayout from "vue-grid-layout";
|
||||
|
||||
const components: { [key: string]: any } = {
|
||||
|
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export enum TimeType {
|
||||
MINUTE_TIME = "MINUTE",
|
||||
HOUR_TIME = "HOUR",
|
||||
@@ -23,19 +24,5 @@ export enum TimeType {
|
||||
export const Languages = [
|
||||
{ label: "English", value: "en" },
|
||||
{ label: "Chinese", value: "zh" },
|
||||
{ label: "Spanish", value: "es" },
|
||||
];
|
||||
|
||||
export const RoutesMap: { [key: string]: string } = {
|
||||
GeneralServices: "GENERAL",
|
||||
Database: "VIRTUAL_DATABASE",
|
||||
MeshServices: "MESH",
|
||||
ControlPanel: "MESH_CP",
|
||||
DataPanel: "MESH_DP",
|
||||
Linux: "OS_LINUX",
|
||||
SkyWalkingServer: "SO11Y_OAP",
|
||||
Satellite: "SO11Y_SATELLITE",
|
||||
Functions: "FAAS",
|
||||
Browser: "BROWSER",
|
||||
KubernetesCluster: "K8S",
|
||||
KubernetesService: "K8S_SERVICE",
|
||||
};
|
||||
|
@@ -14,22 +14,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import axios from "axios";
|
||||
import { cancelToken } from "@/utils/cancelToken";
|
||||
|
||||
async function query(param: {
|
||||
queryStr: string;
|
||||
conditions: { [key: string]: unknown };
|
||||
}) {
|
||||
async function query(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
||||
const res: AxiosResponse = await axios.post(
|
||||
"/graphql",
|
||||
{ query: param.queryStr, variables: { ...param.conditions } },
|
||||
{ cancelToken: cancelToken() }
|
||||
{ cancelToken: cancelToken() },
|
||||
);
|
||||
if (res.data.errors) {
|
||||
res.data.errors = res.data.errors
|
||||
.map((e: { message: string }) => e.message)
|
||||
.join(" ");
|
||||
res.data.errors = res.data.errors.map((e: { message: string }) => e.message).join(" ");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@@ -16,8 +16,7 @@
|
||||
*/
|
||||
|
||||
export const Alarm = {
|
||||
variable:
|
||||
"$keyword: String, $scope: Scope, $duration:Duration!, $tags:[AlarmTag], $paging: Pagination!",
|
||||
variable: "$keyword: String, $scope: Scope, $duration:Duration!, $tags:[AlarmTag], $paging: Pagination!",
|
||||
query: `
|
||||
getAlarm(keyword: $keyword, scope: $scope, duration: $duration, paging: $paging, tags: $tags) {
|
||||
items: msgs {
|
||||
@@ -45,6 +44,5 @@ export const Alarm = {
|
||||
endTime
|
||||
}
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
36
src/graphql/fragments/demand-log.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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 const queryContainers = {
|
||||
variable: "$condition: OndemandContainergQueryCondition!",
|
||||
query: `
|
||||
containers: listContainers(condition: $condition) {
|
||||
errorReason
|
||||
containers
|
||||
}`,
|
||||
};
|
||||
|
||||
export const queryStreamingLogs = {
|
||||
variable: "$condition: OndemandLogQueryCondition",
|
||||
query: `
|
||||
logs: ondemandPodLogs(condition: $condition) {
|
||||
errorReason
|
||||
logs {
|
||||
content
|
||||
}
|
||||
}`,
|
||||
};
|
113
src/graphql/fragments/ebpf.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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 const queryCreateTaskData = {
|
||||
variable: "$serviceId: ID!",
|
||||
query: `
|
||||
createTaskData: queryPrepareCreateEBPFProfilingTaskData(serviceId: $serviceId) {
|
||||
couldProfiling
|
||||
processLabels
|
||||
}`,
|
||||
};
|
||||
export const createEBPFTask = {
|
||||
variable: "$request: EBPFProfilingTaskFixedTimeCreationRequest!",
|
||||
query: `
|
||||
createTaskData: createEBPFProfilingFixedTimeTask(request: $request) {
|
||||
status
|
||||
errorReason
|
||||
id
|
||||
}`,
|
||||
};
|
||||
export const queryEBPFTasks = {
|
||||
variable: "$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!]",
|
||||
query: `
|
||||
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets) {
|
||||
taskId
|
||||
serviceName
|
||||
serviceId
|
||||
serviceInstanceId
|
||||
serviceInstanceName
|
||||
processLabels
|
||||
taskStartTime
|
||||
triggerType
|
||||
fixedTriggerDuration
|
||||
targetType
|
||||
createTime
|
||||
}`,
|
||||
};
|
||||
export const queryEBPFSchedules = {
|
||||
variable: "$taskId: ID!",
|
||||
query: `
|
||||
eBPFSchedules: queryEBPFProfilingSchedules(taskId: $taskId) {
|
||||
scheduleId
|
||||
taskId
|
||||
process {
|
||||
id
|
||||
name
|
||||
serviceId
|
||||
serviceName
|
||||
instanceId
|
||||
instanceName
|
||||
agentId
|
||||
detectType
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
labels
|
||||
}
|
||||
startTime
|
||||
endTime
|
||||
}`,
|
||||
};
|
||||
|
||||
export const analysisEBPFResult = {
|
||||
variable:
|
||||
"$scheduleIdList: [ID!]!, $timeRanges: [EBPFProfilingAnalyzeTimeRange!]!, $aggregateType: EBPFProfilingAnalyzeAggregateType",
|
||||
query: `
|
||||
analysisEBPFResult: analysisEBPFProfilingResult(scheduleIdList: $scheduleIdList, timeRanges: $timeRanges, aggregateType: $aggregateType) {
|
||||
tip
|
||||
trees {
|
||||
elements {
|
||||
id
|
||||
parentId
|
||||
symbol
|
||||
stackType
|
||||
dumpCount
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const createNetworkProfiling = {
|
||||
variable: "$request: EBPFProfilingNetworkTaskRequest!",
|
||||
query: `
|
||||
createEBPFNetworkProfiling(request: $request) {
|
||||
status
|
||||
errorReason
|
||||
id
|
||||
}`,
|
||||
};
|
||||
|
||||
export const keepNetworkProfiling = {
|
||||
variable: "$taskId: ID!",
|
||||
query: `
|
||||
keepEBPFNetworkProfiling(taskId: $taskId) {
|
||||
status
|
||||
errorReason
|
||||
}`,
|
||||
};
|
@@ -35,6 +35,5 @@ export const FetchEvents = {
|
||||
startTime
|
||||
endTime
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
@@ -30,7 +30,6 @@ export const QueryBrowserErrorLogs = {
|
||||
stack
|
||||
grade
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -54,7 +53,6 @@ export const QueryServiceLogs = {
|
||||
value
|
||||
}
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -63,3 +61,15 @@ export const QueryLogsByKeywords = {
|
||||
query: `
|
||||
support: supportQueryLogsByKeywords`,
|
||||
};
|
||||
|
||||
export const LogTagKeys = {
|
||||
variable: "$duration: Duration!",
|
||||
query: `
|
||||
tagKeys: queryLogTagAutocompleteKeys(duration: $duration)`,
|
||||
};
|
||||
|
||||
export const LogTagValues = {
|
||||
variable: "$tagKey: String!, $duration: Duration!",
|
||||
query: `
|
||||
tagValues: queryLogTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
|
||||
};
|
||||
|
@@ -41,7 +41,6 @@ export const Instances = {
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
layer
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
@@ -49,6 +48,29 @@ export const Instances = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const Processes = {
|
||||
variable: "$instanceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
processes: listProcesses(instanceId: $instanceId, duration: $duration) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
instanceId
|
||||
instanceName
|
||||
agentId
|
||||
detectType
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
labels
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const Endpoints = {
|
||||
variable: "$serviceId: ID!, $keyword: String!",
|
||||
query: `
|
||||
@@ -83,7 +105,6 @@ export const getInstance = {
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
layer
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
@@ -104,3 +125,24 @@ export const getEndpoint = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const getProcess = {
|
||||
variable: "$processId: ID!",
|
||||
query: `
|
||||
process: getProcess(processId: $processId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
instanceId
|
||||
instanceName
|
||||
agentId
|
||||
detectType
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@@ -53,8 +53,7 @@ export const EndpointTopology = {
|
||||
}`,
|
||||
};
|
||||
export const InstanceTopology = {
|
||||
variable:
|
||||
"$clientServiceId: ID!, $serverServiceId: ID!, $duration: Duration!",
|
||||
variable: "$clientServiceId: ID!, $serverServiceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
topology: getServiceInstanceTopology(clientServiceId: $clientServiceId,
|
||||
serverServiceId: $serverServiceId, duration: $duration) {
|
||||
@@ -75,3 +74,28 @@ export const InstanceTopology = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const ProcessTopology = {
|
||||
variable: "$serviceInstanceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
topology: getProcessTopology(serviceInstanceId: $serviceInstanceId,
|
||||
duration: $duration) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
isReal
|
||||
serviceName
|
||||
serviceId
|
||||
serviceInstanceId
|
||||
serviceInstanceName
|
||||
}
|
||||
calls {
|
||||
id
|
||||
source
|
||||
detectPoints
|
||||
target
|
||||
sourceComponents
|
||||
targetComponents
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@@ -27,7 +27,6 @@ export const Traces = {
|
||||
isError
|
||||
traceIds
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -70,7 +69,37 @@ export const TraceSpans = {
|
||||
value
|
||||
}
|
||||
}
|
||||
attachedEvents {
|
||||
startTime {
|
||||
seconds
|
||||
nanos
|
||||
}
|
||||
event
|
||||
endTime {
|
||||
seconds
|
||||
nanos
|
||||
}
|
||||
tags {
|
||||
key
|
||||
value
|
||||
}
|
||||
summary {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const TraceTagKeys = {
|
||||
variable: "$duration: Duration!",
|
||||
query: `
|
||||
tagKeys: queryTraceTagAutocompleteKeys(duration: $duration)`,
|
||||
};
|
||||
|
||||
export const TraceTagValues = {
|
||||
variable: "$tagKey: String!, $duration: Duration!",
|
||||
query: `
|
||||
tagValues: queryTraceTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
|
||||
};
|
||||
|
@@ -14,7 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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 * as app from "./query/app";
|
||||
import * as selector from "./query/selector";
|
||||
@@ -25,6 +26,8 @@ import * as log from "./query/log";
|
||||
import * as profile from "./query/profile";
|
||||
import * as alarm from "./query/alarm";
|
||||
import * as event from "./query/event";
|
||||
import * as ebpf from "./query/ebpf";
|
||||
import * as demandLog from "./query/demand-log";
|
||||
|
||||
const query: { [key: string]: string } = {
|
||||
...app,
|
||||
@@ -36,6 +39,8 @@ const query: { [key: string]: string } = {
|
||||
...profile,
|
||||
...alarm,
|
||||
...event,
|
||||
...ebpf,
|
||||
...demandLog,
|
||||
};
|
||||
class Graphql {
|
||||
private queryData = "";
|
||||
@@ -51,13 +56,11 @@ class Graphql {
|
||||
query: query[this.queryData],
|
||||
variables: variablesData,
|
||||
},
|
||||
{ cancelToken: cancelToken() }
|
||||
{ cancelToken: cancelToken() },
|
||||
)
|
||||
.then((res: AxiosResponse) => {
|
||||
if (res.data.errors) {
|
||||
res.data.errors = res.data.errors
|
||||
.map((e: { message: string }) => e.message)
|
||||
.join(" ");
|
||||
res.data.errors = res.data.errors.map((e: { message: string }) => e.message).join(" ");
|
||||
}
|
||||
return res;
|
||||
})
|
||||
|
22
src/graphql/query/demand-log.ts
Normal 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.
|
||||
*/
|
||||
|
||||
import { queryContainers, queryStreamingLogs } from "../fragments/demand-log";
|
||||
|
||||
export const fetchContainers = `query listContainers(${queryContainers.variable}) {${queryContainers.query}}`;
|
||||
|
||||
export const fetchDemandPodLogs = `query ondemandPodLogs(${queryStreamingLogs.variable}) {${queryStreamingLogs.query}}`;
|
40
src/graphql/query/ebpf.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
queryCreateTaskData,
|
||||
createEBPFTask,
|
||||
queryEBPFTasks,
|
||||
queryEBPFSchedules,
|
||||
analysisEBPFResult,
|
||||
createNetworkProfiling,
|
||||
keepNetworkProfiling,
|
||||
} from "../fragments/ebpf";
|
||||
|
||||
export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`;
|
||||
|
||||
export const saveEBPFTask = `mutation createEBPFTask(${createEBPFTask.variable}) {${createEBPFTask.query}}`;
|
||||
|
||||
export const getEBPFTasks = `query queryEBPFTasks(${queryEBPFTasks.variable}) {${queryEBPFTasks.query}}`;
|
||||
|
||||
export const getEBPFSchedules = `query queryEBPFSchedules(${queryEBPFSchedules.variable}) {${queryEBPFSchedules.query}}`;
|
||||
|
||||
export const getEBPFResult = `query analysisEBPFResult(${analysisEBPFResult.variable}) {${analysisEBPFResult.query}}`;
|
||||
|
||||
export const newNetworkProfiling = `mutation createNetworkProfiling(${createNetworkProfiling.variable}) {${createNetworkProfiling.query}}`;
|
||||
|
||||
export const aliveNetworkProfiling = `mutation keepNetworkProfiling(${keepNetworkProfiling.variable}) {${keepNetworkProfiling.query}}`;
|
@@ -19,9 +19,13 @@ import {
|
||||
QueryBrowserErrorLogs,
|
||||
QueryServiceLogs,
|
||||
QueryLogsByKeywords,
|
||||
LogTagValues,
|
||||
LogTagKeys,
|
||||
} from "../fragments/log";
|
||||
|
||||
export const queryBrowserErrorLogs = `query queryBrowserErrorLogs(${QueryBrowserErrorLogs.variable}) {
|
||||
${QueryBrowserErrorLogs.query}}`;
|
||||
export const queryServiceLogs = `query queryLogs(${QueryServiceLogs.variable}) {${QueryServiceLogs.query}}`;
|
||||
export const queryLogsByKeywords = `query queryLogsByKeywords {${QueryLogsByKeywords.query}}`;
|
||||
export const queryLogTagValues = `query queryTagValues(${LogTagValues.variable}) {${LogTagValues.query}}`;
|
||||
export const queryLogTagKeys = `query queryTagKeys(${LogTagKeys.variable}) {${LogTagKeys.query}}`;
|
||||
|
@@ -22,6 +22,8 @@ import {
|
||||
getService,
|
||||
getInstance,
|
||||
getEndpoint,
|
||||
Processes,
|
||||
getProcess,
|
||||
} from "../fragments/selector";
|
||||
|
||||
export const queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||
@@ -30,4 +32,6 @@ export const queryInstances = `query queryInstances(${Instances.variable}) {${In
|
||||
export const queryLayers = `query listLayer {${Layers.query}}`;
|
||||
export const queryService = `query queryService(${getService.variable}) {${getService.query}}`;
|
||||
export const queryInstance = `query queryInstance(${getInstance.variable}) {${getInstance.query}}`;
|
||||
export const queryEndpoint = `query queryInstance(${getEndpoint.variable}) {${getEndpoint.query}}`;
|
||||
export const queryEndpoint = `query queryEndpoint(${getEndpoint.variable}) {${getEndpoint.query}}`;
|
||||
export const queryProcesses = `query queryProcesses(${Processes.variable}) {${Processes.query}}`;
|
||||
export const queryProcess = `query queryProcess(${getProcess.variable}) {${getProcess.query}}`;
|
||||
|
@@ -14,12 +14,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
InstanceTopology,
|
||||
EndpointTopology,
|
||||
ServicesTopology,
|
||||
} from "../fragments/topology";
|
||||
import { InstanceTopology, EndpointTopology, ServicesTopology, ProcessTopology } from "../fragments/topology";
|
||||
|
||||
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
|
||||
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;
|
||||
export const getServicesTopology = `query queryData(${ServicesTopology.variable}) {${ServicesTopology.query}}`;
|
||||
export const getProcessTopology = `query queryData(${ProcessTopology.variable}) {${ProcessTopology.query}}`;
|
||||
|
@@ -15,8 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Traces, TraceSpans } from "../fragments/trace";
|
||||
import { Traces, TraceSpans, TraceTagKeys, TraceTagValues } from "../fragments/trace";
|
||||
|
||||
export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`;
|
||||
|
||||
export const queryTrace = `query queryTrace(${TraceSpans.variable}) {${TraceSpans.query}}`;
|
||||
|
||||
export const queryTraceTagKeys = `query queryTraceTagKeys(${TraceTagKeys.variable}) {${TraceTagKeys.query}}`;
|
||||
|
||||
export const queryTraceTagValues = `query queryTraceTagValues(${TraceTagValues.variable}) {${TraceTagValues.query}}`;
|
||||
|
@@ -21,6 +21,7 @@ export enum MetricQueryTypes {
|
||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
||||
READHEATMAP = "readHeatMap",
|
||||
ReadSampledRecords = "readSampledRecords",
|
||||
ReadRecords = "readRecords",
|
||||
}
|
||||
|
||||
export enum Calculations {
|
||||
@@ -29,10 +30,16 @@ export enum Calculations {
|
||||
ByteToMB = "byteToMB",
|
||||
ByteToGB = "byteToGB",
|
||||
Apdex = "apdex",
|
||||
Precision = "precision",
|
||||
ConvertSeconds = "convertSeconds",
|
||||
ConvertMilliseconds = "convertMilliseconds",
|
||||
MsTos = "msTos",
|
||||
MsToS = "msTos",
|
||||
Average = "average",
|
||||
PercentageAvg = "percentageAvg",
|
||||
ApdexAvg = "apdexAvg",
|
||||
SecondToDay = "secondToDay",
|
||||
NanosecondToMillisecond = "nanosecondToMillisecond",
|
||||
CPM5D = "cpm5d",
|
||||
CPM5DAvg = "cpm5dAvg",
|
||||
}
|
||||
export enum sizeEnum {
|
||||
XS = "XS",
|
||||
@@ -61,7 +68,7 @@ screenMap.set(sizeEnum.LG, screenEnum.LG);
|
||||
screenMap.set(sizeEnum.XL, screenEnum.XL);
|
||||
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
||||
|
||||
export const RespFields: any = {
|
||||
export const RespFields: { [key: string]: string } = {
|
||||
readMetricsValues: `{
|
||||
label
|
||||
values {
|
||||
@@ -96,4 +103,10 @@ export const RespFields: any = {
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
readRecords: `{
|
||||
id
|
||||
name
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
||||
|
120
src/hooks/useAssociateProcessor.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import dateFormatStep from "@/utils/dateFormat";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import type { EventParams } from "@/types/app";
|
||||
|
||||
export default function associateProcessor(props: any) {
|
||||
function eventAssociate() {
|
||||
if (!props.filters) {
|
||||
return;
|
||||
}
|
||||
if (!props.filters.duration) {
|
||||
return props.option;
|
||||
}
|
||||
if (!props.option.series[0]) {
|
||||
return;
|
||||
}
|
||||
const list = props.option.series[0].data.map((d: (number | string)[]) => d[0]);
|
||||
if (!list.includes(props.filters.duration.endTime)) {
|
||||
return;
|
||||
}
|
||||
const markArea = {
|
||||
silent: true,
|
||||
itemStyle: {
|
||||
opacity: 0.3,
|
||||
},
|
||||
data: [
|
||||
[
|
||||
{
|
||||
xAxis: props.filters.duration.startTime,
|
||||
},
|
||||
{
|
||||
xAxis: props.filters.duration.endTime,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
const series = (window as any).structuredClone(props.option.series);
|
||||
for (const [key, temp] of series.entries()) {
|
||||
if (key === 0) {
|
||||
temp.markArea = markArea;
|
||||
}
|
||||
}
|
||||
const options = {
|
||||
...props.option,
|
||||
series,
|
||||
};
|
||||
return options;
|
||||
}
|
||||
function traceFilters(currentParams: Nullable<EventParams>) {
|
||||
const appStore = useAppStoreWithOut();
|
||||
|
||||
if (!currentParams) {
|
||||
return;
|
||||
}
|
||||
const start = appStore.intervalUnix[currentParams.dataIndex];
|
||||
const { step } = appStore.durationRow;
|
||||
let duration = undefined;
|
||||
|
||||
if (start) {
|
||||
const end = start;
|
||||
duration = {
|
||||
start: dateFormatStep(getLocalTime(appStore.utc, new Date(start)), step, true),
|
||||
end: dateFormatStep(getLocalTime(appStore.utc, new Date(end)), step, true),
|
||||
step,
|
||||
};
|
||||
}
|
||||
const relatedTrace = props.relatedTrace || {};
|
||||
const status = relatedTrace.status;
|
||||
const queryOrder = relatedTrace.queryOrder;
|
||||
const latency = relatedTrace.latency;
|
||||
const series = props.option.series || [];
|
||||
const item: any = {
|
||||
duration,
|
||||
queryOrder,
|
||||
status,
|
||||
};
|
||||
if (latency) {
|
||||
const latencyList = series.map((d: { name: string; data: number[][] }, index: number) => {
|
||||
const data = [
|
||||
d.data[currentParams.dataIndex][1],
|
||||
series[index + 1] ? series[index + 1].data[currentParams.dataIndex][1] : Infinity,
|
||||
];
|
||||
return {
|
||||
label: d.name + "--" + (series[index + 1] ? series[index + 1].name : "Infinity"),
|
||||
value: String(index),
|
||||
data,
|
||||
};
|
||||
});
|
||||
item.latency = latencyList;
|
||||
}
|
||||
const value = series.map((d: { name: string; data: number[][] }, index: number) => {
|
||||
return {
|
||||
label: d.name,
|
||||
value: String(index),
|
||||
data: d.data[currentParams.dataIndex][1],
|
||||
date: d.data[currentParams.dataIndex][0],
|
||||
};
|
||||
});
|
||||
item.metricValue = value;
|
||||
return item;
|
||||
}
|
||||
|
||||
return { eventAssociate, traceFilters };
|
||||
}
|
@@ -14,7 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* 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 { screenMap, sizeEnum, screenEnum } from "./data";
|
||||
|
||||
@@ -40,9 +41,7 @@ export function useBreakpoint(): any {
|
||||
};
|
||||
}
|
||||
|
||||
export function createBreakpointListen(
|
||||
fn?: (opt: CreateCallbackParams) => void
|
||||
): any {
|
||||
export function createBreakpointListen(fn?: (opt: CreateCallbackParams) => void): any {
|
||||
const screenRef = ref<sizeEnum>(sizeEnum.XL || "");
|
||||
const realWidthRef = ref(window.innerWidth);
|
||||
|
||||
|
@@ -14,19 +14,64 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import type { LayoutConfig } from "@/types/dashboard";
|
||||
|
||||
export default function getDashboard(param: {
|
||||
name: string;
|
||||
layer: string;
|
||||
entity: string;
|
||||
}) {
|
||||
export default function getDashboard(param?: { name: string; layer: string; entity: string }) {
|
||||
const dashboardStore = useDashboardStore();
|
||||
const opt = param || dashboardStore.currentDashboard;
|
||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||
const dashboard = list.find(
|
||||
(d: { name: string; layer: string; entity: string }) =>
|
||||
d.name === param.name &&
|
||||
d.entity === param.entity &&
|
||||
d.layer === param.layer
|
||||
d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer,
|
||||
);
|
||||
const all = dashboardStore.layout;
|
||||
const widgets: LayoutConfig[] = [];
|
||||
for (const item of all) {
|
||||
if (item.type === "Tab") {
|
||||
widgets.push(item);
|
||||
if (item.children && item.children.length) {
|
||||
for (const child of item.children) {
|
||||
if (child.children && child.children.length) {
|
||||
widgets.push(...child.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
widgets.push(item);
|
||||
}
|
||||
}
|
||||
function associationWidget(sourceId: string, filters: unknown, type: string) {
|
||||
const widget = widgets.find((d: { type: string }) => d.type === type);
|
||||
if (!widget) {
|
||||
return ElMessage.info(`There has no a ${type} widget in the dashboard`);
|
||||
}
|
||||
const item = {
|
||||
...widget,
|
||||
filters,
|
||||
};
|
||||
dashboardStore.setWidget(item);
|
||||
const targetTabIndex = (widget.id || "").split("-");
|
||||
const sourceTabindex = (sourceId || "").split("-") || [];
|
||||
let container: Nullable<Element>;
|
||||
|
||||
return dashboard;
|
||||
if (targetTabIndex[1] === undefined) {
|
||||
container = document.querySelector(".ds-main");
|
||||
} else {
|
||||
const w = widgets.find((d: any) => d.id === targetTabIndex[0]);
|
||||
container = document.querySelector(".tab-layout");
|
||||
const layout: Nullable<Element> = document.querySelector(".ds-main");
|
||||
if (w && layout) {
|
||||
layout.scrollTop = w.y * 10 + w.h * 5;
|
||||
}
|
||||
}
|
||||
if (targetTabIndex[1] && targetTabIndex[1] !== sourceTabindex[1]) {
|
||||
dashboardStore.setActiveTabIndex(Number(targetTabIndex[1]));
|
||||
}
|
||||
if (container && widget) {
|
||||
container.scrollTop = widget.y * 10 + widget.h * 5;
|
||||
}
|
||||
}
|
||||
return { dashboard, widgets, associationWidget };
|
||||
}
|
||||
|
@@ -14,14 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
BarSeriesOption,
|
||||
LineSeriesOption,
|
||||
HeatmapSeriesOption,
|
||||
PieSeriesOption,
|
||||
SankeySeriesOption,
|
||||
} from "echarts/charts";
|
||||
import {
|
||||
import type { BarSeriesOption, LineSeriesOption, HeatmapSeriesOption, SankeySeriesOption } from "echarts/charts";
|
||||
import type {
|
||||
TitleComponentOption,
|
||||
TooltipComponentOption,
|
||||
GridComponentOption,
|
||||
@@ -46,14 +40,10 @@ export type ECOption = echarts.ComposeOption<
|
||||
| DatasetComponentOption
|
||||
| LegendComponentOption
|
||||
| HeatmapSeriesOption
|
||||
| PieSeriesOption
|
||||
| SankeySeriesOption
|
||||
>;
|
||||
|
||||
export function useECharts(
|
||||
elRef: Ref<HTMLDivElement>,
|
||||
theme: "light" | "dark" | "default" = "default"
|
||||
): any {
|
||||
export function useECharts(elRef: Ref<HTMLDivElement>, theme: "light" | "dark" | "default" = "default"): any {
|
||||
const getDarkMode = computed(() => {
|
||||
return theme === "default" ? "light" : theme;
|
||||
});
|
||||
@@ -79,7 +69,11 @@ export function useECharts(
|
||||
if (!el || !unref(el)) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = el.getBoundingClientRect();
|
||||
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
chartInstance = echarts.init(el, t);
|
||||
const { removeEvent } = useEventListener({
|
||||
el: window,
|
||||
@@ -129,7 +123,7 @@ export function useECharts(
|
||||
initCharts(theme as "default");
|
||||
setOptions(cacheOptions.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
tryOnUnmounted(() => {
|
||||
|
@@ -43,16 +43,13 @@ export function useEventListener({
|
||||
if (el) {
|
||||
const element = ref(el as Element) as Ref<Element>;
|
||||
|
||||
const handler = isDebounce
|
||||
? useDebounceFn(listener, wait)
|
||||
: useThrottleFn(listener, wait);
|
||||
const handler = isDebounce ? useDebounceFn(listener, wait) : useThrottleFn(listener, wait);
|
||||
const realHandler = wait ? handler : listener;
|
||||
const removeEventListener = (e: Element) => {
|
||||
isAddRef.value = true;
|
||||
e.removeEventListener(name, realHandler, options);
|
||||
};
|
||||
const addEventListener = (e: Element) =>
|
||||
e.addEventListener(name, realHandler, options);
|
||||
const addEventListener = (e: Element) => e.addEventListener(name, realHandler, options);
|
||||
|
||||
const removeWatch = watch(
|
||||
element,
|
||||
@@ -64,7 +61,7 @@ export function useEventListener({
|
||||
});
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
remove = () => {
|
||||
|
132
src/hooks/useLegendProcessor.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { LegendOptions } from "@/types/dashboard";
|
||||
import { isDef } from "@/utils/is";
|
||||
|
||||
export default function useLegendProcess(legend?: LegendOptions) {
|
||||
let isRight = false;
|
||||
if (legend && legend.toTheRight) {
|
||||
isRight = true;
|
||||
}
|
||||
function showEchartsLegend(keys: string[]) {
|
||||
if (legend && isDef(legend.show)) {
|
||||
if (legend.asTable && legend.show) {
|
||||
return false;
|
||||
}
|
||||
return legend.show;
|
||||
}
|
||||
if (keys.length === 1) {
|
||||
return false;
|
||||
}
|
||||
if (legend && legend.asTable) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function aggregations(data: { [key: string]: number[] }, intervalTime: string[]) {
|
||||
const source: { [key: string]: unknown }[] = [];
|
||||
const keys = Object.keys(data || {}).filter((i: any) => Array.isArray(data[i]) && data[i].length);
|
||||
const headers = [];
|
||||
|
||||
for (const [key, value] of keys.entries()) {
|
||||
const arr = JSON.parse(JSON.stringify(data[value]));
|
||||
const item: { [key: string]: unknown } = {
|
||||
name: value,
|
||||
topN: arr
|
||||
.map((d: number, index: number) => {
|
||||
return {
|
||||
key: intervalTime[index],
|
||||
value: d,
|
||||
};
|
||||
})
|
||||
.sort((a: { key: string; value: number }, b: { key: string; value: number }) => b.value - a.value)
|
||||
.filter((_: unknown, index: number) => index < 10),
|
||||
};
|
||||
if (legend) {
|
||||
if (legend.min) {
|
||||
item.min = Math.min(...data[value]).toFixed(2);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "min", label: "Min" });
|
||||
}
|
||||
}
|
||||
if (legend.max) {
|
||||
item.max = Math.max(...data[value]).toFixed(2);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "max", label: "Max" });
|
||||
}
|
||||
}
|
||||
if (legend.mean) {
|
||||
const total = data[value].reduce((prev: number, next: number) => {
|
||||
prev += Number(next);
|
||||
return prev;
|
||||
}, 0);
|
||||
item.mean = (total / data[value].length).toFixed(4);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "mean", label: "Mean" });
|
||||
}
|
||||
}
|
||||
if (legend.total) {
|
||||
item.total = data[value]
|
||||
.reduce((prev: number, next: number) => {
|
||||
prev += Number(next);
|
||||
return prev;
|
||||
}, 0)
|
||||
.toFixed(2);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "total", label: "Total" });
|
||||
}
|
||||
}
|
||||
}
|
||||
source.push(item);
|
||||
}
|
||||
|
||||
return { source, headers };
|
||||
}
|
||||
function chartColors(keys: string[]) {
|
||||
let color: string[] = [];
|
||||
switch (keys.length) {
|
||||
case 2:
|
||||
color = ["#FF6A84", "#a0b1e6"];
|
||||
break;
|
||||
case 1:
|
||||
color = ["#3f96e3"];
|
||||
break;
|
||||
default:
|
||||
color = [
|
||||
"#30A4EB",
|
||||
"#45BFC0",
|
||||
"#FFCC55",
|
||||
"#FF6A84",
|
||||
"#a0a7e6",
|
||||
"#c23531",
|
||||
"#2f4554",
|
||||
"#61a0a8",
|
||||
"#d48265",
|
||||
"#91c7ae",
|
||||
"#749f83",
|
||||
"#ca8622",
|
||||
"#bda29a",
|
||||
"#6e7074",
|
||||
"#546570",
|
||||
"#c4ccd3",
|
||||
];
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
return { showEchartsLegend, isRight, aggregations, chartColors };
|
||||
}
|
32
src/hooks/useListConfig.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { MetricQueryTypes, Calculations } from "./data";
|
||||
export function useListConfig(config: any, index: string) {
|
||||
const i = Number(index);
|
||||
const types = [Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg];
|
||||
const calculation = config.metricConfig && config.metricConfig[i] && config.metricConfig[i].calculation;
|
||||
const isLinear =
|
||||
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
||||
!types.includes(calculation);
|
||||
const isAvg =
|
||||
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
||||
types.includes(calculation);
|
||||
return {
|
||||
isLinear,
|
||||
isAvg,
|
||||
};
|
||||
}
|
469
src/hooks/useMetricsProcessor.ts
Normal file
@@ -0,0 +1,469 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import dayjs from "dayjs";
|
||||
import { RespFields, MetricQueryTypes, Calculations } from "./data";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import type { Instance, Endpoint, Service } from "@/types/selector";
|
||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||
import { MetricCatalog } from "@/views/dashboard/data";
|
||||
|
||||
export function useQueryProcessor(config: any) {
|
||||
if (!(config.metrics && config.metrics[0])) {
|
||||
return;
|
||||
}
|
||||
if (!(config.metricTypes && config.metricTypes[0])) {
|
||||
return;
|
||||
}
|
||||
const appStore = useAppStoreWithOut();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
|
||||
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
||||
return;
|
||||
}
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`];
|
||||
const isRelation = ["ServiceRelation", "ServiceInstanceRelation", "EndpointRelation", "ProcessRelation"].includes(
|
||||
dashboardStore.entity,
|
||||
);
|
||||
if (isRelation && !selectorStore.currentDestService) {
|
||||
return;
|
||||
}
|
||||
const fragment = config.metrics.map((name: string, index: number) => {
|
||||
const metricType = config.metricTypes[index] || "";
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
if ([MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics].includes(metricType)) {
|
||||
variables.push(`$condition${index}: TopNCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
parentService: ["All"].includes(dashboardStore.entity) ? null : selectorStore.currentService.value,
|
||||
normal: selectorStore.currentService ? selectorStore.currentService.normal : true,
|
||||
scope: config.catalog,
|
||||
topN: c.topN || 10,
|
||||
order: c.sortOrder || "DES",
|
||||
};
|
||||
} else {
|
||||
const entity = {
|
||||
scope: config.catalog,
|
||||
serviceName: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.value,
|
||||
normal: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.normal,
|
||||
serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", "ProcessRelation"].includes(
|
||||
dashboardStore.entity,
|
||||
)
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
processName: dashboardStore.entity.includes("Process")
|
||||
? selectorStore.currentProcess && selectorStore.currentProcess.value
|
||||
: undefined,
|
||||
destNormal: isRelation ? selectorStore.currentDestService.normal : undefined,
|
||||
destServiceName: isRelation ? selectorStore.currentDestService.value : undefined,
|
||||
destServiceInstanceName: ["ServiceInstanceRelation", "ProcessRelation"].includes(dashboardStore.entity)
|
||||
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
destEndpointName:
|
||||
dashboardStore.entity === "EndpointRelation"
|
||||
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
destProcessName: dashboardStore.entity.includes("ProcessRelation")
|
||||
? selectorStore.currentDestProcess && selectorStore.currentDestProcess.value
|
||||
: undefined,
|
||||
};
|
||||
if ([MetricQueryTypes.ReadRecords].includes(metricType)) {
|
||||
variables.push(`$condition${index}: RecordCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
parentEntity: entity,
|
||||
topN: c.topN || 10,
|
||||
order: c.sortOrder || "DES",
|
||||
};
|
||||
} else {
|
||||
entity.scope = dashboardStore.entity;
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
variables.push(`$labels${index}: [String!]!`);
|
||||
conditions[`labels${index}`] = labels;
|
||||
}
|
||||
variables.push(`$condition${index}: MetricsCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
entity,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
} else {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
}
|
||||
});
|
||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
|
||||
return {
|
||||
queryStr,
|
||||
conditions,
|
||||
};
|
||||
}
|
||||
export function useSourceProcessor(
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
config: {
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricConfig: MetricConfigOpt[];
|
||||
},
|
||||
) {
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
if (!resp.data) {
|
||||
ElMessage.error("The query is wrong");
|
||||
return {};
|
||||
}
|
||||
const source: { [key: string]: unknown } = {};
|
||||
const keys = Object.keys(resp.data);
|
||||
|
||||
config.metricTypes.forEach((type: string, index) => {
|
||||
const m = config.metrics[index];
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
|
||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
||||
source[c.label || m] = (resp.data[keys[index]] && calculateExp(resp.data[keys[index]].values.values, c)) || [];
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const resVal = Object.values(resp.data)[0] || [];
|
||||
const labels = (c.label || "").split(",").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) {
|
||||
const values = item.values.values.map((d: { value: number }) => aggregation(Number(d.value), c));
|
||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||
if (labels[indexNum] && indexNum > -1) {
|
||||
source[labels[indexNum]] = values;
|
||||
} else {
|
||||
source[item.label] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadMetricsValue) {
|
||||
source[m] = aggregation(Number(Object.values(resp.data)[0]), c);
|
||||
}
|
||||
if (
|
||||
(
|
||||
[MetricQueryTypes.ReadRecords, MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics] as string[]
|
||||
).includes(type)
|
||||
) {
|
||||
source[m] = (Object.values(resp.data)[0] || []).map((d: { value: unknown; name: string }) => {
|
||||
d.value = aggregation(Number(d.value), c);
|
||||
|
||||
return d;
|
||||
});
|
||||
}
|
||||
if (type === MetricQueryTypes.READHEATMAP) {
|
||||
const resVal = Object.values(resp.data)[0] || {};
|
||||
const nodes = [] as any;
|
||||
if (!(resVal && resVal.values)) {
|
||||
source[m] = { nodes: [] };
|
||||
return;
|
||||
}
|
||||
resVal.values.forEach((items: { values: number[] }, x: number) => {
|
||||
const grids = items.values.map((val: number, y: number) => [x, y, val]);
|
||||
|
||||
nodes.push(...grids);
|
||||
});
|
||||
let buckets = [] as any;
|
||||
if (resVal.buckets.length) {
|
||||
buckets = [resVal.buckets[0].min, ...resVal.buckets.map((item: { min: string; max: string }) => item.max)];
|
||||
}
|
||||
|
||||
source[m] = { nodes, buckets }; // nodes: number[][]
|
||||
}
|
||||
});
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
export function useQueryPodsMetrics(
|
||||
pods: Array<Instance | Endpoint | Service | any>,
|
||||
config: {
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricConfig: MetricConfigOpt[];
|
||||
},
|
||||
scope: string,
|
||||
) {
|
||||
const metricTypes = (config.metricTypes || []).filter((m: string) => m);
|
||||
if (!metricTypes.length) {
|
||||
return;
|
||||
}
|
||||
const metrics = (config.metrics || []).filter((m: string) => m);
|
||||
if (!metrics.length) {
|
||||
return;
|
||||
}
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`];
|
||||
const currentService = selectorStore.currentService || {};
|
||||
const fragmentList = pods.map((d: (Instance | Endpoint | Service) & { normal: boolean }, index: number) => {
|
||||
const param = {
|
||||
scope,
|
||||
serviceName: scope === "Service" ? d.label : currentService.label,
|
||||
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
|
||||
endpointName: scope === "Endpoint" ? d.label : undefined,
|
||||
normal: scope === "Service" ? d.normal : currentService.normal,
|
||||
};
|
||||
const f = metrics.map((name: string, idx: number) => {
|
||||
const metricType = metricTypes[idx] || "";
|
||||
variables.push(`$condition${index}${idx}: MetricsCondition!`);
|
||||
conditions[`condition${index}${idx}`] = {
|
||||
name,
|
||||
entity: param,
|
||||
};
|
||||
let labelStr = "";
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const c = config.metricConfig[idx] || {};
|
||||
variables.push(`$labels${index}${idx}: [String!]!`);
|
||||
labelStr = `labels: $labels${index}${idx}, `;
|
||||
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
conditions[`labels${index}${idx}`] = labels;
|
||||
}
|
||||
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[metricType]}`;
|
||||
});
|
||||
return f;
|
||||
});
|
||||
const fragment = fragmentList.flat(1).join(" ");
|
||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
|
||||
export function usePodsSource(
|
||||
pods: Array<Instance | Endpoint>,
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
config: {
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricConfig: MetricConfigOpt[];
|
||||
},
|
||||
): any {
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
const names: string[] = [];
|
||||
const metricConfigArr: MetricConfigOpt[] = [];
|
||||
const metricTypesArr: string[] = [];
|
||||
const data = pods.map((d: Instance | any, idx: number) => {
|
||||
config.metrics.map((name: string, index: number) => {
|
||||
const c: any = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
const key = name + idx + index;
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
||||
d[name] = aggregation(resp.data[key], c);
|
||||
if (idx === 0) {
|
||||
names.push(name);
|
||||
metricConfigArr.push(c);
|
||||
metricTypesArr.push(config.metricTypes[index]);
|
||||
}
|
||||
}
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
||||
d[name] = {};
|
||||
if (
|
||||
[Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg].includes(
|
||||
c.calculation,
|
||||
)
|
||||
) {
|
||||
d[name]["avg"] = calculateExp(resp.data[key].values.values, c);
|
||||
}
|
||||
d[name]["values"] = resp.data[key].values.values.map((val: { value: number }) => aggregation(val.value, c));
|
||||
if (idx === 0) {
|
||||
names.push(name);
|
||||
metricConfigArr.push(c);
|
||||
metricTypesArr.push(config.metricTypes[index]);
|
||||
}
|
||||
}
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const resVal = resp.data[key] || [];
|
||||
const labels = (c.label || "").split(",").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++) {
|
||||
const item = resVal[i];
|
||||
const values = item.values.values.map((d: { value: number }) => aggregation(Number(d.value), c));
|
||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||
let key = item.label;
|
||||
if (labels[indexNum] && indexNum > -1) {
|
||||
key = labels[indexNum];
|
||||
}
|
||||
if (!d[key]) {
|
||||
d[key] = {};
|
||||
}
|
||||
if (
|
||||
[Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg].includes(
|
||||
c.calculation,
|
||||
)
|
||||
) {
|
||||
d[key]["avg"] = calculateExp(item.values.values, c);
|
||||
}
|
||||
d[key]["values"] = values;
|
||||
if (idx === 0) {
|
||||
names.push(key);
|
||||
metricConfigArr.push({ ...c, index: i });
|
||||
metricTypesArr.push(config.metricTypes[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return d;
|
||||
});
|
||||
return { data, names, metricConfigArr, metricTypesArr };
|
||||
}
|
||||
export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
|
||||
const appStore = useAppStoreWithOut();
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
ids,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`, `$ids: [ID!]!`];
|
||||
const fragmentList = metrics.map((d: string, index: number) => {
|
||||
conditions[`m${index}`] = d;
|
||||
variables.push(`$m${index}: String!`);
|
||||
|
||||
return `${d}: getValues(metric: {
|
||||
name: $m${index}
|
||||
ids: $ids
|
||||
}, duration: $duration) {
|
||||
values {
|
||||
id
|
||||
value
|
||||
}
|
||||
}`;
|
||||
});
|
||||
const queryStr = `query queryData(${variables}) {${fragmentList.join(" ")}}`;
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
function calculateExp(arr: { value: number }[], config: { calculation?: string }): (number | string)[] {
|
||||
const sum = arr.map((d: { value: number }) => d.value).reduce((a, b) => a + b);
|
||||
let data: (number | string)[] = [];
|
||||
switch (config.calculation) {
|
||||
case Calculations.Average:
|
||||
data = [(sum / arr.length).toFixed(2)];
|
||||
break;
|
||||
case Calculations.PercentageAvg:
|
||||
data = [(sum / arr.length / 100).toFixed(2)];
|
||||
break;
|
||||
case Calculations.ApdexAvg:
|
||||
data = [(sum / arr.length / 10000).toFixed(2)];
|
||||
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:
|
||||
data = arr.map((d) => aggregation(d.value, config));
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
export function aggregation(val: number, config: { calculation?: string }): number | string {
|
||||
let data: number | string = Number(val);
|
||||
|
||||
switch (config.calculation) {
|
||||
case Calculations.Percentage:
|
||||
data = (val / 100).toFixed(2);
|
||||
break;
|
||||
case Calculations.PercentageAvg:
|
||||
data = (val / 100).toFixed(2);
|
||||
break;
|
||||
case Calculations.ByteToKB:
|
||||
data = (val / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.ByteToMB:
|
||||
data = (val / 1024 / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.ByteToGB:
|
||||
data = (val / 1024 / 1024 / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.Apdex:
|
||||
data = (val / 10000).toFixed(2);
|
||||
break;
|
||||
case Calculations.CPM5D:
|
||||
data = val / 100000 < 1 && val / 100000 !== 0 ? (val / 100000).toFixed(5) : (val / 100000).toFixed(2);
|
||||
break;
|
||||
case Calculations.ConvertSeconds:
|
||||
data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
case Calculations.ConvertMilliseconds:
|
||||
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
case Calculations.MsToS:
|
||||
data = (val / 1000).toFixed(2);
|
||||
break;
|
||||
case Calculations.SecondToDay:
|
||||
data = (val / 86400).toFixed(2);
|
||||
break;
|
||||
case Calculations.NanosecondToMillisecond:
|
||||
data = (val / 1000 / 1000).toFixed(2);
|
||||
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:
|
||||
data;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function useGetMetricEntity(metric: string, metricType: any) {
|
||||
if (!metric || !metricType) {
|
||||
return;
|
||||
}
|
||||
let catalog = "";
|
||||
const dashboardStore = useDashboardStore();
|
||||
if (
|
||||
[MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics, MetricQueryTypes.ReadRecords].includes(
|
||||
metricType,
|
||||
)
|
||||
) {
|
||||
const res = await dashboardStore.fetchMetricList(metric);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
const c: string = res.data.metrics[0].catalog;
|
||||
catalog = (MetricCatalog as any)[c];
|
||||
}
|
||||
|
||||
return catalog;
|
||||
}
|
@@ -1,387 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import dayjs from "dayjs";
|
||||
import { RespFields, MetricQueryTypes, Calculations } from "./data";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { Instance, Endpoint, Service } from "@/types/selector";
|
||||
import { MetricConfigOpt } from "@/types/dashboard";
|
||||
import { MetricCatalog } from "@/views/dashboard/data";
|
||||
|
||||
export function useQueryProcessor(config: any) {
|
||||
if (!(config.metrics && config.metrics[0])) {
|
||||
return;
|
||||
}
|
||||
if (!(config.metricTypes && config.metricTypes[0])) {
|
||||
return;
|
||||
}
|
||||
const appStore = useAppStoreWithOut();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
|
||||
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
||||
return;
|
||||
}
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`];
|
||||
const isRelation = [
|
||||
"ServiceRelation",
|
||||
"ServiceInstanceRelation",
|
||||
"EndpointRelation",
|
||||
].includes(dashboardStore.entity);
|
||||
if (isRelation && !selectorStore.currentDestService) {
|
||||
return;
|
||||
}
|
||||
const fragment = config.metrics.map((name: string, index: number) => {
|
||||
const metricType = config.metricTypes[index] || "";
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
if (
|
||||
[
|
||||
MetricQueryTypes.ReadSampledRecords,
|
||||
MetricQueryTypes.SortMetrics,
|
||||
].includes(metricType)
|
||||
) {
|
||||
variables.push(`$condition${index}: TopNCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
parentService: ["All"].includes(dashboardStore.entity)
|
||||
? null
|
||||
: selectorStore.currentService.value,
|
||||
normal: selectorStore.currentService
|
||||
? selectorStore.currentService.normal
|
||||
: true,
|
||||
scope: config.catalog,
|
||||
topN: c.topN || 10,
|
||||
order: c.sortOrder || "DES",
|
||||
};
|
||||
} else {
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const labels = (c.labelsIndex || "")
|
||||
.split(",")
|
||||
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
variables.push(`$labels${index}: [String!]!`);
|
||||
conditions[`labels${index}`] = labels;
|
||||
}
|
||||
variables.push(`$condition${index}: MetricsCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
entity: {
|
||||
scope: dashboardStore.entity,
|
||||
serviceName:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.value,
|
||||
normal:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.normal,
|
||||
serviceInstanceName: dashboardStore.entity.includes("ServiceInstance")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
destNormal: isRelation
|
||||
? selectorStore.currentDestService.normal
|
||||
: undefined,
|
||||
destServiceName: isRelation
|
||||
? selectorStore.currentDestService.value
|
||||
: undefined,
|
||||
destServiceInstanceName:
|
||||
dashboardStore.entity === "ServiceInstanceRelation"
|
||||
? selectorStore.currentDestPod &&
|
||||
selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
destEndpointName:
|
||||
dashboardStore.entity === "EndpointRelation"
|
||||
? selectorStore.currentDestPod &&
|
||||
selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
} else {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
}
|
||||
});
|
||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
return {
|
||||
queryStr,
|
||||
conditions,
|
||||
};
|
||||
}
|
||||
export function useSourceProcessor(
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
config: {
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricConfig: MetricConfigOpt[];
|
||||
}
|
||||
) {
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
const source: { [key: string]: unknown } = {};
|
||||
const keys = Object.keys(resp.data);
|
||||
|
||||
config.metricTypes.forEach((type: string, index) => {
|
||||
const m = config.metrics[index];
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
|
||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
||||
source[m] = resp.data[keys[index]].values.values.map(
|
||||
(d: { value: number }) => aggregation(d.value, c)
|
||||
);
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const resVal = Object.values(resp.data)[0] || [];
|
||||
const labels = (c.label || "")
|
||||
.split(",")
|
||||
.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) {
|
||||
const values = item.values.values.map((d: { value: number }) =>
|
||||
aggregation(Number(d.value), c)
|
||||
);
|
||||
|
||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||
if (labels[indexNum] && indexNum > -1) {
|
||||
source[labels[indexNum]] = values;
|
||||
} else {
|
||||
source[item.label] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadMetricsValue) {
|
||||
source[m] = aggregation(Number(Object.values(resp.data)[0]), c);
|
||||
}
|
||||
if (
|
||||
type === MetricQueryTypes.SortMetrics ||
|
||||
type === MetricQueryTypes.ReadSampledRecords
|
||||
) {
|
||||
source[m] = (Object.values(resp.data)[0] || []).map(
|
||||
(d: { value: unknown; name: string }) => {
|
||||
d.value = aggregation(Number(d.value), c);
|
||||
|
||||
return d;
|
||||
}
|
||||
);
|
||||
}
|
||||
if (type === MetricQueryTypes.READHEATMAP) {
|
||||
const resVal = Object.values(resp.data)[0] || {};
|
||||
const nodes = [] as any;
|
||||
if (!(resVal && resVal.values)) {
|
||||
source[m] = { nodes: [] };
|
||||
return;
|
||||
}
|
||||
resVal.values.forEach((items: { values: number[] }, x: number) => {
|
||||
const grids = items.values.map((val: number, y: number) => [x, y, val]);
|
||||
|
||||
nodes.push(...grids);
|
||||
});
|
||||
let buckets = [] as any;
|
||||
if (resVal.buckets.length) {
|
||||
buckets = [
|
||||
resVal.buckets[0].min,
|
||||
...resVal.buckets.map(
|
||||
(item: { min: string; max: string }) => item.max
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
source[m] = { nodes, buckets }; // nodes: number[][]
|
||||
}
|
||||
});
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
export function useQueryPodsMetrics(
|
||||
pods: Array<Instance | Endpoint | Service | any>,
|
||||
config: { metrics: string[]; metricTypes: string[] },
|
||||
scope: string
|
||||
) {
|
||||
if (!(config.metrics && config.metrics[0])) {
|
||||
return;
|
||||
}
|
||||
if (!(config.metricTypes && config.metricTypes[0])) {
|
||||
return;
|
||||
}
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`];
|
||||
const currentService = selectorStore.currentService || {};
|
||||
const fragmentList = pods.map(
|
||||
(
|
||||
d: (Instance | Endpoint | Service) & { normal: boolean },
|
||||
index: number
|
||||
) => {
|
||||
const param = {
|
||||
scope,
|
||||
serviceName: scope === "Service" ? d.label : currentService.label,
|
||||
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
|
||||
endpointName: scope === "Endpoint" ? d.label : undefined,
|
||||
normal: scope === "Service" ? d.normal : currentService.normal,
|
||||
};
|
||||
const f = config.metrics.map((name: string, idx: number) => {
|
||||
const metricType = config.metricTypes[idx] || "";
|
||||
conditions[`condition${index}${idx}`] = {
|
||||
name,
|
||||
entity: param,
|
||||
};
|
||||
variables.push(`$condition${index}${idx}: MetricsCondition!`);
|
||||
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, duration: $duration)${RespFields[metricType]}`;
|
||||
});
|
||||
return f;
|
||||
}
|
||||
);
|
||||
const fragment = fragmentList.flat(1).join(" ");
|
||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
export function usePodsSource(
|
||||
pods: Array<Instance | Endpoint>,
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
config: {
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricConfig: MetricConfigOpt[];
|
||||
}
|
||||
): any {
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
const data = pods.map((d: Instance | any, idx: number) => {
|
||||
config.metrics.map((name: string, index: number) => {
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
const key = name + idx + index;
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
||||
d[name] = aggregation(resp.data[key], c);
|
||||
}
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
||||
d[name] = resp.data[key].values.values.map((d: { value: number }) =>
|
||||
aggregation(d.value, c)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return d;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
|
||||
const appStore = useAppStoreWithOut();
|
||||
const conditions: { [key: string]: unknown } = {
|
||||
duration: appStore.durationTime,
|
||||
ids,
|
||||
};
|
||||
const variables: string[] = [`$duration: Duration!`, `$ids: [ID!]!`];
|
||||
const fragmentList = metrics.map((d: string, index: number) => {
|
||||
conditions[`m${index}`] = d;
|
||||
variables.push(`$m${index}: String!`);
|
||||
|
||||
return `${d}: getValues(metric: {
|
||||
name: $m${index}
|
||||
ids: $ids
|
||||
}, duration: $duration) {
|
||||
values {
|
||||
id
|
||||
value
|
||||
}
|
||||
}`;
|
||||
});
|
||||
const queryStr = `query queryData(${variables}) {${fragmentList.join(" ")}}`;
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
|
||||
export function aggregation(val: number, config: any): number | string {
|
||||
let data: number | string = Number(val);
|
||||
|
||||
switch (config.calculation) {
|
||||
case Calculations.Percentage:
|
||||
data = val / 100;
|
||||
break;
|
||||
case Calculations.ByteToKB:
|
||||
data = val / 1024;
|
||||
break;
|
||||
case Calculations.ByteToMB:
|
||||
data = val / 1024 / 1024;
|
||||
break;
|
||||
case Calculations.ByteToGB:
|
||||
data = val / 1024 / 1024 / 1024;
|
||||
break;
|
||||
case Calculations.Apdex:
|
||||
data = val / 10000;
|
||||
break;
|
||||
case Calculations.ConvertSeconds:
|
||||
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
case Calculations.ConvertMilliseconds:
|
||||
data = dayjs.unix(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
case Calculations.Precision:
|
||||
data = data.toFixed(2);
|
||||
break;
|
||||
case Calculations.MsTos:
|
||||
data = val / 1000;
|
||||
break;
|
||||
default:
|
||||
data;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function useGetMetricEntity(metric: string, metricType: any) {
|
||||
if (!metric || !metricType) {
|
||||
return;
|
||||
}
|
||||
let catalog = "";
|
||||
const dashboardStore = useDashboardStore();
|
||||
if (
|
||||
[
|
||||
MetricQueryTypes.ReadSampledRecords,
|
||||
MetricQueryTypes.SortMetrics,
|
||||
].includes(metricType)
|
||||
) {
|
||||
const res = await dashboardStore.fetchMetricList(metric);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
const c: string = res.data.metrics[0].catalog;
|
||||
catalog = (MetricCatalog as any)[c];
|
||||
}
|
||||
|
||||
return catalog;
|
||||
}
|
@@ -18,11 +18,7 @@ import { ref, watch } from "vue";
|
||||
import { tryOnUnmounted } from "@vueuse/core";
|
||||
import { isFunction } from "@/utils/is";
|
||||
|
||||
export function useTimeoutFn(
|
||||
handle: Fn<any>,
|
||||
wait: number,
|
||||
native = false
|
||||
): any {
|
||||
export function useTimeoutFn(handle: Fn<any>, wait: number, native = false): any {
|
||||
if (!isFunction(handle)) {
|
||||
throw new Error("handle is not Function!");
|
||||
}
|
||||
@@ -36,7 +32,7 @@ export function useTimeoutFn(
|
||||
(maturity) => {
|
||||
maturity && handle();
|
||||
},
|
||||
{ immediate: false }
|
||||
{ immediate: false },
|
||||
);
|
||||
}
|
||||
return { readyRef, stop, start };
|
||||
|
@@ -22,15 +22,15 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { AppMain, SideBar, NavBar } from "./components";
|
||||
import { AppMain, SideBar, NavBar } from "./components";
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.app-wrapper {
|
||||
.app-wrapper {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.main-container {
|
||||
.main-container {
|
||||
flex-grow: 2;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -21,22 +21,10 @@ limitations under the License. -->
|
||||
</router-view>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
const appStore = useAppStoreWithOut();
|
||||
if (!appStore.utc) {
|
||||
const res = appStore.queryOAPTimeInfo();
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.app-main {
|
||||
.app-main {
|
||||
height: calc(100% - 40px);
|
||||
background: #f7f9fa;
|
||||
}
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
@@ -13,31 +13,22 @@ 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. -->
|
||||
<template>
|
||||
<div class="nav-bar flex-h" :class="{ dark: theme === 'dark' }">
|
||||
<div class="title">{{ appStore.pageTitle || t(pageName) }}</div>
|
||||
<div class="nav-bar flex-h">
|
||||
<div class="title">{{ route.name === "ViewWidget" ? "" : appStore.pageTitle || t(pageName) }}</div>
|
||||
<div class="app-config">
|
||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||
<TimePicker
|
||||
:value="time"
|
||||
:value="[appStore.durationRow.start, appStore.durationRow.end]"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeTimeRange"
|
||||
/>
|
||||
<span>
|
||||
UTC{{ appStore.utcHour >= 0 ? "+" : ""
|
||||
}}{{ `${appStore.utcHour}:${appStore.utcMin}` }}
|
||||
</span>
|
||||
<span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
|
||||
<span title="refresh" class="ghost ml-5 cp" @click="handleReload">
|
||||
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
||||
</span>
|
||||
<span class="version ml-5 cp">
|
||||
<el-popover
|
||||
trigger="hover"
|
||||
width="250"
|
||||
placement="bottom"
|
||||
effect="light"
|
||||
:content="appStore.version"
|
||||
>
|
||||
<el-popover trigger="hover" width="250" placement="bottom" effect="light" :content="appStore.version">
|
||||
<template #reference>
|
||||
<span>
|
||||
<Icon iconName="info_outline" size="middle" />
|
||||
@@ -49,85 +40,90 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const route = useRoute();
|
||||
const pageName = ref<string>("");
|
||||
const timeRange = ref<number>(0);
|
||||
const theme = ref<string>("light");
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const route = useRoute();
|
||||
const pageName = ref<string>("");
|
||||
const timeRange = ref<number>(0);
|
||||
|
||||
getVersion();
|
||||
const setConfig = (value: string) => {
|
||||
resetDuration();
|
||||
getVersion();
|
||||
const setConfig = (value: string) => {
|
||||
pageName.value = value || "";
|
||||
// theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
||||
};
|
||||
const time = computed(() => [
|
||||
appStore.durationRow.start,
|
||||
appStore.durationRow.end,
|
||||
]);
|
||||
const handleReload = () => {
|
||||
const gap =
|
||||
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
appStore.setDuration(timeFormat(time));
|
||||
};
|
||||
function changeTimeRange(val: Date[] | any) {
|
||||
timeRange.value =
|
||||
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
};
|
||||
|
||||
function handleReload() {
|
||||
const gap = appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||
const dates: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
appStore.setDuration(timeFormat(dates));
|
||||
}
|
||||
|
||||
function changeTimeRange(val: Date[] | any) {
|
||||
timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
if (timeRange.value) {
|
||||
return;
|
||||
}
|
||||
appStore.setDuration(timeFormat(val));
|
||||
}
|
||||
setConfig(String(route.meta.title));
|
||||
watch(
|
||||
}
|
||||
setConfig(String(route.meta.title));
|
||||
watch(
|
||||
() => route.meta.title,
|
||||
(title: unknown) => {
|
||||
setConfig(String(title));
|
||||
}
|
||||
);
|
||||
async function getVersion() {
|
||||
if (appStore.version) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
);
|
||||
async function getVersion() {
|
||||
const res = await appStore.fetchVersion();
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
function resetDuration() {
|
||||
const { duration }: any = route.params;
|
||||
if (duration) {
|
||||
const d = JSON.parse(duration);
|
||||
|
||||
appStore.updateDurationRow({
|
||||
start: new Date(d.start),
|
||||
end: new Date(d.end),
|
||||
step: d.step,
|
||||
});
|
||||
appStore.updateUTC(d.utc);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.nav-bar {
|
||||
padding: 5px 10px 5px 28px;
|
||||
.nav-bar {
|
||||
padding: 5px 10px;
|
||||
text-align: left;
|
||||
justify-content: space-between;
|
||||
background-color: #fafbfc;
|
||||
border-bottom: 1px solid #dfe4e8;
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-bar.dark {
|
||||
.nav-bar.dark {
|
||||
background-color: #333840;
|
||||
border-bottom: 1px solid #252a2f;
|
||||
color: #fafbfc;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
.nav-tabs {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|