mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-01-13 13:09:05 +01:00
Merge pull request #199 from ClusterCockpit/197_apply_chartjs_update
197 apply chartjs update
This commit is contained in:
commit
cf04f420e0
217
web/frontend/package-lock.json
generated
217
web/frontend/package-lock.json
generated
@ -11,7 +11,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/plugin-replace": "^5.0.2",
|
"@rollup/plugin-replace": "^5.0.2",
|
||||||
"@urql/svelte": "^4.0.1",
|
"@urql/svelte": "^4.0.1",
|
||||||
|
"chart.js": "^4.3.3",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
|
"svelte-chartjs": "^3.1.2",
|
||||||
"sveltestrap": "^5.10.0",
|
"sveltestrap": "^5.10.0",
|
||||||
"uplot": "^1.6.24",
|
"uplot": "^1.6.24",
|
||||||
"wonka": "^6.3.2"
|
"wonka": "^6.3.2"
|
||||||
@ -27,9 +29,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@0no-co/graphql.web": {
|
"node_modules/@0no-co/graphql.web": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.0.4.tgz",
|
||||||
"integrity": "sha512-6Yaxyv6rOwRkLIvFaL0NrLDgfNqC/Ng9QOPmTmlqW4mORXMEKmh5NYGkIvvt5Yw8fZesnMAqkj8cIqTj8f40cQ==",
|
"integrity": "sha512-W3ezhHGfO0MS1PtGloaTpg0PbaT8aZSmmaerL7idtU5F7oCI+uu25k+MsMS31BVFlp4aMkHSrNRxiD72IlK8TA==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||||
},
|
},
|
||||||
@ -40,9 +42,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.0.1",
|
"@jridgewell/set-array": "^1.0.1",
|
||||||
@ -54,9 +56,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
@ -72,9 +74,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/source-map": {
|
"node_modules/@jridgewell/source-map": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
|
||||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.0",
|
"@jridgewell/gen-mapping": "^0.3.0",
|
||||||
@ -82,24 +84,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.14",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.14",
|
"version": "0.3.19",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
||||||
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
|
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
|
||||||
|
},
|
||||||
"node_modules/@popperjs/core": {
|
"node_modules/@popperjs/core": {
|
||||||
"version": "2.11.0",
|
"version": "2.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==",
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
@ -131,9 +138,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-node-resolve": {
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
"version": "15.0.2",
|
"version": "15.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz",
|
||||||
"integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==",
|
"integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^5.0.1",
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
@ -176,14 +183,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-terser": {
|
"node_modules/@rollup/plugin-terser": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz",
|
||||||
"integrity": "sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==",
|
"integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialize-javascript": "^6.0.0",
|
"serialize-javascript": "^6.0.1",
|
||||||
"smob": "^0.0.6",
|
"smob": "^1.0.0",
|
||||||
"terser": "^5.15.1"
|
"terser": "^5.17.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
@ -197,15 +204,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-terser/node_modules/serialize-javascript": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"randombytes": "^2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/pluginutils": {
|
"node_modules/@rollup/pluginutils": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
|
||||||
@ -239,30 +237,30 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@urql/core": {
|
"node_modules/@urql/core": {
|
||||||
"version": "4.0.7",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@urql/core/-/core-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@urql/core/-/core-4.1.1.tgz",
|
||||||
"integrity": "sha512-UtZ9oSbSFODXzFydgLCXpAQz26KGT1d6uEfcylKphiRWNXSWZi8k7vhJXNceNm/Dn0MiZ+kaaJHKcnGY1jvHRQ==",
|
"integrity": "sha512-iIoAy6BY+BUZZ7KIpnMT7C9q+ULf5ZCVxGe3/i7WZSJBrQa2h1QkIMhL+8fAKmOn9gt83jSIv5drWWnhZ9izEA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0no-co/graphql.web": "^1.0.1",
|
"@0no-co/graphql.web": "^1.0.1",
|
||||||
"wonka": "^6.3.2"
|
"wonka": "^6.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@urql/svelte": {
|
"node_modules/@urql/svelte": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.0.4.tgz",
|
||||||
"integrity": "sha512-WbsVjuK7IUNlJlvXAgevjQunoso0T+AngFlb0zafDvay6HN47Zc3CSVbAlP8KjETjERUMJLuiqknmPFFm2GEFQ==",
|
"integrity": "sha512-HYz9dHdqEcs9d82WWczQ3XG+zuup3TS01H+txaij/QfQ+KHjrlrn0EkOHQQd1S+H8+nFjFU2x9+HE3+3fuwL1A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@urql/core": "^4.0.0",
|
"@urql/core": "^4.1.0",
|
||||||
"wonka": "^6.3.2"
|
"wonka": "^6.3.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": "^3.0.0"
|
"svelte": "^3.0.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.8.0",
|
"version": "8.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
||||||
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
|
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -304,6 +302,17 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.3.tgz",
|
||||||
|
"integrity": "sha512-aTk7pBw+x6sQYhon/NR3ikfUJuym/LdgpTlgZRe2PaEhjUMKBKyNaFCMVRAyTEWYFNO7qRu7iQVqOw/OqzxZxQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
@ -313,13 +322,13 @@
|
|||||||
"node_modules/commondir": {
|
"node_modules/commondir": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
||||||
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.2.2",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@ -376,9 +385,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/graphql": {
|
"node_modules/graphql": {
|
||||||
"version": "16.6.0",
|
"version": "16.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.7.1.tgz",
|
||||||
"integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==",
|
"integrity": "sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||||
}
|
}
|
||||||
@ -427,9 +436,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.12.0",
|
"version": "2.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
|
||||||
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
|
"integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
@ -441,7 +450,7 @@
|
|||||||
"node_modules/is-module": {
|
"node_modules/is-module": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||||
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/is-reference": {
|
"node_modules/is-reference": {
|
||||||
@ -512,12 +521,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.2",
|
"version": "1.22.4",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
|
||||||
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
|
"integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.11.0",
|
"is-core-module": "^2.13.0",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
},
|
},
|
||||||
@ -538,9 +547,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "3.21.0",
|
"version": "3.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz",
|
||||||
"integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==",
|
"integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@ -569,9 +578,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-svelte": {
|
"node_modules/rollup-plugin-svelte": {
|
||||||
"version": "7.1.4",
|
"version": "7.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.6.tgz",
|
||||||
"integrity": "sha512-Jm0FCydR7k8bBGe7wimXAes8x2zEK10Ew3f3lEZwYor/Zya3X0AZVeSAPRH7yiXB9hWQVzJu597EUeNwGDTdjQ==",
|
"integrity": "sha512-nVFRBpGWI2qUY1OcSiEEA/kjCY2+vAjO9BI8SzA7NRrh2GTunLd6w2EYmnMt/atgdg8GvcNjLsmZmbQs/u4SQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^4.1.0",
|
"@rollup/pluginutils": "^4.1.0",
|
||||||
@ -618,10 +627,19 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/serialize-javascript": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"randombytes": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/smob": {
|
"node_modules/smob": {
|
||||||
"version": "0.0.6",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/smob/-/smob-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.4.0.tgz",
|
||||||
"integrity": "sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==",
|
"integrity": "sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
@ -656,32 +674,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte": {
|
"node_modules/svelte": {
|
||||||
"version": "3.58.0",
|
"version": "3.59.2",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
|
||||||
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==",
|
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-chartjs": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-3+6gY2IJ9Ua8R9pk3iS1ypa7Z9OoXCJb9oPwIfTp7caJM+X+RrWnH2CTkGAq7FeSxc2nnmW08tYN88Q8Y+5M+w==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": "^3.5.0 || ^4.0.0",
|
||||||
|
"svelte": "^3.45.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sveltestrap": {
|
"node_modules/sveltestrap": {
|
||||||
"version": "5.10.0",
|
"version": "5.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.1.tgz",
|
||||||
"integrity": "sha512-k6Ob+6G2AMYvBidXHBKM9W28fJqFHbmosqCe/NC8pv6TV7K+v47Yw+zmnLWkjqCzzmjkSLkL48SrHZrlWc9mYQ==",
|
"integrity": "sha512-FIvPIEU1VolqMN1wi2XrC8aehWVbIJEST7zPfPbOUUfPimyx9giN4nA3We5wkXrBUaifXA8CSIwuHFvf3CmYQw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.9.2"
|
"@popperjs/core": "^2.11.8"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": "^3.29.0"
|
"svelte": "^3.53.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.17.1",
|
"version": "5.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
|
||||||
"integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==",
|
"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^8.8.2",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
},
|
},
|
||||||
@ -693,14 +720,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uplot": {
|
"node_modules/uplot": {
|
||||||
"version": "1.6.24",
|
"version": "1.6.25",
|
||||||
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.24.tgz",
|
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.25.tgz",
|
||||||
"integrity": "sha512-WpH2BsrFrqxkMu+4XBvc0eCDsRBhzoq9crttYeSI0bfxpzR5YoSVzZXOKFVWcVC7sp/aDXrdDPbDZGCtck2PVg=="
|
"integrity": "sha512-eWLAhEaGtIcVBiS67mC2UC0yV+G6eYLS2rU67N4F2JVWjt7uBMg4xKXUYGW0dEz9G+m7fNatjCVXHts4gjyuMQ=="
|
||||||
},
|
},
|
||||||
"node_modules/wonka": {
|
"node_modules/wonka": {
|
||||||
"version": "6.3.2",
|
"version": "6.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.4.tgz",
|
||||||
"integrity": "sha512-2xXbQ1LnwNS7egVm1HPhW2FyKrekolzhpM3mCwXdQr55gO+tAiY76rhb32OL9kKsW8taj++iP7C6hxlVzbnvrw=="
|
"integrity": "sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg=="
|
||||||
},
|
},
|
||||||
"node_modules/wrappy": {
|
"node_modules/wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/plugin-replace": "^5.0.2",
|
"@rollup/plugin-replace": "^5.0.2",
|
||||||
"@urql/svelte": "^4.0.1",
|
"@urql/svelte": "^4.0.1",
|
||||||
|
"chart.js": "^4.3.3",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
|
"svelte-chartjs": "^3.1.2",
|
||||||
"sveltestrap": "^5.10.0",
|
"sveltestrap": "^5.10.0",
|
||||||
"uplot": "^1.6.24",
|
"uplot": "^1.6.24",
|
||||||
"wonka": "^6.3.2"
|
"wonka": "^6.3.2"
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
import { init, convert2uplot } from './utils.js'
|
import { init, convert2uplot } from './utils.js'
|
||||||
import { getContext, onMount } from 'svelte'
|
import { getContext, onMount } from 'svelte'
|
||||||
import { queryStore, gql, getContextClient } from '@urql/svelte'
|
import { queryStore, gql, getContextClient } from '@urql/svelte'
|
||||||
import { Row, Col, Spinner, Card, Table } from 'sveltestrap'
|
import { Row, Col, Spinner, Card, Table, Icon } from 'sveltestrap'
|
||||||
import Filters from './filters/Filters.svelte'
|
import Filters from './filters/Filters.svelte'
|
||||||
import PlotSelection from './PlotSelection.svelte'
|
import PlotSelection from './PlotSelection.svelte'
|
||||||
import Histogramuplot from './plots/Histogramuplot.svelte'
|
import Histogramuplot from './plots/Histogramuplot.svelte'
|
||||||
import Histogram, { binsFromFootprint } from './plots/Histogram.svelte'
|
import Pie, { colors } from './plots/Pie.svelte'
|
||||||
|
import { binsFromFootprint } from './plots/Histogram.svelte'
|
||||||
import ScatterPlot from './plots/Scatter.svelte'
|
import ScatterPlot from './plots/Scatter.svelte'
|
||||||
import PlotTable from './PlotTable.svelte'
|
import PlotTable from './PlotTable.svelte'
|
||||||
import Roofline from './plots/Roofline.svelte'
|
import Roofline from './plots/Roofline.svelte'
|
||||||
@ -30,7 +31,7 @@
|
|||||||
let filterComponent; // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the
|
let filterComponent; // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the
|
||||||
let jobFilters = [];
|
let jobFilters = [];
|
||||||
let rooflineMaxY;
|
let rooflineMaxY;
|
||||||
let colWidth;
|
let colWidth1, colWidth2, colWidth3, colWidth4;
|
||||||
let numBins = 50;
|
let numBins = 50;
|
||||||
let maxY = -1;
|
let maxY = -1;
|
||||||
const ccconfig = getContext('cc-config')
|
const ccconfig = getContext('cc-config')
|
||||||
@ -135,82 +136,104 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{:else if $statsQuery.data}
|
{:else if $statsQuery.data}
|
||||||
<Row>
|
<Row cols={3} class="mb-4">
|
||||||
<div class="col-3" bind:clientWidth={colWidth}>
|
<Col>
|
||||||
<div style="height: 40%">
|
<Table>
|
||||||
<Table>
|
<tr>
|
||||||
<tr>
|
<th scope="col">Total Jobs</th>
|
||||||
<th scope="col">Total Jobs</th>
|
<td>{$statsQuery.data.stats[0].totalJobs}</td>
|
||||||
<td>{$statsQuery.data.stats[0].totalJobs}</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<th scope="col">Short Jobs</th>
|
||||||
<th scope="col">Short Jobs</th>
|
<td>{$statsQuery.data.stats[0].shortJobs}</td>
|
||||||
<td>{$statsQuery.data.stats[0].shortJobs}</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<th scope="col">Total Walltime</th>
|
||||||
<th scope="col">Total Walltime</th>
|
<td>{$statsQuery.data.stats[0].totalWalltime}</td>
|
||||||
<td>{$statsQuery.data.stats[0].totalWalltime}</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<th scope="col">Total Core Hours</th>
|
||||||
<th scope="col">Total Core Hours</th>
|
<td>{$statsQuery.data.stats[0].totalCoreHours}</td>
|
||||||
<td>{$statsQuery.data.stats[0].totalCoreHours}</td>
|
</tr>
|
||||||
</tr>
|
</Table>
|
||||||
</Table>
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<div bind:clientWidth={colWidth1}>
|
||||||
|
<h5>Top Users</h5>
|
||||||
|
{#key $statsQuery.data.topUsers}
|
||||||
|
<Pie
|
||||||
|
size={colWidth1}
|
||||||
|
sliceLabel='Hours'
|
||||||
|
quantities={$statsQuery.data.topUsers.sort((a, b) => b.count - a.count).map((tu) => tu.count)}
|
||||||
|
entities={$statsQuery.data.topUsers.sort((a, b) => b.count - a.count).map((tu) => tu.name)}
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
<div style="height: 60%;">
|
</Col>
|
||||||
{#key $statsQuery.data.topUsers}
|
<Col>
|
||||||
<h4>Top Users (by node hours)</h4>
|
<Table>
|
||||||
<Histogram
|
<tr class="mb-2"><th>Legend</th><th>User Name</th><th>Node Hours</th></tr>
|
||||||
width={colWidth - 25} height={300 * 0.5} small={true}
|
{#each $statsQuery.data.topUsers.sort((a, b) => b.count - a.count) as { name, count }, i}
|
||||||
data={$statsQuery.data.topUsers.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))}
|
<tr>
|
||||||
label={(x) => x < $statsQuery.data.topUsers.length ? $statsQuery.data.topUsers[Math.floor(x)].name : 'No Users'}
|
<td><Icon name="circle-fill" style="color: {colors[i]};"/></td>
|
||||||
ylabel="Node Hours [h]"/>
|
<th scope="col"><a href="/monitoring/user/{name}?cluster={cluster.name}">{name}</a></th>
|
||||||
|
<td>{count}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</Table>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row cols={3} class="mb-2">
|
||||||
|
<Col>
|
||||||
|
{#if $rooflineQuery.fetching}
|
||||||
|
<Spinner />
|
||||||
|
{:else if $rooflineQuery.error}
|
||||||
|
<Card body color="danger">{$rooflineQuery.error.message}</Card>
|
||||||
|
{:else if $rooflineQuery.data && cluster}
|
||||||
|
<div bind:clientWidth={colWidth2}>
|
||||||
|
{#key $rooflineQuery.data}
|
||||||
|
<Roofline
|
||||||
|
width={colWidth2} height={300}
|
||||||
|
tiles={$rooflineQuery.data.rooflineHeatmap}
|
||||||
|
cluster={cluster.subClusters.length == 1 ? cluster.subClusters[0] : null}
|
||||||
|
maxY={rooflineMaxY} />
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
<div class="col-3">
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<div bind:clientWidth={colWidth3}>
|
||||||
{#key $statsQuery.data.stats[0].histDuration}
|
{#key $statsQuery.data.stats[0].histDuration}
|
||||||
<Histogramuplot
|
<Histogramuplot
|
||||||
|
width={colWidth3} height={300}
|
||||||
data={convert2uplot($statsQuery.data.stats[0].histDuration)}
|
data={convert2uplot($statsQuery.data.stats[0].histDuration)}
|
||||||
width={colWidth - 25}
|
|
||||||
title="Duration Distribution"
|
title="Duration Distribution"
|
||||||
xlabel="Current Runtimes"
|
xlabel="Current Runtimes"
|
||||||
xunit="Hours"
|
xunit="Hours"
|
||||||
ylabel="Number of Jobs"
|
ylabel="Number of Jobs"
|
||||||
yunit="Jobs"/>
|
yunit="Jobs"/>
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<div bind:clientWidth={colWidth4}>
|
||||||
{#key $statsQuery.data.stats[0].histNumNodes}
|
{#key $statsQuery.data.stats[0].histNumNodes}
|
||||||
<Histogramuplot
|
<Histogramuplot
|
||||||
|
width={colWidth4} height={300}
|
||||||
data={convert2uplot($statsQuery.data.stats[0].histNumNodes)}
|
data={convert2uplot($statsQuery.data.stats[0].histNumNodes)}
|
||||||
width={colWidth - 25}
|
|
||||||
title="Number of Nodes Distribution"
|
title="Number of Nodes Distribution"
|
||||||
xlabel="Allocated Nodes"
|
xlabel="Allocated Nodes"
|
||||||
xunit="Nodes"
|
xunit="Nodes"
|
||||||
ylabel="Number of Jobs"
|
ylabel="Number of Jobs"
|
||||||
yunit="Jobs"/>
|
yunit="Jobs"/>
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
</Col>
|
||||||
{#if $rooflineQuery.fetching}
|
|
||||||
<Spinner />
|
|
||||||
{:else if $rooflineQuery.error}
|
|
||||||
<Card body color="danger">{$rooflineQuery.error.message}</Card>
|
|
||||||
{:else if $rooflineQuery.data && cluster}
|
|
||||||
{#key $rooflineQuery.data}
|
|
||||||
<Roofline
|
|
||||||
width={colWidth - 25}
|
|
||||||
tiles={$rooflineQuery.data.rooflineHeatmap}
|
|
||||||
cluster={cluster.subClusters.length == 1 ? cluster.subClusters[0] : null}
|
|
||||||
maxY={rooflineMaxY} />
|
|
||||||
{/key}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</Row>
|
</Row>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<br/>
|
<hr class="my-6"/>
|
||||||
|
|
||||||
{#if $footprintsQuery.error}
|
{#if $footprintsQuery.error}
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
@ -284,7 +307,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
h4 {
|
h5 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -20,12 +20,11 @@
|
|||||||
} from "sveltestrap";
|
} from "sveltestrap";
|
||||||
import PlotTable from "./PlotTable.svelte";
|
import PlotTable from "./PlotTable.svelte";
|
||||||
import Metric from "./Metric.svelte";
|
import Metric from "./Metric.svelte";
|
||||||
import PolarPlot from "./plots/Polar.svelte";
|
import Polar from "./plots/Polar.svelte";
|
||||||
import Roofline from "./plots/Roofline.svelte";
|
import Roofline from "./plots/Roofline.svelte";
|
||||||
import JobInfo from "./joblist/JobInfo.svelte";
|
import JobInfo from "./joblist/JobInfo.svelte";
|
||||||
import TagManagement from "./TagManagement.svelte";
|
import TagManagement from "./TagManagement.svelte";
|
||||||
import MetricSelection from "./MetricSelection.svelte";
|
import MetricSelection from "./MetricSelection.svelte";
|
||||||
import Zoom from "./Zoom.svelte";
|
|
||||||
import StatsTable from "./StatsTable.svelte";
|
import StatsTable from "./StatsTable.svelte";
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
@ -134,7 +133,6 @@
|
|||||||
jobTags,
|
jobTags,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
statsTable;
|
statsTable;
|
||||||
$: polarPlotSize = Math.min(fullWidth / 3 - 10, 300);
|
|
||||||
$: document.title = $initq.fetching
|
$: document.title = $initq.fetching
|
||||||
? "Loading..."
|
? "Loading..."
|
||||||
: $initq.error
|
: $initq.error
|
||||||
@ -246,9 +244,8 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
<Col>
|
<Col>
|
||||||
<PolarPlot
|
<Polar
|
||||||
width={polarPlotSize}
|
size={fullWidth / 4.1}
|
||||||
height={polarPlotSize}
|
|
||||||
metrics={ccconfig[
|
metrics={ccconfig[
|
||||||
`job_view_polarPlotMetrics:${$initq.data.job.cluster}`
|
`job_view_polarPlotMetrics:${$initq.data.job.cluster}`
|
||||||
] || ccconfig[`job_view_polarPlotMetrics`]}
|
] || ccconfig[`job_view_polarPlotMetrics`]}
|
||||||
@ -259,7 +256,7 @@
|
|||||||
<Col>
|
<Col>
|
||||||
<Roofline
|
<Roofline
|
||||||
width={fullWidth / 3 - 10}
|
width={fullWidth / 3 - 10}
|
||||||
height={polarPlotSize}
|
height={fullWidth / 5}
|
||||||
cluster={clusters
|
cluster={clusters
|
||||||
.find((c) => c.name == $initq.data.job.cluster)
|
.find((c) => c.name == $initq.data.job.cluster)
|
||||||
.subClusters.find(
|
.subClusters.find(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import Refresher from './joblist/Refresher.svelte'
|
import Refresher from './joblist/Refresher.svelte'
|
||||||
import Roofline, { transformPerNodeData } from './plots/Roofline.svelte'
|
import Roofline, { transformPerNodeData } from './plots/Roofline.svelte'
|
||||||
import Histogram from './plots/Histogram.svelte'
|
import Pie, { colors } from './plots/Pie.svelte'
|
||||||
import Histogramuplot from './plots/Histogramuplot.svelte'
|
import Histogramuplot from './plots/Histogramuplot.svelte'
|
||||||
import { Row, Col, Spinner, Card, CardHeader, CardTitle, CardBody, Table, Progress, Icon } from 'sveltestrap'
|
import { Row, Col, Spinner, Card, CardHeader, CardTitle, CardBody, Table, Progress, Icon } from 'sveltestrap'
|
||||||
import { init, convert2uplot } from './utils.js'
|
import { init, convert2uplot } from './utils.js'
|
||||||
@ -160,21 +160,24 @@
|
|||||||
<Row cols={4}>
|
<Row cols={4}>
|
||||||
<Col class="p-2">
|
<Col class="p-2">
|
||||||
<div bind:clientWidth={colWidth1}>
|
<div bind:clientWidth={colWidth1}>
|
||||||
<h4 class="mb-3 text-center">Top Users</h4>
|
<h4 class="text-center">Top Users</h4>
|
||||||
{#key $mainQuery.data}
|
{#key $mainQuery.data}
|
||||||
<Histogram
|
<Pie
|
||||||
width={colWidth1 - 25}
|
size={colWidth1}
|
||||||
data={$mainQuery.data.topUsers.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))}
|
sliceLabel='Jobs'
|
||||||
label={(x) => x < $mainQuery.data.topUsers.length ? $mainQuery.data.topUsers[Math.floor(x)].name : '0'}
|
quantities={$mainQuery.data.topUsers.sort((a, b) => b.count - a.count).map((tu) => tu.count)}
|
||||||
xlabel="User Name" ylabel="Number of Jobs" />
|
entities={$mainQuery.data.topUsers.sort((a, b) => b.count - a.count).map((tu) => tu.name)}
|
||||||
|
|
||||||
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col class="px-4 py-2">
|
<Col class="px-4 py-2">
|
||||||
<Table>
|
<Table>
|
||||||
<tr class="mb-2"><th>User Name</th><th>Number of Nodes</th></tr>
|
<tr class="mb-2"><th>Legend</th><th>User Name</th><th>Number of Nodes</th></tr>
|
||||||
{#each $mainQuery.data.topUsers.sort((a, b) => b.count - a.count) as { name, count }}
|
{#each $mainQuery.data.topUsers.sort((a, b) => b.count - a.count) as { name, count }, i}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><Icon name="circle-fill" style="color: {colors[i]};"/></td>
|
||||||
<th scope="col"><a href="/monitoring/user/{name}?cluster={cluster}&state=running">{name}</a></th>
|
<th scope="col"><a href="/monitoring/user/{name}?cluster={cluster}&state=running">{name}</a></th>
|
||||||
<td>{count}</td>
|
<td>{count}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -182,20 +185,22 @@
|
|||||||
</Table>
|
</Table>
|
||||||
</Col>
|
</Col>
|
||||||
<Col class="p-2">
|
<Col class="p-2">
|
||||||
<h4 class="mb-3 text-center">Top Projects</h4>
|
<h4 class="text-center">Top Projects</h4>
|
||||||
{#key $mainQuery.data}
|
{#key $mainQuery.data}
|
||||||
<Histogram
|
<Pie
|
||||||
width={colWidth1 - 25}
|
size={colWidth1}
|
||||||
data={$mainQuery.data.topProjects.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))}
|
sliceLabel='Jobs'
|
||||||
label={(x) => x < $mainQuery.data.topProjects.length ? $mainQuery.data.topProjects[Math.floor(x)].name : '0'}
|
quantities={$mainQuery.data.topProjects.sort((a, b) => b.count - a.count).map((tp) => tp.count)}
|
||||||
xlabel="Project Code" ylabel="Number of Jobs" />
|
entities={$mainQuery.data.topProjects.sort((a, b) => b.count - a.count).map((tp) => tp.name)}
|
||||||
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
</Col>
|
</Col>
|
||||||
<Col class="px-4 py-2">
|
<Col class="px-4 py-2">
|
||||||
<Table>
|
<Table>
|
||||||
<tr class="mb-2"><th>Project Code</th><th>Number of Nodes</th></tr>
|
<tr class="mb-2"><th>Legend</th><th>Project Code</th><th>Number of Nodes</th></tr>
|
||||||
{#each $mainQuery.data.topProjects.sort((a, b) => b.count - a.count) as { name, count }}
|
{#each $mainQuery.data.topProjects.sort((a, b) => b.count - a.count) as { name, count }, i}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><Icon name="circle-fill" style="color: {colors[i]};"/></td>
|
||||||
<th scope="col"><a href="/monitoring/jobs/?cluster={cluster}&state=running&project={name}&projectMatch=eq">{name}</a></th>
|
<th scope="col"><a href="/monitoring/jobs/?cluster={cluster}&state=running&project={name}&projectMatch=eq">{name}</a></th>
|
||||||
<td>{count}</td>
|
<td>{count}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -232,4 +237,4 @@
|
|||||||
{/key}
|
{/key}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{/if}
|
{/if}
|
@ -137,7 +137,7 @@
|
|||||||
{#key $stats.data.jobsStatistics[0].histDuration}
|
{#key $stats.data.jobsStatistics[0].histDuration}
|
||||||
<Histogramuplot
|
<Histogramuplot
|
||||||
data={convert2uplot($stats.data.jobsStatistics[0].histDuration)}
|
data={convert2uplot($stats.data.jobsStatistics[0].histDuration)}
|
||||||
width={w2 - 25} height={histogramHeight}
|
width={w1 - 25} height={histogramHeight}
|
||||||
title="Duration Distribution"
|
title="Duration Distribution"
|
||||||
xlabel="Current Runtimes"
|
xlabel="Current Runtimes"
|
||||||
xunit="Hours"
|
xunit="Hours"
|
||||||
|
79
web/frontend/src/plots/Pie.svelte
Normal file
79
web/frontend/src/plots/Pie.svelte
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<script context="module">
|
||||||
|
// http://tsitsul.in/blog/coloropt/ : 12 colors normal
|
||||||
|
export const colors = [
|
||||||
|
'rgb(235,172,35)',
|
||||||
|
'rgb(184,0,88)',
|
||||||
|
'rgb(0,140,249)',
|
||||||
|
'rgb(0,110,0)',
|
||||||
|
'rgb(0,187,173)',
|
||||||
|
'rgb(209,99,230)',
|
||||||
|
'rgb(178,69,2)',
|
||||||
|
'rgb(255,146,135)',
|
||||||
|
'rgb(89,84,214)',
|
||||||
|
'rgb(0,198,248)',
|
||||||
|
'rgb(135,133,0)',
|
||||||
|
'rgb(0,167,108)',
|
||||||
|
'rgb(189,189,189)'
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
import { Pie } from 'svelte-chartjs';
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
ArcElement,
|
||||||
|
CategoryScale
|
||||||
|
} from 'chart.js';
|
||||||
|
|
||||||
|
ChartJS.register(
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
ArcElement,
|
||||||
|
CategoryScale
|
||||||
|
);
|
||||||
|
|
||||||
|
export let size
|
||||||
|
export let sliceLabel
|
||||||
|
export let quantities
|
||||||
|
export let entities
|
||||||
|
export let displayLegend = false
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
labels: entities,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: sliceLabel,
|
||||||
|
data: quantities,
|
||||||
|
fill: 1,
|
||||||
|
backgroundColor: colors.slice(0, quantities.length),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
animation: false,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: displayLegend
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="chart-container" style="--container-width: {size}; --container-height: {size}">
|
||||||
|
<Pie {data} {options}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.chart-container {
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
height: var(--container-height);
|
||||||
|
width: var(--container-width);
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,22 +1,34 @@
|
|||||||
<div>
|
|
||||||
<canvas bind:this={canvasElement} width="{width}" height="{height}"></canvas>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount, getContext } from 'svelte'
|
import { getContext } from 'svelte'
|
||||||
|
import { Radar } from 'svelte-chartjs';
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
Filler,
|
||||||
|
PointElement,
|
||||||
|
RadialLinearScale,
|
||||||
|
LineElement
|
||||||
|
} from 'chart.js';
|
||||||
|
|
||||||
|
ChartJS.register(
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
Filler,
|
||||||
|
PointElement,
|
||||||
|
RadialLinearScale,
|
||||||
|
LineElement
|
||||||
|
);
|
||||||
|
|
||||||
|
export let size
|
||||||
export let metrics
|
export let metrics
|
||||||
export let width
|
|
||||||
export let height
|
|
||||||
export let cluster
|
export let cluster
|
||||||
export let jobMetrics
|
export let jobMetrics
|
||||||
|
|
||||||
const fontSize = 12
|
|
||||||
const fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"'
|
|
||||||
const metricConfig = getContext('metrics')
|
const metricConfig = getContext('metrics')
|
||||||
|
|
||||||
let ctx, canvasElement
|
|
||||||
|
|
||||||
const labels = metrics.filter(name => {
|
const labels = metrics.filter(name => {
|
||||||
if (!jobMetrics.find(m => m.name == name && m.scope == "node")) {
|
if (!jobMetrics.find(m => m.name == name && m.scope == "node")) {
|
||||||
console.warn(`PolarPlot: No metric data for '${name}'`)
|
console.warn(`PolarPlot: No metric data for '${name}'`)
|
||||||
@ -46,145 +58,49 @@
|
|||||||
return avg / metric.series.length
|
return avg / metric.series.length
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = [
|
const data = {
|
||||||
{
|
labels: labels,
|
||||||
name: 'Max',
|
datasets: [
|
||||||
values: getValuesForStat(getMax),
|
{
|
||||||
color: 'rgb(0, 102, 255)',
|
label: 'Max',
|
||||||
areaColor: 'rgba(0, 102, 255, 0.25)'
|
data: getValuesForStat(getMax),
|
||||||
},
|
fill: 1,
|
||||||
{
|
backgroundColor: 'rgba(0, 102, 255, 0.25)',
|
||||||
name: 'Avg',
|
borderColor: 'rgb(0, 102, 255)',
|
||||||
values: getValuesForStat(getAvg),
|
pointBackgroundColor: 'rgb(0, 102, 255)',
|
||||||
color: 'rgb(255, 153, 0)',
|
pointBorderColor: '#fff',
|
||||||
areaColor: 'rgba(255, 153, 0, 0.25)'
|
pointHoverBackgroundColor: '#fff',
|
||||||
}
|
pointHoverBorderColor: 'rgb(0, 102, 255)'
|
||||||
]
|
},
|
||||||
|
{
|
||||||
function render() {
|
label: 'Avg',
|
||||||
if (!width || Number.isNaN(width))
|
data: getValuesForStat(getAvg),
|
||||||
return
|
fill: true,
|
||||||
|
backgroundColor: 'rgba(255, 153, 0, 0.25)',
|
||||||
const centerX = width / 2
|
borderColor: 'rgb(255, 153, 0)',
|
||||||
const centerY = height / 2 - 15
|
pointBackgroundColor: 'rgb(255, 153, 0)',
|
||||||
const radius = (Math.min(width, height) / 2) - 50
|
pointBorderColor: '#fff',
|
||||||
|
pointHoverBackgroundColor: '#fff',
|
||||||
// Draw circles
|
pointHoverBorderColor: 'rgb(255, 153, 0)'
|
||||||
ctx.lineWidth = 1
|
|
||||||
ctx.strokeStyle = '#999999'
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(centerX, centerY, radius * 1.0, 0, Math.PI * 2, false)
|
|
||||||
ctx.stroke()
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(centerX, centerY, radius * 0.666, 0, Math.PI * 2, false)
|
|
||||||
ctx.stroke()
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(centerX, centerY, radius * 0.333, 0, Math.PI * 2, false)
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
// Axis
|
|
||||||
ctx.font = `${fontSize}px ${fontFamily}`
|
|
||||||
ctx.textAlign = 'center'
|
|
||||||
ctx.fillText('1/3',
|
|
||||||
Math.floor(centerX + radius * 0.333),
|
|
||||||
Math.floor(centerY + 15))
|
|
||||||
ctx.fillText('2/3',
|
|
||||||
Math.floor(centerX + radius * 0.666),
|
|
||||||
Math.floor(centerY + 15))
|
|
||||||
ctx.fillText('1.0',
|
|
||||||
Math.floor(centerX + radius * 1.0),
|
|
||||||
Math.floor(centerY + 15))
|
|
||||||
|
|
||||||
// Label text and straight lines from center
|
|
||||||
for (let i = 0; i < labels.length; i++) {
|
|
||||||
const angle = 2 * Math.PI * ((i + 1) / labels.length)
|
|
||||||
const dx = Math.cos(angle) * radius
|
|
||||||
const dy = Math.sin(angle) * radius
|
|
||||||
ctx.fillText(labels[i],
|
|
||||||
Math.floor(centerX + dx * 1.1),
|
|
||||||
Math.floor(centerY + dy * 1.1))
|
|
||||||
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(centerX, centerY)
|
|
||||||
ctx.lineTo(centerX + dx, centerY + dy)
|
|
||||||
ctx.stroke()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let dataset of data) {
|
|
||||||
console.assert(dataset.values.length === labels.length, 'this will look confusing')
|
|
||||||
ctx.fillStyle = dataset.color
|
|
||||||
ctx.strokeStyle = dataset.color
|
|
||||||
const points = []
|
|
||||||
for (let i = 0; i < dataset.values.length; i++) {
|
|
||||||
const value = dataset.values[i]
|
|
||||||
const angle = 2 * Math.PI * ((i + 1) / labels.length)
|
|
||||||
const x = centerX + Math.cos(angle) * radius * value
|
|
||||||
const y = centerY + Math.sin(angle) * radius * value
|
|
||||||
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(x, y, 3, 0, Math.PI * 2, false)
|
|
||||||
ctx.fill()
|
|
||||||
|
|
||||||
points.push({ x, y })
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
// "Fill" the shape this dataset has
|
|
||||||
ctx.fillStyle = dataset.areaColor
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(points[0].x, points[0].y)
|
|
||||||
for (let p of points)
|
|
||||||
ctx.lineTo(p.x, p.y)
|
|
||||||
ctx.lineTo(points[0].x, points[0].y)
|
|
||||||
ctx.stroke()
|
|
||||||
ctx.fill()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Legend at the bottom left corner
|
|
||||||
ctx.textAlign = 'left'
|
|
||||||
let paddingLeft = 0
|
|
||||||
for (let dataset of data) {
|
|
||||||
const text = `${dataset.name}: `
|
|
||||||
const textWidth = ctx.measureText(text).width
|
|
||||||
ctx.fillStyle = 'black'
|
|
||||||
ctx.fillText(text, paddingLeft, height - 20)
|
|
||||||
|
|
||||||
ctx.fillStyle = dataset.color
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(paddingLeft + textWidth + 5, height - 25, 5, 0, Math.PI * 2, false)
|
|
||||||
ctx.fill()
|
|
||||||
|
|
||||||
paddingLeft += textWidth + 15
|
|
||||||
}
|
|
||||||
ctx.fillStyle = 'black'
|
|
||||||
ctx.fillText(`Values relative to respective peak.`, 0, height - 7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mounted = false
|
// No custom defined options but keep for clarity
|
||||||
onMount(() => {
|
const options = {
|
||||||
canvasElement.width = width
|
maintainAspectRatio: false,
|
||||||
canvasElement.height = height
|
animation: false
|
||||||
ctx = canvasElement.getContext('2d')
|
|
||||||
render(ctx, data, width, height)
|
|
||||||
mounted = true
|
|
||||||
})
|
|
||||||
|
|
||||||
let timeoutId = null
|
|
||||||
function sizeChanged() {
|
|
||||||
if (!mounted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (timeoutId != null)
|
|
||||||
clearTimeout(timeoutId)
|
|
||||||
|
|
||||||
timeoutId = setTimeout(() => {
|
|
||||||
timeoutId = null
|
|
||||||
|
|
||||||
canvasElement.width = width
|
|
||||||
canvasElement.height = height
|
|
||||||
ctx = canvasElement.getContext('2d')
|
|
||||||
render(ctx, data, width, height)
|
|
||||||
}, 250)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$: sizeChanged(width, height)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<Radar {data} {options} width={size} height={size}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user