diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db99fb2..6c2fc9b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: - name: Install Go uses: actions/setup-go@v4 with: - go-version: 1.19.x + go-version: 1.20.x - name: Checkout code uses: actions/checkout@v3 - name: Build, Vet & Test diff --git a/go.mod b/go.mod index 4de12ec..2a92f5c 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module github.com/ClusterCockpit/cc-backend go 1.18 require ( - github.com/99designs/gqlgen v0.17.40 + github.com/99designs/gqlgen v0.17.45 github.com/ClusterCockpit/cc-units v0.4.0 github.com/Masterminds/squirrel v1.5.3 github.com/go-co-op/gocron v1.25.0 github.com/go-ldap/ldap/v3 v3.4.4 github.com/go-sql-driver/mysql v1.7.0 - github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang-migrate/migrate/v4 v4.15.2 github.com/google/gops v0.3.27 github.com/gorilla/handlers v1.5.1 @@ -23,8 +23,8 @@ require ( github.com/qustavo/sqlhooks/v2 v2.1.0 github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 github.com/swaggo/http-swagger v1.3.3 - github.com/swaggo/swag v1.16.2 - github.com/vektah/gqlparser/v2 v2.5.10 + github.com/swaggo/swag v1.16.3 + github.com/vektah/gqlparser/v2 v2.5.11 golang.org/x/crypto v0.21.0 golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea ) @@ -38,22 +38,22 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/containerd/containerd v1.6.18 // indirect github.com/coreos/go-oidc/v3 v3.9.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/deepmap/oapi-codegen v1.12.4 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-jose/go-jose/v3 v3.0.1 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.4.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect @@ -74,17 +74,17 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sosodev/duration v1.2.0 // indirect github.com/swaggo/files v1.0.0 // indirect - github.com/urfave/cli/v2 v2.25.7 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/urfave/cli/v2 v2.27.1 // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/mod v0.14.0 // indirect + golang.org/x/mod v0.16.0 // indirect golang.org/x/net v0.22.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.16.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/tools v0.19.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 2658092..d89d64b 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -github.com/99designs/gqlgen v0.17.40 h1:/l8JcEVQ93wqIfmH9VS1jsAkwm6eAF1NwQn3N+SDqBY= -github.com/99designs/gqlgen v0.17.40/go.mod h1:b62q1USk82GYIVjC60h02YguAZLqYZtvWml8KkhJps4= +github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= +github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -113,6 +113,7 @@ github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:m github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= @@ -130,6 +131,7 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY= github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= @@ -354,8 +356,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -476,28 +478,24 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -551,8 +549,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.15.2 h1:vU+M05vs6jWHKDdmE1Ecwj0BznygFc4QsdRe2E/L7kc= github.com/golang-migrate/migrate/v4 v4.15.2/go.mod h1:f2toGLkYqD3JH+Todi4aZ2ZdbeUNx4sIwiOK96rE9Lw= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -649,8 +647,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -707,8 +705,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE= -github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -1071,7 +1069,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -1138,8 +1136,6 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1147,18 +1143,15 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4= github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc= github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc= github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo= -github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= -github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -1173,10 +1166,10 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU= -github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= +github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= +github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= +github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= @@ -1196,8 +1189,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1292,8 +1285,6 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1346,8 +1337,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1417,8 +1408,6 @@ golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1456,7 +1445,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1691,8 +1680,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1869,8 +1858,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= diff --git a/internal/api/rest.go b/internal/api/rest.go index 807e7ae..dadabcd 100644 --- a/internal/api/rest.go +++ b/internal/api/rest.go @@ -114,12 +114,11 @@ type UpdateUserApiResponse struct { // StopJobApiRequest model type StopJobApiRequest struct { - // Stop Time of job as epoch + JobId *int64 `json:"jobId" example:"123000"` + Cluster *string `json:"cluster" example:"fritz"` + StartTime *int64 `json:"startTime" example:"1649723812"` + State schema.JobState `json:"jobState" validate:"required" example:"completed"` StopTime int64 `json:"stopTime" validate:"required" example:"1649763839"` - State schema.JobState `json:"jobState" validate:"required" example:"completed"` // Final job state - JobId *int64 `json:"jobId" example:"123000"` // Cluster Job ID of job - Cluster *string `json:"cluster" example:"fritz"` // Cluster of job - StartTime *int64 `json:"startTime" example:"1649723812"` // Start Time of job as epoch } // DeleteJobApiRequest model @@ -176,9 +175,9 @@ type GetCompleteJobApiResponse struct { } type JobMetricWithName struct { + Metric *schema.JobMetric `json:"metric"` Name string `json:"name"` Scope schema.MetricScope `json:"scope"` - Metric *schema.JobMetric `json:"metric"` } type ApiReturnedUser struct { @@ -482,6 +481,18 @@ func (api *RestApi) getCompleteJobById(rw http.ResponseWriter, r *http.Request) return } + job.Tags, err = api.JobRepository.GetTags(&job.ID) + if err != nil { + handleError(err, http.StatusInternalServerError, rw) + return + + } + if _, err = api.JobRepository.FetchMetadata(job); err != nil { + + handleError(err, http.StatusInternalServerError, rw) + return + } + var scopes []schema.MetricScope if job.NumNodes == 1 { @@ -492,7 +503,7 @@ func (api *RestApi) getCompleteJobById(rw http.ResponseWriter, r *http.Request) var data schema.JobData - if r.URL.Query().Has("all-metrics") { + if r.URL.Query().Get("all-metrics") == "true" { data, err = metricdata.LoadData(job, nil, scopes, r.Context()) if err != nil { log.Warn("Error while loading job data") @@ -564,6 +575,18 @@ func (api *RestApi) getJobById(rw http.ResponseWriter, r *http.Request) { return } + job.Tags, err = api.JobRepository.GetTags(&job.ID) + if err != nil { + handleError(err, http.StatusInternalServerError, rw) + return + + } + if _, err = api.JobRepository.FetchMetadata(job); err != nil { + + handleError(err, http.StatusInternalServerError, rw) + return + } + var metrics GetJobApiRequest if err = decode(r.Body, &metrics); err != nil { http.Error(rw, err.Error(), http.StatusBadRequest) @@ -1218,7 +1241,7 @@ func (api *RestApi) createUser(rw http.ResponseWriter, r *http.Request) { return } - rw.Write([]byte(fmt.Sprintf("User %v successfully created!\n", username))) + fmt.Fprintf(rw, "User %v successfully created!\n", username) } // deleteUser godoc diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go index 83bfee3..c1af752 100644 --- a/internal/auth/jwt.go +++ b/internal/auth/jwt.go @@ -17,7 +17,7 @@ import ( "github.com/ClusterCockpit/cc-backend/internal/repository" "github.com/ClusterCockpit/cc-backend/pkg/log" "github.com/ClusterCockpit/cc-backend/pkg/schema" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" ) type JWTAuthenticator struct { @@ -49,8 +49,8 @@ func (ja *JWTAuthenticator) Init() error { func (ja *JWTAuthenticator) AuthViaJWT( rw http.ResponseWriter, - r *http.Request) (*schema.User, error) { - + r *http.Request, +) (*schema.User, error) { rawtoken := r.Header.Get("X-Auth-Token") if rawtoken == "" { rawtoken = r.Header.Get("Authorization") @@ -73,9 +73,9 @@ func (ja *JWTAuthenticator) AuthViaJWT( log.Warn("Error while parsing JWT token") return nil, err } - if err := token.Claims.Valid(); err != nil { + if !token.Valid { log.Warn("jwt token claims are not valid") - return nil, err + return nil, errors.New("jwt token claims are not valid") } // Token is valid, extract payload @@ -88,7 +88,6 @@ func (ja *JWTAuthenticator) AuthViaJWT( if config.Keys.JwtConfig.ValidateUser { ur := repository.GetUserRepository() user, err := ur.GetUser(sub) - // Deny any logins for unknown usernames if err != nil { log.Warn("Could not find user from JWT in internal database.") @@ -117,7 +116,6 @@ func (ja *JWTAuthenticator) AuthViaJWT( // Generate a new JWT that can be used for authentication func (ja *JWTAuthenticator) ProvideJWT(user *schema.User) (string, error) { - if ja.privateKey == nil { return "", errors.New("environment variable 'JWT_PRIVATE_KEY' not set") } diff --git a/internal/auth/jwtCookieSession.go b/internal/auth/jwtCookieSession.go index 3748836..01f5746 100644 --- a/internal/auth/jwtCookieSession.go +++ b/internal/auth/jwtCookieSession.go @@ -17,7 +17,7 @@ import ( "github.com/ClusterCockpit/cc-backend/internal/repository" "github.com/ClusterCockpit/cc-backend/pkg/log" "github.com/ClusterCockpit/cc-backend/pkg/schema" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" ) type JWTCookieSessionAuthenticator struct { @@ -90,8 +90,8 @@ func (ja *JWTCookieSessionAuthenticator) CanLogin( user *schema.User, username string, rw http.ResponseWriter, - r *http.Request) (*schema.User, bool) { - + r *http.Request, +) (*schema.User, bool) { jc := config.Keys.JwtConfig cookieName := "" if jc.CookieName != "" { @@ -113,8 +113,8 @@ func (ja *JWTCookieSessionAuthenticator) CanLogin( func (ja *JWTCookieSessionAuthenticator) Login( user *schema.User, rw http.ResponseWriter, - r *http.Request) (*schema.User, error) { - + r *http.Request, +) (*schema.User, error) { jc := config.Keys.JwtConfig jwtCookie, err := r.Cookie(jc.CookieName) var rawtoken string @@ -144,10 +144,9 @@ func (ja *JWTCookieSessionAuthenticator) Login( return nil, err } - // Check token validity and extract paypload - if err := token.Claims.Valid(); err != nil { + if !token.Valid { log.Warn("jwt token claims are not valid") - return nil, err + return nil, errors.New("jwt token claims are not valid") } claims := token.Claims.(jwt.MapClaims) diff --git a/internal/auth/jwtSession.go b/internal/auth/jwtSession.go index 286bb82..541e31e 100644 --- a/internal/auth/jwtSession.go +++ b/internal/auth/jwtSession.go @@ -17,7 +17,7 @@ import ( "github.com/ClusterCockpit/cc-backend/internal/repository" "github.com/ClusterCockpit/cc-backend/pkg/log" "github.com/ClusterCockpit/cc-backend/pkg/schema" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" ) type JWTSessionAuthenticator struct { @@ -44,8 +44,8 @@ func (ja *JWTSessionAuthenticator) CanLogin( user *schema.User, username string, rw http.ResponseWriter, - r *http.Request) (*schema.User, bool) { - + r *http.Request, +) (*schema.User, bool) { return user, r.Header.Get("Authorization") != "" || r.URL.Query().Get("login-token") != "" } @@ -53,8 +53,8 @@ func (ja *JWTSessionAuthenticator) CanLogin( func (ja *JWTSessionAuthenticator) Login( user *schema.User, rw http.ResponseWriter, - r *http.Request) (*schema.User, error) { - + r *http.Request, +) (*schema.User, error) { rawtoken := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") if rawtoken == "" { rawtoken = r.URL.Query().Get("login-token") @@ -71,9 +71,9 @@ func (ja *JWTSessionAuthenticator) Login( return nil, err } - if err = token.Claims.Valid(); err != nil { + if !token.Valid { log.Warn("jwt token claims are not valid") - return nil, err + return nil, errors.New("jwt token claims are not valid") } claims := token.Claims.(jwt.MapClaims) diff --git a/internal/config/config.go b/internal/config/config.go index 253951c..76fd62a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -31,6 +31,7 @@ var Keys schema.ProgramConfig = schema.ProgramConfig{ "job_view_nodestats_selectedMetrics": []string{"flops_any", "mem_bw", "mem_used"}, "job_view_polarPlotMetrics": []string{"flops_any", "mem_bw", "mem_used"}, "job_view_selectedMetrics": []string{"flops_any", "mem_bw", "mem_used"}, + "job_view_showFootprint": true, "plot_general_colorBackground": true, "plot_general_colorscheme": []string{"#00bfff", "#0000ff", "#ff00ff", "#ff0000", "#ff8000", "#ffff00", "#80ff00"}, "plot_general_lineWidth": 3, diff --git a/internal/metricdata/cc-metric-store.go b/internal/metricdata/cc-metric-store.go index 4874975..9038af4 100644 --- a/internal/metricdata/cc-metric-store.go +++ b/internal/metricdata/cc-metric-store.go @@ -32,32 +32,32 @@ type CCMetricStoreConfig struct { } type CCMetricStore struct { + here2there map[string]string + there2here map[string]string + client http.Client jwt string url string queryEndpoint string - client http.Client - here2there map[string]string - there2here map[string]string } type ApiQueryRequest struct { Cluster string `json:"cluster"` + Queries []ApiQuery `json:"queries"` + ForAllNodes []string `json:"for-all-nodes"` From int64 `json:"from"` To int64 `json:"to"` WithStats bool `json:"with-stats"` WithData bool `json:"with-data"` - Queries []ApiQuery `json:"queries"` - ForAllNodes []string `json:"for-all-nodes"` } type ApiQuery struct { + Type *string `json:"type,omitempty"` + SubType *string `json:"subtype,omitempty"` Metric string `json:"metric"` Hostname string `json:"host"` - Aggregate bool `json:"aggreg"` - Type *string `json:"type,omitempty"` TypeIds []string `json:"type-ids,omitempty"` - SubType *string `json:"subtype,omitempty"` SubTypeIds []string `json:"subtype-ids,omitempty"` + Aggregate bool `json:"aggreg"` } type ApiQueryResponse struct { @@ -67,16 +67,15 @@ type ApiQueryResponse struct { type ApiMetricData struct { Error *string `json:"error"` + Data []schema.Float `json:"data"` From int64 `json:"from"` To int64 `json:"to"` - Data []schema.Float `json:"data"` Avg schema.Float `json:"avg"` Min schema.Float `json:"min"` Max schema.Float `json:"max"` } func (ccms *CCMetricStore) Init(rawConfig json.RawMessage) error { - var config CCMetricStoreConfig if err := json.Unmarshal(rawConfig, &config); err != nil { log.Warn("Error while unmarshaling raw json config") @@ -122,8 +121,8 @@ func (ccms *CCMetricStore) toLocalName(metric string) string { func (ccms *CCMetricStore) doRequest( ctx context.Context, - body *ApiQueryRequest) (*ApiQueryResponse, error) { - + body *ApiQueryRequest, +) (*ApiQueryResponse, error) { buf := &bytes.Buffer{} if err := json.NewEncoder(buf).Encode(body); err != nil { log.Warn("Error while encoding request body") @@ -162,8 +161,8 @@ func (ccms *CCMetricStore) LoadData( job *schema.Job, metrics []string, scopes []schema.MetricScope, - ctx context.Context) (schema.JobData, error) { - + ctx context.Context, +) (schema.JobData, error) { queries, assignedScope, err := ccms.buildQueries(job, metrics, scopes) if err != nil { log.Warn("Error while building queries") @@ -186,7 +185,7 @@ func (ccms *CCMetricStore) LoadData( } var errors []string - var jobData schema.JobData = make(schema.JobData) + jobData := make(schema.JobData) for i, row := range resBody.Results { query := req.Queries[i] metric := ccms.toLocalName(query.Metric) @@ -206,7 +205,7 @@ func (ccms *CCMetricStore) LoadData( jobData[metric][scope] = jobMetric } - for _, res := range row { + for ndx, res := range row { if res.Error != nil { /* Build list for "partial errors", if any */ errors = append(errors, fmt.Sprintf("failed to fetch '%s' from host '%s': %s", query.Metric, query.Hostname, *res.Error)) @@ -216,7 +215,7 @@ func (ccms *CCMetricStore) LoadData( id := (*string)(nil) if query.Type != nil { id = new(string) - *id = query.TypeIds[0] + *id = query.TypeIds[ndx] } if res.Avg.IsNaN() || res.Min.IsNaN() || res.Max.IsNaN() { @@ -267,8 +266,8 @@ var ( func (ccms *CCMetricStore) buildQueries( job *schema.Job, metrics []string, - scopes []schema.MetricScope) ([]ApiQuery, []schema.MetricScope, error) { - + scopes []schema.MetricScope, +) ([]ApiQuery, []schema.MetricScope, error) { queries := make([]ApiQuery, 0, len(metrics)*len(scopes)*len(job.Resources)) assignedScope := []schema.MetricScope{} @@ -313,6 +312,11 @@ func (ccms *CCMetricStore) buildQueries( // Accelerator -> Accelerator (Use "accelerator" scope if requested scope is lower than node) if nativeScope == schema.MetricScopeAccelerator && scope.LT(schema.MetricScopeNode) { + if scope != schema.MetricScopeAccelerator { + // Skip all other catched cases + continue + } + queries = append(queries, ApiQuery{ Metric: remoteName, Hostname: host.Hostname, @@ -504,8 +508,8 @@ func (ccms *CCMetricStore) buildQueries( func (ccms *CCMetricStore) LoadStats( job *schema.Job, metrics []string, - ctx context.Context) (map[string]map[string]schema.MetricStatistics, error) { - + ctx context.Context, +) (map[string]map[string]schema.MetricStatistics, error) { queries, _, err := ccms.buildQueries(job, metrics, []schema.MetricScope{schema.MetricScopeNode}) // #166 Add scope shere for analysis view accelerator normalization? if err != nil { log.Warn("Error while building query") @@ -566,8 +570,8 @@ func (ccms *CCMetricStore) LoadNodeData( metrics, nodes []string, scopes []schema.MetricScope, from, to time.Time, - ctx context.Context) (map[string]map[string][]*schema.JobMetric, error) { - + ctx context.Context, +) (map[string]map[string][]*schema.JobMetric, error) { req := ApiQueryRequest{ Cluster: cluster, From: from.Unix(), @@ -652,7 +656,6 @@ func (ccms *CCMetricStore) LoadNodeData( } func intToStringSlice(is []int) []string { - ss := make([]string, len(is)) for i, x := range is { ss[i] = strconv.Itoa(x) diff --git a/internal/repository/job.go b/internal/repository/job.go index 0de871a..329c0ba 100644 --- a/internal/repository/job.go +++ b/internal/repository/job.go @@ -30,13 +30,11 @@ var ( ) type JobRepository struct { - DB *sqlx.DB - driver string - - stmtCache *sq.StmtCache - cache *lrucache.Cache - + DB *sqlx.DB + stmtCache *sq.StmtCache + cache *lrucache.Cache archiveChannel chan *schema.Job + driver string archivePending sync.WaitGroup } diff --git a/internal/repository/migrations/mysql/07_fix-tag-id.down.sql b/internal/repository/migrations/mysql/07_fix-tag-id.down.sql index 4172f4e..9f9959a 100644 --- a/internal/repository/migrations/mysql/07_fix-tag-id.down.sql +++ b/internal/repository/migrations/mysql/07_fix-tag-id.down.sql @@ -1 +1,3 @@ +SET FOREIGN_KEY_CHECKS = 0; ALTER TABLE tag MODIFY id INTEGER; +SET FOREIGN_KEY_CHECKS = 1; diff --git a/internal/repository/migrations/mysql/07_fix-tag-id.up.sql b/internal/repository/migrations/mysql/07_fix-tag-id.up.sql index f8d805f..1abc4b3 100644 --- a/internal/repository/migrations/mysql/07_fix-tag-id.up.sql +++ b/internal/repository/migrations/mysql/07_fix-tag-id.up.sql @@ -1 +1,3 @@ +SET FOREIGN_KEY_CHECKS = 0; ALTER TABLE tag MODIFY id INTEGER AUTO_INCREMENT; +SET FOREIGN_KEY_CHECKS = 1; diff --git a/tools/gen-keypair/main.go b/tools/gen-keypair/main.go index f8c66fe..ff9c5c3 100644 --- a/tools/gen-keypair/main.go +++ b/tools/gen-keypair/main.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 NHR@FAU, University Erlangen-Nuremberg. +// Copyright (C) NHR@FAU, University Erlangen-Nuremberg. // All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -20,7 +20,8 @@ func main() { os.Exit(1) } - fmt.Fprintf(os.Stdout, "JWT_PUBLIC_KEY=%#v\nJWT_PRIVATE_KEY=%#v\n", + fmt.Fprintf(os.Stdout, "ED25519 PUBLIC_KEY=%#v\nED25519 PRIVATE_KEY=%#v\n", base64.StdEncoding.EncodeToString(pub), base64.StdEncoding.EncodeToString(priv)) + fmt.Println("This is NO JWT token. You can generate JWT tokens with cc-backend. Use this keypair for signing and validation of JWT tokens in ClusterCockpit.") } diff --git a/web/frontend/package-lock.json b/web/frontend/package-lock.json index 8874caf..7975773 100644 --- a/web/frontend/package-lock.json +++ b/web/frontend/package-lock.json @@ -9,27 +9,26 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@rollup/plugin-replace": "^5.0.2", - "@urql/svelte": "^4.0.1", - "chart.js": "^4.3.3", + "@rollup/plugin-replace": "^5.0.5", + "@sveltestrap/sveltestrap": "^6.2.6", + "@urql/svelte": "^4.1.0", + "chart.js": "^4.4.2", "date-fns": "^2.30.0", - "date-fns": "^2.30.0", - "graphql": "^16.6.0", - "mathjs": "^12.0.0", - "svelte-chartjs": "^3.1.2", - "sveltestrap": "^5.11.1", - "uplot": "^1.6.24", - "wonka": "^6.3.2" + "graphql": "^16.8.1", + "mathjs": "^12.4.0", + "svelte-chartjs": "^3.1.5", + "uplot": "^1.6.30", + "wonka": "^6.3.4" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-terser": "^0.4.1", - "@timohausmann/quadtree-js": "^1.2.5", - "rollup": "^3.21.0", - "rollup-plugin-css-only": "^4.3.0", - "rollup-plugin-svelte": "^7.1.4", - "svelte": "^3.58.0" + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@timohausmann/quadtree-js": "^1.2.6", + "rollup": "^4.12.1", + "rollup-plugin-css-only": "^4.5.2", + "rollup-plugin-svelte": "^7.1.6", + "svelte": "^4.2.12" } }, "node_modules/@0no-co/graphql.web": { @@ -45,10 +44,22 @@ } } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -57,33 +68,30 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -104,13 +112,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -131,9 +135,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz", - "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==", + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -141,13 +145,13 @@ "estree-walker": "^2.0.2", "glob": "^8.0.3", "is-reference": "1.2.1", - "magic-string": "^0.27.0" + "magic-string": "^0.30.3" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" + "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -156,9 +160,6 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", - "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", @@ -176,7 +177,6 @@ }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" - "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -185,23 +185,18 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", - "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", "dependencies": { "@rollup/pluginutils": "^5.0.1", "magic-string": "^0.30.3" - "magic-string": "^0.30.3" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -209,32 +204,7 @@ } } }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "version": "0.4.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", @@ -249,7 +219,6 @@ }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" - "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -271,7 +240,6 @@ }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -279,6 +247,186 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz", + "integrity": "sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.1.tgz", + "integrity": "sha512-wlzcWiH2Ir7rdMELxFE5vuM7D6TsOcJ2Yw0c3vaBR3VOsJFVTx9xvwnAvhgU5Ii8Gd6+I11qNHwndDscIm0HXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.1.tgz", + "integrity": "sha512-YRXa1+aZIFN5BaImK+84B3uNK8C6+ynKLPgvn29X9s0LTVCByp54TB7tdSMHDR7GTV39bz1lOmlLDuedgTwwHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.1.tgz", + "integrity": "sha512-opjWJ4MevxeA8FhlngQWPBOvVWYNPFkq6/25rGgG+KOy0r8clYwL1CFd+PGwRqqMFVQ4/Qd3sQu5t7ucP7C/Uw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.1.tgz", + "integrity": "sha512-uBkwaI+gBUlIe+EfbNnY5xNyXuhZbDSx2nzzW8tRMjUmpScd6lCQYKY2V9BATHtv5Ef2OBq6SChEP8h+/cxifQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.1.tgz", + "integrity": "sha512-0bK9aG1kIg0Su7OcFTlexkVeNZ5IzEsnz1ept87a0TUgZ6HplSgkJAnFpEVRW7GRcikT4GlPV0pbtVedOaXHQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.1.tgz", + "integrity": "sha512-qB6AFRXuP8bdkBI4D7UPUbE7OQf7u5OL+R94JE42Z2Qjmyj74FtDdLGeriRyBDhm4rQSvqAGCGC01b8Fu2LthQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.1.tgz", + "integrity": "sha512-sHig3LaGlpNgDj5o8uPEoGs98RII8HpNIqFtAI8/pYABO8i0nb1QzT0JDoXF/pxzqO+FkxvwkHZo9k0NJYDedg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.1.tgz", + "integrity": "sha512-nD3YcUv6jBJbBNFvSbp0IV66+ba/1teuBcu+fBBPZ33sidxitc6ErhON3JNavaH8HlswhWMC3s5rgZpM4MtPqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.1.tgz", + "integrity": "sha512-7/XVZqgBby2qp/cO0TQ8uJK+9xnSdJ9ct6gSDdEr4MfABrjTyrW6Bau7HQ73a2a5tPB7hno49A0y1jhWGDN9OQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.1.tgz", + "integrity": "sha512-CYc64bnICG42UPL7TrhIwsJW4QcKkIt9gGlj21gq3VV0LL6XNb1yAdHVp1pIi9gkts9gGcT3OfUYHjGP7ETAiw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.1.tgz", + "integrity": "sha512-LN+vnlZ9g0qlHGlS920GR4zFCqAwbv2lULrR29yGaWP9u7wF5L7GqWu9Ah6/kFZPXPUkpdZwd//TNR+9XC9hvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.1.tgz", + "integrity": "sha512-n+vkrSyphvmU0qkQ6QBNXCGr2mKjhP08mPRM/Xp5Ck2FV4NrHU+y6axzDeixUrCBHVUS51TZhjqrKBBsHLKb2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltestrap/sveltestrap": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-6.2.6.tgz", + "integrity": "sha512-iB50tbVzsFXp0M10pe3XywRkNxjKPIHXJzV44mb1FhajWNWwxme8MkBis9m2QNivM2hyw5zDHjgGuzwTOB76JQ==", + "dependencies": { + "@popperjs/core": "^2.11.8" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0 || ^5.0.0-next.0" + } + }, "node_modules/@timohausmann/quadtree-js": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@timohausmann/quadtree-js/-/quadtree-js-1.2.6.tgz", @@ -289,9 +437,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/resolve": { "version": "1.20.2", @@ -300,20 +445,20 @@ "dev": true }, "node_modules/@urql/core": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@urql/core/-/core-4.2.0.tgz", - "integrity": "sha512-GRkZ4kECR9UohWAjiSk2UYUetco6/PqSrvyC4AH6g16tyqEShA63M232cfbE1J9XJPaGNjia14Gi+oOqzp144w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-4.3.0.tgz", + "integrity": "sha512-wT+FeL8DG4x5o6RfHEnONNFVDM3616ouzATMYUClB6CB+iIu2mwfBKd7xSUxYOZmwtxna5/hDRQdMl3nbQZlnw==", "dependencies": { "@0no-co/graphql.web": "^1.0.1", "wonka": "^6.3.2" } }, "node_modules/@urql/svelte": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.0.4.tgz", - "integrity": "sha512-HYz9dHdqEcs9d82WWczQ3XG+zuup3TS01H+txaij/QfQ+KHjrlrn0EkOHQQd1S+H8+nFjFU2x9+HE3+3fuwL1A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@urql/svelte/-/svelte-4.1.0.tgz", + "integrity": "sha512-Ov3EclCjaXPPTjKNTcIDlAG3qY/jhLjl/J9yyz9FeLUQ9S2jEgsvlzNXibrY27f4ihD4gH36CNGuj1XOi5hEEQ==", "dependencies": { - "@urql/core": "^4.1.0", + "@urql/core": "^4.3.0", "wonka": "^6.3.2" }, "peerDependencies": { @@ -321,13 +466,9 @@ } }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "bin": { "acorn": "bin/acorn" }, @@ -335,6 +476,22 @@ "node": ">=0.4.0" } }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -369,14 +526,34 @@ } }, "node_modules/chart.js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", - "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", + "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", "dependencies": { "@kurkle/color": "^0.3.0" }, "engines": { - "pnpm": ">=7" + "pnpm": ">=8" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/code-red/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" } }, "node_modules/commander": { @@ -403,6 +580,18 @@ "url": "https://www.patreon.com/infusion" } }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -432,6 +621,14 @@ "node": ">=0.10.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-latex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", @@ -482,13 +679,6 @@ "funding": { "url": "https://github.com/sponsors/ljharb" } - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } }, "node_modules/glob": { "version": "8.1.0", @@ -510,9 +700,6 @@ } }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "version": "16.8.1", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", @@ -521,21 +708,15 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dev": true, "dependencies": { "function-bind": "^1.1.2" - "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" - "node": ">= 0.4" } }, "node_modules/inflight": { @@ -570,16 +751,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { "hasown": "^2.0.0" - "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -605,25 +782,28 @@ "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + }, "node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", - "dev": true, - "dev": true, + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { "node": ">=12" } }, "node_modules/mathjs": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.0.0.tgz", - "integrity": "sha512-Oz3swPplNPe7taoP6WrkKhQzhDE2SwvOgLzu8H3EN+hEadw2GjEJUm6Xl+hrioHoB8g2BYb3gfw1glSzhdBKYw==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.4.0.tgz", + "integrity": "sha512-4Moy0RNjwMSajEkGGxNUyMMC/CZAcl87WBopvNsJWB4E4EFebpTedr+0/rhqmnOSTH3Wu/3WfiWiw6mqiaHxVw==", "dependencies": { - "@babel/runtime": "^7.23.2", + "@babel/runtime": "^7.23.9", "complex.js": "^2.1.1", "decimal.js": "^10.4.3", "escape-latex": "^1.2.0", @@ -640,6 +820,11 @@ "node": ">= 18" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, "node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -667,6 +852,32 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/periscopic/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/periscopic/node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -688,19 +899,11 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" - }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", @@ -727,28 +930,38 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.1.tgz", + "integrity": "sha512-ggqQKvx/PsB0FaWXhIvVkSWh7a/PCLQAsMjBc+nA2M8Rv2/HG0X6zvixAB7KyZBRtifBUhy5k8voQX/mRnABPg==", "devOptional": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.1", + "@rollup/rollup-android-arm64": "4.12.1", + "@rollup/rollup-darwin-arm64": "4.12.1", + "@rollup/rollup-darwin-x64": "4.12.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.1", + "@rollup/rollup-linux-arm64-gnu": "4.12.1", + "@rollup/rollup-linux-arm64-musl": "4.12.1", + "@rollup/rollup-linux-riscv64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-musl": "4.12.1", + "@rollup/rollup-win32-arm64-msvc": "4.12.1", + "@rollup/rollup-win32-ia32-msvc": "4.12.1", + "@rollup/rollup-win32-x64-msvc": "4.12.1", "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-css-only": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz", - "integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==", "version": "4.5.2", "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.5.2.tgz", "integrity": "sha512-7rj9+jB17Pz8LNcPgtMUb16JcgD8lxQMK9HcGfAVhMK3na/WXes3oGIo5QsrQQVqtgAU6q6KnQNXJrYunaUIQQ==", @@ -761,7 +974,6 @@ }, "peerDependencies": { "rollup": "<5" - "rollup": "<5" } }, "node_modules/rollup-plugin-svelte": { @@ -820,18 +1032,15 @@ "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, "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==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/smob": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", - "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", "version": "1.4.1", "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", @@ -846,6 +1055,14 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -869,40 +1086,58 @@ } }, "node_modules/svelte": { - "version": "3.59.2", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz", - "integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz", + "integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, "engines": { - "node": ">= 8" + "node": ">=16" } }, "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==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.5.tgz", + "integrity": "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA==", "peerDependencies": { "chart.js": "^3.5.0 || ^4.0.0", - "svelte": "^3.45.0" + "svelte": "^4.0.0" } }, - "node_modules/sveltestrap": { - "version": "5.11.2", - "resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz", - "integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==", - "version": "5.11.2", - "resolved": "https://registry.npmjs.org/sveltestrap/-/sveltestrap-5.11.2.tgz", - "integrity": "sha512-fkLqIUh2QHBoom7v6kHI85grLeOqplmvtnTiA5Ck2gchzpVmwXWaWpf8qWhCFxfDuMhJBPlWbJvtSmwpDEowrg==", + "node_modules/svelte/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dependencies": { - "@popperjs/core": "^2.11.8" - }, - "peerDependencies": { - "svelte": "^3.53.1" + "@types/estree": "^1.0.0" + } + }, + "node_modules/svelte/node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" } }, "node_modules/terser": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.25.0.tgz", - "integrity": "sha512-we0I9SIsfvNUMP77zC9HG+MylwYYsGFSBG8qm+13oud2Yh+O104y614FRbyjpxys16jZwot72Fpi827YvGzuqg==", + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -931,12 +1166,9 @@ } }, "node_modules/uplot": { - "version": "1.6.27", - "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz", - "integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg==" - "version": "1.6.27", - "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.27.tgz", - "integrity": "sha512-78U4ss5YeU65kQkOC/QAKiyII+4uo+TYUJJKvuxRzeSpk/s5sjpY1TL0agkmhHBBShpvLtmbHIEiM7+C5lBULg==" + "version": "1.6.30", + "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.30.tgz", + "integrity": "sha512-48oVVRALM/128ttW19F2a2xobc2WfGdJ0VJFX00099CfqbCTuML7L2OrTKxNzeFP34eo1+yJbqFSoFAp2u28/Q==" }, "node_modules/wonka": { "version": "6.3.4", diff --git a/web/frontend/package.json b/web/frontend/package.json index cc84e1a..c70e57a 100644 --- a/web/frontend/package.json +++ b/web/frontend/package.json @@ -7,25 +7,25 @@ "dev": "rollup -c -w" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-terser": "^0.4.1", - "@timohausmann/quadtree-js": "^1.2.5", - "rollup": "^3.21.0", - "rollup-plugin-css-only": "^4.3.0", - "rollup-plugin-svelte": "^7.1.4", - "svelte": "^3.58.0" + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@timohausmann/quadtree-js": "^1.2.6", + "rollup": "^4.12.1", + "rollup-plugin-css-only": "^4.5.2", + "rollup-plugin-svelte": "^7.1.6", + "svelte": "^4.2.12" }, "dependencies": { - "@rollup/plugin-replace": "^5.0.2", - "@urql/svelte": "^4.0.1", - "chart.js": "^4.3.3", + "@rollup/plugin-replace": "^5.0.5", + "@sveltestrap/sveltestrap": "^6.2.6", + "@urql/svelte": "^4.1.0", + "chart.js": "^4.4.2", "date-fns": "^2.30.0", - "graphql": "^16.6.0", - "mathjs": "^12.0.0", - "svelte-chartjs": "^3.1.2", - "sveltestrap": "^5.11.1", - "uplot": "^1.6.24", - "wonka": "^6.3.2" + "graphql": "^16.8.1", + "mathjs": "^12.4.0", + "svelte-chartjs": "^3.1.5", + "uplot": "^1.6.30", + "wonka": "^6.3.4" } } diff --git a/web/frontend/src/Analysis.root.svelte b/web/frontend/src/Analysis.root.svelte index 163d511..0592f28 100644 --- a/web/frontend/src/Analysis.root.svelte +++ b/web/frontend/src/Analysis.root.svelte @@ -1,440 +1,610 @@ - {#if $initq.fetching || $statsQuery.fetching || $footprintsQuery.fetching} - - - + {#if $initq.fetching || $statsQuery.fetching || $footprintsQuery.fetching} + + + + {/if} + + {#if $initq.error} + {$initq.error.message} + {:else if cluster} + mc.name)} + bind:metricsInHistograms + bind:metricsInScatterplots + /> {/if} - - {#if $initq.error} - {$initq.error.message} - {:else if cluster} - mc.name)} - bind:metricsInHistograms={metricsInHistograms} - bind:metricsInScatterplots={metricsInScatterplots} /> - {/if} - - - { - jobFilters = detail.filters; - }} /> - + + + { + jobFilters = detail.filters; + }} + /> + -
+
{#if $statsQuery.error} - - - {$statsQuery.error.message} - - + + + {$statsQuery.error.message} + + {:else if $statsQuery.data} - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total Jobs{$statsQuery.data.stats[0].totalJobs}
Short Jobs{$statsQuery.data.stats[0].shortJobs}
Total Walltime{$statsQuery.data.stats[0].totalWalltime}
Total Node Hours{$statsQuery.data.stats[0].totalNodeHours}
Total Core Hours{$statsQuery.data.stats[0].totalCoreHours}
Total Accelerator Hours{$statsQuery.data.stats[0].totalAccHours}
- - -
-
Top - + {#each groupOptions as option} + + {/each} + +
+ {#key $topQuery.data} + {#if $topQuery.fetching} + + {:else if $topQuery.error} + {$topQuery.error.message} + {:else} + t[sortSelection.key], + )} + entities={$topQuery.data.topList.map((t) => t.id)} + /> + {/if} + {/key} +
+ + + {#key $topQuery.data} + {#if $topQuery.fetching} + + {:else if $topQuery.error} + {$topQuery.error.message} + {:else} + + + + + - {#key $topQuery.data} - {#if $topQuery.fetching} - - {:else if $topQuery.error} - {$topQuery.error.message} + + + {#each $topQuery.data.topList as te, i} + + + {#if groupSelection.key == "user"} + {:else} -
Legend{groupSelection.label} + - - {#key $topQuery.data} - {#if $topQuery.fetching} - - {:else if $topQuery.error} - {$topQuery.error.message} - {:else} - t[sortSelection.key])} - entities={$topQuery.data.topList.map((t) => t.id)} - /> - {/if} - {/key} - - -
{te.id}
- - - - - - {#each $topQuery.data.topList as te, i} - - - {#if groupSelection.key == 'user'} - - {:else} - - {/if} - - - {/each} -
Legend{groupSelection.label} - -
{te.id}{te.id}{te[sortSelection.key]}
+ {te.id} {/if} - {/key} - -
- - - {#if $rooflineQuery.fetching} - - {:else if $rooflineQuery.error} - {$rooflineQuery.error.message} - {:else if $rooflineQuery.data && cluster} -
- {#key $rooflineQuery.data} - - {/key} -
- {/if} - - -
- {#key $statsQuery.data.stats[0].histDuration} - - {/key} -
- - -
- {#key $statsQuery.data.stats[0].histNumCores} - - {/key} -
- -
+ {te[sortSelection.key]} + + {/each} + + {/if} + {/key} + + + + + {#if $rooflineQuery.fetching} + + {:else if $rooflineQuery.error} + {$rooflineQuery.error.message} + {:else if $rooflineQuery.data && cluster} +
+ {#key $rooflineQuery.data} + + {/key} +
+ {/if} + + +
+ {#key $statsQuery.data.stats[0].histDuration} + + {/key} +
+ + +
+ {#key $statsQuery.data.stats[0].histNumCores} + + {/key} +
+ +
{/if} -
+
{#if $footprintsQuery.error} - - - {$footprintsQuery.error.message} - - + + + {$footprintsQuery.error.message} + + {:else if $footprintsQuery.data && $initq.data} - - - - These histograms show the distribution of the averages of all jobs matching the filters. Each job/average is weighted by its node hours by default - (Accelerator hours for native accelerator scope metrics, coreHours for native core scope metrics). - Note that some metrics could be disabled for specific subclusters as per metricConfig and thus could affect shown average values. - -
- -
- - - ({ metric, ...binsFromFootprint( - $footprintsQuery.data.footprints.timeWeights, - metricConfig(cluster.name, metric)?.scope, - $footprintsQuery.data.footprints.metrics.find(f => f.metric == metric).data, numBins) }))} - itemsPerRow={ccconfig.plot_view_plotsPerRow}> - - - - - -
- - - - Each circle represents one job. The size of a circle is proportional to its node hours. Darker circles mean multiple jobs have the same averages for the respective metrics. - Note that some metrics could be disabled for specific subclusters as per metricConfig and thus could affect shown average values. - -
- -
- - - ({ - m1, f1: $footprintsQuery.data.footprints.metrics.find(f => f.metric == m1).data, - m2, f2: $footprintsQuery.data.footprints.metrics.find(f => f.metric == m2).data }))} - itemsPerRow={ccconfig.plot_view_plotsPerRow}> - - - - - + + + + These histograms show the distribution of the averages of all jobs + matching the filters. Each job/average is weighted by its node hours by + default (Accelerator hours for native accelerator scope metrics, + coreHours for native core scope metrics). Note that some metrics could + be disabled for specific subclusters as per metricConfig and thus could + affect shown average values. + +
+ +
+ + + ({ + metric, + ...binsFromFootprint( + $footprintsQuery.data.footprints.timeWeights, + metricConfig(cluster.name, metric)?.scope, + $footprintsQuery.data.footprints.metrics.find( + (f) => f.metric == metric, + ).data, + numBins, + ), + }))} + itemsPerRow={ccconfig.plot_view_plotsPerRow} + > + + + + +
+ + + + Each circle represents one job. The size of a circle is proportional to + its node hours. Darker circles mean multiple jobs have the same averages + for the respective metrics. Note that some metrics could be disabled for + specific subclusters as per metricConfig and thus could affect shown + average values. + +
+ +
+ + + ({ + m1, + f1: $footprintsQuery.data.footprints.metrics.find( + (f) => f.metric == m1, + ).data, + m2, + f2: $footprintsQuery.data.footprints.metrics.find( + (f) => f.metric == m2, + ).data, + }))} + itemsPerRow={ccconfig.plot_view_plotsPerRow} + > + + + + {/if} diff --git a/web/frontend/src/Config.root.svelte b/web/frontend/src/Config.root.svelte index 6df579f..ddd714f 100644 --- a/web/frontend/src/Config.root.svelte +++ b/web/frontend/src/Config.root.svelte @@ -1,31 +1,30 @@ {#if isAdmin == true} - + - Admin Options + Admin Options - - + + {/if} - - Plotting Options - - + + Plotting Options + + diff --git a/web/frontend/src/Header.svelte b/web/frontend/src/Header.svelte index 03c8cd0..cc96dd0 100644 --- a/web/frontend/src/Header.svelte +++ b/web/frontend/src/Header.svelte @@ -1,178 +1,169 @@ - - ClusterCockpit Logo - - (isOpen = !isOpen)} /> - (isOpen = detail.isOpen)} - > - - - + + ClusterCockpit Logo + + (isOpen = !isOpen)} /> + (isOpen = detail.isOpen)} + > + + + diff --git a/web/frontend/src/HistogramSelection.svelte b/web/frontend/src/HistogramSelection.svelte index 9856742..39b1872 100644 --- a/web/frontend/src/HistogramSelection.svelte +++ b/web/frontend/src/HistogramSelection.svelte @@ -1,65 +1,73 @@ - (isOpen = !isOpen)}> - - Select metrics presented in histograms - - - - {#each availableMetrics as metric (metric)} - - - {metric} - - {/each} - - - - - - + (isOpen = !isOpen)}> + Select metrics presented in histograms + + + {#each availableMetrics as metric (metric)} + + + {metric} + + {/each} + + + + + + diff --git a/web/frontend/src/Job.root.svelte b/web/frontend/src/Job.root.svelte index 42cfee8..758cef9 100644 --- a/web/frontend/src/Job.root.svelte +++ b/web/frontend/src/Job.root.svelte @@ -1,43 +1,50 @@ - - {#if $initq.error} - {$initq.error.message} - {:else if $initq.data} - - {:else} - - {/if} - - {#if $jobMetrics.data} - {#key $jobMetrics.data} - - - - {/key} - {/if} - {#if $jobMetrics.data && $initq.data} - {#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0} - {#if authlevel > roles.manager} - -
- Concurrent Jobs -
-
    -
  • - See All -
  • - {#each $initq.data.job.concurrentJobs.items as pjob, index} -
  • - {pjob.jobId} -
  • - {/each} -
- - {:else} - -
- {$initq.data.job.concurrentJobs.items.length} Concurrent - Jobs -
-

- Number of shared jobs on the same node with overlapping - runtimes. -

- - {/if} - {/if} - - - - - c.name == $initq.data.job.cluster) - .subClusters.find( - (sc) => sc.name == $initq.data.job.subCluster - )} - data={ - transformDataForRoofline ( - $jobMetrics.data.jobMetrics.find((m) => m.name == "flops_any" && m.scope == "node").metric, - $jobMetrics.data.jobMetrics.find((m) => m.name == "mem_bw" && m.scope == "node").metric - ) - } - /> - + + {#if $initq.error} + {$initq.error.message} + {:else if $initq.data} + {:else} - - + {/if} + + {#if $jobMetrics.data && showFootprint} + {#key $jobMetrics.data} + + + + {/key} + {/if} + {#if $jobMetrics.data && $initq.data} + {#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0} + {#if authlevel > roles.manager} + +
+ Concurrent Jobs +
+
    +
  • + See All +
  • + {#each $initq.data.job.concurrentJobs.items as pjob, index} +
  • + {pjob.jobId} +
  • + {/each} +
+ + {:else} + +
+ {$initq.data.job.concurrentJobs.items.length} Concurrent Jobs +
+

+ Number of shared jobs on the same node with overlapping runtimes. +

+ + {/if} + {/if} + + + + + c.name == $initq.data.job.cluster) + .subClusters.find((sc) => sc.name == $initq.data.job.subCluster)} + data={transformDataForRoofline( + $jobMetrics.data.jobMetrics.find( + (m) => m.name == "flops_any" && m.scope == "node", + ).metric, + $jobMetrics.data.jobMetrics.find( + (m) => m.name == "mem_bw" && m.scope == "node", + ).metric, + )} + /> + + {:else} + + + {/if}
- - {#if $initq.data} - - {/if} - - - {#if $initq.data} - - {/if} - - - - {#if $jobMetrics.error} - {#if $initq.data.job.monitoringStatus == 0 || $initq.data.job.monitoringStatus == 2} - Not monitored or archiving failed -
- {/if} - {$jobMetrics.error.message} - {:else if $jobMetrics.fetching} - - {:else if $jobMetrics.data && $initq.data} - - {#if item.data} - - statsTable.moreLoaded(detail)} - job={$initq.data.job} - metricName={item.metric} - rawData={item.data.map((x) => x.metric)} - scopes={item.data.map((x) => x.scope)} - {width} - isShared={$initq.data.job.exclusive != 1} - resources={$initq.data.job.resources} - /> - {:else} - No dataset returned for {item.metric} - {/if} - + + {#if $jobMetrics.error} + {#if $initq.data.job.monitoringStatus == 0 || $initq.data.job.monitoringStatus == 2} + Not monitored or archiving failed +
+ {/if} + {$jobMetrics.error.message} + {:else if $jobMetrics.fetching} + + {:else if $jobMetrics.data && $initq.data} + + {#if item.data} + statsTable.moreLoaded(detail)} + job={$initq.data.job} + metricName={item.metric} + rawData={item.data.map((x) => x.metric)} + scopes={item.data.map((x) => x.scope)} + {width} + isShared={$initq.data.job.exclusive != 1} + resources={$initq.data.job.resources} + /> + {:else} + No dataset returned for {item.metric} {/if} - + + {/if} +
- - {#if $initq.data} - - {#if somethingMissing} - -
- - - Missing Metrics/Reseources - - - {#if missingMetrics.length > 0} -

- No data at all is available for the - metrics: {missingMetrics.join(", ")} -

- {/if} - {#if missingHosts.length > 0} -

- Some metrics are missing for the - following hosts: -

-
    - {#each missingHosts as missing} -
  • - {missing.hostname}: {missing.metrics.join( - ", " - )} -
  • - {/each} -
- {/if} -
-
-
-
- {/if} - - {#if $jobMetrics.data} - {#key $jobMetrics.data} - - {/key} - {/if} - - -
- {#if $initq.data.job.metaData?.jobScript} -
{$initq.data.job.metaData?.jobScript}
- {:else} - No job script available - {/if} -
-
- -
- {#if $initq.data.job.metaData?.slurmInfo} -
{$initq.data.job.metaData?.slurmInfo}
- {:else} - No additional slurm information available - {/if} -
-
-
+ + {#if $initq.data} + + {#if somethingMissing} + +
+ + + Missing Metrics/Reseources + + + {#if missingMetrics.length > 0} +

+ No data at all is available for the metrics: {missingMetrics.join( + ", ", + )} +

+ {/if} + {#if missingHosts.length > 0} +

Some metrics are missing for the following hosts:

+
    + {#each missingHosts as missing} +
  • + {missing.hostname}: {missing.metrics.join(", ")} +
  • + {/each} +
+ {/if} +
+
+
+
{/if} - + + {#if $jobMetrics.data} + {#key $jobMetrics.data} + + {/key} + {/if} + + +
+ {#if $initq.data.job.metaData?.jobScript} +
{$initq.data.job.metaData?.jobScript}
+ {:else} + No job script available + {/if} +
+
+ +
+ {#if $initq.data.job.metaData?.slurmInfo} +
{$initq.data.job.metaData?.slurmInfo}
+ {:else} + No additional slurm information available + {/if} +
+
+
+ {/if} +
{#if $initq.data} - + {/if} diff --git a/web/frontend/src/JobFootprint.svelte b/web/frontend/src/JobFootprint.svelte index 30034c0..8ed8089 100644 --- a/web/frontend/src/JobFootprint.svelte +++ b/web/frontend/src/JobFootprint.svelte @@ -1,232 +1,265 @@ - - - {#if view === 'job'} + {#if view === "job"} - - Core Metrics Footprint - + + Core Metrics Footprint + + {/if} + + {#each footprintData as fpd, index} +
+
 {fpd.name}
+ +
+
+ + {#if fpd.impact === 3 || fpd.impact === -1} + + {:else if fpd.impact === 2} + + {/if} + + {#if fpd.impact === 3} + + {:else if fpd.impact === 2} + + {:else if fpd.impact === 1} + + {:else if fpd.impact === 0} + + {:else if fpd.impact === -1} + + {/if} +
+
+ + {fpd.avg} / {fpd.max} + {fpd.unit}   +
+
+ {fpd.message} +
+
+ +
+ {/each} + {#if job?.metaData?.message} +
+ {@html job.metaData.message} {/if} - - {#each footprintData as fpd, index} -
-
 {fpd.name}
-
-
- - {#if fpd.impact === 3 || fpd.impact === -1} - - {:else if fpd.impact === 2} - - {/if} - - {#if fpd.impact === 3} - - {:else if fpd.impact === 2} - - {:else if fpd.impact === 1} - - {:else if fpd.impact === 0} - - {:else if fpd.impact === -1} - - {/if} -
-
- - {fpd.avg} / {fpd.max} {fpd.unit}   -
-
- {fpd.message} -
-
- -
- {/each} - {#if job?.metaData?.message} -
- {@html job.metaData.message} - {/if} -
+
diff --git a/web/frontend/src/Jobs.root.svelte b/web/frontend/src/Jobs.root.svelte index d7cbf37..204a4e3 100644 --- a/web/frontend/src/Jobs.root.svelte +++ b/web/frontend/src/Jobs.root.svelte @@ -1,102 +1,121 @@ - {#if $initq.fetching} - - - - {:else if $initq.error} - - {$initq.error.message} - - {/if} + {#if $initq.fetching} + + + + {:else if $initq.error} + + {$initq.error.message} + + {/if} - - - - - - - { - selectedCluster = detail.filters[0]?.cluster ? detail.filters[0].cluster.eq : null - jobList.update(detail.filters) - } - } /> - + + + + + + + { + selectedCluster = detail.filters[0]?.cluster + ? detail.filters[0].cluster.eq + : null; + jobList.update(detail.filters); + }} + /> + - - filterComponent.update(detail)}/> - - - jobList.refresh()} /> - + + filterComponent.update(detail)} + /> + + + jobList.refresh()} /> + -
+
- - - + + + - + + bind:cluster={selectedCluster} + configName="plot_list_selectedMetrics" + bind:metrics + bind:isOpen={isMetricsSelectionOpen} + bind:showFootprint + view="list" +/> diff --git a/web/frontend/src/List.root.svelte b/web/frontend/src/List.root.svelte index c004736..bc1ac6f 100644 --- a/web/frontend/src/List.root.svelte +++ b/web/frontend/src/List.root.svelte @@ -2,52 +2,58 @@ @component List of users or projects --> - - - - - - - - { - jobFilters = detail.filters; - }} - /> - + + + + + + + + { + jobFilters = detail.filters; + }} + /> + - + + + + {#if type == "USER"} + + {/if} + + + + + + + + {#if $stats.fetching} + + + + {:else if $stats.error} + + + + {:else if $stats.data} + {#each sort($stats.data.rows, sorting, nameFilter) as row (row.id)} - + - {/if} - - - - - - - - {#if $stats.fetching} - - - - {:else if $stats.error} - - - - {:else if $stats.data} - {#each sort($stats.data.rows, sorting, nameFilter) as row (row.id)} - - - {#if type == "USER"} - - {/if} - - - - - + {scrambleNames ? scramble(row.id) : row.id} + {:else if type == "PROJECT"} + {scrambleNames ? scramble(row.id) : row.id} {:else} - - - - {/each} - {/if} - + {row.id} + {/if} + + {#if type == "USER"} + + {/if} + + + + + + {:else} + + + + {/each} + {/if} +
+ {{ + USER: "Username", + PROJECT: "Project Name", + }[type]} + + + Name + + + Total Jobs + + + Total Walltime + + + Total Core Hours + + + Total Accelerator Hours + +
{$stats.error.message}
- {({ - USER: "Username", - PROJECT: "Project Name", - })[type]} - - {#if type == "USER"} - - Name - - - Total Jobs - - - Total Walltime - - - Total Core Hours - - - Total Accelerator Hours - -
{$stats.error.message}
- {#if type == "USER"} - {scrambleNames ? scramble(row.id) : row.id} - {:else if type == "PROJECT"} - {scrambleNames ? scramble(row.id) : row.id} - {:else} - {row.id} - {/if} - {scrambleNames ? scramble(row?.name?row.name:"-") : row?.name?row.name:"-"}{row.totalJobs}{row.totalWalltime}{row.totalCoreHours}{row.totalAccHours}
No {type.toLowerCase()}s/jobs found
{scrambleNames + ? scramble(row?.name ? row.name : "-") + : row?.name + ? row.name + : "-"}{row.totalJobs}{row.totalWalltime}{row.totalCoreHours}{row.totalAccHours}
No {type.toLowerCase()}s/jobs found
diff --git a/web/frontend/src/Metric.svelte b/web/frontend/src/Metric.svelte index 8ff0a58..6022ffb 100644 --- a/web/frontend/src/Metric.svelte +++ b/web/frontend/src/Metric.svelte @@ -1,95 +1,118 @@ + - - {metricName} ({(metricConfig?.unit?.prefix ? metricConfig.unit.prefix : '') + - (metricConfig?.unit?.base ? metricConfig.unit.base : '')}) - - - {#if job.resources.length > 1} - + + {metricName} ({(metricConfig?.unit?.prefix + ? metricConfig.unit.prefix + : "") + (metricConfig?.unit?.base ? metricConfig.unit.base : "")}) + + + {#if job.resources.length > 1} + + {/if} {#key series} - {#if fetching == true} - - {:else if error != null} - {error.message} - {:else if series != null} - - {/if} + {#if fetching == true} + + {:else if error != null} + {error.message} + {:else if series != null} + + {/if} {/key} diff --git a/web/frontend/src/MetricSelection.svelte b/web/frontend/src/MetricSelection.svelte index 5f55cb7..689abef 100644 --- a/web/frontend/src/MetricSelection.svelte +++ b/web/frontend/src/MetricSelection.svelte @@ -8,181 +8,206 @@ --> - - - (isOpen = !isOpen)}> - - Configure columns (Metric availability shown) - - - - {#if view === 'list'} -
  • - Show Footprint -
  • -
    - {/if} - {#each newMetricsOrder as metric, index (metric)} -
  • columnsDragStart(event, index)} - on:drop|preventDefault={event => columnsDrag(event, index)} - on:dragenter={() => columnHovering = index} - class:is-active={columnHovering === index}> - {#if unorderedMetrics.includes(metric)} - - {:else} - - {/if} - {metric} - - {cluster == null ? - clusters // No single cluster specified: List Clusters with Metric - .filter(c => c.metricConfig.find(m => m.name == metric) != null) - .map(c => c.name).join(', ') : - clusters // Single cluster requested: List Subclusters with do not have metric remove flag - .filter(c => c.name == cluster) - .filter(c => c.metricConfig.find(m => m.name == metric) != null) - .map(function(c) { - let scNames = c.subClusters.map(sc => sc.name) - scNames.forEach(function(scName){ - let met = c.metricConfig.find(m => m.name == metric) - let msc = met.subClusters.find(msc => msc.name == scName) - if (msc != null) { - if (msc.remove == true) { - scNames = scNames.filter(scn => scn != msc.name) - } - } - }) - return scNames - }) - .join(', ')} - -
  • - {/each} -
    -
    - - - + (isOpen = !isOpen)}> + Configure columns (Metric availability shown) + + + {#if view === "list"} +
  • + Show Footprint +
  • +
    + {/if} + {#each newMetricsOrder as metric, index (metric)} +
  • columnsDragStart(event, index)} + on:drop|preventDefault={(event) => columnsDrag(event, index)} + on:dragenter={() => (columnHovering = index)} + class:is-active={columnHovering === index} + > + {#if unorderedMetrics.includes(metric)} + + {:else} + + {/if} + {metric} + + {cluster == null + ? clusters // No single cluster specified: List Clusters with Metric + .filter( + (c) => c.metricConfig.find((m) => m.name == metric) != null, + ) + .map((c) => c.name) + .join(", ") + : clusters // Single cluster requested: List Subclusters with do not have metric remove flag + .filter((c) => c.name == cluster) + .filter( + (c) => c.metricConfig.find((m) => m.name == metric) != null, + ) + .map(function (c) { + let scNames = c.subClusters.map((sc) => sc.name); + scNames.forEach(function (scName) { + let met = c.metricConfig.find((m) => m.name == metric); + let msc = met.subClusters.find( + (msc) => msc.name == scName, + ); + if (msc != null) { + if (msc.remove == true) { + scNames = scNames.filter((scn) => scn != msc.name); + } + } + }); + return scNames; + }) + .join(", ")} + +
  • + {/each} +
    +
    + + +
    + + diff --git a/web/frontend/src/NavbarLinks.svelte b/web/frontend/src/NavbarLinks.svelte index 6861da5..24ecddf 100644 --- a/web/frontend/src/NavbarLinks.svelte +++ b/web/frontend/src/NavbarLinks.svelte @@ -1,39 +1,38 @@ {#each links as item} - {#if !item.perCluster} - {item.title} - {:else} - - - - {item.title} - - - {#each clusters as cluster} - - {cluster.name} - - {/each} - - - {/if} + {#if !item.perCluster} + {item.title} + {:else} + + + + {item.title} + + + {#each clusters as cluster} + + {cluster.name} + + {/each} + + + {/if} {/each} diff --git a/web/frontend/src/NavbarTools.svelte b/web/frontend/src/NavbarTools.svelte index f6ded90..f44b4e9 100644 --- a/web/frontend/src/NavbarTools.svelte +++ b/web/frontend/src/NavbarTools.svelte @@ -1,143 +1,153 @@ diff --git a/web/frontend/src/Node.root.svelte b/web/frontend/src/Node.root.svelte index b23c71e..0a5a75e 100644 --- a/web/frontend/src/Node.root.svelte +++ b/web/frontend/src/Node.root.svelte @@ -1,238 +1,230 @@ - {#if $initq.error} - {$initq.error.message} - {:else if $initq.fetching} + {#if $initq.error} + {$initq.error.message} + {:else if $initq.fetching} + + {:else} + + + + {hostname} ({cluster}) + + + + {#if $nodeJobsData.fetching} - {:else} - - - - {hostname} ({cluster}) - - - - {#if $nodeJobsData.fetching} - - {:else if $nodeJobsData.data} - Currently running jobs on this node: {$nodeJobsData.data.jobs - .count} - [ - View in Job List ] - {:else} - No currently running jobs. - {/if} - - - { - const diff = Date.now() - to - from = new Date(from.getTime() + diff) - to = new Date(to.getTime() + diff) - }} /> - - - - - {/if} + {:else if $nodeJobsData.data} + Currently running jobs on this node: {$nodeJobsData.data.jobs.count} + [ + View in Job List ] + {:else} + No currently running jobs. + {/if} + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + + + + {/if}
    - - {#if $nodeMetricsData.error} - {$nodeMetricsData.error.message} - {:else if $nodeMetricsData.fetching || $initq.fetching} - + + {#if $nodeMetricsData.error} + {$nodeMetricsData.error.message} + {:else if $nodeMetricsData.fetching || $initq.fetching} + + {:else} + ({ + ...m, + disabled: checkMetricDisabled( + m.name, + cluster, + $nodeMetricsData.data.nodeMetrics[0].subCluster, + ), + })) + .sort((a, b) => a.name.localeCompare(b.name))} + > +

    + {item.name} + {metricUnits[item.name]} +

    + {#if item.disabled === false && item.metric} + c.name == cluster)} + subCluster={$nodeMetricsData.data.nodeMetrics[0].subCluster} + series={item.metric.series} + resources={[{ hostname: hostname }]} + forNode={true} + /> + {:else if item.disabled === true && item.metric} + Metric disabled for subcluster {item.name}:{$nodeMetricsData.data.nodeMetrics[0] + .subCluster} {:else} - ({ - ...m, - disabled: checkMetricDisabled( - m.name, - cluster, - $nodeMetricsData.data.nodeMetrics[0].subCluster - ), - })) - .sort((a, b) => a.name.localeCompare(b.name))} - > -

    - {item.name} - {metricUnits[item.name]} -

    - {#if item.disabled === false && item.metric} - c.name == cluster)} - subCluster={$nodeMetricsData.data.nodeMetrics[0] - .subCluster} - series={item.metric.series} - resources={[{hostname: hostname}]} - forNode={true} - /> - {:else if item.disabled === true && item.metric} - Metric disabled for subcluster {item.name}:{$nodeMetricsData.data.nodeMetrics[0] - .subCluster} - {:else} - No dataset returned for {item.name} - {/if} -
    + No dataset returned for {item.name} {/if} - +
    + {/if} +
    diff --git a/web/frontend/src/PlotSelection.svelte b/web/frontend/src/PlotSelection.svelte index 449de64..b4cf58b 100644 --- a/web/frontend/src/PlotSelection.svelte +++ b/web/frontend/src/PlotSelection.svelte @@ -1,139 +1,163 @@ - - - (isHistogramConfigOpen = !isHistogramConfigOpen)}> - - Select metrics presented in histograms - - - - {#each availableMetrics as metric (metric)} - - updateConfiguration({ - name: 'analysis_view_histogramMetrics', - value: metricsInHistograms - })} /> + (isHistogramConfigOpen = !isHistogramConfigOpen)} +> + Select metrics presented in histograms + + + {#each availableMetrics as metric (metric)} + + + updateConfiguration({ + name: "analysis_view_histogramMetrics", + value: metricsInHistograms, + })} + /> - {metric} - - {/each} - - - - - + {metric} + + {/each} + + + + + - (isScatterPlotConfigOpen = !isScatterPlotConfigOpen)}> - - Select metric pairs presented in scatter plots - - - - {#each metricsInScatterplots as pair} - - {pair[0]} / {pair[1]} + (isScatterPlotConfigOpen = !isScatterPlotConfigOpen)} +> + Select metric pairs presented in scatter plots + + + {#each metricsInScatterplots as pair} + + {pair[0]} / {pair[1]} - - - {/each} - + + + {/each} + -
    +
    - - - - - - -
    - - - + + + + + + + + +
    diff --git a/web/frontend/src/StatsTable.svelte b/web/frontend/src/StatsTable.svelte index e1d0c02..3a9d84d 100644 --- a/web/frontend/src/StatsTable.svelte +++ b/web/frontend/src/StatsTable.svelte @@ -1,139 +1,154 @@ - - - - {#each selectedMetrics as metric} - - {/each} - - - - {#each selectedMetrics as metric} - {#if selectedScopes[metric] != 'node'} - - {/if} - {#each ['min', 'avg', 'max'] as stat} - - {/each} - {/each} - - - - {#each hosts as host (host)} - - - {#each selectedMetrics as metric (metric)} - - {/each} - + + + + {#each selectedMetrics as metric} + + {/each} + + + + {#each selectedMetrics as metric} + {#if selectedScopes[metric] != "node"} + + {/if} + {#each ["min", "avg", "max"] as stat} + {/each} - + {/each} + + + + {#each hosts as host (host)} + + + {#each selectedMetrics as metric (metric)} + + {/each} + + {/each} +
    - - - - - {metric} - - - -
    NodeId sortBy(metric, stat)}> - {stat} - {#if selectedScopes[metric] == 'node'} - - {/if} -
    {host}
    + + + + + {metric} + + + +
    NodeId sortBy(metric, stat)}> + {stat} + {#if selectedScopes[metric] == "node"} + + {/if} +
    {host}
    -
    +
    + cluster={job.cluster} + configName="job_view_nodestats_selectedMetrics" + allMetrics={new Set(allMetrics)} + bind:metrics={selectedMetrics} + bind:isOpen={isMetricSelectionOpen} +/> diff --git a/web/frontend/src/StatsTableEntry.svelte b/web/frontend/src/StatsTableEntry.svelte index 5e497d4..99cde21 100644 --- a/web/frontend/src/StatsTableEntry.svelte +++ b/web/frontend/src/StatsTableEntry.svelte @@ -1,82 +1,86 @@ {#if series == null || series.length == 0} - No data -{:else if series.length == 1 && scope == 'node'} - - {series[0].statistics.min} - - - {series[0].statistics.avg} - - - {series[0].statistics.max} - + No data +{:else if series.length == 1 && scope == "node"} + + {series[0].statistics.min} + + + {series[0].statistics.avg} + + + {series[0].statistics.max} + {:else} - - - - {#each ['id', 'min', 'avg', 'max'] as field} - - {/each} - - {#each series as s, i} - - - - - - - {/each} -
    sortByField(field)}> - Sort - -
    {s.id ?? i}{s.statistics.min}{s.statistics.avg}{s.statistics.max}
    - + + + + {#each ["id", "min", "avg", "max"] as field} + + {/each} + + {#each series as s, i} + + + + + + + {/each} +
    sortByField(field)}> + Sort + +
    {s.id ?? i}{s.statistics.min}{s.statistics.avg}{s.statistics.max}
    + {/if} diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index d0d7ba1..b5ccec0 100644 --- a/web/frontend/src/Status.root.svelte +++ b/web/frontend/src/Status.root.svelte @@ -1,366 +1,358 @@ - -

    Current utilization of cluster "{cluster}"

    - - - {#if $initq.fetching || $mainQuery.fetching} - - {:else if $initq.error} - {$initq.error.message} - {:else} - - {/if} - - - - - - { - from = new Date(Date.now() - 5 * 60 * 1000); - to = new Date(Date.now()); - }} - /> - + +

    Current utilization of cluster "{cluster}"

    + + + {#if $initq.fetching || $mainQuery.fetching} + + {:else if $initq.error} + {$initq.error.message} + {:else} + + {/if} + + + + + + { + from = new Date(Date.now() - 5 * 60 * 1000); + to = new Date(Date.now()); + }} + /> +
    {#if $mainQuery.error} - - - {$mainQuery.error.message} - - + + + {$mainQuery.error.message} + + {/if}
    @@ -368,358 +360,318 @@ {#if $initq.data && $mainQuery.data} - {#each $initq.data.clusters.find((c) => c.name == cluster).subClusters as subCluster, i} - - - - - SubCluster "{subCluster.name}" - - - - - - - - - - - - - - - - - - -
    Allocated Nodes
    - -
    {allocatedNodes[subCluster.name]} / {subCluster.numberOfNodes} - Nodes
    Flop Rate (Any)
    - -
    - {scaleNumbers( - flopRate[subCluster.name], - subCluster.flopRateSimd.value * - subCluster.numberOfNodes, - flopRateUnitPrefix[subCluster.name] - )}{flopRateUnitBase[subCluster.name]} [Max] -
    MemBw Rate
    - -
    - {scaleNumbers( - memBwRate[subCluster.name], - subCluster.memoryBandwidth.value * - subCluster.numberOfNodes, - memBwRateUnitPrefix[subCluster.name] - )}{memBwRateUnitBase[subCluster.name]} [Max] -
    -
    -
    - - -
    - {#key $mainQuery.data.nodeMetrics} - data.subCluster == subCluster.name - ) - ) - } - /> - {/key} -
    - -
    - {/each} + {#each $initq.data.clusters.find((c) => c.name == cluster).subClusters as subCluster, i} + + + + + SubCluster "{subCluster.name}" + + + + + + + + + + + + + + + + + + +
    Allocated Nodes
    + +
    {allocatedNodes[subCluster.name]} / {subCluster.numberOfNodes} + Nodes
    Flop Rate (Any)
    + +
    + {scaleNumbers( + flopRate[subCluster.name], + subCluster.flopRateSimd.value * subCluster.numberOfNodes, + flopRateUnitPrefix[subCluster.name], + )}{flopRateUnitBase[subCluster.name]} [Max] +
    MemBw Rate
    + +
    + {scaleNumbers( + memBwRate[subCluster.name], + subCluster.memoryBandwidth.value * subCluster.numberOfNodes, + memBwRateUnitPrefix[subCluster.name], + )}{memBwRateUnitBase[subCluster.name]} [Max] +
    +
    +
    + + +
    + {#key $mainQuery.data.nodeMetrics} + data.subCluster == subCluster.name, + ), + )} + /> + {/key} +
    + +
    + {/each} -
    +
    - + + + +
    +

    + Top Users on {cluster.charAt(0).toUpperCase() + cluster.slice(1)} +

    + {#key $topUserQuery.data} + {#if $topUserQuery.fetching} + + {:else if $topUserQuery.error} + {$topUserQuery.error.message} + {:else} + tu[topUserSelection.key], + )} + entities={$topUserQuery.data.topUser.map((tu) => tu.id)} + /> + {/if} + {/key} +
    + + + {#key $topUserQuery.data} + {#if $topUserQuery.fetching} + + {:else if $topUserQuery.error} + {$topUserQuery.error.message} + {:else} + + + + + + + {#each $topUserQuery.data.topUser as tu, i} + + + + + + {/each} +
    LegendUser NameNumber of + +
    {tu.id}{tu[topUserSelection.key]}
    + {/if} + {/key} + + +

    + Top Projects on {cluster.charAt(0).toUpperCase() + cluster.slice(1)} +

    + {#key $topProjectQuery.data} + {#if $topProjectQuery.fetching} + + {:else if $topProjectQuery.error} + {$topProjectQuery.error.message} + {:else} + tp[topProjectSelection.key], + )} + entities={$topProjectQuery.data.topProjects.map((tp) => tp.id)} + /> + {/if} + {/key} + + + {#key $topProjectQuery.data} + {#if $topProjectQuery.fetching} + + {:else if $topProjectQuery.error} + {$topProjectQuery.error.message} + {:else} + + + + + + + {#each $topProjectQuery.data.topProjects as tp, i} + + + + + + {/each} +
    LegendProject CodeNumber of + +
    {tp.id}{tp[topProjectSelection.key]}
    + {/if} + {/key} + +
    +
    + + +
    + {#key $mainQuery.data.stats} + + {/key} +
    + + + {#key $mainQuery.data.stats} + + {/key} + +
    + + +
    + {#key $mainQuery.data.stats} + + {/key} +
    + + + {#key $mainQuery.data.stats} + + {/key} + +
    +
    + {#if metricsInHistograms} - -
    -

    - Top Users on {cluster.charAt(0).toUpperCase() + - cluster.slice(1)} -

    - {#key $topUserQuery.data} - {#if $topUserQuery.fetching} - - {:else if $topUserQuery.error} - {$topUserQuery.error.message} - {:else} - tu[topUserSelection.key] - )} - entities={$topUserQuery.data.topUser.map( - (tu) => tu.id - )} - /> - {/if} - {/key} -
    - - - {#key $topUserQuery.data} - {#if $topUserQuery.fetching} - - {:else if $topUserQuery.error} - {$topUserQuery.error.message} - {:else} - - - - - - - {#each $topUserQuery.data.topUser as tu, i} - - - - - - {/each} -
    LegendUser NameNumber of - -
    {tu.id}{tu[topUserSelection.key]}
    - {/if} - {/key} - - -

    - Top Projects on {cluster.charAt(0).toUpperCase() + - cluster.slice(1)} -

    - {#key $topProjectQuery.data} - {#if $topProjectQuery.fetching} - - {:else if $topProjectQuery.error} - {$topProjectQuery.error.message} - {:else} - tp[topProjectSelection.key] - )} - entities={$topProjectQuery.data.topProjects.map( - (tp) => tp.id - )} - /> - {/if} - {/key} - - - {#key $topProjectQuery.data} - {#if $topProjectQuery.fetching} - - {:else if $topProjectQuery.error} - {$topProjectQuery.error.message} - {:else} - - - - - - - {#each $topProjectQuery.data.topProjects as tp, i} - - - - - - {/each} -
    LegendProject CodeNumber of - -
    {tp.id}{tp[topProjectSelection.key]}
    - {/if} - {/key} - + + {#key $mainQuery.data.stats[0].histMetrics} + + + + {/key} +
    -
    - - -
    - {#key $mainQuery.data.stats} - - {/key} -
    - - - {#key $mainQuery.data.stats} - - {/key} - -
    - - -
    - {#key $mainQuery.data.stats} - - {/key} -
    - - - {#key $mainQuery.data.stats} - - {/key} - -
    -
    - {#if metricsInHistograms} - - - {#key $mainQuery.data.stats[0].histMetrics} - - - - - {/key} - - - {/if} + {/if} {/if} + bind:cluster + bind:metricsInHistograms + bind:isOpen={isHistogramSelectionOpen} +/> diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index d881236..4a7f633 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -1,159 +1,218 @@ - {#if $initq.error} - {$initq.error.message} - {:else if $initq.fetching} - - {:else} - - { - const diff = Date.now() - to - from = new Date(from.getTime() + diff) - to = new Date(to.getTime() + diff) - }} /> - - - - - - - - Metric - - - - - - - Find Node - - - - {/if} - -
    - + {#if $initq.error} + {$initq.error.message} + {:else if $initq.fetching} + + {:else} - {#if $nodesQuery.error} - {$nodesQuery.error.message} - {:else if $nodesQuery.fetching || $initq.fetching} - - {:else} - h.host.includes(hostnameFilter) && h.metrics.some(m => m.name == selectedMetric && m.scope == 'node')) - .map(h => ({ - host: h.host, - subCluster: h.subCluster, - data: h.metrics.find(m => m.name == selectedMetric && m.scope == 'node'), - disabled: checkMetricDisabled(selectedMetric, cluster, h.subCluster) - })) - .sort((a, b) => a.host.localeCompare(b.host)) - }> - -

    {item.host} ({item.subCluster})

    - {#if item.disabled === false && item.data} - c.name == cluster)} - subCluster={item.subCluster} - resources={[{hostname: item.host}]} - forNode={true}/> - {:else if item.disabled === true && item.data} - Metric disabled for subcluster {selectedMetric}:{item.subCluster} - {:else} - No dataset returned for {selectedMetric} - {/if} -
    - {/if} + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + + + + + + Metric + + + + + + + Find Node + + + + {/if} +
    +
    + + + {#if $nodesQuery.error} + {$nodesQuery.error.message} + {:else if $nodesQuery.fetching || $initq.fetching} + + {:else} + + h.host.includes(hostnameFilter) && + h.metrics.some( + (m) => m.name == selectedMetric && m.scope == "node", + ), + ) + .map((h) => ({ + host: h.host, + subCluster: h.subCluster, + data: h.metrics.find( + (m) => m.name == selectedMetric && m.scope == "node", + ), + disabled: checkMetricDisabled( + selectedMetric, + cluster, + h.subCluster, + ), + })) + .sort((a, b) => a.host.localeCompare(b.host))} + > +

    + {item.host} ({item.subCluster}) +

    + {#if item.disabled === false && item.data} + c.name == cluster)} + subCluster={item.subCluster} + resources={[{ hostname: item.host }]} + forNode={true} + /> + {:else if item.disabled === true && item.data} + Metric disabled for subcluster {selectedMetric}:{item.subCluster} + {:else} + No dataset returned for {selectedMetric} + {/if} +
    + {/if} +
    - diff --git a/web/frontend/src/TagManagement.svelte b/web/frontend/src/TagManagement.svelte index 6ab4752..e9fb9e9 100644 --- a/web/frontend/src/TagManagement.svelte +++ b/web/frontend/src/TagManagement.svelte @@ -1,190 +1,234 @@ - - (isOpen = !isOpen)}> - - Manage Tags - {#if pendingChange !== false} - - {:else} - - {/if} - - - + + Manage Tags + {#if pendingChange !== false} + + {:else} + + {/if} + + + -
    +
    - - Search using "type: name". If no tag matches your search, - a button for creating a new one will appear. - + + Search using "type: name". If no tag matches your search, a + button for creating a new one will appear. + -
      - {#each allTagsFiltered as tag} - - +
        + {#each allTagsFiltered as tag} + + - - {#if pendingChange === tag.id} - - {:else if job.tags.find(t => t.id == tag.id)} - - {:else} - - {/if} - - + + {#if pendingChange === tag.id} + + {:else if job.tags.find((t) => t.id == tag.id)} + {:else} - - No tags matching - - {/each} -
      -
      - {#if newTagType && newTagName && isNewTag(newTagType, newTagName)} - - {:else if allTagsFiltered.length == 0} - Search Term is not a valid Tag (type: name) - {/if} - - - - + + {/if} + +
      + {:else} + + No tags matching + + {/each} +
    +
    + {#if newTagType && newTagName && isNewTag(newTagType, newTagName)} + + {:else if allTagsFiltered.length == 0} + Search Term is not a valid Tag (type: name) + {/if} +
    + + +
    + + diff --git a/web/frontend/src/User.root.svelte b/web/frontend/src/User.root.svelte index f368851..c60ea20 100644 --- a/web/frontend/src/User.root.svelte +++ b/web/frontend/src/User.root.svelte @@ -1,237 +1,276 @@ - {#if $initq.fetching} - - - - {:else if $initq.error} - - {$initq.error.message} - - {/if} - + {#if $initq.fetching} + + + + {:else if $initq.error} - + {$initq.error.message} + + {/if} - + + - - - - { - jobFilters = [...detail.filters, { user: { eq: user.username } }] - selectedCluster = jobFilters[0]?.cluster ? jobFilters[0].cluster.eq : null - jobList.update(jobFilters) - }} /> - - - jobList.refresh()} /> - + + + + + + { + jobFilters = [...detail.filters, { user: { eq: user.username } }]; + selectedCluster = jobFilters[0]?.cluster + ? jobFilters[0].cluster.eq + : null; + jobList.update(jobFilters); + }} + /> + + + jobList.refresh()} /> + -
    +
    - {#if $stats.error} - - {$stats.error.message} - - {:else if !$stats.data} - - - - {:else} - - - - - - - - {#if user.name} - - - - - {/if} - {#if user.email} - - - - - {/if} - - - - - - - - - - - - - - - - - -
    Username{scrambleNames ? scramble(user.username) : user.username}
    Name{scrambleNames ? scramble(user.name) : user.name}
    Email{user.email}
    Total Jobs{$stats.data.jobsStatistics[0].totalJobs}
    Short Jobs{$stats.data.jobsStatistics[0].shortJobs}
    Total Walltime{$stats.data.jobsStatistics[0].totalWalltime}
    Total Core Hours{$stats.data.jobsStatistics[0].totalCoreHours}
    - -
    - {#key $stats.data.jobsStatistics[0].histDuration} - - {/key} -
    -
    - {#key $stats.data.jobsStatistics[0].histNumNodes} - - {/key} -
    - {/if} + {#if $stats.error} + + {$stats.error.message} + + {:else if !$stats.data} + + + + {:else} + + + + + + + + {#if user.name} + + + + + {/if} + {#if user.email} + + + + + {/if} + + + + + + + + + + + + + + + + + +
    Username{scrambleNames ? scramble(user.username) : user.username}
    Name{scrambleNames ? scramble(user.name) : user.name}
    Email{user.email}
    Total Jobs{$stats.data.jobsStatistics[0].totalJobs}
    Short Jobs{$stats.data.jobsStatistics[0].shortJobs}
    Total Walltime{$stats.data.jobsStatistics[0].totalWalltime}
    Total Core Hours{$stats.data.jobsStatistics[0].totalCoreHours}
    + +
    + {#key $stats.data.jobsStatistics[0].histDuration} + + {/key} +
    +
    + {#key $stats.data.jobsStatistics[0].histNumNodes} + + {/key} +
    + {/if}
    {#if metricsInHistograms} - - {#if $stats.error} - - {$stats.error.message} - - {:else if !$stats.data} - - - - {:else} - - {#key $stats.data.jobsStatistics[0].histMetrics} - - - - - {/key} - - {/if} - + + {#if $stats.error} + + {$stats.error.message} + + {:else if !$stats.data} + + + + {:else} + + {#key $stats.data.jobsStatistics[0].histMetrics} + + + + {/key} + + {/if} + {/if} -
    +
    - - - + + + - + + + - - + bind:cluster={selectedCluster} + bind:metricsInHistograms + bind:isOpen={isHistogramSelectionOpen} +/> diff --git a/web/frontend/src/Zoom.svelte b/web/frontend/src/Zoom.svelte index ae842fc..c5f73c1 100644 --- a/web/frontend/src/Zoom.svelte +++ b/web/frontend/src/Zoom.svelte @@ -1,60 +1,65 @@
    - - - - - - Window Size: - - - ({windowSize}%) - - - - Window Position: - - - + + + + + + Window Size: + + + ({windowSize}%) + + + + Window Position: + + +
    diff --git a/web/frontend/src/config/AdminSettings.svelte b/web/frontend/src/config/AdminSettings.svelte index 97c5b17..26e1d0f 100644 --- a/web/frontend/src/config/AdminSettings.svelte +++ b/web/frontend/src/config/AdminSettings.svelte @@ -1,54 +1,53 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/web/frontend/src/config/PlotSettings.svelte b/web/frontend/src/config/PlotSettings.svelte index 36326bd..20a7f2e 100644 --- a/web/frontend/src/config/PlotSettings.svelte +++ b/web/frontend/src/config/PlotSettings.svelte @@ -1,171 +1,498 @@ - - - -
    handleSettingSubmit('#line-width-form', 'lw')}> - - -
    Line Width
    - - {#if displayMessage && message.target == 'lw'} -
    - - Update: {message.msg} - -
    - {/if} -
    - -
    - - -
    Width of the lines in the timeseries plots.
    + + + + + handleSettingSubmit("#line-width-form", "lw")} + > + + +
    Line Width
    + + {#if displayMessage && message.target == "lw"} +
    + + Update: {message.msg} +
    - - -
    + {/if} + + +
    + + +
    + Width of the lines in the timeseries plots. +
    +
    + + + - - -
    handleSettingSubmit('#plots-per-row-form', 'ppr')}> - - -
    Plots per Row
    - {#if displayMessage && message.target == 'ppr'}
    Update: {message.msg}
    {/if} -
    - -
    - - -
    How many plots to show next to each other on pages such as /monitoring/job/, /monitoring/system/...
    -
    - -
    -
    + + +
    + handleSettingSubmit("#plots-per-row-form", "ppr")} + > + + +
    Plots per Row
    + {#if displayMessage && message.target == "ppr"}
    + Update: {message.msg} +
    {/if} +
    + +
    + + +
    + How many plots to show next to each other on pages such as + /monitoring/job/, /monitoring/system/... +
    +
    + +
    +
    - - -
    handleSettingSubmit('#backgrounds-form', 'bg')}> - - -
    Colored Backgrounds
    - {#if displayMessage && message.target == 'bg'}
    Update: {message.msg}
    {/if} -
    - -
    -
    - {#if config.plot_general_colorBackground} - - {:else} - - {/if} - -
    -
    - {#if config.plot_general_colorBackground} - - {:else} - - {/if} - -
    -
    - -
    -
    + + +
    + handleSettingSubmit("#backgrounds-form", "bg")} + > + + +
    Colored Backgrounds
    + {#if displayMessage && message.target == "bg"}
    + Update: {message.msg} +
    {/if} +
    + +
    +
    + {#if config.plot_general_colorBackground} + + {:else} + + {/if} + +
    +
    + {#if config.plot_general_colorBackground} + + {:else} + + {/if} + +
    +
    + +
    +
    - - -
    - - -
    Color Scheme for Timeseries Plots
    - {#if displayMessage && message.target == 'cs'}
    Update: {message.msg}
    {/if} -
    - - - - {#each Object.entries(colorschemes) as [name, rgbrow]} - - - - - - {/each} - -
    {name} - {#if rgbrow.join(',') == config.plot_general_colorscheme} - handleSettingSubmit("#colorscheme-form", "cs")}/> - {:else} - handleSettingSubmit("#colorscheme-form", "cs")}/> - {/if} - - {#each rgbrow as rgb} - - {/each} -
    -
    -
    + + +
    + + +
    Color Scheme for Timeseries Plots
    + {#if displayMessage && message.target == "cs"}
    + Update: {message.msg} +
    {/if} +
    + + + + {#each Object.entries(colorschemes) as [name, rgbrow]} + + + + + + {/each} + +
    {name} + {#if rgbrow.join(",") == config.plot_general_colorscheme} + + handleSettingSubmit("#colorscheme-form", "cs")} + /> + {:else} + + handleSettingSubmit("#colorscheme-form", "cs")} + /> + {/if} + + {#each rgbrow as rgb} + + {/each} +
    +
    +
    diff --git a/web/frontend/src/config/admin/AddUser.svelte b/web/frontend/src/config/admin/AddUser.svelte index 2712e17..43f08de 100644 --- a/web/frontend/src/config/admin/AddUser.svelte +++ b/web/frontend/src/config/admin/AddUser.svelte @@ -1,103 +1,156 @@ -
    - Create User -
    - - -
    Must be unique.
    -
    -
    - - -
    Only API users are allowed to have a blank password. Users with a blank password can only authenticate via Tokens.
    -
    -
    - - -
    Only Manager users can have a project. Allows to inspect jobs and users of given project.
    -
    -
    - - -
    Optional, can be blank.
    -
    -
    - - -
    Optional, can be blank.
    -
    + + Create User +
    + + +
    Must be unique.
    +
    +
    + + +
    + Only API users are allowed to have a blank password. Users with a blank + password can only authenticate via Tokens. +
    +
    +
    + + +
    + Only Manager users can have a project. Allows to inspect jobs and users + of given project. +
    +
    +
    + + +
    Optional, can be blank.
    +
    +
    + + +
    Optional, can be blank.
    +
    - -
    -

    Role:

    - {#each roles as role, i} - {#if i == 0} -
    - - -
    - {:else if i == 1} -
    - - -
    - {:else} -
    - - -
    - {/if} - {/each} -
    -

    - - {#if displayMessage}

    {message.msg}
    {/if} -

    -
    +
    +

    Role:

    + {#each roles as role, i} + {#if i == 0} +
    + + +
    + {:else if i == 1} +
    + + +
    + {:else} +
    + + +
    + {/if} + {/each} +
    +

    + + {#if displayMessage}

    + {message.msg} +
    {/if} +

    +
    diff --git a/web/frontend/src/config/admin/EditProject.svelte b/web/frontend/src/config/admin/EditProject.svelte index 857f7db..a4a8d75 100644 --- a/web/frontend/src/config/admin/EditProject.svelte +++ b/web/frontend/src/config/admin/EditProject.svelte @@ -1,97 +1,129 @@ - - Edit Project Managed By User (Manager Only) -
    - - - - - - -
    -

    - {#if displayMessage}Update: {message.msg}{/if} -

    -
    + + Edit Project Managed By User (Manager Only) +
    + + + + + + +
    +

    + {#if displayMessage}Update: {message.msg}{/if} +

    +
    diff --git a/web/frontend/src/config/admin/EditRole.svelte b/web/frontend/src/config/admin/EditRole.svelte index ca14699..f201f38 100644 --- a/web/frontend/src/config/admin/EditRole.svelte +++ b/web/frontend/src/config/admin/EditRole.svelte @@ -1,104 +1,131 @@ - - Edit User Roles -
    - - - - - - -
    -

    - {#if displayMessage}Update: {message.msg}{/if} -

    -
    + + Edit User Roles +
    + + + + + + +
    +

    + {#if displayMessage}Update: {message.msg}{/if} +

    +
    diff --git a/web/frontend/src/config/admin/Options.svelte b/web/frontend/src/config/admin/Options.svelte index 44f9650..8ad3c44 100644 --- a/web/frontend/src/config/admin/Options.svelte +++ b/web/frontend/src/config/admin/Options.svelte @@ -1,29 +1,34 @@ - - Scramble Names / Presentation Mode - - Active? - + + Scramble Names / Presentation Mode + + Active? + diff --git a/web/frontend/src/config/admin/ShowUsers.svelte b/web/frontend/src/config/admin/ShowUsers.svelte index 439bebb..be9b146 100644 --- a/web/frontend/src/config/admin/ShowUsers.svelte +++ b/web/frontend/src/config/admin/ShowUsers.svelte @@ -1,68 +1,87 @@ - - Special Users -

    - Not created by an LDAP sync and/or having a role other than user - -

    -
    - - - - - - - - - - - - - - {#each userList as user} - - - - - {:else} - - - - {/each} - -
    UsernameNameProject(s)EmailRolesJWTDelete
    -
    Loading...
    -
    -
    -
    + + Special Users +

    + Not created by an LDAP sync and/or having a role other than user + +

    +
    + + + + + + + + + + + + + + {#each userList as user} + + + + + {:else} + + + + {/each} + +
    UsernameNameProject(s)EmailRolesJWTDelete
    +
    + Loading... +
    +
    +
    +
    diff --git a/web/frontend/src/config/admin/ShowUsersRow.svelte b/web/frontend/src/config/admin/ShowUsersRow.svelte index 34b2240..9845241 100644 --- a/web/frontend/src/config/admin/ShowUsersRow.svelte +++ b/web/frontend/src/config/admin/ShowUsersRow.svelte @@ -1,28 +1,32 @@ {user.username} {user.name} {user.projects} {user.email} -{user.roles.join(', ')} +{user.roles.join(", ")} - {#if ! jwt} - - {:else} - - {/if} + {#if !jwt} + + {:else} + + {/if} diff --git a/web/frontend/src/filters/Cluster.svelte b/web/frontend/src/filters/Cluster.svelte index 2740b74..9c82321 100644 --- a/web/frontend/src/filters/Cluster.svelte +++ b/web/frontend/src/filters/Cluster.svelte @@ -1,77 +1,95 @@ - (isOpen = !isOpen)}> - - Select Cluster & Slurm Partition - - - {#if $initialized} -

    Cluster

    - - (pendingCluster = null, pendingPartition = null)}> - Any Cluster - - {#each clusters as cluster} - (pendingCluster = cluster.name, pendingPartition = null)}> - {cluster.name} - - {/each} - - {/if} - {#if $initialized && pendingCluster != null} -
    -

    Partiton

    - - (pendingPartition = null)}> - Any Partition - - {#each clusters.find(c => c.name == pendingCluster).partitions as partition} - (pendingPartition = partition)}> - {partition} - - {/each} - - {/if} -
    - - - - - + (isOpen = !isOpen)}> + Select Cluster & Slurm Partition + + {#if $initialized} +

    Cluster

    + + ((pendingCluster = null), (pendingPartition = null))} + > + Any Cluster + + {#each clusters as cluster} + ( + (pendingCluster = cluster.name), (pendingPartition = null) + )} + > + {cluster.name} + + {/each} + + {/if} + {#if $initialized && pendingCluster != null} +
    +

    Partiton

    + + (pendingPartition = null)} + > + Any Partition + + {#each clusters.find((c) => c.name == pendingCluster).partitions as partition} + (pendingPartition = partition)} + > + {partition} + + {/each} + + {/if} +
    + + + + +
    diff --git a/web/frontend/src/filters/Duration.svelte b/web/frontend/src/filters/Duration.svelte index ca2ce45..132ce05 100644 --- a/web/frontend/src/filters/Duration.svelte +++ b/web/frontend/src/filters/Duration.svelte @@ -1,158 +1,244 @@ - (isOpen = !isOpen)}> - - Select Job Duration - - -

    Duration more than

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -
    + (isOpen = !isOpen)}> + Select Job Duration + +

    Duration more than

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +
    -

    Duration less than

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -
    +

    Duration less than

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +
    -

    Duration between

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -

    and

    - - -
    - -
    -
    h
    -
    -
    - - -
    - -
    -
    m
    -
    -
    - -
    -
    - - - - - - +

    Duration between

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +

    and

    + + +
    + +
    +
    h
    +
    +
    + + +
    + +
    +
    m
    +
    +
    + +
    +
    + + + + + +
    diff --git a/web/frontend/src/filters/Filters.svelte b/web/frontend/src/filters/Filters.svelte index 49eaed6..8e7a8ef 100644 --- a/web/frontend/src/filters/Filters.svelte +++ b/web/frontend/src/filters/Filters.svelte @@ -10,373 +10,418 @@ - void update(additionalFilters: Object?): Triggers an update --> - - - - - Filters - - - - Manage Filters - - {#if menuText} - {menuText} - - {/if} - (isClusterOpen = true)}> - Cluster/Partition - - (isJobStatesOpen = true)}> - Job States - - (isStartTimeOpen = true)}> - Start Time - - (isDurationOpen = true)}> - Duration - - (isTagsOpen = true)}> - Tags - - (isResourcesOpen = true)}> - Resources - - (isStatsOpen = true)}> - (isStatsOpen = true)}/> Statistics - - {#if startTimeQuickSelect} - - Start Time Qick Selection - {#each [ - { text: 'Last 6hrs', url: 'last6h', seconds: 6*60*60 }, - // { text: 'Last 12hrs', seconds: 12*60*60 }, - { text: 'Last 24hrs', url: 'last24h', seconds: 24*60*60 }, - // { text: 'Last 48hrs', seconds: 48*60*60 }, - { text: 'Last 7 days', url: 'last7d', seconds: 7*24*60*60 }, - { text: 'Last 30 days', url: 'last30d', seconds: 30*24*60*60 } - ] as {text, url, seconds}} - { - filters.startTime.from = (new Date(Date.now() - seconds * 1000)).toISOString() - filters.startTime.to = (new Date(Date.now())).toISOString() - filters.startTime.text = text, - filters.startTime.url = url - update() - }}> - {text} - - {/each} - {/if} - - - - - {#if filters.cluster} - (isClusterOpen = true)}> - {filters.cluster} - {#if filters.partition} - ({filters.partition}) - {/if} - + + + + + Filters + + + Manage Filters + {#if menuText} + {menuText} + {/if} + (isClusterOpen = true)}> + Cluster/Partition + + (isJobStatesOpen = true)}> + Job States + + (isStartTimeOpen = true)}> + Start Time + + (isDurationOpen = true)}> + Duration + + (isTagsOpen = true)}> + Tags + + (isResourcesOpen = true)}> + Resources + + (isStatsOpen = true)}> + (isStatsOpen = true)} /> Statistics + + {#if startTimeQuickSelect} + + Start Time Qick Selection + {#each [{ text: "Last 6hrs", url: "last6h", seconds: 6 * 60 * 60 }, { text: "Last 24hrs", url: "last24h", seconds: 24 * 60 * 60 }, { text: "Last 7 days", url: "last7d", seconds: 7 * 24 * 60 * 60 }, { text: "Last 30 days", url: "last30d", seconds: 30 * 24 * 60 * 60 }] as { text, url, seconds }} + { + filters.startTime.from = new Date( + Date.now() - seconds * 1000, + ).toISOString(); + filters.startTime.to = new Date(Date.now()).toISOString(); + (filters.startTime.text = text), (filters.startTime.url = url); + update(); + }} + > + + {text} + + {/each} + {/if} + + + + + {#if filters.cluster} + (isClusterOpen = true)}> + {filters.cluster} + {#if filters.partition} + ({filters.partition}) + {/if} + + {/if} - {#if filters.states.length != allJobStates.length} - (isJobStatesOpen = true)}> - {filters.states.join(', ')} - - {/if} + {#if filters.states.length != allJobStates.length} + (isJobStatesOpen = true)}> + {filters.states.join(", ")} + + {/if} - {#if filters.startTime.from || filters.startTime.to} - (isStartTimeOpen = true)}> - {#if filters.startTime.text} - {filters.startTime.text} - {:else} - {new Date(filters.startTime.from).toLocaleString()} - {new Date(filters.startTime.to).toLocaleString()} - {/if} - + {#if filters.startTime.from || filters.startTime.to} + (isStartTimeOpen = true)}> + {#if filters.startTime.text} + {filters.startTime.text} + {:else} + {new Date(filters.startTime.from).toLocaleString()} - {new Date( + filters.startTime.to, + ).toLocaleString()} {/if} + + {/if} - {#if filters.duration.from || filters.duration.to} - (isDurationOpen = true)}> - {Math.floor(filters.duration.from / 3600)}h:{Math.floor(filters.duration.from % 3600 / 60)}m - - - {Math.floor(filters.duration.to / 3600)}h:{Math.floor(filters.duration.to % 3600 / 60)}m - - {/if} + {#if filters.duration.from || filters.duration.to} + (isDurationOpen = true)}> + {Math.floor(filters.duration.from / 3600)}h:{Math.floor( + (filters.duration.from % 3600) / 60, + )}m - + {Math.floor(filters.duration.to / 3600)}h:{Math.floor( + (filters.duration.to % 3600) / 60, + )}m + + {/if} - {#if filters.duration.lessThan} - (isDurationOpen = true)}> - Duration less than {Math.floor(filters.duration.lessThan / 3600)}h:{Math.floor(filters.duration.lessThan % 3600 / 60)}m - - {/if} + {#if filters.duration.lessThan} + (isDurationOpen = true)}> + Duration less than {Math.floor( + filters.duration.lessThan / 3600, + )}h:{Math.floor((filters.duration.lessThan % 3600) / 60)}m + + {/if} - {#if filters.duration.moreThan} - (isDurationOpen = true)}> - Duration more than {Math.floor(filters.duration.moreThan / 3600)}h:{Math.floor(filters.duration.moreThan % 3600 / 60)}m - - {/if} + {#if filters.duration.moreThan} + (isDurationOpen = true)}> + Duration more than {Math.floor( + filters.duration.moreThan / 3600, + )}h:{Math.floor((filters.duration.moreThan % 3600) / 60)}m + + {/if} - {#if filters.tags.length != 0} - (isTagsOpen = true)}> - {#each filters.tags as tagId} - - {/each} - - {/if} + {#if filters.tags.length != 0} + (isTagsOpen = true)}> + {#each filters.tags as tagId} + + {/each} + + {/if} - {#if filters.numNodes.from != null || filters.numNodes.to != null || - filters.numHWThreads.from != null || filters.numHWThreads.to != null || - filters.numAccelerators.from != null || filters.numAccelerators.to != null } - (isResourcesOpen = true)}> - {#if isNodesModified } Nodes: {filters.numNodes.from} - {filters.numNodes.to} {/if} - {#if isNodesModified && isHwthreadsModified }, {/if} - {#if isHwthreadsModified } HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} {/if} - {#if (isNodesModified || isHwthreadsModified) && isAccsModified }, {/if} - {#if isAccsModified } Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to} {/if} - + {#if filters.numNodes.from != null || filters.numNodes.to != null || filters.numHWThreads.from != null || filters.numHWThreads.to != null || filters.numAccelerators.from != null || filters.numAccelerators.to != null} + (isResourcesOpen = true)}> + {#if isNodesModified} + Nodes: {filters.numNodes.from} - {filters.numNodes.to} {/if} + {#if isNodesModified && isHwthreadsModified}, + {/if} + {#if isHwthreadsModified} + HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} + {/if} + {#if (isNodesModified || isHwthreadsModified) && isAccsModified}, + {/if} + {#if isAccsModified} + Accelerators: {filters.numAccelerators.from} - {filters + .numAccelerators.to} + {/if} + + {/if} - {#if filters.node != null } - (isResourcesOpen = true)}> - Node: {filters.node} - - {/if} + {#if filters.node != null} + (isResourcesOpen = true)}> + Node: {filters.node} + + {/if} - {#if filters.stats.length > 0} - (isStatsOpen = true)}> - {filters.stats.map(stat => `${stat.text}: ${stat.from} - ${stat.to}`).join(', ')} - - {/if} - + {#if filters.stats.length > 0} + (isStatsOpen = true)}> + {filters.stats + .map((stat) => `${stat.text}: ${stat.from} - ${stat.to}`) + .join(", ")} + + {/if} + update()} /> + {disableClusterSelection} + bind:isOpen={isClusterOpen} + bind:cluster={filters.cluster} + bind:partition={filters.partition} + on:update={() => update()} +/> update()} /> + bind:isOpen={isJobStatesOpen} + bind:states={filters.states} + on:update={() => update()} +/> { - delete filters.startTime['text'] - delete filters.startTime['url'] - update() - }} /> + bind:isOpen={isStartTimeOpen} + bind:from={filters.startTime.from} + bind:to={filters.startTime.to} + on:update={() => { + delete filters.startTime["text"]; + delete filters.startTime["url"]; + update(); + }} +/> update()} /> + bind:isOpen={isDurationOpen} + bind:lessThan={filters.duration.lessThan} + bind:moreThan={filters.duration.moreThan} + bind:from={filters.duration.from} + bind:to={filters.duration.to} + on:update={() => update()} +/> update()} /> + bind:isOpen={isTagsOpen} + bind:tags={filters.tags} + on:update={() => update()} +/> - update()} /> + update()} +/> - update()} /> + update()} +/> diff --git a/web/frontend/src/filters/InfoBox.svelte b/web/frontend/src/filters/InfoBox.svelte index 58fc8a5..8fe75ab 100644 --- a/web/frontend/src/filters/InfoBox.svelte +++ b/web/frontend/src/filters/InfoBox.svelte @@ -1,11 +1,11 @@ - diff --git a/web/frontend/src/filters/JobStates.svelte b/web/frontend/src/filters/JobStates.svelte index 4e5db2e..e22144f 100644 --- a/web/frontend/src/filters/JobStates.svelte +++ b/web/frontend/src/filters/JobStates.svelte @@ -1,47 +1,76 @@ + - (isOpen = !isOpen)}> - - Select Job States - - - - {#each allJobStates as state} - - - {state} - - {/each} - - - - - - - + (isOpen = !isOpen)}> + Select Job States + + + {#each allJobStates as state} + + + {state} + + {/each} + + + + + + + diff --git a/web/frontend/src/filters/Resources.svelte b/web/frontend/src/filters/Resources.svelte index be5995a..01f1c57 100644 --- a/web/frontend/src/filters/Resources.svelte +++ b/web/frontend/src/filters/Resources.svelte @@ -1,145 +1,242 @@ - (isOpen = !isOpen)}> - - Select number of utilized Resources - - -
    Named Node
    - -
    Number of Nodes
    - { - pendingNumNodes = { from: detail[0], to: detail[1] } - isNodesModified = true - }} - min={minNumNodes} max={maxNumNodes} - firstSlider={pendingNumNodes.from} secondSlider={pendingNumNodes.to} - inputFieldFrom={pendingNumNodes.from} inputFieldTo={pendingNumNodes.to}/> -
    Number of HWThreads (Use for Single-Node Jobs)
    - { - pendingNumHWThreads = { from: detail[0], to: detail[1] } - isHwthreadsModified = true - }} - min={minNumHWThreads} max={maxNumHWThreads} - firstSlider={pendingNumHWThreads.from} secondSlider={pendingNumHWThreads.to} - inputFieldFrom={pendingNumHWThreads.from} inputFieldTo={pendingNumHWThreads.to}/> - {#if maxNumAccelerators != null && maxNumAccelerators > 1} -
    Number of Accelerators
    - { - pendingNumAccelerators = { from: detail[0], to: detail[1] } - isAccsModified = true - }} - min={minNumAccelerators} max={maxNumAccelerators} - firstSlider={pendingNumAccelerators.from} secondSlider={pendingNumAccelerators.to} - inputFieldFrom={pendingNumAccelerators.from} inputFieldTo={pendingNumAccelerators.to}/> - {/if} -
    - - - - - + (isOpen = !isOpen)}> + Select number of utilized Resources + +
    Named Node
    + +
    Number of Nodes
    + { + pendingNumNodes = { from: detail[0], to: detail[1] }; + isNodesModified = true; + }} + min={minNumNodes} + max={maxNumNodes} + firstSlider={pendingNumNodes.from} + secondSlider={pendingNumNodes.to} + inputFieldFrom={pendingNumNodes.from} + inputFieldTo={pendingNumNodes.to} + /> +
    + Number of HWThreads (Use for Single-Node Jobs) +
    + { + pendingNumHWThreads = { from: detail[0], to: detail[1] }; + isHwthreadsModified = true; + }} + min={minNumHWThreads} + max={maxNumHWThreads} + firstSlider={pendingNumHWThreads.from} + secondSlider={pendingNumHWThreads.to} + inputFieldFrom={pendingNumHWThreads.from} + inputFieldTo={pendingNumHWThreads.to} + /> + {#if maxNumAccelerators != null && maxNumAccelerators > 1} +
    Number of Accelerators
    + { + pendingNumAccelerators = { from: detail[0], to: detail[1] }; + isAccsModified = true; + }} + min={minNumAccelerators} + max={maxNumAccelerators} + firstSlider={pendingNumAccelerators.from} + secondSlider={pendingNumAccelerators.to} + inputFieldFrom={pendingNumAccelerators.from} + inputFieldTo={pendingNumAccelerators.to} + /> + {/if} +
    + + + + +
    diff --git a/web/frontend/src/filters/StartTime.svelte b/web/frontend/src/filters/StartTime.svelte index 59f8513..1759b6e 100644 --- a/web/frontend/src/filters/StartTime.svelte +++ b/web/frontend/src/filters/StartTime.svelte @@ -1,86 +1,121 @@ - (isOpen = !isOpen)}> - - Select Start Time - - -

    From

    - - - - - - - - -

    To

    - - - - - - - - -
    - - - - - + (isOpen = !isOpen)}> + Select Start Time + +

    From

    + + + + + + + + +

    To

    + + + + + + + + +
    + + + + +
    diff --git a/web/frontend/src/filters/Stats.svelte b/web/frontend/src/filters/Stats.svelte index cf559da..ee80a4b 100644 --- a/web/frontend/src/filters/Stats.svelte +++ b/web/frontend/src/filters/Stats.svelte @@ -1,115 +1,137 @@ - (isOpen = !isOpen)}> - - Filter based on statistics (of non-running jobs) - - - {#each statistics as stat} -

    {stat.text}

    - (stat.from = detail[0], stat.to = detail[1], stat.enabled = true)} - min={0} max={stat.peak} - firstSlider={stat.from} secondSlider={stat.to} - inputFieldFrom={stat.from} inputFieldTo={stat.to}/> - {/each} -
    - - - - - + (isOpen = !isOpen)}> + Filter based on statistics (of non-running jobs) + + {#each statistics as stat} +

    {stat.text}

    + ( + (stat.from = detail[0]), (stat.to = detail[1]), (stat.enabled = true) + )} + min={0} + max={stat.peak} + firstSlider={stat.from} + secondSlider={stat.to} + inputFieldFrom={stat.from} + inputFieldTo={stat.to} + /> + {/each} +
    + + + + +
    diff --git a/web/frontend/src/filters/Tags.svelte b/web/frontend/src/filters/Tags.svelte index b5a145a..06153ed 100644 --- a/web/frontend/src/filters/Tags.svelte +++ b/web/frontend/src/filters/Tags.svelte @@ -1,67 +1,89 @@ - (isOpen = !isOpen)}> - - Select Tags - - - -
    - - {#if $initialized} - {#each fuzzySearchTags(searchTerm, allTags) as tag (tag)} - - {#if pendingTags.includes(tag.id)} - - {:else} - - {/if} - - - - {:else} - No Tags - {/each} + (isOpen = !isOpen)}> + Select Tags + + +
    + + {#if $initialized} + {#each fuzzySearchTags(searchTerm, allTags) as tag (tag)} + + {#if pendingTags.includes(tag.id)} + + {:else} + {/if} - -
    - - - - - + + + + {:else} + No Tags + {/each} + {/if} +
    +
    + + + + +
    diff --git a/web/frontend/src/filters/TimeSelection.svelte b/web/frontend/src/filters/TimeSelection.svelte index c715b9c..f9c230b 100644 --- a/web/frontend/src/filters/TimeSelection.svelte +++ b/web/frontend/src/filters/TimeSelection.svelte @@ -1,81 +1,96 @@ - - - - {#if timeRange == -1} - from - updateExplicitTimeRange('from', event)}> - to - updateExplicitTimeRange('to', event)}> + + {#if timeRange == -1} + from + updateExplicitTimeRange("from", event)} + > + to + updateExplicitTimeRange("to", event)} + > + {/if} diff --git a/web/frontend/src/filters/UserOrProject.svelte b/web/frontend/src/filters/UserOrProject.svelte index 8235863..983192c 100644 --- a/web/frontend/src/filters/UserOrProject.svelte +++ b/web/frontend/src/filters/UserOrProject.svelte @@ -1,75 +1,84 @@ {#if authlevel >= roles.manager} - - - termChanged()} on:keyup={(event) => termChanged(event.key == 'Enter' ? 0 : throttle)} - placeholder={mode == 'user' ? 'filter username...' : 'filter project...'} /> - + + + termChanged()} + on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)} + placeholder={mode == "user" ? "filter username..." : "filter project..."} + /> + {:else} - - - termChanged()} on:keyup={(event) => termChanged(event.key == 'Enter' ? 0 : throttle)} placeholder='filter project...' - /> - + + + termChanged()} + on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)} + placeholder="filter project..." + /> + {/if} diff --git a/web/frontend/src/joblist/JobInfo.svelte b/web/frontend/src/joblist/JobInfo.svelte index b7ca32a..a30d058 100644 --- a/web/frontend/src/joblist/JobInfo.svelte +++ b/web/frontend/src/joblist/JobInfo.svelte @@ -6,115 +6,138 @@ - jobTags: Defaults to job.tags, usefull for dynamically updating the tags. --> +
    -

    - {job.jobId} ({job.cluster}) - {#if job.metaData?.jobName} -
    - {#if job.metaData?.jobName.length <= 25} -

    {job.metaData.jobName}
    - {:else} -
    {job.metaData.jobName}
    - {/if} - {/if} - {#if job.arrayJobId} - Array Job: #{job.arrayJobId} - {/if} -

    +

    + {job.jobId} + ({job.cluster}) + {#if job.metaData?.jobName} +
    + {#if job.metaData?.jobName.length <= 25} +

    {job.metaData.jobName}
    + {:else} +
    + {job.metaData.jobName} +
    + {/if} + {/if} + {#if job.arrayJobId} + Array Job: #{job.arrayJobId} + {/if} +

    -

    - - - {scrambleNames ? scramble(job.user) : job.user} - - {#if job.userData && job.userData.name} - ({scrambleNames ? scramble(job.userData.name) : job.userData.name}) - {/if} - {#if job.project && job.project != 'no project'} -
    - - - {scrambleNames ? scramble(job.project) : job.project} - - {/if} -

    +

    + + + {scrambleNames ? scramble(job.user) : job.user} + + {#if job.userData && job.userData.name} + ({scrambleNames ? scramble(job.userData.name) : job.userData.name}) + {/if} + {#if job.project && job.project != "no project"} +
    + + + {scrambleNames ? scramble(job.project) : job.project} + + {/if} +

    -

    - {#if job.numNodes == 1} - {job.resources[0].hostname} - {:else} - {job.numNodes} - {/if} - - {#if job.exclusive != 1} - (shared) - {/if} - {#if job.numAcc > 0} - , {job.numAcc} - {/if} - {#if job.numHWThreads > 0} - , {job.numHWThreads} - {/if} -
    - {job.subCluster} -

    +

    + {#if job.numNodes == 1} + {job.resources[0].hostname} + {:else} + {job.numNodes} + {/if} + + {#if job.exclusive != 1} + (shared) + {/if} + {#if job.numAcc > 0} + , {job.numAcc} + {/if} + {#if job.numHWThreads > 0} + , {job.numHWThreads} + {/if} +
    + {job.subCluster} +

    -

    - Start: {(new Date(job.startTime)).toLocaleString()} -
    - Duration: {formatDuration(job.duration)} {job.state} - {#if job.walltime} -
    - Walltime: {formatDuration(job.walltime)} - {/if} -

    +

    + Start: {new Date(job.startTime).toLocaleString()} +
    + Duration: {formatDuration(job.duration)} + {job.state} + {#if job.walltime} +
    + Walltime: {formatDuration(job.walltime)} + {/if} +

    -

    - {#each jobTags as tag} - - {/each} -

    +

    + {#each jobTags as tag} + + {/each} +

    diff --git a/web/frontend/src/joblist/JobList.svelte b/web/frontend/src/joblist/JobList.svelte index 5f8d89b..3efe069 100644 --- a/web/frontend/src/joblist/JobList.svelte +++ b/web/frontend/src/joblist/JobList.svelte @@ -9,284 +9,275 @@ - update(filters?: [JobFilter]) --> -
    - - - - - {#if showFootprint} - - {/if} - {#each metrics as metric (metric)} - - {/each} - - - - {#if $jobs.error} - - - - {:else if $jobs.fetching || !$jobs.data} - - - - {:else if $jobs.data && $initialized} - {#each $jobs.data.jobs.items as job (job)} - - {:else} - - - - {/each} - {/if} - -
    - Job Info - - Job Footprint - - {metric} - {#if $initialized} - ({clusters - .map((cluster) => - cluster.metricConfig.find( - (m) => m.name == metric - ) - ) - .filter((m) => m != null) - .map( - (m) => - (m.unit?.prefix - ? m.unit?.prefix - : "") + - (m.unit?.base ? m.unit?.base : "") - ) // Build unitStr - .reduce( - (arr, unitStr) => - arr.includes(unitStr) - ? arr - : [...arr, unitStr], - [] - ) // w/o this, output would be [unitStr, unitStr] - .join(", ")}) - {/if} -
    -

    {$jobs.error.message}

    -
    - -
    - No jobs found -
    -
    +
    + + + + + {#if showFootprint} + + {/if} + {#each metrics as metric (metric)} + + {/each} + + + + {#if $jobs.error} + + + + {:else if $jobs.fetching || !$jobs.data} + + + + {:else if $jobs.data && $initialized} + {#each $jobs.data.jobs.items as job (job)} + + {:else} + + + + {/each} + {/if} + +
    + Job Info + + Job Footprint + + {metric} + {#if $initialized} + ({clusters + .map((cluster) => + cluster.metricConfig.find((m) => m.name == metric), + ) + .filter((m) => m != null) + .map( + (m) => + (m.unit?.prefix ? m.unit?.prefix : "") + + (m.unit?.base ? m.unit?.base : ""), + ) // Build unitStr + .reduce( + (arr, unitStr) => + arr.includes(unitStr) ? arr : [...arr, unitStr], + [], + ) // w/o this, output would be [unitStr, unitStr] + .join(", ")}) + {/if} +
    +

    {$jobs.error.message}

    +
    + +
    No jobs found
    +
    { - if (detail.itemsPerPage != itemsPerPage) { - updateConfiguration( - detail.itemsPerPage.toString(), - detail.page - ) - } else { - paging = { itemsPerPage: detail.itemsPerPage, page: detail.page } - } - }} + bind:page + {itemsPerPage} + itemText="Jobs" + totalItems={matchedJobs} + on:update={({ detail }) => { + if (detail.itemsPerPage != itemsPerPage) { + updateConfiguration(detail.itemsPerPage.toString(), detail.page); + } else { + paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; + } + }} /> diff --git a/web/frontend/src/joblist/Refresher.svelte b/web/frontend/src/joblist/Refresher.svelte index 2587711..635ffbe 100644 --- a/web/frontend/src/joblist/Refresher.svelte +++ b/web/frontend/src/joblist/Refresher.svelte @@ -5,39 +5,46 @@ - 'reload': When fired, the parent component shoud refresh its contents --> - - - \ No newline at end of file + + + + diff --git a/web/frontend/src/joblist/Row.svelte b/web/frontend/src/joblist/Row.svelte index 4d9013c..dd58241 100644 --- a/web/frontend/src/joblist/Row.svelte +++ b/web/frontend/src/joblist/Row.svelte @@ -9,168 +9,190 @@ --> - - + + + + {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} + + Not monitored or archiving failed - {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} - - Not monitored or archiving failed - - {:else if $metricsQuery.fetching} - - - - {:else if $metricsQuery.error} - - - {$metricsQuery.error.message.length > 500 - ? $metricsQuery.error.message.substring(0, 499) + "..." - : $metricsQuery.error.message} - - - {:else} - {#if showFootprint} - - - - {/if} - {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} - - - {#if metric.disabled == false && metric.data} - - {:else if metric.disabled == true && metric.data} - Metric disabled for subcluster {metric.data.name}:{job.subCluster} - {:else} - No dataset returned - {/if} - - {/each} + {:else if $metricsQuery.fetching} + + + + {:else if $metricsQuery.error} + + + {$metricsQuery.error.message.length > 500 + ? $metricsQuery.error.message.substring(0, 499) + "..." + : $metricsQuery.error.message} + + + {:else} + {#if showFootprint} + + + {/if} + {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} + + + {#if metric.disabled == false && metric.data} + + {:else if metric.disabled == true && metric.data} + Metric disabled for subcluster {metric.data.name}:{job.subCluster} + {:else} + No dataset returned + {/if} + + {/each} + {/if} diff --git a/web/frontend/src/joblist/SortSelection.svelte b/web/frontend/src/joblist/SortSelection.svelte index 5941964..2cc8615 100644 --- a/web/frontend/src/joblist/SortSelection.svelte +++ b/web/frontend/src/joblist/SortSelection.svelte @@ -7,65 +7,94 @@ --> - { isOpen = !isOpen }}> - - Sort rows - - - - {#each sortableColumns as col, i (col)} - - + sortableColumns[i] = { ...sortableColumns[i] }; + activeColumnIdx = i; + sortableColumns = [...sortableColumns]; + sorting = { field: col.field, order: col.order }; + }} + > + + - {col.text} - - {/each} - - - - - + {col.text} + + {/each} + + + + + \ No newline at end of file + .sort { + border: none; + margin: 0; + padding: 0; + background: 0 0; + transition: all 70ms; + } + + diff --git a/web/frontend/src/plots/Histogram.svelte b/web/frontend/src/plots/Histogram.svelte index 499ea4f..8300384 100644 --- a/web/frontend/src/plots/Histogram.svelte +++ b/web/frontend/src/plots/Histogram.svelte @@ -5,221 +5,222 @@ --> {#if data.length > 0} -
    +
    {:else} - Cannot render histogram: No data! + Cannot render histogram: No data! {/if} - - diff --git a/web/frontend/src/plots/MetricPlot.svelte b/web/frontend/src/plots/MetricPlot.svelte index 7bd264c..bd44675 100644 --- a/web/frontend/src/plots/MetricPlot.svelte +++ b/web/frontend/src/plots/MetricPlot.svelte @@ -1,3 +1,122 @@ + + - {#if series[0].data.length > 0} -
    +
    {:else} - Cannot render plot: No series data returned for {metric} + Cannot render plot: No series data returned for {metric} {/if} diff --git a/web/frontend/src/plots/Roofline.svelte b/web/frontend/src/plots/Roofline.svelte index d4ed5f6..1e47f6f 100644 --- a/web/frontend/src/plots/Roofline.svelte +++ b/web/frontend/src/plots/Roofline.svelte @@ -1,254 +1,339 @@ {#if data != null} -
    +
    {:else} - Cannot render roofline: No data! -{/if} \ No newline at end of file + Cannot render roofline: No data! +{/if} +