feat: implement dashboard layouts (#7)

This commit is contained in:
吴晟 Wu Sheng 2021-12-27 16:14:17 +08:00 committed by GitHub
commit 6ee2e0dd9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1224 additions and 246 deletions

31
dist/LICENSE vendored
View File

@ -7,15 +7,22 @@ vuex 4.0.2: https://github.com/vuejs/vuex MIT
dayjs 1.10.7: https://github.com/iamkun/dayjs MIT
lodash 4.17.21: https://github.com/lodash/lodash MIT
vue-i18n 9.1.9: https://github.com/kazupon/vue-i18n MIT
pinia 2.0.5: github.com/posva/pinia MIT
normalize-wheel-es 1.1.1: github.com/sxzz/normalize-wheel-es MIT
async-validator 4.0.7: github.com/yiminghe/async-validator MIT
axios 0.24.0: github.com/axios/axios MIT
memoize-one 6.0.0: github.com/alexreardon/memoize-one MIT
popperjs/core 2.10.2: github.com/popperjs/popper-core MIT
three 0.131.3: github.com/mrdoob/three.js MIT
three-orbit-controls 82.1.0: github.com/mattdesl/three-orbit-controls MIT
vue-demi 0.12.1: github.com/antfu/vue-demi MIT
vueuse/core 6.8.0: github.com/vueuse/vueuse MIT
vue/devtools-api 6.0.0-beta.20.1: github.com/vuejs/vue-devtools MIT
element-plus 1.2.0-beta.3: github.com/element-plus/element-plus MIT
pinia 2.0.5: https://github.com/posva/pinia MIT
normalize-wheel-es 1.1.1: https://github.com/sxzz/normalize-wheel-es MIT
async-validator 4.0.7: https://github.com/yiminghe/async-validator MIT
axios 0.24.0: https://github.com/axios/axios MIT
memoize-one 6.0.0: https://github.com/alexreardon/memoize-one MIT
popperjs/core 2.10.2: https://github.com/popperjs/popper-core MIT
three 0.131.3: https://github.com/mrdoob/three.js MIT
three-orbit-controls 82.1.0: https://github.com/mattdesl/three-orbit-controls MIT
vue-demi 0.12.1: https://github.com/antfu/vue-demi MIT
vueuse/core 6.8.0: https://github.com/vueuse/vueuse MIT
vue/devtools-api 6.0.0-beta.20.1: https://github.com/vuejs/vue-devtools MIT
element-plus 1.2.0-beta.3: https://github.com/element-plus/element-plus MIT
vue-types 4.1.1: https://github.com/dwightjack/vue-types MIT
is-plain-object 5.0.0: https://github.com/jonschlinkert/is-plain-object MIT
vue-grid-layout 3.0.0-beta1: https://github.com/jbaysolutions/vue-grid-layout MIT
interactjs 1.10.11: https://github.com/taye/interact.js MIT
mitt 1.1.2: https://github.com/developit/mitt MIT
element-resize-detector 1.2.4: https://github.com/wnr/element-resize-detector MIT
batch-processor 1.0.0: https://github.com/wnr/batch-processor MIT

21
dist/licenses/LICENSE-batch-processor vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

21
dist/licenses/LICENSE-interactjs vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

21
dist/licenses/LICENSE-is-plain-object vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

21
dist/licenses/LICENSE-mitt vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

21
dist/licenses/LICENSE-vue-grid-layout vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

21
dist/licenses/LICENSE-vue-types vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

259
package-lock.json generated
View File

@ -1321,6 +1321,132 @@
"@hapi/hoek": "^8.3.0"
}
},
"@interactjs/actions": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/actions/-/actions-1.10.11.tgz",
"integrity": "sha512-P39zeefr4hkmKx+5nZ+mrH1s0l2YJ3gIHrthXmE81n6MlMa42m0WtHcTms4C5JTTNBP2EEDY+KGgGxSnmJKvUw==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/auto-scroll": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/auto-scroll/-/auto-scroll-1.10.11.tgz",
"integrity": "sha512-feHNjhi0EMNLV2nQcEgjYPz2mI54aeSW2RiaoNtFLyBvtXKp0b4DmluwDv6DvuXmUpDwD5g/Hk1gGM2rgl7iqQ==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/auto-start": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/auto-start/-/auto-start-1.10.11.tgz",
"integrity": "sha512-cIg5CcalCPtC6AiGq6j/0hKUtL2MweEpvw12FuB19sz2Q9Dye0J4GliHKhOYvtumNinnvfVAZ4FZMqZEuX7YZA==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/core": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/core/-/core-1.10.11.tgz",
"integrity": "sha512-aJ50ccVeszpJt7wPH7Yfqm7f1aG1SA94qd90P0NaESh5/QUXn4CESO6igobo4DFHQ5z+1Rfdl8aphP4JxlH4gw=="
},
"@interactjs/dev-tools": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/dev-tools/-/dev-tools-1.10.11.tgz",
"integrity": "sha512-BP2FNfMbF7zLuOAUGMkDhCo1e1B0fnqyb9ih/Y8yAIJuoLrZxP/9htbsS1vZOIVZ4UgtrId4cYOwfcAZBMQtmw==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/inertia": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/inertia/-/inertia-1.10.11.tgz",
"integrity": "sha512-h+sknCzRqBSyHy4ctPNsq56mxkAMMdwHWD6en7rDEw899gdGKYaXVDVdv1jMfiwNRw0eRFBNoCiol8r3a/a3Jw==",
"requires": {
"@interactjs/interact": "1.10.11",
"@interactjs/offset": "1.10.11"
}
},
"@interactjs/interact": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/interact/-/interact-1.10.11.tgz",
"integrity": "sha512-0iZJ9l547JuBA/lKxK4ARGYVmMqRSsAdA8gXL1zWe51qEIQq8PyWmMipoi8JbDaL7exC2THKwkXu5uq5ndT+iA==",
"requires": {
"@interactjs/core": "1.10.11",
"@interactjs/types": "1.10.11",
"@interactjs/utils": "1.10.11"
}
},
"@interactjs/interactjs": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/interactjs/-/interactjs-1.10.11.tgz",
"integrity": "sha512-cGOxf6rp3Y8/sk88LhIT0XDn4gCiCzAnUG5Kkj9SAqiUO6BK/9+Wbp1IBkNaPgl/8uG8gNHh/dXBrlBBNcqJAg==",
"requires": {
"@interactjs/actions": "1.10.11",
"@interactjs/auto-scroll": "1.10.11",
"@interactjs/auto-start": "1.10.11",
"@interactjs/core": "1.10.11",
"@interactjs/dev-tools": "1.10.11",
"@interactjs/inertia": "1.10.11",
"@interactjs/interact": "1.10.11",
"@interactjs/modifiers": "1.10.11",
"@interactjs/offset": "1.10.11",
"@interactjs/pointer-events": "1.10.11",
"@interactjs/reflow": "1.10.11",
"@interactjs/utils": "1.10.11"
}
},
"@interactjs/modifiers": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/modifiers/-/modifiers-1.10.11.tgz",
"integrity": "sha512-ltqX1RSqeAIikixlQBlyEUdclT5+rbfIGi3sIdLLYaIZQnltYkWqL9MHKx/w5b+hV+Mc0p5MLUFWJbTdkSCZ9g==",
"requires": {
"@interactjs/interact": "1.10.11",
"@interactjs/snappers": "1.10.11"
}
},
"@interactjs/offset": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/offset/-/offset-1.10.11.tgz",
"integrity": "sha512-mBT7eIfy5ivofECiv+VwtEwwIMLV54fT9ujSMWJPduxdSYIHepUWgEf/3zjJknFh6jQc7pqz9dtjvVvyzRCLlQ==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/pointer-events": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/pointer-events/-/pointer-events-1.10.11.tgz",
"integrity": "sha512-yBT8JJVMZ+MgBay5l1WAHnL8ch/mZsRfaFahti+QFYeQyRloDtsWmEMDSYI/Onyy9+hS3gN/ge77ArGciZZ0Ow==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/reflow": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/reflow/-/reflow-1.10.11.tgz",
"integrity": "sha512-NSCtcCkjImOYSbxzzv2kFqR9t49J8KlhEr9UoePc7GyLbNXsiv3WQ3n0ehZd7CgZXQDiVXnP2UnmIOv5Zd4HQg==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/snappers": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/snappers/-/snappers-1.10.11.tgz",
"integrity": "sha512-yYtOMUZ7aFUZ1IYheq9Tj5hZ4J1r5dnaXhLF44WsI/awQ5L0DjZf07GPWof0B+7rZHEVudxyQNbPfFmb+1K94Q==",
"requires": {
"@interactjs/interact": "1.10.11"
}
},
"@interactjs/types": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.11.tgz",
"integrity": "sha512-YRsVFWjL8Gkkvlx3qnjeaxW4fnibSJ9791g8BA7Pv5ANByI64WmtR1vU7A2rXcrOn8XvyCEfY0ss1s8NhZP+MA=="
},
"@interactjs/utils": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/@interactjs/utils/-/utils-1.10.11.tgz",
"integrity": "sha512-410ZoxKF+r1roeSelL+WHXfdryUMg5iykC1XwQ3l6XqNw43IMACzyvTH6k6Pwxj7w7x42nce0Qdn1GQ3Y8xyCw=="
},
"@intervolga/optimize-cssnano-plugin": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@intervolga/optimize-cssnano-plugin/-/optimize-cssnano-plugin-1.0.6.tgz",
@ -4915,6 +5041,11 @@
"integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
"dev": true
},
"batch-processor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz",
"integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@ -7632,6 +7763,14 @@
"normalize-wheel-es": "^1.1.0"
}
},
"element-resize-detector": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz",
"integrity": "sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==",
"requires": {
"batch-processor": "1.0.0"
}
},
"elliptic": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
@ -14726,6 +14865,90 @@
}
}
},
"postcss-html": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.3.0.tgz",
"integrity": "sha512-ewbwd7OGW4dLsErtvZH9HpVMEcXnlhYSzKsr7MepGlOT8imHTIZ/+pdfEruLS+hTYapLTQAWDnoQcJpsYU4uRw==",
"dev": true,
"requires": {
"htmlparser2": "^7.1.2",
"postcss": "^8.4.0",
"postcss-safe-parser": "^6.0.0"
},
"dependencies": {
"dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"dev": true,
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
},
"dependencies": {
"entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
}
}
},
"domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
"dev": true
},
"domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"dev": true,
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0"
}
},
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"dev": true
},
"htmlparser2": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
"dev": true,
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.2",
"domutils": "^2.8.0",
"entities": "^3.0.1"
}
},
"postcss": {
"version": "8.4.5",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
"integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
"dev": true,
"requires": {
"nanoid": "^3.1.30",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.1"
}
},
"source-map-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz",
"integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==",
"dev": true
}
}
},
"postcss-load-config": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz",
@ -19522,6 +19745,27 @@
}
}
},
"vue-grid-layout": {
"version": "3.0.0-beta1",
"resolved": "https://registry.npmjs.org/vue-grid-layout/-/vue-grid-layout-3.0.0-beta1.tgz",
"integrity": "sha512-MsW0yfYNtnAO/uDhfZvkP6effxSJxvhAFbIL37x6Rn3vW9xf0WHVefKaSbQMLpSq3mXnR6ut0pg2Cd5lqIIZzg==",
"requires": {
"@interactjs/actions": "^1.10.2",
"@interactjs/auto-start": "^1.10.2",
"@interactjs/dev-tools": "^1.10.2",
"@interactjs/interactjs": "^1.10.2",
"@interactjs/modifiers": "^1.10.2",
"element-resize-detector": "^1.2.1",
"mitt": "^2.1.0"
},
"dependencies": {
"mitt": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-2.1.0.tgz",
"integrity": "sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg=="
}
}
},
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
@ -19614,6 +19858,21 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"vue-types": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vue-types/-/vue-types-4.1.1.tgz",
"integrity": "sha512-Jq2GZ/w6rExJbLA/h7nHBFLciu+YNekgox0DB64wN1snZ4IIJMq+qnqp1/vE4fc7vEjZcP5KGhLzkkSjIHLRzw==",
"requires": {
"is-plain-object": "5.0.0"
},
"dependencies": {
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
}
}
},
"vuex": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",

