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
|
mitt 1.1.2: https://github.com/developit/mitt MIT
|
||||||
element-resize-detector 1.2.4: https://github.com/wnr/element-resize-detector 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
|
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": {
|
"dependencies": {
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
|
"echarts": "^5.2.2",
|
||||||
"element-plus": "^1.2.0-beta.3",
|
"element-plus": "^1.2.0-beta.3",
|
||||||
"pinia": "^2.0.5",
|
"pinia": "^2.0.5",
|
||||||
"three": "^0.131.3",
|
"three": "^0.131.3",
|
||||||
@ -23,6 +24,7 @@
|
|||||||
"vuex": "^4.0.0-0"
|
"vuex": "^4.0.0-0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/echarts": "^4.9.12",
|
||||||
"@types/jest": "^24.0.19",
|
"@types/jest": "^24.0.19",
|
||||||
"@types/three": "^0.131.0",
|
"@types/three": "^0.131.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||||
@ -39,6 +41,7 @@
|
|||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"@vue/eslint-config-typescript": "^7.0.0",
|
"@vue/eslint-config-typescript": "^7.0.0",
|
||||||
"@vue/test-utils": "^2.0.0-0",
|
"@vue/test-utils": "^2.0.0-0",
|
||||||
|
"babel-jest": "^24.9.0",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-vue": "^7.0.0",
|
"eslint-plugin-vue": "^7.0.0",
|
||||||
@ -55,7 +58,7 @@
|
|||||||
"stylelint-config-standard": "^24.0.0",
|
"stylelint-config-standard": "^24.0.0",
|
||||||
"stylelint-order": "^5.0.0",
|
"stylelint-order": "^5.0.0",
|
||||||
"svg-sprite-loader": "^6.0.11",
|
"svg-sprite-loader": "^6.0.11",
|
||||||
"typescript": "~4.1.5",
|
"typescript": "~4.4.4",
|
||||||
"vue-jest": "^5.0.0-0"
|
"vue-jest": "^5.0.0-0"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
@ -74,9 +77,14 @@
|
|||||||
"ecmaVersion": 2020
|
"ecmaVersion": 2020
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/no-explicit-any": [
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"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": [
|
"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"
|
v-model="selected"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@change="changeSelected"
|
@change="changeSelected"
|
||||||
|
filterable
|
||||||
|
:multiple="multiple"
|
||||||
|
:style="{ borderRadius }"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in options"
|
v-for="item in options"
|
||||||
@ -29,7 +32,7 @@ limitations under the License. -->
|
|||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineProps, ref, defineEmits } from "vue";
|
import { ref, defineEmits } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { ElSelect, ElOption } from "element-plus";
|
import { ElSelect, ElOption } from "element-plus";
|
||||||
|
|
||||||
@ -39,21 +42,32 @@ interface Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(["change"]);
|
const emit = defineEmits(["change"]);
|
||||||
|
/*global defineProps*/
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
options: {
|
options: {
|
||||||
type: Array as PropType<Option[]>,
|
type: Array as PropType<Option[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
value: { type: String, default: "" },
|
value: {
|
||||||
|
type: [Array, String] as PropType<string[] | string>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
size: { type: String, default: "small" },
|
size: { type: String, default: "small" },
|
||||||
placeholder: { type: String, default: "Select a option" },
|
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() {
|
function changeSelected() {
|
||||||
const optionSele = props.options.filter(
|
if (!props.multiple) {
|
||||||
(d: Option) => d.value === selected.value
|
return;
|
||||||
)[0];
|
}
|
||||||
emit("change", optionSele);
|
const options = props.options.filter((d: Option) =>
|
||||||
|
props.multiple
|
||||||
|
? selected.value.includes(d.value)
|
||||||
|
: selected.value === d.value
|
||||||
|
);
|
||||||
|
emit("change", options);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scope>
|
<style lang="scss" scope>
|
||||||
@ -92,4 +106,8 @@ function changeSelected() {
|
|||||||
width: 30px;
|
width: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-input__inner {
|
||||||
|
border-radius: unset !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import Icon from "./Icon.vue";
|
import Icon from "./Icon.vue";
|
||||||
import TimePicker from "./TimePicker.vue";
|
import TimePicker from "./TimePicker.vue";
|
||||||
import Selector from "./Selector.vue";
|
import Selector from "./Selector.vue";
|
||||||
|
import Graph from "./Graph.vue";
|
||||||
import type { App } from "vue";
|
import type { App } from "vue";
|
||||||
import VueGridLayout from "vue-grid-layout";
|
import VueGridLayout from "vue-grid-layout";
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ const components: { [key: string]: any } = {
|
|||||||
TimePicker,
|
TimePicker,
|
||||||
VueGridLayout,
|
VueGridLayout,
|
||||||
Selector,
|
Selector,
|
||||||
|
Graph,
|
||||||
};
|
};
|
||||||
const componentsName: string[] = Object.keys(components);
|
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
|
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 { cancelToken } from "@/utils/cancelToken";
|
||||||
import * as app from "./query/app";
|
import * as app from "./query/app";
|
||||||
import * as selector from "./query/selector";
|
import * as selector from "./query/selector";
|
||||||
|
import * as dashboard from "./query/dashboard";
|
||||||
|
|
||||||
const query: { [key: string]: string } = { ...app, ...selector };
|
const query: { [key: string]: string } = { ...app, ...selector, ...dashboard };
|
||||||
class Graph {
|
class Graph {
|
||||||
private queryData = "";
|
private queryData = "";
|
||||||
public query(queryData: string) {
|
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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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 queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||||
export const queryLayers = `query ${Layers.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">
|
<div class="app-config">
|
||||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||||
<TimePicker
|
<TimePicker
|
||||||
v-model="time"
|
|
||||||
:value="time"
|
:value="time"
|
||||||
position="bottom"
|
position="bottom"
|
||||||
format="YYYY-MM-DD HH:mm"
|
format="YYYY-MM-DD HH:mm"
|
||||||
|
@input="changeTimeRange"
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
UTC{{ utcHour >= 0 ? "+" : ""
|
UTC{{ utcHour >= 0 ? "+" : ""
|
||||||
@ -62,19 +62,18 @@ const setConfig = (value: string) => {
|
|||||||
pageName.value = value || "";
|
pageName.value = value || "";
|
||||||
theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
||||||
};
|
};
|
||||||
const time = computed({
|
const time = computed(() => [
|
||||||
get() {
|
appStore.durationRow.start,
|
||||||
return [appStore.durationRow.start, appStore.durationRow.end];
|
appStore.durationRow.end,
|
||||||
},
|
]);
|
||||||
set(val: Date[]) {
|
function changeTimeRange(val: Date[]) {
|
||||||
timeRange.value =
|
timeRange.value =
|
||||||
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||||
if (timeRange.value) {
|
if (timeRange.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
appStore.setDuration(timeFormat(val));
|
appStore.setDuration(timeFormat(val));
|
||||||
},
|
}
|
||||||
});
|
|
||||||
setConfig(String(route.meta.title));
|
setConfig(String(route.meta.title));
|
||||||
watch(
|
watch(
|
||||||
() => route.meta.title,
|
() => route.meta.title,
|
||||||
@ -93,17 +92,20 @@ watch(
|
|||||||
color: #222;
|
color: #222;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-bar.dark {
|
.nav-bar.dark {
|
||||||
background-color: #333840;
|
background-color: #333840;
|
||||||
border-bottom: 1px solid #252a2f;
|
border-bottom: 1px solid #252a2f;
|
||||||
color: #fafbfc;
|
color: #fafbfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,9 @@ limitations under the License. -->
|
|||||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
||||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span>{{ t(menu.meta.title) }}</span>
|
<span :class="isCollapse ? 'collapse' : ''">{{
|
||||||
|
t(menu.meta.title)
|
||||||
|
}}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item-group>
|
<el-menu-item-group>
|
||||||
@ -88,24 +90,16 @@ limitations under the License. -->
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRouter, RouteRecordRaw, RouteRecordName } from "vue-router";
|
import { useRouter, RouteRecordRaw } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import {
|
|
||||||
ElMenu,
|
|
||||||
ElMenuItem,
|
|
||||||
ElSubMenu,
|
|
||||||
ElMenuItemGroup,
|
|
||||||
ElIcon,
|
|
||||||
} from "element-plus";
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const name: RouteRecordName | null | undefined = String(
|
const name = ref<any>(String(useRouter().currentRoute.value.name));
|
||||||
useRouter().currentRoute.value.name
|
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "")
|
||||||
);
|
|
||||||
const theme = ["VirtualMachine", "Kubernetes"].includes(name || "")
|
|
||||||
? ref("light")
|
? ref("light")
|
||||||
: ref("black");
|
: ref("black");
|
||||||
const routes = useRouter().options.routes;
|
const routes = ref<any>(useRouter().options.routes);
|
||||||
const isCollapse = ref(false);
|
const isCollapse = ref(true);
|
||||||
const controlMenu = () => {
|
const controlMenu = () => {
|
||||||
isCollapse.value = !isCollapse.value;
|
isCollapse.value = !isCollapse.value;
|
||||||
};
|
};
|
||||||
@ -125,40 +119,56 @@ const filterMenus = (menus: any[]) => {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
background: #252a2f;
|
background: #252a2f;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
// box-shadow: 1px 5px 3px #888;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu-vertical:not(.el-menu--collapse) {
|
.el-menu-vertical:not(.el-menu--collapse) {
|
||||||
width: 210px;
|
width: 210px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-icon-collapse {
|
.logo-icon-collapse {
|
||||||
width: 65px;
|
width: 65px;
|
||||||
margin: 15px 0 30px 0;
|
margin: 15px 0 30px 0;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.collapse {
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
visibility: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.logo-icon {
|
.logo-icon {
|
||||||
margin: 15px 0 30px 15px;
|
margin: 15px 0 30px 15px;
|
||||||
width: 110px;
|
width: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-sub-menu .el-icon {
|
.el-sub-menu .el-icon {
|
||||||
height: 26px;
|
height: 26px;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-sub-menu__title {
|
.el-sub-menu__title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-control {
|
.menu-control {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
left: 215px;
|
left: 215px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s linear;
|
transition: all 0.2s linear;
|
||||||
z-index: 9999;
|
z-index: 99;
|
||||||
color: #252a2f;
|
color: #252a2f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-control.collapse {
|
.menu-control.collapse {
|
||||||
left: 70px;
|
left: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-icon.el-sub-menu__icon-arrow {
|
.el-icon.el-sub-menu__icon-arrow {
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,26 @@ const msg = {
|
|||||||
endpoint: "Endpoint",
|
endpoint: "Endpoint",
|
||||||
instance: "Instance",
|
instance: "Instance",
|
||||||
create: "Create",
|
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",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
secondTip: "Select Second",
|
secondTip: "Select Second",
|
||||||
@ -218,7 +238,7 @@ const msg = {
|
|||||||
grade: "Grade",
|
grade: "Grade",
|
||||||
relatedTraceLogs: "Related Logs",
|
relatedTraceLogs: "Related Logs",
|
||||||
setConditions: "More Conditions",
|
setConditions: "More Conditions",
|
||||||
metricName: "Metric Name",
|
metricName: "Select Metric Names",
|
||||||
keywordsOfContent: "Keys Of Content",
|
keywordsOfContent: "Keys Of Content",
|
||||||
excludingKeywordsOfContent: "Exclude Keys Of Content",
|
excludingKeywordsOfContent: "Exclude Keys Of Content",
|
||||||
return: "Return",
|
return: "Return",
|
||||||
@ -247,8 +267,6 @@ const msg = {
|
|||||||
eventsParameters: "Event Parameters",
|
eventsParameters: "Event Parameters",
|
||||||
eventDetail: "Event Detail",
|
eventDetail: "Event Detail",
|
||||||
value: "Value",
|
value: "Value",
|
||||||
tableHeader: "Header Names",
|
|
||||||
tableValues: "Table Values",
|
|
||||||
show: "Show",
|
show: "Show",
|
||||||
hide: "Hide",
|
hide: "Hide",
|
||||||
statistics: "Statistics",
|
statistics: "Statistics",
|
||||||
|
@ -50,6 +50,26 @@ const msg = {
|
|||||||
layer: "层",
|
layer: "层",
|
||||||
endpoint: "端点",
|
endpoint: "端点",
|
||||||
create: "新建",
|
create: "新建",
|
||||||
|
loading: "加载中",
|
||||||
|
selectVisualization: "选择你的可视化",
|
||||||
|
graphStyles: "图形样式",
|
||||||
|
widgetOptions: "组件选项",
|
||||||
|
standardOptions: "标准选项",
|
||||||
|
max: "最大值",
|
||||||
|
min: "最小值",
|
||||||
|
plus: "加法",
|
||||||
|
minus: "减法",
|
||||||
|
multiply: "乘法",
|
||||||
|
divide: "除法",
|
||||||
|
convertToMilliseconds: "转换Unix时间戳(毫秒)",
|
||||||
|
convertToSeconds: "转换Unix时间戳(秒)",
|
||||||
|
smooth: "光滑的",
|
||||||
|
showSymbol: "显示符号",
|
||||||
|
step: "台阶",
|
||||||
|
showValues: "显示值",
|
||||||
|
fontSize: "字体大小",
|
||||||
|
showBackground: "显示背景",
|
||||||
|
areaOpacity: "透明度",
|
||||||
hourTip: "选择小时",
|
hourTip: "选择小时",
|
||||||
minuteTip: "选择分钟",
|
minuteTip: "选择分钟",
|
||||||
secondTip: "选择秒数",
|
secondTip: "选择秒数",
|
||||||
@ -217,7 +237,7 @@ const msg = {
|
|||||||
grade: "等级",
|
grade: "等级",
|
||||||
relatedTraceLogs: "相关的日志",
|
relatedTraceLogs: "相关的日志",
|
||||||
setConditions: "更多条件",
|
setConditions: "更多条件",
|
||||||
metricName: "指标名称",
|
metricName: "选择指标名称",
|
||||||
keywordsOfContent: "内容关键词",
|
keywordsOfContent: "内容关键词",
|
||||||
excludingKeywordsOfContent: "内容不包含的关键词",
|
excludingKeywordsOfContent: "内容不包含的关键词",
|
||||||
return: "返回",
|
return: "返回",
|
||||||
|
@ -20,12 +20,14 @@ import router from "./router";
|
|||||||
import { store } from "./store";
|
import { store } from "./store";
|
||||||
import components from "@/components";
|
import components from "@/components";
|
||||||
import i18n from "./locales";
|
import i18n from "./locales";
|
||||||
import "element-plus/dist/index.css";
|
|
||||||
import "./styles/lib.scss";
|
import "./styles/lib.scss";
|
||||||
import "./styles/reset.scss";
|
import "./styles/reset.scss";
|
||||||
|
import ElementPlus from "element-plus";
|
||||||
|
import "element-plus/dist/index.css";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
|
app.use(ElementPlus, { size: "small", zIndex: 3000 });
|
||||||
app.use(components);
|
app.use(components);
|
||||||
app.use(i18n);
|
app.use(i18n);
|
||||||
app.use(store);
|
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"),
|
component: () => import("@/views/dashboard/Edit.vue"),
|
||||||
name: "Edit",
|
name: "Edit",
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -21,7 +21,6 @@ export const routesGen: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
name: "GeneralService",
|
name: "GeneralService",
|
||||||
redirect: "/generalService",
|
|
||||||
meta: {
|
meta: {
|
||||||
title: "generalService",
|
title: "generalService",
|
||||||
icon: "chart",
|
icon: "chart",
|
||||||
|
@ -53,6 +53,10 @@ router.beforeEach((to, from, next) => {
|
|||||||
}
|
}
|
||||||
(window as any).axiosCancel = [];
|
(window as any).axiosCancel = [];
|
||||||
}
|
}
|
||||||
next();
|
if (to.path === "/") {
|
||||||
|
next({ path: "/generalService" });
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
export default router;
|
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 getLocalTime from "@/utils/localtime";
|
||||||
import getDurationRow from "@/utils/dateTime";
|
import getDurationRow from "@/utils/dateTime";
|
||||||
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
||||||
|
/*global Nullable*/
|
||||||
interface AppState {
|
interface AppState {
|
||||||
durationRow: any;
|
durationRow: any;
|
||||||
utc: string;
|
utc: string;
|
||||||
@ -98,6 +98,7 @@ export const appStore = defineStore({
|
|||||||
actions: {
|
actions: {
|
||||||
setDuration(data: Duration): void {
|
setDuration(data: Duration): void {
|
||||||
this.durationRow = data;
|
this.durationRow = data;
|
||||||
|
localStorage.setItem("durationRow", JSON.stringify(data, null, 0));
|
||||||
if ((window as any).axiosCancel.length !== 0) {
|
if ((window as any).axiosCancel.length !== 0) {
|
||||||
for (const event of (window as any).axiosCancel) {
|
for (const event of (window as any).axiosCancel) {
|
||||||
setTimeout(event(), 0);
|
setTimeout(event(), 0);
|
||||||
|
@ -17,42 +17,177 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import { LayoutConfig } from "@/types/dashboard";
|
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 {
|
interface DashboardState {
|
||||||
showConfig: boolean;
|
showConfig: boolean;
|
||||||
layout: LayoutConfig[];
|
layout: LayoutConfig[];
|
||||||
|
selectedGrid: Nullable<LayoutConfig>; // edit widgets
|
||||||
|
entity: string;
|
||||||
|
layerId: string;
|
||||||
|
activedGridItem: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dashboardStore = defineStore({
|
export const dashboardStore = defineStore({
|
||||||
id: "dashboard",
|
id: "dashboard",
|
||||||
state: (): DashboardState => ({
|
state: (): DashboardState => ({
|
||||||
layout: [],
|
layout: [ConfigData],
|
||||||
showConfig: false,
|
showConfig: false,
|
||||||
|
selectedGrid: null,
|
||||||
|
entity: "",
|
||||||
|
layerId: "",
|
||||||
|
activedGridItem: "",
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setLayout(data: LayoutConfig[]) {
|
setLayout(data: LayoutConfig[]) {
|
||||||
this.layout = data;
|
this.layout = data;
|
||||||
},
|
},
|
||||||
addWidget() {
|
addControl(type: string) {
|
||||||
const newWidget: LayoutConfig = {
|
const newWidget: LayoutConfig = {
|
||||||
x: 0,
|
...NewControl,
|
||||||
y: 0,
|
|
||||||
w: 24,
|
|
||||||
h: 12,
|
|
||||||
i: String(this.layout.length),
|
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) => {
|
this.layout = this.layout.map((d: LayoutConfig) => {
|
||||||
d.y = d.y + newWidget.h;
|
d.y = d.y + newWidget.h;
|
||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
this.layout.push(newWidget);
|
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);
|
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) {
|
setConfigPanel(show: boolean) {
|
||||||
this.showConfig = show;
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { Option } from "@/types/app";
|
import { Option, Duration } from "@/types/app";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graph from "@/graph";
|
import graph from "@/graph";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
@ -45,6 +45,27 @@ export const selectorStore = defineStore({
|
|||||||
}
|
}
|
||||||
return res;
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
export interface Option {
|
export interface Option {
|
||||||
key: string | number;
|
value: string | number;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
export interface Duration {
|
export interface Duration {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { string } from "vue-types";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -24,16 +22,62 @@ export interface LayoutConfig {
|
|||||||
i: string;
|
i: string;
|
||||||
widget?: WidgetConfig;
|
widget?: WidgetConfig;
|
||||||
graph?: GraphConfig;
|
graph?: GraphConfig;
|
||||||
|
standard?: StandardConfig;
|
||||||
|
metrics?: string[];
|
||||||
|
type?: string;
|
||||||
|
queryMetricType?: string;
|
||||||
|
children?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WidgetConfig {
|
export interface WidgetConfig {
|
||||||
title: string;
|
title?: string;
|
||||||
Metrics: string[];
|
tips?: string;
|
||||||
unit: string;
|
|
||||||
tips: string;
|
|
||||||
sortOrder: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphConfig {
|
export interface StandardConfig {
|
||||||
type: string;
|
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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="dashboard-tool">
|
<Tool />
|
||||||
<el-tooltip class="item" effect="dark" content="Add Widget" placement="top">
|
<div class="ds-main" @click="handleClick">
|
||||||
<span class="icon-btn" @click="dashboardStore.addWidget">
|
<grid-layout />
|
||||||
<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 />
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="dashboardStore.showConfig"
|
v-model="dashboardStore.showConfig"
|
||||||
title="Configurations"
|
title="Edit Graph Options"
|
||||||
width="95%"
|
fullscreen
|
||||||
|
:destroy-on-close="true"
|
||||||
@closed="dashboardStore.setConfigPanel(false)"
|
@closed="dashboardStore.setConfigPanel(false)"
|
||||||
>
|
>
|
||||||
<div class="configuration">xxxx</div>
|
<widget-config />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import GridLayout from "./panel/Layout.vue";
|
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 { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { ElDialog, ElTooltip } from "element-plus";
|
|
||||||
|
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
// fetch layout data from serve side
|
// fetch layout data from serve side
|
||||||
const layout: LayoutConfig[] = [
|
// const layout: any[] = [
|
||||||
{ x: 0, y: 0, w: 4, h: 12, i: "0" },
|
// { x: 0, y: 0, w: 4, h: 12, i: "0" },
|
||||||
{ x: 4, y: 0, w: 4, h: 12, i: "1" },
|
// { x: 4, y: 0, w: 4, h: 12, i: "1" },
|
||||||
{ x: 8, y: 0, w: 4, h: 15, i: "2" },
|
// { x: 8, y: 0, w: 4, h: 15, i: "2" },
|
||||||
{ x: 12, y: 0, w: 4, h: 9, i: "3" },
|
// { x: 12, y: 0, w: 4, h: 9, i: "3" },
|
||||||
{ x: 16, y: 0, w: 4, h: 9, i: "4" },
|
// { x: 16, y: 0, w: 4, h: 9, i: "4" },
|
||||||
{ x: 20, y: 0, w: 4, h: 9, i: "5" },
|
// { x: 20, y: 0, w: 4, h: 9, i: "5" },
|
||||||
{ x: 0, y: 12, w: 4, h: 15, i: "7" },
|
// { x: 0, y: 12, w: 4, h: 15, i: "7" },
|
||||||
{ x: 4, y: 12, w: 4, h: 15, i: "8" },
|
// { x: 4, y: 12, w: 4, h: 15, i: "8" },
|
||||||
{ x: 8, y: 15, w: 4, h: 12, i: "9" },
|
// { x: 8, y: 15, w: 4, h: 12, i: "9" },
|
||||||
{ x: 12, y: 9, w: 4, h: 12, i: "10" },
|
// { x: 12, y: 9, w: 4, h: 12, i: "10" },
|
||||||
{ x: 16, y: 9, w: 4, h: 12, i: "11" },
|
// { x: 16, y: 9, w: 4, h: 12, i: "11" },
|
||||||
{ x: 20, y: 9, w: 4, h: 15, i: "12" },
|
// { x: 20, y: 9, w: 4, h: 15, i: "12" },
|
||||||
{ x: 0, y: 27, w: 4, h: 12, i: "14" },
|
// { x: 0, y: 27, w: 4, h: 12, i: "14" },
|
||||||
{ x: 4, y: 27, w: 4, h: 12, i: "15" },
|
// { x: 4, y: 27, w: 4, h: 12, i: "15" },
|
||||||
{ x: 8, y: 27, w: 4, h: 15, i: "16" },
|
// { x: 8, y: 27, w: 4, h: 15, i: "16" },
|
||||||
];
|
// ];
|
||||||
dashboardStore.setLayout(layout);
|
// dashboardStore.setLayout(layout);
|
||||||
|
function handleClick(e: any) {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (e.target.className === "ds-main") {
|
||||||
|
dashboardStore.activeGridItem("");
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.dashboard-tool {
|
|
||||||
text-align: right;
|
|
||||||
padding: 5px 10px;
|
|
||||||
background: rgb(240, 242, 245);
|
|
||||||
border-bottom: 1px solid #dfe4e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ds-main {
|
.ds-main {
|
||||||
height: calc(100% - 40px);
|
height: calc(100% - 45px);
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout {
|
.layout {
|
||||||
@ -101,28 +77,4 @@ dashboardStore.setLayout(layout);
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
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>
|
</style>
|
||||||
|
@ -56,7 +56,6 @@ limitations under the License. -->
|
|||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { ElInput, ElButton } from "element-plus";
|
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { EntityType, Options } from "./data";
|
import { EntityType, Options } from "./data";
|
||||||
import uuid from "@/utils/uuid";
|
import uuid from "@/utils/uuid";
|
||||||
@ -74,11 +73,11 @@ const onCreate = () => {
|
|||||||
router.push(path);
|
router.push(path);
|
||||||
};
|
};
|
||||||
selectorStore.fetchServices("general");
|
selectorStore.fetchServices("general");
|
||||||
function changeLayer(opt: { label: string; value: string }) {
|
function changeLayer(opt: { label: string; value: string }[]) {
|
||||||
states.layer = opt.value;
|
states.layer = opt[0].value;
|
||||||
}
|
}
|
||||||
function changeEntity(opt: { label: string; value: string }) {
|
function changeEntity(opt: { label: string; value: string }[]) {
|
||||||
states.entity = opt.value;
|
states.entity = opt[0].value;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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 = [
|
export const EntityType = [
|
||||||
{ value: "service", label: "Service" },
|
{ value: "service", label: "Service", key: 1 },
|
||||||
{ value: "all", label: "All" },
|
{ value: "all", label: "All", key: 10 },
|
||||||
{ value: "endpoint", label: "Service Endpoint" },
|
{ value: "endpoint", label: "Service Endpoint", key: 3 },
|
||||||
{ value: "serviceInstance", label: "Service Instance" },
|
{ value: "serviceInstance", label: "Service Instance", key: 3 },
|
||||||
{ value: "serviceRelationClient", label: "Service Relation(client)" },
|
{ value: "serviceRelationClient", label: "Service Relation(client)", key: 2 },
|
||||||
{ value: "serviceRelationServer", label: "Service Relation(server)" },
|
{ value: "serviceRelationServer", label: "Service Relation(server)", key: 2 },
|
||||||
{
|
{
|
||||||
value: "serviceInstanceRelationClient",
|
value: "serviceInstanceRelationClient",
|
||||||
label: "Service Instance Relation(client)",
|
label: "Service Instance Relation(client)",
|
||||||
|
key: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "serviceInstanceRelationServer",
|
value: "serviceInstanceRelationServer",
|
||||||
label: "Service Instance Relation(server)",
|
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 = [
|
export const Options = [
|
||||||
{
|
{
|
||||||
value: "layer1",
|
value: "Option1",
|
||||||
label: "layer1",
|
label: "Option1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "layer2",
|
value: "Option2",
|
||||||
label: "layer2",
|
label: "Option2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "layer3",
|
value: "Option3",
|
||||||
label: "layer3",
|
label: "Option3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "layer4",
|
value: "Option4",
|
||||||
label: "layer4",
|
label: "Option4",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "layer5",
|
value: "Option5",
|
||||||
label: "layer5",
|
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"
|
:h="item.h"
|
||||||
:i="item.i"
|
:i="item.i"
|
||||||
:key="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-item>
|
||||||
</grid-layout>
|
</grid-layout>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { LayoutConfig } from "@/types/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();
|
export default defineComponent({
|
||||||
function layoutUpdatedEvent(newLayout: LayoutConfig) {
|
name: "Layout",
|
||||||
dashboardStore.setLayout(newLayout);
|
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>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.vue-grid-layout {
|
.vue-grid-layout {
|
||||||
@ -55,4 +73,8 @@ function layoutUpdatedEvent(newLayout: LayoutConfig) {
|
|||||||
box-shadow: 0px 1px 4px 0px #00000029;
|
box-shadow: 0px 1px 4px 0px #00000029;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vue-grid-item.active {
|
||||||
|
border: 1px solid #409eff;
|
||||||
|
}
|
||||||
</style>
|
</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",
|
"webpack-env",
|
||||||
"jest"
|
"jest"
|
||||||
],
|
],
|
||||||
"typeRoots": ["./node_modules/@types/", "./types"],
|
"typeRoots": ["./node_modules/@types/"],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": [
|
||||||
"src/*"
|
"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>;
|
|
||||||
}
|
|