feat: visualize metrics with custom configurations on widgets
feat: visualize metrics with custom configurations on widgets
3
dist/LICENSE
vendored
@ -26,3 +26,6 @@ interactjs 1.10.11: https://github.com/taye/interact.js MIT
|
||||
mitt 1.1.2: https://github.com/developit/mitt MIT
|
||||
element-resize-detector 1.2.4: https://github.com/wnr/element-resize-detector MIT
|
||||
batch-processor 1.0.0: https://github.com/wnr/batch-processor MIT
|
||||
echarts 5.2.2: https://github.com/apache/echarts Apache-2.0 License
|
||||
zrender 5.2.1: https://github.com/ecomfe/zrender BSD-3-Clause License
|
||||
tslib 2.3.0: https://github.com/Microsoft/tslib 0BSD License
|
201
dist/licenses/LICENSE-echarts
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed 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.
|
12
dist/licenses/LICENSE-tslib
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
29
dist/licenses/LICENSE-zrender
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2017, Baidu Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
36372
package-lock.json
generated
16
package.json
@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
"echarts": "^5.2.2",
|
||||
"element-plus": "^1.2.0-beta.3",
|
||||
"pinia": "^2.0.5",
|
||||
"three": "^0.131.3",
|
||||
@ -23,6 +24,7 @@
|
||||
"vuex": "^4.0.0-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/echarts": "^4.9.12",
|
||||
"@types/jest": "^24.0.19",
|
||||
"@types/three": "^0.131.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
@ -39,6 +41,7 @@
|
||||
"@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",
|
||||
@ -55,7 +58,7 @@
|
||||
"stylelint-config-standard": "^24.0.0",
|
||||
"stylelint-order": "^5.0.0",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
"typescript": "~4.1.5",
|
||||
"typescript": "~4.4.4",
|
||||
"vue-jest": "^5.0.0-0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
@ -74,9 +77,14 @@
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": [
|
||||
"off"
|
||||
]
|
||||
"@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"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
|
18
src/assets/icons/add.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<title>add</title>
|
||||
<path d="M18.984 12.984h-6v6h-1.969v-6h-6v-1.969h6v-6h1.969v6h6v1.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 969 B |
18
src/assets/icons/all_inbox.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<title>all_inbox</title>
|
||||
<path d="M15 15.984h6v3q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-3h6q0 1.219 0.891 2.109t2.109 0.891 2.109-0.891 0.891-2.109zM18.984 9v-3.984h-13.969v3.984h3.984q0 1.219 0.891 2.109t2.109 0.891 2.109-0.891 0.891-2.109h3.984zM18.984 3q0.797 0 1.406 0.609t0.609 1.406v6.984q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-6.984q0-0.797 0.609-1.406t1.406-0.609h13.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
18
src/assets/icons/cancel.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<title>cancel</title>
|
||||
<path d="M17.016 15.609l-3.609-3.609 3.609-3.609-1.406-1.406-3.609 3.609-3.609-3.609-1.406 1.406 3.609 3.609-3.609 3.609 1.406 1.406 3.609-3.609 3.609 3.609zM12 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.93z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
15
src/assets/icons/ellipsis_v.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. -->
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#8a8a8a" d="M512 298.666667a85.333333 85.333333 0 1 0-85.333333-85.333334 85.333333 85.333333 0 0 0 85.333333 85.333334z m0 426.666666a85.333333 85.333333 0 1 0 85.333333 85.333334 85.333333 85.333333 0 0 0-85.333333-85.333334z m0-298.666666a85.333333 85.333333 0 1 0 85.333333 85.333333 85.333333 85.333333 0 0 0-85.333333-85.333333z" /></svg>
|
18
src/assets/icons/info_outline.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<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>
|
After Width: | Height: | Size: 1.2 KiB |
18
src/assets/icons/insert_image.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<title>insert_image</title>
|
||||
<path d="M8.484 13.5l-3.469 4.5h13.969l-4.5-6-3.469 4.5zM21 18.984q0 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.969q0.797 0 1.406 0.609t0.609 1.406v13.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
18
src/assets/icons/keyboard_control.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<title>keyboard_control</title>
|
||||
<path d="M12 9.984q0.797 0 1.406 0.609t0.609 1.406-0.609 1.406-1.406 0.609-1.406-0.609-0.609-1.406 0.609-1.406 1.406-0.609zM18 9.984q0.797 0 1.406 0.609t0.609 1.406-0.609 1.406-1.406 0.609-1.406-0.609-0.609-1.406 0.609-1.406 1.406-0.609zM6 9.984q0.797 0 1.406 0.609t0.609 1.406-0.609 1.406-1.406 0.609-1.406-0.609-0.609-1.406 0.609-1.406 1.406-0.609z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
18
src/assets/icons/library_add.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- 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">
|
||||
<title>library_add</title>
|
||||
<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 |
18
src/assets/icons/review-list.svg
Executable file
@ -0,0 +1,18 @@
|
||||
<!-- 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 fill-rule="evenodd" d="M6.26756439,1 C6.61337381,0.40219863 7.25971764,0 8,0 C8.74028236,0 9.38662619,0.40219863 9.73243561,1 L11,1 C12.6568542,1 14,2.34314575 14,4 L14,12 C14,13.6568542 12.6568542,15 11,15 L5,15 C3.34314575,15 2,13.6568542 2,12 L2,4 C2,2.34314575 3.34314575,1 5,1 L6.26756439,1 Z M5,3 C4.44771525,3 4,3.44771525 4,4 L4,12 C4,12.5522847 4.44771525,13 5,13 L11,13 C11.5522847,13 12,12.5522847 12,12 L12,4 C12,3.44771525 11.5522847,3 11,3 L11,4 L5,4 L5,3 Z M5.5,6 L9.5,6 C9.77614237,6 10,6.22385763 10,6.5 C10,6.77614237 9.77614237,7 9.5,7 L5.5,7 C5.22385763,7 5,6.77614237 5,6.5 C5,6.22385763 5.22385763,6 5.5,6 Z M5.5,8 L10.5,8 C10.7761424,8 11,8.22385763 11,8.5 C11,8.77614237 10.7761424,9 10.5,9 L5.5,9 C5.22385763,9 5,8.77614237 5,8.5 C5,8.22385763 5.22385763,8 5.5,8 Z M5.5,10 L8.5,10 C8.77614237,10 9,10.2238576 9,10.5 C9,10.7761424 8.77614237,11 8.5,11 L5.5,11 C5.22385763,11 5,10.7761424 5,10.5 C5,10.2238576 5.22385763,10 5.5,10 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
60
src/components/Graph.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div ref="chartRef" :style="`height:${height};width:${width};`"></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
watch,
|
||||
ref,
|
||||
defineProps,
|
||||
Ref,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
unref,
|
||||
} from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useECharts } from "@/hooks/useEcharts";
|
||||
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
||||
|
||||
/*global Nullable*/
|
||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const props = defineProps({
|
||||
clickEvent: { type: Function as PropType<(param: unknown) => void> },
|
||||
height: { type: String, default: "100%" },
|
||||
width: { type: String, default: "100%" },
|
||||
option: {
|
||||
type: Object as PropType<{ [key: string]: unknown }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setOptions(props.option);
|
||||
addResizeListener(unref(chartRef), resize);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.option,
|
||||
(opt) => {
|
||||
setOptions(opt);
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
removeResizeListener(unref(chartRef), resize);
|
||||
});
|
||||
</script>
|
@ -18,6 +18,9 @@ limitations under the License. -->
|
||||
v-model="selected"
|
||||
:placeholder="placeholder"
|
||||
@change="changeSelected"
|
||||
filterable
|
||||
:multiple="multiple"
|
||||
:style="{ borderRadius }"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
@ -29,7 +32,7 @@ limitations under the License. -->
|
||||
</el-select>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import { ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { ElSelect, ElOption } from "element-plus";
|
||||
|
||||
@ -39,21 +42,32 @@ interface Option {
|
||||
}
|
||||
|
||||
const emit = defineEmits(["change"]);
|
||||
/*global defineProps*/
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<Option[]>,
|
||||
default: () => [],
|
||||
},
|
||||
value: { type: String, default: "" },
|
||||
value: {
|
||||
type: [Array, String] as PropType<string[] | string>,
|
||||
default: () => [],
|
||||
},
|
||||
size: { type: String, default: "small" },
|
||||
placeholder: { type: String, default: "Select a option" },
|
||||
borderRadius: { type: Number, default: 3 },
|
||||
multiple: { type: Boolean, default: false },
|
||||
});
|
||||
const selected = ref<string>(props.value);
|
||||
const selected = ref<string[] | string>(props.value);
|
||||
function changeSelected() {
|
||||
const optionSele = props.options.filter(
|
||||
(d: Option) => d.value === selected.value
|
||||
)[0];
|
||||
emit("change", optionSele);
|
||||
if (!props.multiple) {
|
||||
return;
|
||||
}
|
||||
const options = props.options.filter((d: Option) =>
|
||||
props.multiple
|
||||
? selected.value.includes(d.value)
|
||||
: selected.value === d.value
|
||||
);
|
||||
emit("change", options);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
@ -92,4 +106,8 @@ function changeSelected() {
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
border-radius: unset !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -17,6 +17,7 @@
|
||||
import Icon from "./Icon.vue";
|
||||
import TimePicker from "./TimePicker.vue";
|
||||
import Selector from "./Selector.vue";
|
||||
import Graph from "./Graph.vue";
|
||||
import type { App } from "vue";
|
||||
import VueGridLayout from "vue-grid-layout";
|
||||
|
||||
@ -25,6 +26,7 @@ const components: { [key: string]: any } = {
|
||||
TimePicker,
|
||||
VueGridLayout,
|
||||
Selector,
|
||||
Graph,
|
||||
};
|
||||
const componentsName: string[] = Object.keys(components);
|
||||
|
||||
|
86
src/graph/fragments/dashboard.ts
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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 TypeOfMetrics = {
|
||||
variable: "$name: String!",
|
||||
query: `typeOfMetrics(name: $name)`,
|
||||
};
|
||||
export const queryMetricsValues = {
|
||||
variable: ["$condition: MetricsCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
readMetricsValues: readMetricsValues(condition: $condition, duration: $duration) {
|
||||
label
|
||||
values {
|
||||
values {value}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const queryMetricsValue = {
|
||||
variable: ["$condition: MetricsCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
readMetricsValue: readMetricsValue(condition: $condition, duration: $duration)`,
|
||||
};
|
||||
|
||||
export const querySortMetrics = {
|
||||
variable: ["$condition: TopNCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
sortMetrics: sortMetrics(condition: $condition, duration: $duration) {
|
||||
name
|
||||
id
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
||||
export const queryLabeledMetricsValues = {
|
||||
variable: [
|
||||
"$condition: MetricsCondition!, $labels: [String!]!, $duration: Duration!",
|
||||
],
|
||||
query: `
|
||||
readLabeledMetricsValues: readLabeledMetricsValues(
|
||||
condition: $condition,
|
||||
labels: $labels,
|
||||
duration: $duration) {
|
||||
label
|
||||
values {
|
||||
values {value}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const queryHeatMap = {
|
||||
variable: ["$condition: MetricsCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
readHeatMap: readHeatMap(condition: $condition, duration: $duration) {
|
||||
values {
|
||||
id
|
||||
values
|
||||
}
|
||||
buckets {
|
||||
min
|
||||
max
|
||||
}
|
||||
}`,
|
||||
};
|
||||
export const querySampledRecords = {
|
||||
variable: ["$condition: TopNCondition!, $duration: Duration!"],
|
||||
query: `
|
||||
readSampledRecords: readSampledRecords(condition: $condition, duration: $duration) {
|
||||
name
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
@ -30,3 +30,26 @@ export const Layers = {
|
||||
layers: listLayers
|
||||
`,
|
||||
};
|
||||
export const Instances = {
|
||||
variable: "$serviceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
getServiceInstances(duration: $duration, serviceId: $serviceId) {
|
||||
key: id
|
||||
label: name
|
||||
language
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const Endpoints = {
|
||||
variable: "$serviceId: ID!, $keyword: String!",
|
||||
query: `
|
||||
getEndpoints: searchEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) {
|
||||
key: id
|
||||
label: name
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@ -18,8 +18,9 @@ import axios, { AxiosPromise, AxiosResponse } from "axios";
|
||||
import { cancelToken } from "@/utils/cancelToken";
|
||||
import * as app from "./query/app";
|
||||
import * as selector from "./query/selector";
|
||||
import * as dashboard from "./query/dashboard";
|
||||
|
||||
const query: { [key: string]: string } = { ...app, ...selector };
|
||||
const query: { [key: string]: string } = { ...app, ...selector, ...dashboard };
|
||||
class Graph {
|
||||
private queryData = "";
|
||||
public query(queryData: string) {
|
||||
|
40
src/graph/query/dashboard.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 {
|
||||
TypeOfMetrics,
|
||||
querySampledRecords,
|
||||
queryHeatMap,
|
||||
queryLabeledMetricsValues,
|
||||
querySortMetrics,
|
||||
queryMetricsValue,
|
||||
queryMetricsValues,
|
||||
} from "../fragments/dashboard";
|
||||
|
||||
export const queryTypeOfMetrics = `query typeOfMetrics(${TypeOfMetrics.variable}) {${TypeOfMetrics.query}}`;
|
||||
|
||||
export const readHeatMap = `query queryData(${queryHeatMap.variable}) {${queryHeatMap.query}}`;
|
||||
|
||||
export const readSampledRecords = `query queryData(${querySampledRecords.variable}) {${querySampledRecords.query}}`;
|
||||
|
||||
export const readLabeledMetricsValues = `query queryData(${queryLabeledMetricsValues.variable}) {
|
||||
${queryLabeledMetricsValues.query}}`;
|
||||
|
||||
export const sortMetrics = `query queryData(${querySortMetrics.variable}) {${querySortMetrics.query}}`;
|
||||
|
||||
export const readMetricsValue = `query queryData(${queryMetricsValue.variable}) {${queryMetricsValue.query}}`;
|
||||
|
||||
export const readMetricsValues = `query queryData(${queryMetricsValues.variable}) {${queryMetricsValues.query}}`;
|
@ -14,7 +14,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Services, Layers } from "../fragments/selector";
|
||||
import { Services, Layers, Endpoints, Instances } from "../fragments/selector";
|
||||
|
||||
export const queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||
export const queryLayers = `query ${Layers.query}`;
|
||||
export const queryEndpoints = `query queryEndpoints(${Endpoints.variable}) {${Endpoints.query}}`;
|
||||
|
||||
export const queryInstances = `query queryInstances(${Instances.variable}) {${Instances.query}}`;
|
||||
|
44
src/hooks/data.ts
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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 enum sizeEnum {
|
||||
XS = "XS",
|
||||
SM = "SM",
|
||||
MD = "MD",
|
||||
LG = "LG",
|
||||
XL = "XL",
|
||||
XXL = "XXL",
|
||||
}
|
||||
|
||||
export enum screenEnum {
|
||||
XS = 480,
|
||||
SM = 576,
|
||||
MD = 768,
|
||||
LG = 992,
|
||||
XL = 1200,
|
||||
XXL = 1600,
|
||||
}
|
||||
|
||||
const screenMap = new Map<sizeEnum, number>();
|
||||
|
||||
screenMap.set(sizeEnum.XS, screenEnum.XS);
|
||||
screenMap.set(sizeEnum.SM, screenEnum.SM);
|
||||
screenMap.set(sizeEnum.MD, screenEnum.MD);
|
||||
screenMap.set(sizeEnum.LG, screenEnum.LG);
|
||||
screenMap.set(sizeEnum.XL, screenEnum.XL);
|
||||
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
||||
|
||||
export { screenMap };
|
106
src/hooks/useBreakpoint.ts
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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 { ref, computed, ComputedRef, unref } from "vue";
|
||||
import { useEventListener } from "./useEventListener";
|
||||
import { screenMap, sizeEnum, screenEnum } from "./data";
|
||||
|
||||
let globalScreenRef: ComputedRef<sizeEnum | undefined>;
|
||||
let globalWidthRef: ComputedRef<number>;
|
||||
let globalRealWidthRef: ComputedRef<number>;
|
||||
|
||||
export interface CreateCallbackParams {
|
||||
screen: ComputedRef<sizeEnum | undefined>;
|
||||
width: ComputedRef<number>;
|
||||
realWidth: ComputedRef<number>;
|
||||
screenEnum: typeof screenEnum;
|
||||
screenMap: Map<sizeEnum, number>;
|
||||
sizeEnum: typeof sizeEnum;
|
||||
}
|
||||
|
||||
export function useBreakpoint(): any {
|
||||
return {
|
||||
screenRef: computed(() => unref(globalScreenRef)),
|
||||
widthRef: globalWidthRef,
|
||||
screenEnum,
|
||||
realWidthRef: globalRealWidthRef,
|
||||
};
|
||||
}
|
||||
|
||||
export function createBreakpointListen(
|
||||
fn?: (opt: CreateCallbackParams) => void
|
||||
): any {
|
||||
const screenRef = ref<sizeEnum>(sizeEnum.XL || "");
|
||||
const realWidthRef = ref(window.innerWidth);
|
||||
|
||||
function getWindowWidth() {
|
||||
const width = document.body.clientWidth;
|
||||
const xs = screenMap.get(sizeEnum.XS) || "";
|
||||
const sm = screenMap.get(sizeEnum.SM) || "";
|
||||
const md = screenMap.get(sizeEnum.MD) || "";
|
||||
const lg = screenMap.get(sizeEnum.LG) || "";
|
||||
const xl = screenMap.get(sizeEnum.XL) || "";
|
||||
if (width < xs) {
|
||||
screenRef.value = sizeEnum.XS;
|
||||
} else if (width < sm) {
|
||||
screenRef.value = sizeEnum.SM;
|
||||
} else if (width < md) {
|
||||
screenRef.value = sizeEnum.MD;
|
||||
} else if (width < lg) {
|
||||
screenRef.value = sizeEnum.LG;
|
||||
} else if (width < xl) {
|
||||
screenRef.value = sizeEnum.XL;
|
||||
} else {
|
||||
screenRef.value = sizeEnum.XXL;
|
||||
}
|
||||
realWidthRef.value = width;
|
||||
}
|
||||
|
||||
useEventListener({
|
||||
el: window,
|
||||
name: "resize",
|
||||
|
||||
listener: () => {
|
||||
getWindowWidth();
|
||||
resizeFn();
|
||||
},
|
||||
// wait: 100,
|
||||
});
|
||||
|
||||
getWindowWidth();
|
||||
globalScreenRef = computed(() => unref(screenRef));
|
||||
globalWidthRef = computed((): number => screenMap.get(unref(screenRef)) || 0);
|
||||
globalRealWidthRef = computed((): number => unref(realWidthRef));
|
||||
|
||||
function resizeFn() {
|
||||
fn?.({
|
||||
screen: globalScreenRef,
|
||||
width: globalWidthRef,
|
||||
realWidth: globalRealWidthRef,
|
||||
screenEnum,
|
||||
screenMap,
|
||||
sizeEnum,
|
||||
});
|
||||
}
|
||||
|
||||
resizeFn();
|
||||
return {
|
||||
screenRef: globalScreenRef,
|
||||
screenEnum,
|
||||
widthRef: globalWidthRef,
|
||||
realWidthRef: globalRealWidthRef,
|
||||
};
|
||||
}
|
153
src/hooks/useEcharts.ts
Normal file
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* 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 {
|
||||
BarSeriesOption,
|
||||
LineSeriesOption,
|
||||
HeatmapSeriesOption,
|
||||
PieSeriesOption,
|
||||
} from "echarts/charts";
|
||||
import {
|
||||
TitleComponentOption,
|
||||
TooltipComponentOption,
|
||||
GridComponentOption,
|
||||
DatasetComponentOption,
|
||||
LegendComponentOption,
|
||||
} from "echarts/components";
|
||||
import type { Ref } from "vue";
|
||||
import { useTimeoutFn } from "./useTimeout";
|
||||
import { tryOnUnmounted } from "@vueuse/core";
|
||||
import { unref, nextTick, watch, computed, ref } from "vue";
|
||||
import { useDebounceFn } from "@vueuse/core";
|
||||
import { useEventListener } from "./useEventListener";
|
||||
import { useBreakpoint } from "./useBreakpoint";
|
||||
import echarts from "@/utils/echarts";
|
||||
|
||||
export type ECOption = echarts.ComposeOption<
|
||||
| BarSeriesOption
|
||||
| LineSeriesOption
|
||||
| TitleComponentOption
|
||||
| TooltipComponentOption
|
||||
| GridComponentOption
|
||||
| DatasetComponentOption
|
||||
| LegendComponentOption
|
||||
| HeatmapSeriesOption
|
||||
| PieSeriesOption
|
||||
>;
|
||||
|
||||
export function useECharts(
|
||||
elRef: Ref<HTMLDivElement>,
|
||||
theme: "light" | "dark" | "default" = "default"
|
||||
): any {
|
||||
const getDarkMode = computed(() => {
|
||||
return theme === "default" ? "light" : theme;
|
||||
});
|
||||
let chartInstance: Nullable<echarts.ECharts> = null;
|
||||
let resizeFn: Fn = resize;
|
||||
const cacheOptions = ref({}) as Ref<ECOption>;
|
||||
let removeResizeFn: Fn = () => ({});
|
||||
|
||||
resizeFn = useDebounceFn(resize, 200);
|
||||
|
||||
const getOptions = computed(() => {
|
||||
if (getDarkMode.value !== "dark") {
|
||||
return cacheOptions.value as ECOption;
|
||||
}
|
||||
return {
|
||||
backgroundColor: "transparent",
|
||||
...cacheOptions.value,
|
||||
} as ECOption;
|
||||
});
|
||||
|
||||
function initCharts(t = theme) {
|
||||
const el = unref(elRef);
|
||||
if (!el || !unref(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
chartInstance = echarts.init(el, t);
|
||||
const { removeEvent } = useEventListener({
|
||||
el: window,
|
||||
name: "resize",
|
||||
listener: resizeFn,
|
||||
});
|
||||
removeResizeFn = removeEvent;
|
||||
const { widthRef, screenEnum } = useBreakpoint();
|
||||
if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) {
|
||||
useTimeoutFn(() => {
|
||||
resizeFn();
|
||||
}, 30);
|
||||
}
|
||||
}
|
||||
|
||||
function setOptions(options: ECOption, clear = true) {
|
||||
cacheOptions.value = options;
|
||||
if (unref(elRef)?.offsetHeight === 0) {
|
||||
useTimeoutFn(() => {
|
||||
setOptions(unref(getOptions));
|
||||
}, 30);
|
||||
return;
|
||||
}
|
||||
nextTick(() => {
|
||||
useTimeoutFn(() => {
|
||||
if (!chartInstance) {
|
||||
initCharts(getDarkMode.value as "default");
|
||||
|
||||
if (!chartInstance) return;
|
||||
}
|
||||
clear && chartInstance?.clear();
|
||||
|
||||
chartInstance?.setOption(unref(getOptions));
|
||||
}, 30);
|
||||
});
|
||||
}
|
||||
|
||||
function resize() {
|
||||
chartInstance?.resize();
|
||||
}
|
||||
|
||||
watch(
|
||||
() => getDarkMode.value,
|
||||
(theme) => {
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
initCharts(theme as "default");
|
||||
setOptions(cacheOptions.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
tryOnUnmounted(() => {
|
||||
if (!chartInstance) return;
|
||||
removeResizeFn();
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
});
|
||||
|
||||
function getInstance(): Nullable<echarts.ECharts> {
|
||||
if (!chartInstance) {
|
||||
initCharts(getDarkMode.value as "default");
|
||||
}
|
||||
return chartInstance;
|
||||
}
|
||||
|
||||
return {
|
||||
setOptions,
|
||||
resize,
|
||||
echarts,
|
||||
getInstance,
|
||||
};
|
||||
}
|
76
src/hooks/useEventListener.ts
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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 { Ref } from "vue";
|
||||
import { ref, watch, unref } from "vue";
|
||||
import { useThrottleFn, useDebounceFn } from "@vueuse/core";
|
||||
|
||||
export type RemoveEventFn = () => void;
|
||||
export interface UseEventParams {
|
||||
el?: Element | Ref<Element | undefined> | Window | any;
|
||||
name: string;
|
||||
listener: EventListener;
|
||||
options?: boolean | AddEventListenerOptions;
|
||||
autoRemove?: boolean;
|
||||
isDebounce?: boolean;
|
||||
wait?: number;
|
||||
}
|
||||
export function useEventListener({
|
||||
el = window,
|
||||
name,
|
||||
listener,
|
||||
options,
|
||||
autoRemove = true,
|
||||
isDebounce = true,
|
||||
wait = 80,
|
||||
}: UseEventParams): { removeEvent: RemoveEventFn } {
|
||||
let remove: RemoveEventFn = () => ({});
|
||||
const isAddRef = ref(false);
|
||||
|
||||
if (el) {
|
||||
const element = ref(el as Element) as Ref<Element>;
|
||||
|
||||
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 removeWatch = watch(
|
||||
element,
|
||||
(v, _ov, cleanUp) => {
|
||||
if (v) {
|
||||
!unref(isAddRef) && addEventListener(v);
|
||||
cleanUp(() => {
|
||||
autoRemove && removeEventListener(v);
|
||||
});
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
remove = () => {
|
||||
removeEventListener(element.value);
|
||||
removeWatch();
|
||||
};
|
||||
}
|
||||
return { removeEvent: remove };
|
||||
}
|
65
src/hooks/useTimeout.ts
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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 { 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 {
|
||||
if (!isFunction(handle)) {
|
||||
throw new Error("handle is not Function!");
|
||||
}
|
||||
|
||||
const { readyRef, stop, start } = useTimeoutRef(wait);
|
||||
if (native) {
|
||||
handle();
|
||||
} else {
|
||||
watch(
|
||||
readyRef,
|
||||
(maturity) => {
|
||||
maturity && handle();
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
}
|
||||
return { readyRef, stop, start };
|
||||
}
|
||||
|
||||
export function useTimeoutRef(wait: number): any {
|
||||
const readyRef = ref(false);
|
||||
|
||||
let timer: TimeoutHandle;
|
||||
function stop(): void {
|
||||
readyRef.value = false;
|
||||
timer && window.clearTimeout(timer);
|
||||
}
|
||||
function start(): void {
|
||||
stop();
|
||||
timer = setTimeout(() => {
|
||||
readyRef.value = true;
|
||||
}, wait);
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
tryOnUnmounted(stop);
|
||||
|
||||
return { readyRef, stop, start };
|
||||
}
|
@ -18,10 +18,10 @@ limitations under the License. -->
|
||||
<div class="app-config">
|
||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||
<TimePicker
|
||||
v-model="time"
|
||||
:value="time"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeTimeRange"
|
||||
/>
|
||||
<span>
|
||||
UTC{{ utcHour >= 0 ? "+" : ""
|
||||
@ -62,19 +62,18 @@ const setConfig = (value: string) => {
|
||||
pageName.value = value || "";
|
||||
theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
||||
};
|
||||
const time = computed({
|
||||
get() {
|
||||
return [appStore.durationRow.start, appStore.durationRow.end];
|
||||
},
|
||||
set(val: Date[]) {
|
||||
timeRange.value =
|
||||
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
if (timeRange.value) {
|
||||
return;
|
||||
}
|
||||
appStore.setDuration(timeFormat(val));
|
||||
},
|
||||
});
|
||||
const time = computed(() => [
|
||||
appStore.durationRow.start,
|
||||
appStore.durationRow.end,
|
||||
]);
|
||||
function changeTimeRange(val: Date[]) {
|
||||
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(
|
||||
() => route.meta.title,
|
||||
@ -93,17 +92,20 @@ watch(
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.nav-bar.dark {
|
||||
background-color: #333840;
|
||||
border-bottom: 1px solid #252a2f;
|
||||
color: #fafbfc;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -37,7 +37,9 @@ limitations under the License. -->
|
||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||
</el-icon>
|
||||
<span>{{ t(menu.meta.title) }}</span>
|
||||
<span :class="isCollapse ? 'collapse' : ''">{{
|
||||
t(menu.meta.title)
|
||||
}}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
@ -88,24 +90,16 @@ limitations under the License. -->
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useRouter, RouteRecordRaw, RouteRecordName } from "vue-router";
|
||||
import { useRouter, RouteRecordRaw } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import {
|
||||
ElMenu,
|
||||
ElMenuItem,
|
||||
ElSubMenu,
|
||||
ElMenuItemGroup,
|
||||
ElIcon,
|
||||
} from "element-plus";
|
||||
|
||||
const { t } = useI18n();
|
||||
const name: RouteRecordName | null | undefined = String(
|
||||
useRouter().currentRoute.value.name
|
||||
);
|
||||
const theme = ["VirtualMachine", "Kubernetes"].includes(name || "")
|
||||
const name = ref<any>(String(useRouter().currentRoute.value.name));
|
||||
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "")
|
||||
? ref("light")
|
||||
: ref("black");
|
||||
const routes = useRouter().options.routes;
|
||||
const isCollapse = ref(false);
|
||||
const routes = ref<any>(useRouter().options.routes);
|
||||
const isCollapse = ref(true);
|
||||
const controlMenu = () => {
|
||||
isCollapse.value = !isCollapse.value;
|
||||
};
|
||||
@ -125,40 +119,56 @@ const filterMenus = (menus: any[]) => {
|
||||
height: 100%;
|
||||
background: #252a2f;
|
||||
font-weight: bold;
|
||||
// box-shadow: 1px 5px 3px #888;
|
||||
}
|
||||
|
||||
.el-menu-vertical:not(.el-menu--collapse) {
|
||||
width: 210px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.logo-icon-collapse {
|
||||
width: 65px;
|
||||
margin: 15px 0 30px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.collapse {
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
margin: 15px 0 30px 15px;
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.el-sub-menu .el-icon {
|
||||
height: 26px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.el-sub-menu__title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.menu-control {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 215px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s linear;
|
||||
z-index: 9999;
|
||||
z-index: 99;
|
||||
color: #252a2f;
|
||||
}
|
||||
|
||||
.menu-control.collapse {
|
||||
left: 70px;
|
||||
}
|
||||
|
||||
.el-icon.el-sub-menu__icon-arrow {
|
||||
height: 12px;
|
||||
}
|
||||
|
@ -52,6 +52,26 @@ const msg = {
|
||||
endpoint: "Endpoint",
|
||||
instance: "Instance",
|
||||
create: "Create",
|
||||
loading: "Loading",
|
||||
selectVisualization: "Select your visualization",
|
||||
graphStyles: "Graph styles",
|
||||
widgetOptions: "Widget options",
|
||||
standardOptions: "Standard options",
|
||||
max: "Max",
|
||||
min: "Min",
|
||||
plus: "Plus",
|
||||
minus: "Minus",
|
||||
multiply: "Multiply",
|
||||
divide: "Divide",
|
||||
convertToMilliseconds: "Convert Unix Timestamp(milliseconds)",
|
||||
convertToSeconds: "Convert Unix Timestamp(seconds)",
|
||||
smooth: "Smooth",
|
||||
showSymbol: "Show Symbol",
|
||||
step: "Step",
|
||||
showValues: "Show Values",
|
||||
fontSize: "Font Size",
|
||||
showBackground: "Show Background",
|
||||
areaOpacity: "Area Opacity",
|
||||
hourTip: "Select Hour",
|
||||
minuteTip: "Select Minute",
|
||||
secondTip: "Select Second",
|
||||
@ -218,7 +238,7 @@ const msg = {
|
||||
grade: "Grade",
|
||||
relatedTraceLogs: "Related Logs",
|
||||
setConditions: "More Conditions",
|
||||
metricName: "Metric Name",
|
||||
metricName: "Select Metric Names",
|
||||
keywordsOfContent: "Keys Of Content",
|
||||
excludingKeywordsOfContent: "Exclude Keys Of Content",
|
||||
return: "Return",
|
||||
@ -247,8 +267,6 @@ const msg = {
|
||||
eventsParameters: "Event Parameters",
|
||||
eventDetail: "Event Detail",
|
||||
value: "Value",
|
||||
tableHeader: "Header Names",
|
||||
tableValues: "Table Values",
|
||||
show: "Show",
|
||||
hide: "Hide",
|
||||
statistics: "Statistics",
|
||||
|
@ -50,6 +50,26 @@ const msg = {
|
||||
layer: "层",
|
||||
endpoint: "端点",
|
||||
create: "新建",
|
||||
loading: "加载中",
|
||||
selectVisualization: "选择你的可视化",
|
||||
graphStyles: "图形样式",
|
||||
widgetOptions: "组件选项",
|
||||
standardOptions: "标准选项",
|
||||
max: "最大值",
|
||||
min: "最小值",
|
||||
plus: "加法",
|
||||
minus: "减法",
|
||||
multiply: "乘法",
|
||||
divide: "除法",
|
||||
convertToMilliseconds: "转换Unix时间戳(毫秒)",
|
||||
convertToSeconds: "转换Unix时间戳(秒)",
|
||||
smooth: "光滑的",
|
||||
showSymbol: "显示符号",
|
||||
step: "台阶",
|
||||
showValues: "显示值",
|
||||
fontSize: "字体大小",
|
||||
showBackground: "显示背景",
|
||||
areaOpacity: "透明度",
|
||||
hourTip: "选择小时",
|
||||
minuteTip: "选择分钟",
|
||||
secondTip: "选择秒数",
|
||||
@ -217,7 +237,7 @@ const msg = {
|
||||
grade: "等级",
|
||||
relatedTraceLogs: "相关的日志",
|
||||
setConditions: "更多条件",
|
||||
metricName: "指标名称",
|
||||
metricName: "选择指标名称",
|
||||
keywordsOfContent: "内容关键词",
|
||||
excludingKeywordsOfContent: "内容不包含的关键词",
|
||||
return: "返回",
|
||||
|
@ -20,12 +20,14 @@ import router from "./router";
|
||||
import { store } from "./store";
|
||||
import components from "@/components";
|
||||
import i18n from "./locales";
|
||||
import "element-plus/dist/index.css";
|
||||
import "./styles/lib.scss";
|
||||
import "./styles/reset.scss";
|
||||
import ElementPlus from "element-plus";
|
||||
import "element-plus/dist/index.css";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(ElementPlus, { size: "small", zIndex: 3000 });
|
||||
app.use(components);
|
||||
app.use(i18n);
|
||||
app.use(store);
|
||||
|
@ -48,7 +48,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/dashboard/edit/:layerId/:entityId/:dashboardId",
|
||||
path: "/dashboard/edit/:layerId/:entity/:dashboardId",
|
||||
component: () => import("@/views/dashboard/Edit.vue"),
|
||||
name: "Edit",
|
||||
meta: {
|
||||
|
@ -21,7 +21,6 @@ export const routesGen: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "GeneralService",
|
||||
redirect: "/generalService",
|
||||
meta: {
|
||||
title: "generalService",
|
||||
icon: "chart",
|
||||
|
@ -53,6 +53,10 @@ router.beforeEach((to, from, next) => {
|
||||
}
|
||||
(window as any).axiosCancel = [];
|
||||
}
|
||||
next();
|
||||
if (to.path === "/") {
|
||||
next({ path: "/generalService" });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
export default router;
|
||||
|
51
src/store/data.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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 NewControl = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 24,
|
||||
h: 12,
|
||||
i: "0",
|
||||
type: "Widget",
|
||||
widget: {
|
||||
title: "Title",
|
||||
},
|
||||
graph: {},
|
||||
standard: {},
|
||||
};
|
||||
export const ConfigData: any = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 8,
|
||||
h: 12,
|
||||
i: "0",
|
||||
metrics: ["service_resp_time"],
|
||||
queryMetricType: "readMetricsValues",
|
||||
type: "Widget",
|
||||
widget: {
|
||||
title: "Title",
|
||||
tips: "Tooltip",
|
||||
},
|
||||
graph: {
|
||||
type: "Line",
|
||||
},
|
||||
standard: {
|
||||
sortOrder: "DEC",
|
||||
unit: "min",
|
||||
},
|
||||
children: [],
|
||||
};
|
@ -20,7 +20,7 @@ import { Duration, DurationTime } from "@/types/app";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import getDurationRow from "@/utils/dateTime";
|
||||
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
||||
|
||||
/*global Nullable*/
|
||||
interface AppState {
|
||||
durationRow: any;
|
||||
utc: string;
|
||||
@ -98,6 +98,7 @@ export const appStore = defineStore({
|
||||
actions: {
|
||||
setDuration(data: Duration): void {
|
||||
this.durationRow = data;
|
||||
localStorage.setItem("durationRow", JSON.stringify(data, null, 0));
|
||||
if ((window as any).axiosCancel.length !== 0) {
|
||||
for (const event of (window as any).axiosCancel) {
|
||||
setTimeout(event(), 0);
|
||||
|
@ -17,42 +17,177 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
|
||||
import graph from "@/graph";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { ConfigData } from "../data";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { NewControl } from "../data";
|
||||
interface DashboardState {
|
||||
showConfig: boolean;
|
||||
layout: LayoutConfig[];
|
||||
selectedGrid: Nullable<LayoutConfig>; // edit widgets
|
||||
entity: string;
|
||||
layerId: string;
|
||||
activedGridItem: string;
|
||||
}
|
||||
|
||||
export const dashboardStore = defineStore({
|
||||
id: "dashboard",
|
||||
state: (): DashboardState => ({
|
||||
layout: [],
|
||||
layout: [ConfigData],
|
||||
showConfig: false,
|
||||
selectedGrid: null,
|
||||
entity: "",
|
||||
layerId: "",
|
||||
activedGridItem: "",
|
||||
}),
|
||||
actions: {
|
||||
setLayout(data: LayoutConfig[]) {
|
||||
this.layout = data;
|
||||
},
|
||||
addWidget() {
|
||||
addControl(type: string) {
|
||||
const newWidget: LayoutConfig = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 24,
|
||||
h: 12,
|
||||
...NewControl,
|
||||
i: String(this.layout.length),
|
||||
type,
|
||||
};
|
||||
if (type === "Tab") {
|
||||
newWidget.h = 24;
|
||||
newWidget.children = [
|
||||
{
|
||||
name: "Tab1",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "Tab2",
|
||||
children: [],
|
||||
},
|
||||
];
|
||||
}
|
||||
this.layout = this.layout.map((d: LayoutConfig) => {
|
||||
d.y = d.y + newWidget.h;
|
||||
return d;
|
||||
});
|
||||
this.layout.push(newWidget);
|
||||
this.activedGridItem = newWidget.i;
|
||||
},
|
||||
removeWidget(item: LayoutConfig) {
|
||||
addTabItem(item: LayoutConfig) {
|
||||
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i);
|
||||
if (!this.layout[idx].children) {
|
||||
return;
|
||||
}
|
||||
const len = this.layout[idx].children?.length || 0;
|
||||
const i = {
|
||||
name: "Tab" + (len + 1),
|
||||
children: [],
|
||||
};
|
||||
this.layout[idx].children?.push(i);
|
||||
},
|
||||
addTabWidget(tabIndex: number) {
|
||||
const activedGridItem = this.activedGridItem.split("-")[0];
|
||||
const idx = this.layout.findIndex(
|
||||
(d: LayoutConfig) => d.i === activedGridItem
|
||||
);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
const { children } = this.layout[idx].children[tabIndex];
|
||||
const newWidget = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 24,
|
||||
h: 12,
|
||||
i: String(children.length),
|
||||
type: "Widget",
|
||||
widget: {
|
||||
title: "Title",
|
||||
},
|
||||
graph: {},
|
||||
standard: {},
|
||||
};
|
||||
if (this.layout[idx].children) {
|
||||
const items = children.map((d: LayoutConfig) => {
|
||||
d.y = d.y + newWidget.h;
|
||||
return d;
|
||||
});
|
||||
items.push(newWidget);
|
||||
this.layout[idx].children[tabIndex].children = items;
|
||||
}
|
||||
},
|
||||
activeGridItem(index: string) {
|
||||
this.activedGridItem = index;
|
||||
},
|
||||
removeControls(item: LayoutConfig) {
|
||||
this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i);
|
||||
},
|
||||
removeTabItem(item: LayoutConfig, index: number) {
|
||||
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i);
|
||||
if (this.layout[idx].children) {
|
||||
this.layout[idx].children?.splice(index, 1);
|
||||
}
|
||||
},
|
||||
setConfigPanel(show: boolean) {
|
||||
this.showConfig = show;
|
||||
},
|
||||
selectWidget(widget: Nullable<LayoutConfig>) {
|
||||
this.selectedGrid = widget;
|
||||
},
|
||||
setLayer(id: string) {
|
||||
this.layerId = id;
|
||||
},
|
||||
setEntity(type: string) {
|
||||
this.entity = type;
|
||||
},
|
||||
setConfigs(param: { [key: string]: unknown }) {
|
||||
const actived = this.activedGridItem.split("-");
|
||||
const index = this.layout.findIndex(
|
||||
(d: LayoutConfig) => actived[0] === d.i
|
||||
);
|
||||
|
||||
if (actived.length === 3) {
|
||||
this.layout[index].children[actived[1]].children[actived[2]] = {
|
||||
...this.layout[index],
|
||||
...param,
|
||||
};
|
||||
this.selectedGrid = this.layout[index];
|
||||
return;
|
||||
}
|
||||
this.layout[index] = {
|
||||
...this.layout[index],
|
||||
...param,
|
||||
};
|
||||
this.selectedGrid = this.layout[index];
|
||||
},
|
||||
async fetchMetricType(item: string) {
|
||||
const res: AxiosResponse = await graph
|
||||
.query("queryTypeOfMetrics")
|
||||
.params({ name: item });
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async fetchMetricValue(config: LayoutConfig) {
|
||||
// if (!config.queryMetricType) {
|
||||
// return;
|
||||
// }
|
||||
config.queryMetricType = "readMetricsValues";
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
const variable = {
|
||||
condition: {
|
||||
name: "service_resp_time",
|
||||
entity: {
|
||||
normal: true,
|
||||
scope: "Service",
|
||||
serviceName: "agentless::app",
|
||||
},
|
||||
},
|
||||
duration: appStoreWithOut.durationTime,
|
||||
};
|
||||
const res: AxiosResponse = await graph
|
||||
.query(config.queryMetricType)
|
||||
.params(variable);
|
||||
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Option } from "@/types/app";
|
||||
import { Option, Duration } from "@/types/app";
|
||||
import { store } from "@/store";
|
||||
import graph from "@/graph";
|
||||
import { AxiosResponse } from "axios";
|
||||
@ -45,6 +45,27 @@ export const selectorStore = defineStore({
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async getServiceInstances(params: {
|
||||
serviceId: string;
|
||||
duration: Duration;
|
||||
}): Promise<AxiosResponse> {
|
||||
const res: AxiosResponse = await graph
|
||||
.query("queryInstances")
|
||||
.params(params);
|
||||
return res;
|
||||
},
|
||||
async getEndpoints(params: {
|
||||
keyword: string;
|
||||
serviceId: string;
|
||||
}): Promise<AxiosResponse> {
|
||||
if (!params.keyword) {
|
||||
params.keyword = "";
|
||||
}
|
||||
const res: AxiosResponse = await graph
|
||||
.query("queryEndpoints")
|
||||
.params(params);
|
||||
return res;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
2
src/types/app.d.ts
vendored
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export interface Option {
|
||||
key: string | number;
|
||||
value: string | number;
|
||||
label: string;
|
||||
}
|
||||
export interface Duration {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { string } from "vue-types";
|
||||
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
@ -24,16 +22,62 @@ export interface LayoutConfig {
|
||||
i: string;
|
||||
widget?: WidgetConfig;
|
||||
graph?: GraphConfig;
|
||||
standard?: StandardConfig;
|
||||
metrics?: string[];
|
||||
type?: string;
|
||||
queryMetricType?: string;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export interface WidgetConfig {
|
||||
title: string;
|
||||
Metrics: string[];
|
||||
unit: string;
|
||||
tips: string;
|
||||
sortOrder: string;
|
||||
title?: string;
|
||||
tips?: string;
|
||||
}
|
||||
|
||||
export interface GraphConfig {
|
||||
type: string;
|
||||
export interface StandardConfig {
|
||||
sortOrder?: string;
|
||||
unit?: string;
|
||||
max?: string;
|
||||
min?: string;
|
||||
plus?: string;
|
||||
minus?: string;
|
||||
multiply?: string;
|
||||
divide?: string;
|
||||
milliseconds?: string;
|
||||
seconds?: string;
|
||||
}
|
||||
|
||||
export type GraphConfig = BarConfig | LineConfig | CardConfig | TableConfig;
|
||||
export interface BarConfig {
|
||||
type?: string;
|
||||
showBackground?: boolean;
|
||||
}
|
||||
export interface LineConfig extends AreaConfig {
|
||||
type?: string;
|
||||
smooth?: boolean;
|
||||
showSymbol?: boolean;
|
||||
step?: boolean;
|
||||
}
|
||||
|
||||
export interface AreaConfig {
|
||||
type?: string;
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
export interface CardConfig {
|
||||
type?: string;
|
||||
fontSize?: number;
|
||||
showUint: boolean;
|
||||
}
|
||||
|
||||
export interface TableConfig {
|
||||
type?: string;
|
||||
showTableValues: boolean;
|
||||
tableHeaderCol1: string;
|
||||
tableHeaderCol2: string;
|
||||
}
|
||||
|
||||
export interface TopListConfig {
|
||||
type?: string;
|
||||
topN: number;
|
||||
}
|
||||
|
17
src/types/echarts.d.ts
vendored
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.
|
||||
*/
|
||||
declare module "echarts";
|
29
src/types/events.d.ts
vendored
Normal 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.
|
||||
*/
|
||||
export type Event = {
|
||||
uuid: string;
|
||||
source: SourceInput;
|
||||
name: string;
|
||||
type: string;
|
||||
message: string;
|
||||
parameters: { key: string; value: string }[];
|
||||
startTime: number | string;
|
||||
endTime: number | string;
|
||||
entityType?: string;
|
||||
checked?: boolean;
|
||||
scope?: string;
|
||||
};
|
44
src/types/index.d.ts
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
declare interface Fn<T = any, R = T> {
|
||||
(...arg: T[]): R;
|
||||
}
|
||||
|
||||
declare interface PromiseFn<T = any, R = T> {
|
||||
(...arg: T[]): Promise<R>;
|
||||
}
|
||||
|
||||
declare type RefType<T> = T | null;
|
||||
|
||||
declare type LabelValueOptions = {
|
||||
label: string;
|
||||
value: any;
|
||||
[key: string]: string | number | boolean;
|
||||
}[];
|
||||
|
||||
declare type EmitType = (event: string, ...args: any[]) => void;
|
||||
|
||||
declare type TargetContext = "_self" | "_blank";
|
||||
|
||||
declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> {
|
||||
$el: T;
|
||||
}
|
||||
|
||||
declare type ComponentRef<T extends HTMLElement = HTMLDivElement> =
|
||||
ComponentElRef<T> | null;
|
||||
|
||||
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>;
|
33
src/utils/copy.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 { ElNotification } from "element-plus";
|
||||
export default (value: string): void => {
|
||||
const input = document.createElement("input");
|
||||
input.value = value;
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
if (document.execCommand("Copy")) {
|
||||
document.execCommand("Copy");
|
||||
}
|
||||
input.remove();
|
||||
ElNotification({
|
||||
title: "Success",
|
||||
message: "Copied",
|
||||
type: "success",
|
||||
});
|
||||
};
|
48
src/utils/echarts.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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 * as echarts from "echarts/core";
|
||||
|
||||
import { BarChart, LineChart, PieChart, HeatmapChart } from "echarts/charts";
|
||||
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
DataZoomComponent,
|
||||
VisualMapComponent,
|
||||
TimelineComponent,
|
||||
} from "echarts/components";
|
||||
|
||||
import { SVGRenderer } from "echarts/renderers";
|
||||
|
||||
echarts.use([
|
||||
LegendComponent,
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
BarChart,
|
||||
LineChart,
|
||||
PieChart,
|
||||
HeatmapChart,
|
||||
SVGRenderer,
|
||||
DataZoomComponent,
|
||||
VisualMapComponent,
|
||||
TimelineComponent,
|
||||
]);
|
||||
|
||||
export default echarts;
|
56
src/utils/event.ts
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
const isServer = typeof window === "undefined";
|
||||
|
||||
function resizeHandler(entries: any[]): void {
|
||||
for (const entry of entries) {
|
||||
const listeners = entry.target.__resizeListeners__ || [];
|
||||
if (listeners.length) {
|
||||
listeners.forEach((fn: () => any) => {
|
||||
fn();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addResizeListener(element: any, fn: () => unknown): void {
|
||||
if (isServer) return;
|
||||
if (!element.__resizeListeners__) {
|
||||
element.__resizeListeners__ = [];
|
||||
element.__ro__ = new ResizeObserver(resizeHandler);
|
||||
element.__ro__.observe(element);
|
||||
}
|
||||
element.__resizeListeners__.push(fn);
|
||||
}
|
||||
|
||||
export function removeResizeListener(element: any, fn: () => unknown): void {
|
||||
if (!element || !element.__resizeListeners__) return;
|
||||
element.__resizeListeners__.splice(
|
||||
element.__resizeListeners__.indexOf(fn),
|
||||
1
|
||||
);
|
||||
if (!element.__resizeListeners__.length) {
|
||||
element.__ro__.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
export function triggerWindowResize(): void {
|
||||
const event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("resize", true, true);
|
||||
(event as any).eventType = "message";
|
||||
window.dispatchEvent(event);
|
||||
}
|
100
src/utils/is.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
const toString = Object.prototype.toString;
|
||||
|
||||
export function is(val: unknown, type: string): boolean {
|
||||
return toString.call(val) === `[object ${type}]`;
|
||||
}
|
||||
|
||||
export function isDef<T = unknown>(val?: T): val is T {
|
||||
return typeof val !== "undefined";
|
||||
}
|
||||
|
||||
export function isUnDef<T = unknown>(val?: T): val is T {
|
||||
return !isDef(val);
|
||||
}
|
||||
|
||||
export function isObject(val: unknown): val is Record<any, any> {
|
||||
return val !== null && is(val, "Object");
|
||||
}
|
||||
|
||||
export function isDate(val: unknown): val is Date {
|
||||
return is(val, "Date");
|
||||
}
|
||||
|
||||
export function isNull(val: unknown): val is null {
|
||||
return val === null;
|
||||
}
|
||||
|
||||
export function isNullAndUnDef(val: unknown): val is null | undefined {
|
||||
return isUnDef(val) && isNull(val);
|
||||
}
|
||||
|
||||
export function isNullOrUnDef(val: unknown): val is null | undefined {
|
||||
return isUnDef(val) || isNull(val);
|
||||
}
|
||||
|
||||
export function isNumber(val: unknown): val is number {
|
||||
return is(val, "Number");
|
||||
}
|
||||
|
||||
export function isPromise<T = any>(val: unknown): val is Promise<T> {
|
||||
return (
|
||||
is(val, "Promise") &&
|
||||
isObject(val) &&
|
||||
isFunction(val.then) &&
|
||||
isFunction(val.catch)
|
||||
);
|
||||
}
|
||||
|
||||
export function isString(val: unknown): val is string {
|
||||
return is(val, "String");
|
||||
}
|
||||
|
||||
export function isFunction(val: unknown): val is () => unknown {
|
||||
return typeof val === "function";
|
||||
}
|
||||
|
||||
export function isBoolean(val: unknown): val is boolean {
|
||||
return is(val, "Boolean");
|
||||
}
|
||||
|
||||
export function isRegExp(val: unknown): val is RegExp {
|
||||
return is(val, "RegExp");
|
||||
}
|
||||
|
||||
export function isArray(val: unknown): boolean {
|
||||
return Array.isArray(val);
|
||||
}
|
||||
|
||||
export function isWindow(val: unknown): val is Window {
|
||||
return typeof window !== "undefined" && is(val, "Window");
|
||||
}
|
||||
|
||||
export function isElement(val: unknown): val is Element {
|
||||
return isObject(val) && !!val.tagName;
|
||||
}
|
||||
|
||||
export function isMap(val: unknown): val is Map<any, any> {
|
||||
return is(val, "Map");
|
||||
}
|
||||
export function isEmptyObject<T = unknown>(val: T): val is T {
|
||||
if (isObject(val)) {
|
||||
return Object.keys(val).length === 0;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -13,82 +13,58 @@ 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="dashboard-tool">
|
||||
<el-tooltip class="item" effect="dark" content="Add Widget" placement="top">
|
||||
<span class="icon-btn" @click="dashboardStore.addWidget">
|
||||
<Icon size="sm" iconName="playlist_add" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="Settings" placement="top">
|
||||
<span class="icon-btn" @click="dashboardStore.setConfigPanel(true)">
|
||||
<Icon size="sm" iconName="settings" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="Import" placement="top">
|
||||
<span class="icon-btn">
|
||||
<Icon size="sm" iconName="folder_open" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="Export" placement="top">
|
||||
<span class="icon-btn">
|
||||
<Icon size="sm" iconName="save_alt" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="item" effect="dark" content="Apply" placement="top">
|
||||
<span class="icon-btn">
|
||||
<Icon size="sm" iconName="save" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="ds-main">
|
||||
<GridLayout />
|
||||
<Tool />
|
||||
<div class="ds-main" @click="handleClick">
|
||||
<grid-layout />
|
||||
<el-dialog
|
||||
v-model="dashboardStore.showConfig"
|
||||
title="Configurations"
|
||||
width="95%"
|
||||
title="Edit Graph Options"
|
||||
fullscreen
|
||||
:destroy-on-close="true"
|
||||
@closed="dashboardStore.setConfigPanel(false)"
|
||||
>
|
||||
<div class="configuration">xxxx</div>
|
||||
<widget-config />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import GridLayout from "./panel/Layout.vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
// import { LayoutConfig } from "@/types/dashboard";
|
||||
import Tool from "./panel/Tool.vue";
|
||||
import WidgetConfig from "./configuration/ConfigEdit.vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { ElDialog, ElTooltip } from "element-plus";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
// fetch layout data from serve side
|
||||
const layout: LayoutConfig[] = [
|
||||
{ x: 0, y: 0, w: 4, h: 12, i: "0" },
|
||||
{ x: 4, y: 0, w: 4, h: 12, i: "1" },
|
||||
{ x: 8, y: 0, w: 4, h: 15, i: "2" },
|
||||
{ x: 12, y: 0, w: 4, h: 9, i: "3" },
|
||||
{ x: 16, y: 0, w: 4, h: 9, i: "4" },
|
||||
{ x: 20, y: 0, w: 4, h: 9, i: "5" },
|
||||
{ x: 0, y: 12, w: 4, h: 15, i: "7" },
|
||||
{ x: 4, y: 12, w: 4, h: 15, i: "8" },
|
||||
{ x: 8, y: 15, w: 4, h: 12, i: "9" },
|
||||
{ x: 12, y: 9, w: 4, h: 12, i: "10" },
|
||||
{ x: 16, y: 9, w: 4, h: 12, i: "11" },
|
||||
{ x: 20, y: 9, w: 4, h: 15, i: "12" },
|
||||
{ x: 0, y: 27, w: 4, h: 12, i: "14" },
|
||||
{ x: 4, y: 27, w: 4, h: 12, i: "15" },
|
||||
{ x: 8, y: 27, w: 4, h: 15, i: "16" },
|
||||
];
|
||||
dashboardStore.setLayout(layout);
|
||||
// const layout: any[] = [
|
||||
// { x: 0, y: 0, w: 4, h: 12, i: "0" },
|
||||
// { x: 4, y: 0, w: 4, h: 12, i: "1" },
|
||||
// { x: 8, y: 0, w: 4, h: 15, i: "2" },
|
||||
// { x: 12, y: 0, w: 4, h: 9, i: "3" },
|
||||
// { x: 16, y: 0, w: 4, h: 9, i: "4" },
|
||||
// { x: 20, y: 0, w: 4, h: 9, i: "5" },
|
||||
// { x: 0, y: 12, w: 4, h: 15, i: "7" },
|
||||
// { x: 4, y: 12, w: 4, h: 15, i: "8" },
|
||||
// { x: 8, y: 15, w: 4, h: 12, i: "9" },
|
||||
// { x: 12, y: 9, w: 4, h: 12, i: "10" },
|
||||
// { x: 16, y: 9, w: 4, h: 12, i: "11" },
|
||||
// { x: 20, y: 9, w: 4, h: 15, i: "12" },
|
||||
// { x: 0, y: 27, w: 4, h: 12, i: "14" },
|
||||
// { x: 4, y: 27, w: 4, h: 12, i: "15" },
|
||||
// { x: 8, y: 27, w: 4, h: 15, i: "16" },
|
||||
// ];
|
||||
// dashboardStore.setLayout(layout);
|
||||
function handleClick(e: any) {
|
||||
e.stopPropagation();
|
||||
if (e.target.className === "ds-main") {
|
||||
dashboardStore.activeGridItem("");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-tool {
|
||||
text-align: right;
|
||||
padding: 5px 10px;
|
||||
background: rgb(240, 242, 245);
|
||||
border-bottom: 1px solid #dfe4e8;
|
||||
}
|
||||
|
||||
.ds-main {
|
||||
height: calc(100% - 40px);
|
||||
height: calc(100% - 45px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.layout {
|
||||
@ -101,28 +77,4 @@ dashboardStore.setLayout(layout);
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ds-config {
|
||||
width: 340px;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 0 2px 0 #ccc;
|
||||
text-align: center;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
background-color: #eee;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.configuration {
|
||||
height: 600px;
|
||||
}
|
||||
</style>
|
||||
|
@ -56,7 +56,6 @@ limitations under the License. -->
|
||||
import { reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import router from "@/router";
|
||||
import { ElInput, ElButton } from "element-plus";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { EntityType, Options } from "./data";
|
||||
import uuid from "@/utils/uuid";
|
||||
@ -74,11 +73,11 @@ const onCreate = () => {
|
||||
router.push(path);
|
||||
};
|
||||
selectorStore.fetchServices("general");
|
||||
function changeLayer(opt: { label: string; value: string }) {
|
||||
states.layer = opt.value;
|
||||
function changeLayer(opt: { label: string; value: string }[]) {
|
||||
states.layer = opt[0].value;
|
||||
}
|
||||
function changeEntity(opt: { label: string; value: string }) {
|
||||
states.entity = opt.value;
|
||||
function changeEntity(opt: { label: string; value: string }[]) {
|
||||
states.entity = opt[0].value;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
387
src/views/dashboard/configuration/ConfigEdit.vue
Normal file
@ -0,0 +1,387 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div class="widget-config flex-v">
|
||||
<div class="graph">
|
||||
<div class="header">
|
||||
<span>{{ states.widget.title }}</span>
|
||||
<div class="tips" v-show="states.widget.tips">
|
||||
<el-tooltip :content="states.widget.tips">
|
||||
<Icon iconName="info_outline" size="sm" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="render-chart">
|
||||
<component
|
||||
:is="states.graph.type"
|
||||
:intervalTime="appStoreWithOut.intervalTime"
|
||||
:data="states.source"
|
||||
:config="states.graph"
|
||||
/>
|
||||
<div v-show="!states.graph.type" class="no-data">{{ t("noData") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse" :style="{ height: configHeight + 'px' }">
|
||||
<el-collapse
|
||||
v-model="states.activeNames"
|
||||
:style="{ '--el-collapse-header-font-size': '15px' }"
|
||||
>
|
||||
<el-collapse-item :title="t('metricName')" name="1">
|
||||
<div>
|
||||
<Selector
|
||||
:value="states.metrics"
|
||||
:options="metricOpts"
|
||||
:multiple="true"
|
||||
size="mini"
|
||||
placeholder="Select a metric"
|
||||
@change="changeMetrics"
|
||||
class="selectors"
|
||||
/>
|
||||
<Selector
|
||||
v-if="states.valueType"
|
||||
:value="states.valueType"
|
||||
:options="states.valueTypes"
|
||||
size="mini"
|
||||
placeholder="Select a metric"
|
||||
@change="changeValueType"
|
||||
class="selectors"
|
||||
v-loading="loading"
|
||||
/>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('selectVisualization')" name="2">
|
||||
<div class="chart-types">
|
||||
<span
|
||||
v-for="(type, index) in ChartTypes"
|
||||
:key="index"
|
||||
@click="changeChartType(type)"
|
||||
:class="{ active: type.value === states.graph.type }"
|
||||
>
|
||||
{{ type.label }}
|
||||
</span>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('graphStyles')" name="3">
|
||||
<component
|
||||
:is="`${states.graph.type}Config`"
|
||||
:config="states.graph"
|
||||
@update="updateGraphOptions"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('widgetOptions')" name="4">
|
||||
<WidgetOptions
|
||||
:config="states.widget"
|
||||
@update="updateWidgetOptions"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('standardOptions')" name="5">
|
||||
<StandardOptions
|
||||
:config="states.standard"
|
||||
@update="updateStandardOptions"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button size="mini">
|
||||
{{ t("cancel") }}
|
||||
</el-button>
|
||||
<el-button size="mini" type="primary" @click="applyConfig">
|
||||
{{ t("apply") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { reactive, defineComponent, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import {
|
||||
ValuesTypes,
|
||||
MetricQueryTypes,
|
||||
ChartTypes,
|
||||
DefaultGraphConfig,
|
||||
} from "../data";
|
||||
import { Option } from "@/types/app";
|
||||
import { WidgetConfig, GraphConfig, StandardConfig } from "@/types/dashboard";
|
||||
import graphs from "../graphs";
|
||||
import configs from "./graph-styles";
|
||||
import WidgetOptions from "./WidgetOptions.vue";
|
||||
import StandardOptions from "./StandardOptions.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ConfigEdit",
|
||||
components: {
|
||||
...graphs,
|
||||
...configs,
|
||||
WidgetOptions,
|
||||
StandardOptions,
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(false);
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const states = reactive<{
|
||||
metrics: string[];
|
||||
valueTypes: Option[];
|
||||
valueType: string;
|
||||
metricQueryType: string;
|
||||
activeNames: string;
|
||||
source: any;
|
||||
index: string;
|
||||
graph: GraphConfig;
|
||||
widget: WidgetConfig | any;
|
||||
standard: StandardConfig;
|
||||
}>({
|
||||
metrics: selectedGrid.metrics || [],
|
||||
valueTypes: [],
|
||||
valueType: "",
|
||||
metricQueryType: "",
|
||||
activeNames: "1",
|
||||
source: {},
|
||||
index: selectedGrid.i,
|
||||
graph: selectedGrid.graph,
|
||||
widget: selectedGrid.widget,
|
||||
standard: selectedGrid.standard,
|
||||
});
|
||||
if (states.metrics[0]) {
|
||||
queryMetricType(states.metrics[0]);
|
||||
}
|
||||
|
||||
async function changeMetrics(arr: Option[]) {
|
||||
if (!arr.length) {
|
||||
states.valueTypes = [];
|
||||
states.valueType = "";
|
||||
return;
|
||||
}
|
||||
states.metrics = arr.map((d: Option) => String(d.value));
|
||||
if (arr[0].value) {
|
||||
queryMetricType(String(arr[0].value));
|
||||
}
|
||||
}
|
||||
|
||||
async function queryMetricType(metric: string) {
|
||||
loading.value = true;
|
||||
const resp = await dashboardStore.fetchMetricType(metric);
|
||||
loading.value = false;
|
||||
if (resp.error) {
|
||||
ElMessage.error(resp.data.error);
|
||||
return;
|
||||
}
|
||||
const { typeOfMetrics } = resp.data;
|
||||
states.valueTypes = ValuesTypes[typeOfMetrics];
|
||||
states.valueType = ValuesTypes[typeOfMetrics][0].value;
|
||||
queryMetrics();
|
||||
}
|
||||
|
||||
function changeValueType(val: Option[]) {
|
||||
states.valueType = String(val[0].value);
|
||||
states.metricQueryType = (MetricQueryTypes as any)[states.valueType];
|
||||
queryMetrics();
|
||||
}
|
||||
|
||||
function changeChartType(item: Option) {
|
||||
states.graph = {
|
||||
...DefaultGraphConfig[item.value],
|
||||
};
|
||||
}
|
||||
|
||||
const metricOpts = [
|
||||
{ value: "service_apdex", label: "service_apdex" },
|
||||
{ value: "service_sla", label: "service_sla" },
|
||||
{ value: "service_cpm", label: "service_cpm" },
|
||||
{ value: "service_resp_time", label: "service_resp_time" },
|
||||
{ value: "service_percentile", label: "service_percentile" },
|
||||
{
|
||||
value: "service_mq_consume_latency",
|
||||
label: "service_mq_consume_latency",
|
||||
},
|
||||
{ value: "service_mq_consume_count", label: "service_mq_consume_count" },
|
||||
];
|
||||
const configHeight = document.documentElement.clientHeight - 520;
|
||||
|
||||
function updateWidgetOptions(param: { [key: string]: unknown }) {
|
||||
states.widget = {
|
||||
...states.widget,
|
||||
...param,
|
||||
};
|
||||
}
|
||||
|
||||
function updateGraphOptions(param: { [key: string]: unknown }) {
|
||||
states.graph = {
|
||||
...states.graph,
|
||||
...param,
|
||||
};
|
||||
}
|
||||
|
||||
function updateStandardOptions(param: { [key: string]: unknown }) {
|
||||
states.standard = {
|
||||
...states.standard,
|
||||
...param,
|
||||
};
|
||||
}
|
||||
|
||||
async function queryMetrics() {
|
||||
const json = await dashboardStore.fetchMetricValue(
|
||||
dashboardStore.selectedGrid
|
||||
);
|
||||
if (!json) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (json.error) {
|
||||
return;
|
||||
}
|
||||
const metricVal = json.data.readMetricsValues.values.values.map(
|
||||
(d: { value: number }) => d.value + 1
|
||||
);
|
||||
const m = states.metrics[0];
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
states.source = {
|
||||
[m]: metricVal,
|
||||
};
|
||||
}
|
||||
|
||||
queryMetrics();
|
||||
|
||||
function applyConfig() {
|
||||
const opts = {
|
||||
...dashboardStore.selectedGrid,
|
||||
metrics: states.metrics,
|
||||
queryMetricType: states.valueType,
|
||||
widget: states.widget,
|
||||
graph: states.graph,
|
||||
standard: states.standard,
|
||||
};
|
||||
dashboardStore.setConfigs(opts);
|
||||
dashboardStore.setConfigPanel(false);
|
||||
}
|
||||
|
||||
return {
|
||||
states,
|
||||
changeChartType,
|
||||
changeValueType,
|
||||
changeMetrics,
|
||||
t,
|
||||
appStoreWithOut,
|
||||
ChartTypes,
|
||||
metricOpts,
|
||||
updateWidgetOptions,
|
||||
configHeight,
|
||||
updateGraphOptions,
|
||||
updateStandardOptions,
|
||||
applyConfig,
|
||||
loading,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.widget-config {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.graph {
|
||||
position: relative;
|
||||
min-width: 1280px;
|
||||
border: 1px solid #eee;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
background-color: aliceblue;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tips {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.render-chart {
|
||||
padding: 5px;
|
||||
height: 350px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.selectors {
|
||||
width: 500px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.el-collapse-item__header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.config {
|
||||
min-width: 1280px;
|
||||
}
|
||||
|
||||
.chart-types {
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
border-right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span:nth-last-child(1) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
line-height: 350px;
|
||||
}
|
||||
|
||||
span.active {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #eee;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
margin-top: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
169
src/views/dashboard/configuration/StandardOptions.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("unit") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.unit"
|
||||
size="mini"
|
||||
placeholder="Please input Unit"
|
||||
@change="changeStandardOpt({ unit: state.unit })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("sortOrder") }}</span>
|
||||
<Selector
|
||||
:value="state.sortOrder"
|
||||
:options="SortOrder"
|
||||
size="mini"
|
||||
placeholder="Select a sort order"
|
||||
class="selector"
|
||||
@change="changeStandardOpt({ sortOrder: state.sortOrder })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("max") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.max"
|
||||
size="mini"
|
||||
placeholder="auto"
|
||||
@change="changeStandardOpt({ max: state.max })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("min") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.min"
|
||||
size="mini"
|
||||
placeholder="auto"
|
||||
@change="changeStandardOpt({ min: state.min })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("plus") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.plus"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="changeStandardOpt({ plus: state.plus })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("minus") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.minus"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="changeStandardOpt({ minus: state.minus })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("multiply") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.multiply"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="changeStandardOpt({ multiply: state.multiply })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("divide") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.divide"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="changeStandardOpt({ divide: state.divide })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("convertToMilliseconds") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.milliseconds"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="changeStandardOpt({ milliseconds: state.milliseconds })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("convertToSeconds") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="state.seconds"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="changeStandardOpt({ seconds: state.seconds })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, defineProps, defineEmits } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { SortOrder } from "../data";
|
||||
import { StandardConfig } from "@/types/dashboard";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<StandardConfig>,
|
||||
default: () => ({ unit: "", sortOrder: "DES" }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const { t } = useI18n();
|
||||
const state = reactive({
|
||||
unit: props.config.unit,
|
||||
max: "",
|
||||
min: "",
|
||||
plus: "",
|
||||
minus: "",
|
||||
multiply: "",
|
||||
divide: "",
|
||||
milliseconds: "",
|
||||
seconds: "",
|
||||
sortOrder: props.config.sortOrder,
|
||||
});
|
||||
|
||||
function changeStandardOpt(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.selector {
|
||||
width: 500px;
|
||||
}
|
||||
</style>
|
73
src/views/dashboard/configuration/WidgetOptions.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("title") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="title"
|
||||
size="mini"
|
||||
placeholder="Please input title"
|
||||
@change="updateWidgetConfig({ title })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("tooltipsContent") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="tips"
|
||||
size="mini"
|
||||
placeholder="Please input tips"
|
||||
@change="updateWidgetConfig({ tips })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineEmits, defineProps } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { WidgetConfig } from "@/types/dashboard";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<WidgetConfig>,
|
||||
default: () => ({ title: "", tooltips: "" }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const { t } = useI18n();
|
||||
const title = ref<string>(props.config.title || "");
|
||||
const tips = ref<string>(props.config.tips || "");
|
||||
|
||||
function updateWidgetConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
63
src/views/dashboard/configuration/graph-styles/Area.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="label">{{ t("areaOpacity") }}</span>
|
||||
<el-slider
|
||||
class="bar-width"
|
||||
v-model="opacity"
|
||||
show-input
|
||||
input-size="small"
|
||||
:min="0.1"
|
||||
:max="1"
|
||||
:step="0.1"
|
||||
@change="updateConfig({ opacity })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { AreaConfig } from "@/types/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<AreaConfig>,
|
||||
default: () => ({ opacity: 0.4 }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const opacity = ref(props.config.opacity);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.bar-width {
|
||||
width: 500px;
|
||||
margin-top: -13px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
59
src/views/dashboard/configuration/graph-styles/Bar.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="label">{{ t("showBackground") }}</span>
|
||||
<el-switch
|
||||
v-model="showBackground"
|
||||
active-text="Yes"
|
||||
inactive-text="No"
|
||||
@change="changeConfig({ showBackground })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { BarConfig } from "@/types/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<BarConfig>,
|
||||
default: () => ({ showBackground: true, barWidth: 30 }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const showBackground = ref(props.config.showBackground || false);
|
||||
|
||||
function changeConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.bar-width {
|
||||
width: 500px;
|
||||
margin-top: -13px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
63
src/views/dashboard/configuration/graph-styles/Card.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="label">{{ t("fontSize") }}</span>
|
||||
<el-slider
|
||||
class="slider"
|
||||
v-model="fontSize"
|
||||
show-input
|
||||
input-size="small"
|
||||
:min="0.1"
|
||||
:max="1"
|
||||
:step="0.1"
|
||||
@change="updateConfig({ fontSize })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { CardConfig } from "@/types/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<CardConfig>,
|
||||
default: () => ({ fontSize: 12 }),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const fontSize = ref(props.config.fontSize);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.slider {
|
||||
width: 500px;
|
||||
margin-top: -13px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
73
src/views/dashboard/configuration/graph-styles/Line.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="label">{{ t("smooth") }}</span>
|
||||
<el-switch
|
||||
v-model="smooth"
|
||||
active-text="Yes"
|
||||
inactive-text="No"
|
||||
@change="updateConfig({ smooth })"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">{{ t("showSymbol") }}</span>
|
||||
<el-switch
|
||||
v-model="showSymbol"
|
||||
active-text="Yes"
|
||||
inactive-text="No"
|
||||
@change="updateConfig({ showSymbol })"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">{{ t("step") }}</span>
|
||||
<el-switch
|
||||
v-model="step"
|
||||
active-text="Yes"
|
||||
inactive-text="No"
|
||||
@change="updateConfig({ step })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { LineConfig } from "@/types/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<LineConfig>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const smooth = ref(props.config.smooth);
|
||||
const showSymbol = ref(props.config.showSymbol);
|
||||
const step = ref(props.config.step);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
84
src/views/dashboard/configuration/graph-styles/Table.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="label">{{ t("showValues") }}</span>
|
||||
<el-switch
|
||||
v-model="showTableValues"
|
||||
active-text="Yes"
|
||||
inactive-text="No"
|
||||
@change="updateConfig({ showTableValues })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("tableHeaderCol1") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="tableHeaderCol1"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="updateConfig({ tableHeaderCol1 })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("tableHeaderCol2") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="tableHeaderCol2"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
@change="updateConfig({ tableHeaderCol2 })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { TableConfig } from "@/types/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<TableConfig>,
|
||||
default: () => ({
|
||||
showTableValues: true,
|
||||
tableHeaderCol1: "",
|
||||
tableHeaderCol2: "",
|
||||
}),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const showTableValues = ref(props.config.showTableValues);
|
||||
const tableHeaderCol1 = ref(props.config.tableHeaderCol1);
|
||||
const tableHeaderCol2 = ref(props.config.tableHeaderCol2);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.slider {
|
||||
width: 500px;
|
||||
margin-top: -13px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
59
src/views/dashboard/configuration/graph-styles/TopList.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="label">{{ t("maxItemNum") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="topN"
|
||||
size="mini"
|
||||
placeholder="none"
|
||||
type="number"
|
||||
:min="1"
|
||||
:max="100"
|
||||
@change="updateConfig({ topN })"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, ref, defineEmits } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { TopListConfig } from "@/types/dashboard";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object as PropType<TopListConfig>,
|
||||
default: () => ({
|
||||
topN: 10,
|
||||
}),
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(["update"]);
|
||||
const topN = ref(props.config.topN);
|
||||
|
||||
function updateConfig(param: { [key: string]: unknown }) {
|
||||
emits("update", param);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
26
src/views/dashboard/configuration/graph-styles/index.ts
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.
|
||||
*/
|
||||
|
||||
import AreaConfig from "./Area.vue";
|
||||
import LineConfig from "./Line.vue";
|
||||
import BarConfig from "./Bar.vue";
|
||||
|
||||
export default {
|
||||
AreaConfig,
|
||||
LineConfig,
|
||||
BarConfig,
|
||||
};
|
35
src/views/dashboard/controls/Image.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<input v-show="!imgUrl" type="file" @change="fileChange" accept="image/*" />
|
||||
<img v-if="imgUrl" :src="imgUrl" alt="" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
const imgUrl = ref<string>("");
|
||||
const fileChange = (e: any) => {
|
||||
const fileList = e.target.files;
|
||||
if (fileList.length === 0) {
|
||||
imgUrl.value = "";
|
||||
return;
|
||||
}
|
||||
const file = fileList[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event: any) => {
|
||||
imgUrl.value = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
</script>
|
263
src/views/dashboard/controls/Tab.vue
Normal file
@ -0,0 +1,263 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div class="flex-h tab-header">
|
||||
<div class="tabs">
|
||||
<span
|
||||
v-for="(child, idx) in data.children || []"
|
||||
:key="idx"
|
||||
:class="{ active: activeTabIndex === idx }"
|
||||
@click="clickTabs($event, idx)"
|
||||
>
|
||||
<input
|
||||
@click="editTabName($event, idx)"
|
||||
v-model="child.name"
|
||||
placeholder="Please input"
|
||||
class="tab-name"
|
||||
:readonly="isNaN(editTabIndex)"
|
||||
:class="{ view: isNaN(editTabIndex) }"
|
||||
/>
|
||||
<Icon
|
||||
v-show="activeTabIndex === idx"
|
||||
size="sm"
|
||||
iconName="cancel"
|
||||
@click="deleteTabItem(idx)"
|
||||
/>
|
||||
</span>
|
||||
<span class="tab-icons">
|
||||
<el-tooltip effect="dark" content="Add tab items" placement="bottom">
|
||||
<i @click="addTabItem">
|
||||
<Icon size="middle" iconName="add" />
|
||||
</i>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" content="Add widgets" placement="bottom">
|
||||
<i @click="addTabWidget">
|
||||
<Icon size="middle" iconName="playlist_add" />
|
||||
</i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<div class="operations">
|
||||
<Icon size="sm" iconName="clearclose" @click="removeTab" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-layout">
|
||||
<grid-layout
|
||||
v-if="state.layout.length"
|
||||
v-model:layout="state.layout"
|
||||
:col-num="24"
|
||||
:row-height="10"
|
||||
:is-draggable="true"
|
||||
:is-resizable="true"
|
||||
@layout-updated="layoutUpdatedEvent"
|
||||
>
|
||||
<grid-item
|
||||
v-for="item in state.layout"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:w="item.w"
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="item.i"
|
||||
@click="clickTabGrid($event, item)"
|
||||
:class="{ active: activeTabWidget === item.i }"
|
||||
>
|
||||
<Widget
|
||||
:data="item"
|
||||
:activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
|
||||
/>
|
||||
</grid-item>
|
||||
</grid-layout>
|
||||
<div class="no-data-tips" v-else>Please add widgets.</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, reactive, ref, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import Widget from "./Widget.vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<LayoutConfig>,
|
||||
default: () => ({ children: [] }),
|
||||
},
|
||||
active: { type: Boolean, default: false },
|
||||
});
|
||||
const dashboardStore = useDashboardStore();
|
||||
const activeTabIndex = ref<number>(0);
|
||||
const activeTabWidget = ref<string>("0");
|
||||
const editTabIndex = ref<number>(NaN); // edit tab item name
|
||||
const state = reactive<{
|
||||
layout: LayoutConfig[];
|
||||
}>({
|
||||
layout:
|
||||
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children,
|
||||
});
|
||||
|
||||
function layoutUpdatedEvent(newLayout: LayoutConfig[]) {
|
||||
state.layout = newLayout;
|
||||
}
|
||||
function clickTabs(e: Event, idx: number) {
|
||||
e.stopPropagation();
|
||||
activeTabIndex.value = idx;
|
||||
}
|
||||
function removeTab() {
|
||||
dashboardStore.removeControls(props.data);
|
||||
}
|
||||
function deleteTabItem(idx: number) {
|
||||
dashboardStore.removeTabItem(props.data, idx);
|
||||
}
|
||||
function addTabItem() {
|
||||
dashboardStore.addTabItem(props.data);
|
||||
}
|
||||
function editTabName(el: Event, index: number) {
|
||||
el.stopPropagation();
|
||||
editTabIndex.value = index;
|
||||
}
|
||||
function handleClick(el: any) {
|
||||
if (el.target.className === "tab-name") {
|
||||
return;
|
||||
}
|
||||
editTabIndex.value = NaN;
|
||||
}
|
||||
function addTabWidget(e: Event) {
|
||||
e.stopPropagation();
|
||||
activeTabWidget.value = String(state.layout.length);
|
||||
dashboardStore.addTabWidget(activeTabIndex.value);
|
||||
dashboardStore.activeGridItem(
|
||||
`${props.data.i}-${activeTabIndex.value}-${activeTabWidget.value}`
|
||||
);
|
||||
}
|
||||
function clickTabGrid(e: Event, item: LayoutConfig) {
|
||||
e.stopPropagation();
|
||||
activeTabWidget.value = item.i;
|
||||
dashboardStore.activeGridItem(
|
||||
`${props.data.i}-${activeTabIndex.value}-${item.i}`
|
||||
);
|
||||
}
|
||||
document.body.addEventListener("click", handleClick, false);
|
||||
watch(
|
||||
() =>
|
||||
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children,
|
||||
(data) => {
|
||||
state.layout = data;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => dashboardStore.activedGridItem,
|
||||
(data) => {
|
||||
const i = data.split("-");
|
||||
if (i[0] === props.data.i && activeTabIndex.value === Number(i[1])) {
|
||||
activeTabWidget.value = i[2];
|
||||
} else {
|
||||
activeTabWidget.value = "";
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tabs {
|
||||
height: 40px;
|
||||
color: #ccc;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
margin: 0 10px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab-name {
|
||||
max-width: 80px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
outline: none;
|
||||
color: #333;
|
||||
font-style: normal;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.tab-icons {
|
||||
color: #333;
|
||||
|
||||
i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.view {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input.tab-name {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
span.active {
|
||||
border-bottom: 1px solid #409eff;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.operations {
|
||||
color: #aaa;
|
||||
cursor: pointer;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.vue-grid-layout {
|
||||
background: #f7f9fa;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.vue-grid-item:not(.vue-grid-placeholder) {
|
||||
background: #fff;
|
||||
box-shadow: 0px 1px 4px 0px #00000029;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.tab-layout {
|
||||
height: calc(100% - 55px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.vue-grid-item.active {
|
||||
border: 1px solid #409eff;
|
||||
}
|
||||
|
||||
.no-data-tips {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
padding-top: 30px;
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
188
src/views/dashboard/controls/Widget.vue
Normal file
@ -0,0 +1,188 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div class="widget">
|
||||
<div class="header flex-h">
|
||||
<div>{{ data.widget?.title || "" }}</div>
|
||||
<div>
|
||||
<el-tooltip :content="data.widget?.tips">
|
||||
<Icon
|
||||
iconName="info_outline"
|
||||
size="sm"
|
||||
class="operation"
|
||||
v-show="data.widget?.tips"
|
||||
/>
|
||||
</el-tooltip>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
trigger="click"
|
||||
:style="{ width: '100px' }"
|
||||
>
|
||||
<template #reference>
|
||||
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
||||
</template>
|
||||
<div class="tools" @click="editConfig">
|
||||
<span>{{ t("edit") }}</span>
|
||||
</div>
|
||||
<div class="tools" @click="removeWidget">
|
||||
<span>{{ t("delete") }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body" v-if="data.graph?.type" v-loading="loading">
|
||||
<component
|
||||
:is="data.graph.type"
|
||||
:intervalTime="appStoreWithOut.intervalTime"
|
||||
:data="state.source"
|
||||
:config="data.graph"
|
||||
:standard="data.standard"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="no-data">{{ t("noData") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { toRefs, reactive, defineComponent, ref, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import graphs from "../graphs";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const props = {
|
||||
data: {
|
||||
type: Object as PropType<LayoutConfig>,
|
||||
default: () => ({ widget: {} }),
|
||||
},
|
||||
activeIndex: { type: String, default: "" },
|
||||
};
|
||||
export default defineComponent({
|
||||
name: "Widget",
|
||||
components: { ...graphs },
|
||||
props,
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
const loading = ref<boolean>(false);
|
||||
const state = reactive({
|
||||
source: {},
|
||||
});
|
||||
const { data } = toRefs(props);
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
const dashboardStore = useDashboardStore();
|
||||
queryMetrics();
|
||||
async function queryMetrics() {
|
||||
loading.value = true;
|
||||
const json = await dashboardStore.fetchMetricValue(props.data);
|
||||
loading.value = false;
|
||||
if (!json) {
|
||||
return;
|
||||
}
|
||||
if (json.error) {
|
||||
ElMessage.error(json.error);
|
||||
return;
|
||||
}
|
||||
const metricVal = json.data.readMetricsValues.values.values.map(
|
||||
(d: any) => d.value
|
||||
);
|
||||
const m = props.data.metrics && props.data.metrics[0];
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
state.source = {
|
||||
[m]: metricVal,
|
||||
};
|
||||
}
|
||||
|
||||
function removeWidget() {
|
||||
dashboardStore.removeControls(props.data);
|
||||
}
|
||||
function editConfig() {
|
||||
dashboardStore.setConfigPanel(true);
|
||||
dashboardStore.selectWidget(props.data);
|
||||
if (props.activeIndex) {
|
||||
dashboardStore.activeGridItem(props.activeIndex);
|
||||
} else {
|
||||
dashboardStore.activeGridItem(props.data.i);
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => [props.data.queryMetricType, props.data.metrics],
|
||||
(data, old) => {
|
||||
if (data[0] === old[0] && data[1] === old[1]) {
|
||||
return;
|
||||
}
|
||||
queryMetrics();
|
||||
}
|
||||
);
|
||||
return {
|
||||
state,
|
||||
appStoreWithOut,
|
||||
removeWidget,
|
||||
editConfig,
|
||||
data,
|
||||
loading,
|
||||
t,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.widget {
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 30px;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #eee;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.operation {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tools {
|
||||
padding: 5px 0;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 5px 10px;
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
}
|
||||
|
||||
.no-data {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
@ -14,42 +14,214 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const ChartTypes = [
|
||||
{ label: "Bar", value: "Bar" },
|
||||
{ label: "Line", value: "Line" },
|
||||
{ label: "Area", value: "Area" },
|
||||
{ label: "Heatmap", value: "Heatmap" },
|
||||
{ label: "Pie", value: "Pie" },
|
||||
{ label: "Card", value: "Card" },
|
||||
{ label: "Top List", value: "TopList" },
|
||||
{ label: "Table", value: "Table" },
|
||||
{ label: "Endpoint List", value: "EndpointList" },
|
||||
{ label: "Instance List", value: "InstanceList" },
|
||||
];
|
||||
export const DefaultGraphConfig: { [key: string]: any } = {
|
||||
Bar: {
|
||||
type: "Bar",
|
||||
showBackground: true,
|
||||
},
|
||||
Line: {
|
||||
type: "Line",
|
||||
step: false,
|
||||
smooth: false,
|
||||
showSymbol: false,
|
||||
},
|
||||
Area: {
|
||||
type: "Area",
|
||||
opacity: 0.4,
|
||||
},
|
||||
Card: {
|
||||
type: "Card",
|
||||
fontSize: 14,
|
||||
showUint: true,
|
||||
},
|
||||
Table: {
|
||||
type: "Card",
|
||||
showTableValues: true,
|
||||
tableHeaderCol1: "",
|
||||
tableHeaderCol2: "",
|
||||
},
|
||||
TopList: {
|
||||
type: "TopList",
|
||||
topN: 10,
|
||||
},
|
||||
};
|
||||
|
||||
export enum MetricQueryTypes {
|
||||
ReadMetricsValue = "readMetricsValue",
|
||||
ReadMetricsValues = "readMetricsValues",
|
||||
SortMetrics = "sortMetrics",
|
||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
||||
READHEATMAP = "readHeatMap",
|
||||
ReadSampledRecords = "readSampledRecords",
|
||||
}
|
||||
export enum MetricsType {
|
||||
UNKNOWN = "UNKNOWN",
|
||||
REGULAR_VALUE = "REGULAR_VALUE",
|
||||
LABELED_VALUE = "LABELED_VALUE",
|
||||
HEATMAP = "HEATMAP",
|
||||
SAMPLED_RECORD = "SAMPLED_RECORD",
|
||||
}
|
||||
export const ValuesTypes: {
|
||||
[key: string]: Array<{ label: string; value: string }>;
|
||||
} = {
|
||||
REGULAR_VALUE: [
|
||||
{ label: "read all values in the duration", value: "readMetricsValues" },
|
||||
{
|
||||
label: "read the single value in the duration",
|
||||
value: "readMetricsValue",
|
||||
},
|
||||
{ label: "get sorted top N values", value: "sortMetrics" },
|
||||
],
|
||||
LABELED_VALUE: [
|
||||
{
|
||||
label: "read all values of labels in the duration",
|
||||
value: "readLabeledMetricsValues",
|
||||
},
|
||||
],
|
||||
HEATMAP: [
|
||||
{ label: "read heatmap values in the duration", value: "readHeatMap" },
|
||||
],
|
||||
SAMPLED_RECORD: [
|
||||
{ label: "get sorted topN values", value: "readSampledRecords" },
|
||||
],
|
||||
};
|
||||
export const MetricChartType: { [key: string]: string } = {
|
||||
readMetricsValue: "ChartNum",
|
||||
readMetricsValues: "ChartLine",
|
||||
sortMetrics: "ChartSlow",
|
||||
readLabeledMetricsValues: "ChartLine",
|
||||
readHeatMap: "ChartHeatmap",
|
||||
readSampledRecords: "ChartSlow",
|
||||
};
|
||||
export const CalculationType = [
|
||||
{ label: "Plus", value: "+" },
|
||||
{ label: "Minus", value: "-" },
|
||||
{ label: "Multiplication", value: "*" },
|
||||
{ label: "Division", value: "/" },
|
||||
{ label: "Convert Unix Timestamp(milliseconds)", value: "milliseconds" },
|
||||
{ label: "Convert Unix Timestamp(seconds)", value: "seconds" },
|
||||
];
|
||||
export const ReadValueChartType = [
|
||||
{ value: "ChartNum", label: "Digital Card" },
|
||||
{ value: "ChartSlow", label: "Slow Chart" },
|
||||
];
|
||||
|
||||
export const MaxItemNum = 10;
|
||||
|
||||
export enum MetricsName {
|
||||
SERVICE_RESP_TIME = "service_resp_time",
|
||||
SERVICE_SLA = "service_sla",
|
||||
SERVICE_CPM = "service_cpm",
|
||||
SERVICE_PERCENTILE = "service_percentile",
|
||||
SERVICE_APDEX = "service_apdex",
|
||||
}
|
||||
export const EntityType = [
|
||||
{ value: "service", label: "Service" },
|
||||
{ value: "all", label: "All" },
|
||||
{ value: "endpoint", label: "Service Endpoint" },
|
||||
{ value: "serviceInstance", label: "Service Instance" },
|
||||
{ value: "serviceRelationClient", label: "Service Relation(client)" },
|
||||
{ value: "serviceRelationServer", label: "Service Relation(server)" },
|
||||
{ value: "service", label: "Service", key: 1 },
|
||||
{ value: "all", label: "All", key: 10 },
|
||||
{ value: "endpoint", label: "Service Endpoint", key: 3 },
|
||||
{ value: "serviceInstance", label: "Service Instance", key: 3 },
|
||||
{ value: "serviceRelationClient", label: "Service Relation(client)", key: 2 },
|
||||
{ value: "serviceRelationServer", label: "Service Relation(server)", key: 2 },
|
||||
{
|
||||
value: "serviceInstanceRelationClient",
|
||||
label: "Service Instance Relation(client)",
|
||||
key: 4,
|
||||
},
|
||||
{
|
||||
value: "serviceInstanceRelationServer",
|
||||
label: "Service Instance Relation(server)",
|
||||
key: 4,
|
||||
},
|
||||
{ value: "endpointRelation", label: "Endpoint Relation" },
|
||||
{ value: "endpointRelation", label: "Endpoint Relation", key: 4 },
|
||||
];
|
||||
export const SortOrder = [
|
||||
{ label: "DES", value: "DES" },
|
||||
{ label: "ASC", value: "ASC" },
|
||||
];
|
||||
export const ToolIcons = [
|
||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||
{ name: "all_inbox", content: "Add Tab", id: "addTab" },
|
||||
// { name: "insert_image", content: "Add Image", id: "addImage" },
|
||||
{ name: "save_alt", content: "Export", id: "export" },
|
||||
{ name: "folder_open", content: "Import", id: "import" },
|
||||
{ name: "settings", content: "Settings", id: "settings" },
|
||||
{ name: "save", content: "Apply", id: "applay" },
|
||||
];
|
||||
export const Options = [
|
||||
{
|
||||
value: "layer1",
|
||||
label: "layer1",
|
||||
value: "Option1",
|
||||
label: "Option1",
|
||||
},
|
||||
{
|
||||
value: "layer2",
|
||||
label: "layer2",
|
||||
value: "Option2",
|
||||
label: "Option2",
|
||||
},
|
||||
{
|
||||
value: "layer3",
|
||||
label: "layer3",
|
||||
value: "Option3",
|
||||
label: "Option3",
|
||||
},
|
||||
{
|
||||
value: "layer4",
|
||||
label: "layer4",
|
||||
value: "Option4",
|
||||
label: "Option4",
|
||||
},
|
||||
{
|
||||
value: "layer5",
|
||||
label: "layer5",
|
||||
value: "Option5",
|
||||
label: "Option5",
|
||||
},
|
||||
];
|
||||
export const SelectOpts = [
|
||||
{
|
||||
value: "guide",
|
||||
label: "Guide",
|
||||
children: [
|
||||
{
|
||||
value: "disciplines",
|
||||
label: "Disciplines",
|
||||
children: [
|
||||
{
|
||||
value: "consistency",
|
||||
label: "Consistency",
|
||||
},
|
||||
{
|
||||
value: "feedback",
|
||||
label: "Feedback",
|
||||
},
|
||||
{
|
||||
value: "efficiency",
|
||||
label: "Efficiency",
|
||||
},
|
||||
{
|
||||
value: "controllability",
|
||||
label: "Controllability",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "navigation",
|
||||
label: "Navigation",
|
||||
children: [
|
||||
{
|
||||
value: "side nav",
|
||||
label: "Side Navigation",
|
||||
},
|
||||
{
|
||||
value: "top nav",
|
||||
label: "Top Navigation",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
36
src/views/dashboard/graphs/Area.vue
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. -->
|
||||
|
||||
<template>
|
||||
<Line :data="data" :intervalTime="intervalTime" :config="config" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import Line from "./Line.vue";
|
||||
import { AreaConfig } from "@/types/dashboard";
|
||||
|
||||
defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
config: {
|
||||
type: Object as PropType<AreaConfig>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
</script>
|
185
src/views/dashboard/graphs/Bar.vue
Normal file
@ -0,0 +1,185 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { Event } from "@/types/events";
|
||||
import { BarConfig } from "@/types/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
theme: { type: String, default: "light" },
|
||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
||||
config: {
|
||||
type: Object as PropType<BarConfig>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const option = computed(() => getOption());
|
||||
|
||||
function getOption() {
|
||||
const keys = Object.keys(props.data || {}).filter(
|
||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||
);
|
||||
const startP = keys.length > 1 ? 50 : 15;
|
||||
const diff = 15;
|
||||
const markAreas = (props.itemEvents || []).map(
|
||||
(event: Event, index: number) => {
|
||||
return [
|
||||
{
|
||||
name: `${event.name}:${event.type}`,
|
||||
xAxis: event.startTime,
|
||||
y: startP + diff * index,
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
||||
color: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: event.message,
|
||||
xAxis: event.endTime,
|
||||
y: startP + diff * (index + 1),
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
const temp = keys.map((i: string, index: number) => {
|
||||
if (!props.intervalTime) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
data: props.data[i].map((item: number, itemIndex: number) => [
|
||||
props.intervalTime[itemIndex],
|
||||
item,
|
||||
]),
|
||||
name: i,
|
||||
type: "bar",
|
||||
symbol: "none",
|
||||
stack: "sum",
|
||||
lineStyle: {
|
||||
width: 1.5,
|
||||
type: "dotted",
|
||||
},
|
||||
showBackground: props.config.showBackground,
|
||||
backgroundStyle: {
|
||||
color: "rgba(180, 180, 180, 0.1)",
|
||||
},
|
||||
markArea:
|
||||
index === 0
|
||||
? {
|
||||
silent: false,
|
||||
data: markAreas,
|
||||
label: {
|
||||
show: false,
|
||||
width: 60,
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
position: "bottom",
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
});
|
||||
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,
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
// backgroundColor: "rgb(50,50,50)",
|
||||
// textStyle: {
|
||||
// fontSize: 13,
|
||||
// color: "#ccc",
|
||||
// },
|
||||
// enterable: true,
|
||||
// extraCssText: "max-height: 300px; overflow: auto;",
|
||||
},
|
||||
legend: {
|
||||
type: "scroll",
|
||||
show: keys.length === 1 ? false : true,
|
||||
icon: "circle",
|
||||
top: 0,
|
||||
left: 0,
|
||||
itemWidth: 12,
|
||||
textStyle: {
|
||||
color: "#333",
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: keys.length === 1 ? 15 : 40,
|
||||
left: 0,
|
||||
right: 10,
|
||||
bottom: 5,
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
axisTick: {
|
||||
lineStyle: { color: "#c1c5ca41" },
|
||||
alignWithLabel: true,
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: "rgba(0,0,0,0)" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
splitLine: { lineStyle: { color: "#c1c5ca41", type: "dashed" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
},
|
||||
series: temp,
|
||||
};
|
||||
}
|
||||
</script>
|
54
src/views/dashboard/graphs/Card.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<!-- 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. -->
|
||||
|
||||
<template>
|
||||
<div class="chart-card" :style="{ fontSize: `${config.fontSize}px` }">
|
||||
{{
|
||||
typeof data[key] === "string"
|
||||
? data[key]
|
||||
: isNaN(data[key])
|
||||
? null
|
||||
: data[key].toFixed(2)
|
||||
}}
|
||||
<span v-show="config.showUint">{{ standard.unit }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, PropType } from "vue";
|
||||
import { defineProps } from "vue";
|
||||
import { CardConfig, StandardConfig } from "@/types/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<CardConfig>,
|
||||
default: () => ({ fontSize: 12, showUint: true }),
|
||||
},
|
||||
standard: {
|
||||
type: Object as PropType<StandardConfig>,
|
||||
default: () => ({ unit: "" }),
|
||||
},
|
||||
});
|
||||
const key = computed(() => Object.keys(props.data)[0]);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chart-card {
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
34
src/views/dashboard/graphs/EndpointList.vue
Normal file
@ -0,0 +1,34 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<el-table :data="data" style="width: 100%">
|
||||
<el-table-column prop="label" label="Endpoints" />
|
||||
</el-table>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
defineProps({
|
||||
data: {
|
||||
type: Array as PropType<{ label: string; value: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
</script>
|
157
src/views/dashboard/graphs/HeatMap.vue
Normal file
@ -0,0 +1,157 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { StandardConfig } from "@/types/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ nodes: number[][]; buckets: number[][] }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
config: {
|
||||
type: Object as PropType<any>,
|
||||
default: () => ({}),
|
||||
},
|
||||
standard: {
|
||||
type: Object as PropType<StandardConfig>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const option = computed(() => getOption());
|
||||
function getOption() {
|
||||
const source = (props.data.nodes || []).map((d: number[]) => d[2]);
|
||||
const maxItem = Math.max(...source);
|
||||
const minItem = Math.min(...source);
|
||||
const colorBox = [
|
||||
"#fff",
|
||||
"#FDF0F0",
|
||||
"#FAE2E2",
|
||||
"#F8D3D3",
|
||||
"#F6C4C4",
|
||||
"#F4B5B5",
|
||||
"#F1A7A7",
|
||||
"#EF9898",
|
||||
"#E86C6C",
|
||||
"#E44E4E",
|
||||
"#E23F3F",
|
||||
"#DF3131",
|
||||
"#DD2222",
|
||||
"#CE2020",
|
||||
"#C01D1D",
|
||||
"#B11B1B",
|
||||
"#A21919",
|
||||
"#851414",
|
||||
"#761212",
|
||||
"#671010",
|
||||
];
|
||||
return {
|
||||
tooltip: {
|
||||
position: "top",
|
||||
formatter: (a: any) =>
|
||||
`${a.data[1] * 100}${props.standard.unit} [ ${a.data[2]} ]`,
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: "#ccc",
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 15,
|
||||
left: 0,
|
||||
right: 10,
|
||||
bottom: 5,
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: props.intervalTime,
|
||||
axisTick: {
|
||||
lineStyle: { color: "#c1c5ca" },
|
||||
alignWithLabel: true,
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: "rgba(0,0,0,0)" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
},
|
||||
visualMap: [
|
||||
{
|
||||
min: minItem,
|
||||
max: maxItem,
|
||||
show: false,
|
||||
type: "piecewise",
|
||||
calculable: true,
|
||||
pieces: generatePieces(maxItem, colorBox, minItem),
|
||||
},
|
||||
],
|
||||
yAxis: {
|
||||
type: "category",
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
splitLine: { lineStyle: { color: "#c1c5ca", type: "dashed" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
data: props.data.buckets,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "heatmap",
|
||||
data: props.data.nodes || [],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowColor: "rgba(0, 0, 0, 0.5)",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
function generatePieces(maxValue: number, colorBox: string[], minItem: number) {
|
||||
if (maxValue < minItem) {
|
||||
return [];
|
||||
}
|
||||
const pieces = [];
|
||||
let quotient = 1;
|
||||
let temp = {} as { min: number; max: number; color: string };
|
||||
temp.max = minItem;
|
||||
temp.min = minItem;
|
||||
temp.color = colorBox[0];
|
||||
pieces.push(temp);
|
||||
if (maxValue && maxValue >= 19) {
|
||||
quotient = Math.floor(maxValue / 19);
|
||||
for (let i = 1; i < 20; i++) {
|
||||
temp = {} as any;
|
||||
if (i === 1) {
|
||||
temp.min = minItem;
|
||||
} else {
|
||||
temp.min = quotient * (i - 1);
|
||||
}
|
||||
temp.max = quotient * i;
|
||||
temp.color = colorBox[i];
|
||||
pieces.push(temp);
|
||||
}
|
||||
}
|
||||
const length = pieces.length;
|
||||
if (length) {
|
||||
const item = pieces[length - 1];
|
||||
item.max = maxValue;
|
||||
}
|
||||
return pieces;
|
||||
}
|
||||
</script>
|
34
src/views/dashboard/graphs/InstanceList.vue
Normal file
@ -0,0 +1,34 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<el-table :data="data" style="width: 100%">
|
||||
<el-table-column prop="label" label="Service Instances" />
|
||||
</el-table>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
defineProps({
|
||||
data: {
|
||||
type: Array as PropType<{ label: string; value: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
</script>
|
191
src/views/dashboard/graphs/Line.vue
Normal file
@ -0,0 +1,191 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { Event } from "@/types/events";
|
||||
import { LineConfig } from "@/types/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[] }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
theme: { type: String, default: "light" },
|
||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
||||
config: {
|
||||
type: Object as PropType<LineConfig>,
|
||||
default: () => ({
|
||||
step: false,
|
||||
smooth: false,
|
||||
showSymbol: false,
|
||||
opacity: 0.4,
|
||||
}),
|
||||
},
|
||||
});
|
||||
const option = computed(() => getOption());
|
||||
function getOption() {
|
||||
const keys = Object.keys(props.data || {}).filter(
|
||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||
);
|
||||
const startP = keys.length > 1 ? 50 : 15;
|
||||
const diff = 10;
|
||||
const markAreas = (props.itemEvents || []).map(
|
||||
(event: Event, index: number) => {
|
||||
return [
|
||||
{
|
||||
name: `${event.name}:${event.type}`,
|
||||
xAxis: event.startTime,
|
||||
y: startP + diff * index,
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
||||
color: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: event.message,
|
||||
xAxis: event.endTime,
|
||||
y: startP + diff * (index + 1),
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
const temp = keys.map((i: any, index: number) => {
|
||||
const serie: any = {
|
||||
data: props.data[i].map((item: any, itemIndex: number) => [
|
||||
props.intervalTime[itemIndex],
|
||||
item,
|
||||
]),
|
||||
name: i,
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
barMaxWidth: 10,
|
||||
step: props.config.step,
|
||||
smooth: props.config.smooth,
|
||||
showSymbol: true,
|
||||
lineStyle: {
|
||||
width: 1.5,
|
||||
type: "solid",
|
||||
},
|
||||
markArea:
|
||||
index === 0
|
||||
? {
|
||||
silent: false,
|
||||
data: markAreas,
|
||||
label: {
|
||||
show: false,
|
||||
width: 60,
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
position: "bottom",
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
if (props.config.type === "Area") {
|
||||
serie.areaStyle = {
|
||||
opacity: props.config.opacity || 0.4,
|
||||
};
|
||||
}
|
||||
return serie;
|
||||
});
|
||||
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,
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
backgroundColor: "rgb(50,50,50)",
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: "#ccc",
|
||||
},
|
||||
enterable: true,
|
||||
extraCssText: "max-height: 300px; overflow: auto;",
|
||||
},
|
||||
legend: {
|
||||
type: "scroll",
|
||||
show: keys.length === 1 ? false : true,
|
||||
icon: "circle",
|
||||
top: 0,
|
||||
left: 0,
|
||||
itemWidth: 12,
|
||||
textStyle: {
|
||||
color: props.theme === "dark" ? "#fff" : "#333",
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: keys.length === 1 ? 15 : 55,
|
||||
left: 0,
|
||||
right: 10,
|
||||
bottom: 5,
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
axisTick: {
|
||||
lineStyle: { color: "#c1c5ca41" },
|
||||
alignWithLabel: true,
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLine: { lineStyle: { color: "rgba(0,0,0,0)" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
splitLine: { lineStyle: { color: "#c1c5ca41", type: "dashed" } },
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
},
|
||||
series: temp,
|
||||
};
|
||||
}
|
||||
</script>
|
65
src/views/dashboard/graphs/Pie.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<Graph :option="option" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<{ name: string; value: number }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<{ sortOrder: string }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const option = computed(() => getOption());
|
||||
function getOption() {
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
},
|
||||
legend: {
|
||||
type: "scroll",
|
||||
show: props.data.length === 1 ? false : true,
|
||||
icon: "circle",
|
||||
top: 0,
|
||||
left: 0,
|
||||
itemWidth: 12,
|
||||
textStyle: {
|
||||
color: "#333",
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "pie",
|
||||
radius: "50%",
|
||||
data: props.data,
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: "rgba(0, 0, 0, 0.5)",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
</script>
|
156
src/views/dashboard/graphs/Table.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<!-- 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. -->
|
||||
|
||||
<template>
|
||||
<div class="chart-table">
|
||||
<div ref="chartTable">
|
||||
<div
|
||||
class="row header flex-h"
|
||||
:style="`width: ${nameWidth + initWidth}px`"
|
||||
>
|
||||
<div class="name" :style="`width: ${nameWidth}px`">
|
||||
{{ config.tableHeaderCol1 || $t("name") }}
|
||||
<i class="r cp" ref="draggerName"
|
||||
><rk-icon icon="settings_ethernet"
|
||||
/></i>
|
||||
</div>
|
||||
<div class="value-col" v-if="config.showTableValues">
|
||||
{{ config.tableHeaderCol2 || $t("value") }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row flex-h"
|
||||
v-for="key in dataKeys"
|
||||
:key="key"
|
||||
:style="`width: ${nameWidth + initWidth}px`"
|
||||
>
|
||||
<div :style="`width: ${nameWidth}px`">{{ key }}</div>
|
||||
<div class="value-col" v-if="config.showTableValues">
|
||||
{{ data[key][data[key].length - 1 || 0] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps, computed, ref, onMounted } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<{ [key: string]: number[][] }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<{
|
||||
showTableValues: boolean;
|
||||
tableHeaderCol2: string;
|
||||
tableHeaderCol1: string;
|
||||
}>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
/*global Nullable*/
|
||||
const chartTable = ref<Nullable<HTMLElement>>(null);
|
||||
const initWidth = ref<number>(0);
|
||||
const nameWidth = ref<number>(0);
|
||||
const draggerName = ref<Nullable<HTMLElement>>(null);
|
||||
onMounted(() => {
|
||||
if (!chartTable.value) {
|
||||
return;
|
||||
}
|
||||
const width = props.config.showTableValues
|
||||
? chartTable.value.offsetWidth / 2
|
||||
: chartTable.value.offsetWidth;
|
||||
initWidth.value = props.config.showTableValues
|
||||
? chartTable.value.offsetWidth / 2
|
||||
: 0;
|
||||
nameWidth.value = width - 5;
|
||||
if (!draggerName.value) {
|
||||
return;
|
||||
}
|
||||
draggerName.value.onmousedown = (event: MouseEvent) => {
|
||||
const diffX = event.clientX;
|
||||
const copy = nameWidth;
|
||||
document.onmousemove = (documentEvent) => {
|
||||
const moveX = documentEvent.clientX - diffX;
|
||||
nameWidth.value = Number(copy) + Number(moveX);
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
});
|
||||
const dataKeys = computed(() => {
|
||||
const keys = Object.keys(props.data || {}).filter(
|
||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||
);
|
||||
return keys;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chart-table {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
|
||||
.name {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.row {
|
||||
border-left: 1px solid #ccc;
|
||||
height: 20px;
|
||||
|
||||
div {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
border-right: 1px solid #ccc;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div:last-child {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div:nth-last-child(2) {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.row:first-child {
|
||||
div {
|
||||
border-top: 1px solid #ccc;
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.value-col {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
116
src/views/dashboard/graphs/TopList.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<!-- 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. -->
|
||||
|
||||
<template>
|
||||
<div class="chart-slow-i" v-for="(i, index) in datas" :key="index">
|
||||
<Icon
|
||||
iconName="review-list"
|
||||
size="sm"
|
||||
@click="handleClick((i.traceIds && i.traceIds[0]) || i.name)"
|
||||
/>
|
||||
<div class="mb-5 ell">
|
||||
<span class="calls sm mr-10">{{ i.value }}</span>
|
||||
<span class="cp link-hover">
|
||||
{{ i.name + getTraceId(i) }}
|
||||
</span>
|
||||
</div>
|
||||
<el-progress
|
||||
:stroke-width="10"
|
||||
:percentage="(i.value / maxValue) * 100"
|
||||
color="#bf99f8"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { defineProps, computed } from "vue";
|
||||
import copy from "@/utils/copy";
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<
|
||||
{ name: string; value: number; traceIds: string[] }[]
|
||||
>,
|
||||
default: () => [],
|
||||
},
|
||||
config: {
|
||||
type: Object as PropType<{ sortOrder: string }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const maxValue = computed(() => {
|
||||
if (!props.data.length) {
|
||||
return 0;
|
||||
}
|
||||
const temp: number[] = props.data.map((i: any) => i.value);
|
||||
return Math.max.apply(null, temp);
|
||||
});
|
||||
const getTraceId = (i: { [key: string]: (number | string)[] }): string => {
|
||||
return i.traceIds && i.traceIds[0] ? ` - ${i.traceIds[0]}` : "";
|
||||
};
|
||||
const datas: any = () => {
|
||||
if (!props.data.length) {
|
||||
return [];
|
||||
}
|
||||
const { sortOrder } = props.config;
|
||||
const val: any = props.data;
|
||||
|
||||
switch (sortOrder) {
|
||||
case "DES":
|
||||
val.sort((a: any, b: any) => b.value - a.value);
|
||||
break;
|
||||
case "ASC":
|
||||
val.sort((a: any, b: any) => a.value - b.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
function handleClick(i: string) {
|
||||
copy(i);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.progress-bar {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.chart-slow-i {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.chart-slow {
|
||||
height: 100%;
|
||||
|
||||
.calls {
|
||||
padding: 0 5px;
|
||||
display: inline-block;
|
||||
background-color: #40454e;
|
||||
color: #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-slow-link {
|
||||
padding: 4px 10px 7px 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
will-change: opacity, background-color;
|
||||
transition: opacity 0.3s, background-color 0.3s;
|
||||
}
|
||||
</style>
|
36
src/views/dashboard/graphs/index.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.
|
||||
*/
|
||||
|
||||
import Area from "./Area.vue";
|
||||
import Line from "./Line.vue";
|
||||
import Bar from "./Bar.vue";
|
||||
import Heatmap from "./HeatMap.vue";
|
||||
import TopList from "./TopList.vue";
|
||||
import Table from "./Table.vue";
|
||||
import Pie from "./Pie.vue";
|
||||
import Card from "./Card.vue";
|
||||
|
||||
export default {
|
||||
Line,
|
||||
Bar,
|
||||
Heatmap,
|
||||
TopList,
|
||||
Area,
|
||||
Table,
|
||||
Pie,
|
||||
Card,
|
||||
};
|
@ -29,20 +29,38 @@ limitations under the License. -->
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="item.i"
|
||||
@click="clickGrid(item)"
|
||||
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
||||
>
|
||||
<Widget :item="item" />
|
||||
<component :is="item.type" :data="item" />
|
||||
</grid-item>
|
||||
</grid-layout>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import Widget from "./Widget.vue";
|
||||
import Widget from "../controls/Widget.vue";
|
||||
import Tab from "../controls/Tab.vue";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
function layoutUpdatedEvent(newLayout: LayoutConfig) {
|
||||
dashboardStore.setLayout(newLayout);
|
||||
}
|
||||
export default defineComponent({
|
||||
name: "Layout",
|
||||
components: { Widget, Tab },
|
||||
setup() {
|
||||
const dashboardStore = useDashboardStore();
|
||||
function layoutUpdatedEvent(newLayout: LayoutConfig[]) {
|
||||
dashboardStore.setLayout(newLayout);
|
||||
}
|
||||
function clickGrid(item: LayoutConfig) {
|
||||
dashboardStore.activeGridItem(item.i);
|
||||
}
|
||||
return {
|
||||
dashboardStore,
|
||||
layoutUpdatedEvent,
|
||||
clickGrid,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.vue-grid-layout {
|
||||
@ -55,4 +73,8 @@ function layoutUpdatedEvent(newLayout: LayoutConfig) {
|
||||
box-shadow: 0px 1px 4px 0px #00000029;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.vue-grid-item.active {
|
||||
border: 1px solid #409eff;
|
||||
}
|
||||
</style>
|
||||
|
169
src/views/dashboard/panel/Tool.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<!-- 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. -->
|
||||
<template>
|
||||
<div class="dashboard-tool flex-h">
|
||||
<div class="flex-h">
|
||||
<div class="selectors-item" v-if="states.key < 3">
|
||||
<span class="label">$Service</span>
|
||||
<Selector
|
||||
:value="states.service"
|
||||
:options="Options"
|
||||
size="mini"
|
||||
placeholder="Select a service"
|
||||
@change="changeService"
|
||||
class="selectors"
|
||||
:borderRadius="4"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectors-item" v-if="states.key === 3 || states.key === 4">
|
||||
<span class="label">$ServiceInstance</span>
|
||||
<el-cascader
|
||||
placeholder="Select a instance"
|
||||
:options="SelectOpts"
|
||||
size="mini"
|
||||
filterable
|
||||
:style="{ minWidth: '300px' }"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectors-item" v-if="states.key === 2">
|
||||
<span class="label">$DestinationService</span>
|
||||
<Selector
|
||||
:value="states.service"
|
||||
:options="Options"
|
||||
size="mini"
|
||||
placeholder="Select a service"
|
||||
:borderRadius="0"
|
||||
@change="changeService"
|
||||
class="selectors"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectors-item" v-if="states.key === 4">
|
||||
<span class="label">$DestinationServiceInstance</span>
|
||||
<el-cascader
|
||||
placeholder="Select a instance"
|
||||
:options="SelectOpts"
|
||||
size="mini"
|
||||
filterable
|
||||
:style="{ minWidth: '300px' }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-icons">
|
||||
<el-tooltip
|
||||
v-for="(t, index) in ToolIcons"
|
||||
:key="index"
|
||||
class="item"
|
||||
:content="t.content"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon-btn" @click="clickIcons(t)">
|
||||
<Icon size="sm" :iconName="t.name" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { Options, SelectOpts, EntityType, ToolIcons } from "../data";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
const params = useRoute().params;
|
||||
const states = reactive<{
|
||||
entity: string | string[];
|
||||
layerId: string | string[];
|
||||
service: string;
|
||||
pod: string;
|
||||
destService: string;
|
||||
destPod: string;
|
||||
key: number;
|
||||
}>({
|
||||
service: Options[0].value,
|
||||
pod: Options[0].value, // instances and endpoints
|
||||
destService: "",
|
||||
destPod: "",
|
||||
key: EntityType.filter((d: any) => d.value === params.entity)[0].key || 0,
|
||||
entity: params.entity,
|
||||
layerId: params.layerId,
|
||||
});
|
||||
|
||||
dashboardStore.setLayer(states.layerId);
|
||||
dashboardStore.setEntity(states.entity);
|
||||
|
||||
function changeService(val: { value: string; label: string }) {
|
||||
states.service = val.value;
|
||||
}
|
||||
|
||||
function clickIcons(t: { id: string; content: string; name: string }) {
|
||||
switch (t.id) {
|
||||
case "addWidget":
|
||||
dashboardStore.addControl("Widget");
|
||||
break;
|
||||
case "addTab":
|
||||
dashboardStore.addControl("Tab");
|
||||
break;
|
||||
case "addImage":
|
||||
dashboardStore.addControl("Image");
|
||||
break;
|
||||
case "settings":
|
||||
dashboardStore.setConfigPanel(true);
|
||||
break;
|
||||
default:
|
||||
dashboardStore.addControl("Widget");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-tool {
|
||||
text-align: right;
|
||||
padding: 5px;
|
||||
background: rgb(240, 242, 245);
|
||||
border-bottom: 1px solid #dfe4e8;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 12px;
|
||||
display: inline-block;
|
||||
padding: 4px 2px;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
margin-left: 6px;
|
||||
cursor: pointer;
|
||||
background-color: #eee;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.item {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.selectors {
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.selectors-item {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
@ -1,71 +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. -->
|
||||
<template>
|
||||
<div class="widget">
|
||||
<div class="header flex-h">
|
||||
<div>title</div>
|
||||
<div class="operations">
|
||||
<Icon
|
||||
class="mr-5"
|
||||
size="sm"
|
||||
iconName="createmode_editedit"
|
||||
@click="setConfig"
|
||||
/>
|
||||
<Icon size="sm" iconName="clearclose" @click="removeWidget" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="body">chart</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const props = defineProps({
|
||||
item: { type: Object as PropType<LayoutConfig> },
|
||||
});
|
||||
const dashboardStore = useDashboardStore();
|
||||
function removeWidget() {
|
||||
dashboardStore.removeWidget(props.item);
|
||||
}
|
||||
function setConfig() {
|
||||
dashboardStore.setConfigPanel(true);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.widget {
|
||||
font-size: 12px;
|
||||
// position: relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 30px;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #eee;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.operations {
|
||||
color: #aaa;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
@ -34,7 +34,7 @@
|
||||
"webpack-env",
|
||||
"jest"
|
||||
],
|
||||
"typeRoots": ["./node_modules/@types/", "./types"],
|
||||
"typeRoots": ["./node_modules/@types/"],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
|
114
type.d.ts
vendored
@ -1,114 +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 type {
|
||||
ComponentRenderProxy,
|
||||
VNode,
|
||||
VNodeChild,
|
||||
ComponentPublicInstance,
|
||||
FunctionalComponent,
|
||||
PropType as VuePropType,
|
||||
} from "vue";
|
||||
|
||||
declare module "three";
|
||||
declare module "three-orbit-controls";
|
||||
declare module "element-plus";
|
||||
declare global {
|
||||
const __APP_INFO__: {
|
||||
pkg: {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies: Recordable<string>;
|
||||
devDependencies: Recordable<string>;
|
||||
};
|
||||
lastBuildTime: string;
|
||||
};
|
||||
|
||||
// vue
|
||||
declare type PropType<T> = VuePropType<T>;
|
||||
declare type VueNode = VNodeChild | JSX.Element;
|
||||
|
||||
export type Writable<T> = {
|
||||
-readonly [P in keyof T]: T[P];
|
||||
};
|
||||
|
||||
declare type Nullable<T> = T | null;
|
||||
declare type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
declare type Recordable<T = any> = Record<string, T>;
|
||||
declare type ReadonlyRecordable<T = any> = {
|
||||
readonly [key: string]: T;
|
||||
};
|
||||
declare type Indexable<T = any> = {
|
||||
[key: string]: T;
|
||||
};
|
||||
declare type DeepPartial<T> = {
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
};
|
||||
declare type TimeoutHandle = ReturnType<typeof setTimeout>;
|
||||
declare type IntervalHandle = ReturnType<typeof setInterval>;
|
||||
|
||||
declare interface ChangeEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
}
|
||||
|
||||
declare interface WheelEvent {
|
||||
path?: EventTarget[];
|
||||
}
|
||||
interface ImportMetaEnv extends ViteEnv {
|
||||
__: unknown;
|
||||
}
|
||||
|
||||
declare interface ViteEnv {
|
||||
VITE_PORT: number;
|
||||
VITE_USE_MOCK: boolean;
|
||||
VITE_USE_PWA: boolean;
|
||||
VITE_PUBLIC_PATH: string;
|
||||
VITE_PROXY: [string, string][];
|
||||
VITE_GLOB_APP_TITLE: string;
|
||||
VITE_GLOB_APP_SHORT_NAME: string;
|
||||
VITE_USE_CDN: boolean;
|
||||
VITE_DROP_CONSOLE: boolean;
|
||||
VITE_BUILD_COMPRESS: "gzip" | "brotli" | "none";
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean;
|
||||
VITE_LEGACY: boolean;
|
||||
VITE_USE_IMAGEMIN: boolean;
|
||||
VITE_GENERATE_UI: string;
|
||||
}
|
||||
|
||||
declare function parseInt(s: string | number, radix?: number): number;
|
||||
|
||||
declare function parseFloat(string: string | number): number;
|
||||
|
||||
namespace JSX {
|
||||
type Element = VNode;
|
||||
type ElementClass = ComponentRenderProxy;
|
||||
interface ElementAttributesProperty {
|
||||
$props: any;
|
||||
}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
}
|
||||
interface IntrinsicAttributes {
|
||||
[elem: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module "vue" {
|
||||
export type JSXComponent<Props = any> =
|
||||
| { new (): ComponentPublicInstance<Props> }
|
||||
| FunctionalComponent<Props>;
|
||||
}
|