View File

@ -16,8 +16,10 @@
"three": "^0.131.3",
"three-orbit-controls": "^82.1.0",
"vue": "^3.0.0",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.1.9",
"vue-router": "^4.0.0-0",
"vue-types": "^4.1.1",
"vuex": "^4.0.0-0"
},
"devDependencies": {
@ -43,6 +45,7 @@
"husky": "^7.0.4",
"lint-staged": "^12.1.3",
"node-sass": "^6.0.1",
"postcss-html": "^1.3.0",
"postcss-scss": "^4.0.2",
"prettier": "^2.2.1",
"sass-loader": "^10.2.0",
@ -109,7 +112,7 @@
"*.vue": [
"eslint --fix",
"prettier --write",
"stylelint --fix"
"stylelint --fix --custom-syntax postcss-html"
],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"prettier --write--parser json"

View 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>clearclose</title>
<path d="M18.984 6.422l-5.578 5.578 5.578 5.578-1.406 1.406-5.578-5.578-5.578 5.578-1.406-1.406 5.578-5.578-5.578-5.578 1.406-1.406 5.578 5.578 5.578-5.578z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View 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>createmode_editedit</title>
<path d="M20.719 7.031l-1.828 1.828-3.75-3.75 1.828-1.828q0.281-0.281 0.703-0.281t0.703 0.281l2.344 2.344q0.281 0.281 0.281 0.703t-0.281 0.703zM3 17.25l11.063-11.063 3.75 3.75-11.063 11.063h-3.75v-3.75z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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>folder_open</title>
<path d="M20.016 18v-9.984h-16.031v9.984h16.031zM20.016 6q0.797 0 1.383 0.609t0.586 1.406v9.984q0 0.797-0.586 1.406t-1.383 0.609h-16.031q-0.797 0-1.383-0.609t-0.586-1.406v-12q0-0.797 0.586-1.406t1.383-0.609h6l2.016 2.016h8.016z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

18
src/assets/icons/save.svg Normal file
View 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>save</title>
<path d="M15 9v-3.984h-9.984v3.984h9.984zM12 18.984q1.219 0 2.109-0.891t0.891-2.109-0.891-2.109-2.109-0.891-2.109 0.891-0.891 2.109 0.891 2.109 2.109 0.891zM17.016 3l3.984 3.984v12q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.844 0-1.43-0.586t-0.586-1.43v-13.969q0-0.844 0.586-1.43t1.43-0.586h12z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View 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>save_alt</title>
<path d="M12.984 12.656l2.625-2.578 1.406 1.406-5.016 5.016-5.016-5.016 1.406-1.406 2.625 2.578v-9.656h1.969v9.656zM18.984 12h2.016v6.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.984h2.016v6.984h13.969v-6.984z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,95 @@
<!-- 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-select
:size="size"
v-model="selected"
:placeholder="placeholder"
@change="changeSelected"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</template>
<script lang="ts" setup>
import { defineProps, ref, defineEmits } from "vue";
import type { PropType } from "vue";
import { ElSelect, ElOption } from "element-plus";
interface Option {
label: string;
value: string;
}
const emit = defineEmits(["change"]);
const props = defineProps({
options: {
type: Array as PropType<Option[]>,
default: () => [],
},
value: { type: String, default: "" },
size: { type: String, default: "small" },
placeholder: { type: String, default: "Select a option" },
});
const selected = ref<string>(props.value);
function changeSelected() {
const optionSele = props.options.filter(
(d: Option) => d.value === selected.value
)[0];
emit("change", optionSele);
}
</script>
<style lang="scss" scope>
.icon {
width: 16px;
height: 16px;
vertical-align: middle;
fill: currentColor;
&.sm {
width: 14px;
height: 14px;
}
&.middle {
width: 18px;
height: 18px;
}
&.lg {
width: 24px;
height: 24px;
}
&.loading {
animation: loading 1.5s linear infinite;
}
&.logo {
height: 30px;
width: 110px;
}
&.xl {
height: 30px;
width: 30px;
}
}
</style>

View File

@ -16,13 +16,21 @@
*/
import Icon from "./Icon.vue";
import TimePicker from "./TimePicker.vue";
import Selector from "./Selector.vue";
import type { App } from "vue";
import VueGridLayout from "vue-grid-layout";
const components: { [key: string]: any } = { Icon, TimePicker };
const components: { [key: string]: any } = {
Icon,
TimePicker,
VueGridLayout,
Selector,
};
const componentsName: string[] = Object.keys(components);
export default {
install: (vue: App): void => {
vue.use(components["VueGridLayout"]);
componentsName.forEach((i) => {
vue.component(i, components[i]);
});

View File

@ -24,6 +24,7 @@ limitations under the License. -->
<script lang="ts" setup></script>
<style lang="scss" scoped>
.app-main {
height: calc(100% - 128px);
height: calc(100% - 40px);
background: #f7f9fa;
}
</style>

View File

@ -17,6 +17,7 @@
const msg = {
generalService: "General Service",
services: "Services",
service: "Service",
traces: "Traces",
metrics: "Metrics",
serviceMesh: "Service Mesh",
@ -43,8 +44,14 @@ const msg = {
eventList: "Event List",
databasePanel: "Database Panel",
meshServicePanel: "Service Panel",
newDashboard: "New a dashboard",
newDashboard: "Create a new dashboard",
dashboardEdit: "Edit the dashboard",
edit: "Edit",
delete: "Delete",
layer: "Layer",
endpoint: "Endpoint",
instance: "Instance",
create: "Create",
hourTip: "Select Hour",
minuteTip: "Select Minute",
secondTip: "Select Second",
@ -71,9 +78,6 @@ const msg = {
reload: "Reload",
usermode: "User Mode",
editmode: "Edit Mode",
currentService: "Current Service",
currentEndpoint: "Current Endpoint",
currentInstance: "Current Instance",
currentVersion: "Current Version",
currentPage: "Current Page",
version: "Version",
@ -109,8 +113,6 @@ const msg = {
all: "All",
success: "Success",
error: "Error",
service: "Service",
instance: "Instance",
endpoints: "Endpoints",
cache: "Cache",
global: "Global",
@ -190,7 +192,6 @@ const msg = {
noneParentService: "No Parent Service",
serviceGroup: "Service Group",
endpointFilter: "Endpoint Filter",
editConfig: "Edit Config",
databaseView: "Database",
browserView: "Browser",
metricsView: "NOC - Network Operation Center",
@ -257,6 +258,7 @@ const msg = {
scope: "Scope",
destService: "Destination Service",
destServiceInstance: "Destination Service Instance",
destEndpoint: "Destination Endpoint",
eventSource: "Event Source",
modalTitle: "Inspection",
selectRedirectPage: "Do you want to inspect Traces or Logs of %s service?",

View File

@ -45,6 +45,11 @@ const msg = {
meshServicePanel: "服务面板",
newDashboard: "新增仪表盘",
dashboardEdit: "编辑仪表盘",
edit: "编辑",
delete: "删除",
layer: "层",
endpoint: "端点",
create: "新建",
hourTip: "选择小时",
minuteTip: "选择分钟",
secondTip: "选择秒数",
@ -70,9 +75,6 @@ const msg = {
reload: "刷新",
usermode: "用户模式",
editmode: "编辑模式",
currentService: "当前服务",
currentEndpoint: "当前端点",
currentInstance: "当前实例",
currentVersion: "当前版本",
currentPage: "当前页面",
version: "版本",
@ -190,7 +192,6 @@ const msg = {
noneParentService: "不设置父服务",
serviceGroup: "服务组",
endpointFilter: "端点过滤器",
editConfig: "编辑",
databaseView: "数据库视图",
browserView: "浏览器视图",
metricsView: "大屏视图",
@ -255,6 +256,7 @@ const msg = {
scope: "范围",
destService: "终点服务",
destServiceInstance: "终点实例",
destEndpoint: "终点端点",
eventSource: "事件资源",
modalTitle: "查看",
selectRedirectPage: "查看 %s 服务的追踪或日志?",

View File

@ -48,29 +48,9 @@ export const routesDashboard: Array<RouteRecordRaw> = [
},
},
{
path: "/dashboard/edit/service/:serviceId",
path: "/dashboard/edit/:layerId/:entityId/:dashboardId",
component: () => import("@/views/dashboard/Edit.vue"),
name: "serviceEdit",
meta: {
title: "dashboardEdit",
exact: false,
notShow: true,
},
},
{
path: "/dashboard/edit/endpoint/:serviceId/:endpointId",
component: () => import("@/views/dashboard/Edit.vue"),
name: "endpointEdit",
meta: {
title: "dashboardEdit",
exact: false,
notShow: true,
},
},
{
path: "/dashboard/edit/instance/:serviceId/:instanceId",
component: () => import("@/views/dashboard/Edit.vue"),
name: "instanceEdit",
name: "Edit",
meta: {
title: "dashboardEdit",
exact: false,

View File

@ -27,7 +27,7 @@ interface AppState {
utcHour: number;
utcMin: number;
eventStack: (() => unknown)[];
timer: ReturnType<typeof setInterval> | null;
timer: Nullable<any>;
}
export const appStore = defineStore({

View File

@ -0,0 +1,61 @@
/**
* 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 { defineStore } from "pinia";
import { store } from "@/store";
import { LayoutConfig } from "@/types/dashboard";
interface DashboardState {
showConfig: boolean;
layout: LayoutConfig[];
}
export const dashboardStore = defineStore({
id: "dashboard",
state: (): DashboardState => ({
layout: [],
showConfig: false,
}),
actions: {
setLayout(data: LayoutConfig[]) {
this.layout = data;
},
addWidget() {
const newWidget: LayoutConfig = {
x: 0,
y: 0,
w: 24,
h: 12,
i: String(this.layout.length),
};
this.layout = this.layout.map((d: LayoutConfig) => {
d.y = d.y + newWidget.h;
return d;
});
this.layout.push(newWidget);
},
removeWidget(item: LayoutConfig) {
this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i);
},
setConfigPanel(show: boolean) {
this.showConfig = show;
},
},
});
export function useDashboardStore(): any {
return dashboardStore(store);
}

View File

@ -29,9 +29,8 @@ export const selectorStore = defineStore({
state: (): SelectorState => ({
services: [],
}),
getters: {},
actions: {
async fetchLayers() {
async fetchLayers(): Promise<AxiosResponse> {
const res: AxiosResponse = await graph.query("queryLayers").params({});
return res;

39
src/types/dashboard.ts Normal file
View File

@ -0,0 +1,39 @@
import { string } from "vue-types";
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* 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 interface LayoutConfig {
x: number;
y: number;
w: number;
h: number;
i: string;
widget?: WidgetConfig;
graph?: GraphConfig;
}
export interface WidgetConfig {
title: string;
Metrics: string[];
unit: string;
tips: string;
sortOrder: string;
}
export interface GraphConfig {
type: string;
}

31
src/types/vue-grid-layout.d.ts vendored Normal file
View File

@ -0,0 +1,31 @@
/**
* 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 "vue-grid-layout" {
import Vue from "vue";
export class GridLayout extends Vue {}
export class GridItem extends Vue {}
export interface GridItemData {
x: number;
y: number;
w: number;
h: number;
i: string;
}
}

27
src/utils/uuid.ts Normal file
View File

@ -0,0 +1,27 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default function uuid(): string {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
/* tslint:disable */
const r = (Math.random() * 16) | 0;
/* tslint:disable */
const v = c === "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}

View File

@ -12,4 +12,117 @@ 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>dashboard edit</template>
<template>
<div class="dashboard-tool">
<el-tooltip class="item" effect="dark" content="Add Widget" placement="top">
<span class="icon-btn" @click="dashboardStore.addWidget">
<Icon size="sm" iconName="playlist_add" />
</span>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="Settings" placement="top">
<span class="icon-btn" @click="dashboardStore.setConfigPanel(true)">
<Icon size="sm" iconName="settings" />
</span>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="Import" placement="top">
<span class="icon-btn">
<Icon size="sm" iconName="folder_open" />
</span>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="Export" placement="top">
<span class="icon-btn">
<Icon size="sm" iconName="save_alt" />
</span>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="Apply" placement="top">
<span class="icon-btn">
<Icon size="sm" iconName="save" />
</span>
</el-tooltip>
</div>
<div class="ds-main">
<GridLayout />
<el-dialog
v-model="dashboardStore.showConfig"
title="Configurations"
width="95%"
@closed="dashboardStore.setConfigPanel(false)"
>
<div class="configuration">xxxx</div>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import GridLayout from "./panel/Layout.vue";
import { LayoutConfig } from "@/types/dashboard";
import { useDashboardStore } from "@/store/modules/dashboard";
import { ElDialog, ElTooltip } from "element-plus";
const dashboardStore = useDashboardStore();
// fetch layout data from serve side
const layout: LayoutConfig[] = [
{ x: 0, y: 0, w: 4, h: 12, i: "0" },
{ x: 4, y: 0, w: 4, h: 12, i: "1" },
{ x: 8, y: 0, w: 4, h: 15, i: "2" },
{ x: 12, y: 0, w: 4, h: 9, i: "3" },
{ x: 16, y: 0, w: 4, h: 9, i: "4" },
{ x: 20, y: 0, w: 4, h: 9, i: "5" },
{ x: 0, y: 12, w: 4, h: 15, i: "7" },
{ x: 4, y: 12, w: 4, h: 15, i: "8" },
{ x: 8, y: 15, w: 4, h: 12, i: "9" },
{ x: 12, y: 9, w: 4, h: 12, i: "10" },
{ x: 16, y: 9, w: 4, h: 12, i: "11" },
{ x: 20, y: 9, w: 4, h: 15, i: "12" },
{ x: 0, y: 27, w: 4, h: 12, i: "14" },
{ x: 4, y: 27, w: 4, h: 12, i: "15" },
{ x: 8, y: 27, w: 4, h: 15, i: "16" },
];
dashboardStore.setLayout(layout);
</script>
<style lang="scss" scoped>
.dashboard-tool {
text-align: right;
padding: 5px 10px;
background: rgb(240, 242, 245);
border-bottom: 1px solid #dfe4e8;
}
.ds-main {
height: calc(100% - 40px);
}
.layout {
height: 100%;
flex-grow: 2;
overflow: hidden;
}
.grids {
height: 100%;
overflow-y: auto;
}
.ds-config {
width: 340px;
background-color: #fff;
box-shadow: 2px 0 2px 0 #ccc;
text-align: center;
border-left: 1px solid #eee;
}
.icon-btn {
display: inline-block;
padding: 0 5px;
text-align: center;
border: 1px solid #ccc;
border-radius: 3px;
margin-left: 8px;
cursor: pointer;
background-color: #eee;
color: #666;
}
.configuration {
height: 600px;
}
</style>

View File

@ -40,17 +40,17 @@ limitations under the License. -->
<el-table-column label="Operations">
<template #default="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">
View
{{ t("view") }}
</el-button>
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">
Edit
{{ t("edit") }}
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>
Delete
{{ t("delete") }}
</el-button>
</template>
</el-table-column>

View File

@ -14,195 +14,97 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="new-dashboard">
<h4>Create a new dashboard</h4>
<div class="title">{{ t("newDashboard") }}</div>
<div class="item">
<div class="label">Name</div>
<div class="label">{{ t("name") }}</div>
<el-input
size="small"
v-model="state.name"
v-model="states.name"
placeholder="Please input name"
/>
</div>
<div class="item">
<div class="label">Layer</div>
<el-select
<div class="label">{{ t("layer") }}</div>
<Selector
:value="states.layer"
:options="Options"
size="small"
v-model="state.layer"
placeholder="Select a layer"
@change="changeLayer"
class="selectors"
>
<el-option
v-for="item in Options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
/>
</div>
<div class="item">
<div class="label">Entity</div>
<el-select
<div class="label">{{ t("entityType") }}</div>
<Selector
:value="states.entity"
:options="EntityType"
size="small"
v-model="state.entity"
placeholder="Select a entity"
@change="changeEntity"
class="selectors"
>
<el-option
v-for="item in EntityType"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="item" v-show="state.entity === EntityType[0].value">
<div class="label">Service</div>
<el-select
size="small"
v-model="state.service"
placeholder="Select a service"
class="selectors"
>
<el-option
v-for="item in Options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="item" v-show="state.entity === EntityType[2].value">
<div class="label">Service / Endpoint</div>
<el-cascader
v-model="state.serviceEndpoint"
:options="SelectOpt"
:props="props"
size="small"
@change="handleChange"
:style="{ width: '600px' }"
></el-cascader>
</div>
<div class="item" v-show="state.entity === EntityType[3].value">
<div class="label">Service / Instance</div>
<el-cascader
v-model="state.serviceInstance"
:options="SelectOpt"
:props="props"
size="small"
@change="handleChange"
:style="{ width: '600px' }"
></el-cascader>
</div>
<div class="item" v-show="state.entity === EntityType[4].value">
<div class="label">Destination Service</div>
<el-select
size="small"
v-model="state.destService"
placeholder="Select"
class="selectors"
>
<el-option
v-for="item in Options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="item" v-show="state.entity === EntityType[5].value">
<span class="label">Destination Service / Endpoint</span>
<el-cascader
v-model="state.destServiceEndpoint"
:options="SelectOpt"
:props="props"
@change="handleChange"
:style="{ width: '600px' }"
></el-cascader>
</div>
<div class="item" v-show="state.entity === EntityType[6].value">
<span class="label">Destination Service / Instance</span>
<el-cascader
v-model="state.destServiceInstance"
:options="SelectOpt"
:props="props"
@change="handleChange"
:style="{ width: '600px' }"
></el-cascader>
/>
</div>
<div class="btn">
<el-button class="create" size="small" type="primary" @click="onCreate">
Create
{{ t("create") }}
</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive } from "vue";
import { useI18n } from "vue-i18n";
import router from "@/router";
import {
ElSelect,
ElOption,
ElCascader,
ElInput,
ElButton,
} from "element-plus";
import { ElInput, ElButton } from "element-plus";
import { useSelectorStore } from "@/store/modules/selectors";
import { EntityType, SelectOpt, Options } from "./data";
import { EntityType, Options } from "./data";
import uuid from "@/utils/uuid";
const { t } = useI18n();
const selectorStore = useSelectorStore();
const props = {
expandTrigger: "hover",
};
const state = reactive({
const states = reactive({
name: "",
layer: "",
layer: Options[0].value,
entity: EntityType[0].value,
service: "",
serviceEndpoint: "",
serviceInstance: "",
destService: "",
destServiceEndpoint: "",
destServiceInstance: "",
});
const handleChange = (value: any) => {
console.log(value);
};
const onCreate = () => {
let path = `/dashboard/edit/${state.entity}/`;
switch (state.entity) {
case EntityType[0].value:
path += state.service;
break;
case EntityType[2].value:
path += `${state.service}/${state.serviceEndpoint}`;
break;
case EntityType[3].value:
path += `${state.service}/${state.serviceInstance}`;
break;
}
const id = uuid();
const path = `/dashboard/edit/${states.layer}/${states.entity}/${id}`;
router.push(path);
};
selectorStore.fetchServices("general");
function changeLayer(opt: { label: string; value: string }) {
states.layer = opt.value;
}
function changeEntity(opt: { label: string; value: string }) {
states.entity = opt.value;
}
</script>
<style lang="scss" scoped>
.title {
font-size: 18px;
font-weight: bold;
padding-top: 20px;
}
.new-dashboard {
margin: 0 auto;
}
.item {
margin-top: 20px;
}
.new-dashboard,
.selectors,
.el-cascader-menu {
.selectors {
width: 600px;
}
.create {
width: 600px;
}
.btn {
margin-top: 40px;
}

View File

@ -19,69 +19,37 @@ export const EntityType = [
{ value: "all", label: "All" },
{ value: "endpoint", label: "Service Endpoint" },
{ value: "serviceInstance", label: "Service Instance" },
{ value: "serviceRelation", label: "Service Relation" },
{ value: "serviceInstanceRelation", label: "Service Instance Relation" },
{ value: "endpointRelation", label: "Endpoint Relation" },
];
export const SelectOpt = [
{ value: "serviceRelationClient", label: "Service Relation(client)" },
{ value: "serviceRelationServer", label: "Service Relation(server)" },
{
value: "guide",
label: "Guide",
children: [
{
value: "disciplines",
label: "Disciplines",
children: [
{
value: "consistency",
label: "Consistency",
},
{
value: "feedback",
label: "Feedback",
},
{
value: "efficiency",
label: "Efficiency",
},
],
},
{
value: "navigation",
label: "Navigation",
children: [
{
value: "side nav",
label: "Side Navigation",
},
{
value: "top nav",
label: "Top Navigation",
},
],
},
],
value: "serviceInstanceRelationClient",
label: "Service Instance Relation(client)",
},
{
value: "serviceInstanceRelationServer",
label: "Service Instance Relation(server)",
},
{ value: "endpointRelation", label: "Endpoint Relation" },
];
export const Options = [
{
value: "Option1",
label: "Option1",
value: "layer1",
label: "layer1",
},
{
value: "Option2",
label: "Option2",
value: "layer2",
label: "layer2",
},
{
value: "Option3",
label: "Option3",
value: "layer3",
label: "layer3",
},
{
value: "Option4",
label: "Option4",
value: "layer4",
label: "layer4",
},
{
value: "Option5",
label: "Option5",
value: "layer5",
label: "layer5",
},
];

View File

@ -0,0 +1,58 @@
<!-- 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>
<grid-layout
v-model:layout="dashboardStore.layout"
:col-num="24"
:row-height="10"
:is-draggable="true"
:is-resizable="true"
@layout-updated="layoutUpdatedEvent"
>
<grid-item
v-for="item in dashboardStore.layout"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
>
<Widget :item="item" />
</grid-item>
</grid-layout>
</template>
<script lang="ts" setup>
import { useDashboardStore } from "@/store/modules/dashboard";
import { LayoutConfig } from "@/types/dashboard";
import Widget from "./Widget.vue";
const dashboardStore = useDashboardStore();
function layoutUpdatedEvent(newLayout: LayoutConfig) {
dashboardStore.setLayout(newLayout);
}
</script>
<style lang="scss" scoped>
.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;
}
</style>

View File

@ -0,0 +1,71 @@
<!-- 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>

View File

@ -34,6 +34,7 @@
"webpack-env",
"jest"
],
"typeRoots": ["./node_modules/@types/", "./types"],
"paths": {
"@/*": [
"src/*"

114
type.d.ts vendored Normal file
View File

@ -0,0 +1,114 @@
/**
* 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>;
}