1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Migrate to material react table

This commit is contained in:
Bill Thornton 2024-08-26 17:10:35 -04:00
parent 6b4ad3717f
commit 694ba9718d
4 changed files with 480 additions and 198 deletions

388
package-lock.json generated
View file

@ -22,6 +22,7 @@
"@mui/icons-material": "5.15.19",
"@mui/material": "5.15.19",
"@mui/x-data-grid": "7.6.1",
"@mui/x-date-pickers": "7.14.0",
"@react-hook/resize-observer": "2.0.2",
"@tanstack/react-query": "5.51.24",
"@tanstack/react-query-devtools": "5.51.24",
@ -48,6 +49,7 @@
"lodash-es": "4.17.21",
"markdown-it": "14.1.0",
"material-design-icons-iconfont": "6.7.0",
"material-react-table": "2.13.1",
"native-promise-only": "0.8.1",
"pdfjs-dist": "3.11.174",
"react": "18.3.1",
@ -2006,10 +2008,9 @@
"dev": true
},
"node_modules/@babel/runtime": {
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
"integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
"license": "MIT",
"version": "7.25.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz",
"integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@ -5418,12 +5419,12 @@
"license": "MIT"
},
"node_modules/@mui/private-theming": {
"version": "5.15.14",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz",
"integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==",
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz",
"integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/utils": "^5.15.14",
"@mui/utils": "^5.16.6",
"prop-types": "^15.8.1"
},
"engines": {
@ -5444,9 +5445,9 @@
}
},
"node_modules/@mui/styled-engine": {
"version": "5.15.14",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz",
"integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==",
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz",
"integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@emotion/cache": "^11.11.0",
@ -5475,15 +5476,15 @@
}
},
"node_modules/@mui/system": {
"version": "5.15.15",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.15.tgz",
"integrity": "sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==",
"version": "5.16.7",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz",
"integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/private-theming": "^5.15.14",
"@mui/styled-engine": "^5.15.14",
"@mui/types": "^7.2.14",
"@mui/utils": "^5.15.14",
"@mui/private-theming": "^5.16.6",
"@mui/styled-engine": "^5.16.6",
"@mui/types": "^7.2.15",
"@mui/utils": "^5.16.6",
"clsx": "^2.1.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
@ -5514,9 +5515,9 @@
}
},
"node_modules/@mui/types": {
"version": "7.2.14",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz",
"integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==",
"version": "7.2.15",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz",
"integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==",
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0"
},
@ -5527,14 +5528,16 @@
}
},
"node_modules/@mui/utils": {
"version": "5.15.14",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz",
"integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==",
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz",
"integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@types/prop-types": "^15.7.11",
"@mui/types": "^7.2.15",
"@types/prop-types": "^15.7.12",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
"react-is": "^18.3.1"
},
"engines": {
"node": ">=12.0.0"
@ -5554,9 +5557,9 @@
}
},
"node_modules/@mui/utils/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
"node_modules/@mui/x-data-grid": {
"version": "7.6.1",
@ -5584,6 +5587,70 @@
"react-dom": "^17.0.0 || ^18.0.0"
}
},
"node_modules/@mui/x-date-pickers": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.14.0.tgz",
"integrity": "sha512-3xI3xYVxqPU4//KfE4FcR+Zs7UT4kkDPvA+IDOcQdRUyVwmcXCjBuJZgKgJMqSCNK/KIJZQQrpmy5XGHOKTbdA==",
"dependencies": {
"@babel/runtime": "^7.25.0",
"@mui/system": "^5.16.7",
"@mui/utils": "^5.16.6",
"@types/react-transition-group": "^4.4.11",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.15.14",
"date-fns": "^2.25.0 || ^3.2.0",
"date-fns-jalali": "^2.13.0-0 || ^3.2.0-0",
"dayjs": "^1.10.7",
"luxon": "^3.0.2",
"moment": "^2.29.4",
"moment-hijri": "^2.1.2",
"moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"date-fns": {
"optional": true
},
"date-fns-jalali": {
"optional": true
},
"dayjs": {
"optional": true
},
"luxon": {
"optional": true
},
"moment": {
"optional": true
},
"moment-hijri": {
"optional": true
},
"moment-jalaali": {
"optional": true
}
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -6254,6 +6321,21 @@
"node": ">=10"
}
},
"node_modules/@tanstack/match-sorter-utils": {
"version": "8.15.1",
"resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.15.1.tgz",
"integrity": "sha512-PnVV3d2poenUM31ZbZi/yXkBu3J7kd5k2u51CGwwNojag451AjTH9N6n41yjXz2fpLeewleyLBmNS6+HcGDlXw==",
"dependencies": {
"remove-accents": "0.5.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/query-core": {
"version": "5.51.24",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.24.tgz",
@ -6307,6 +6389,62 @@
"react": "^18 || ^19"
}
},
"node_modules/@tanstack/react-table": {
"version": "8.19.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.19.3.tgz",
"integrity": "sha512-MtgPZc4y+cCRtU16y1vh1myuyZ2OdkWgMEBzyjYsoMWMicKZGZvcDnub3Zwb6XF2pj9iRMvm1SO1n57lS0vXLw==",
"dependencies": {
"@tanstack/table-core": "8.19.3"
},
"engines": {
"node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/@tanstack/react-virtual": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.8.3.tgz",
"integrity": "sha512-9ICwbDUUzN99CJIGc373i8NLoj6zFTKI2Hlcmo0+lCSAhPQ5mxq4dGOMKmLYoEFyHcGQ64Bd6ZVbnPpM6lNK5w==",
"dependencies": {
"@tanstack/virtual-core": "3.8.3"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@tanstack/table-core": {
"version": "8.19.3",
"resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.19.3.tgz",
"integrity": "sha512-IqREj9ADoml9zCAouIG/5kCGoyIxPFdqdyoxis9FisXFi5vT+iYfEfLosq4xkU/iDbMcEuAj+X8dWRLvKYDNoQ==",
"engines": {
"node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/virtual-core": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.3.tgz",
"integrity": "sha512-vd2A2TnM5lbnWZnHi9B+L2gPtkSeOtJOAw358JqokIH1+v2J7vUAzFVPwB/wrye12RFOurffXu33plm4uQ+JBQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@ -6585,9 +6723,9 @@
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
},
"node_modules/@types/prop-types": {
"version": "15.7.11",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
"version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
},
"node_modules/@types/qs": {
"version": "6.9.7",
@ -6630,9 +6768,9 @@
}
},
"node_modules/@types/react-transition-group": {
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz",
"integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==",
"version": "4.4.11",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
"integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
"dependencies": {
"@types/react": "*"
}
@ -13202,6 +13340,15 @@
"resolved": "https://registry.npmjs.org/headroom.js/-/headroom.js-0.12.0.tgz",
"integrity": "sha512-iXnAafUm3FdzfJ91uixLws2hkKI1jC8bAKK/pt7XYr8Ie1jO7xbK48Ycpl9tUPyBgkzuj1p/PhJS0fy4E/5anA=="
},
"node_modules/highlight-words": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/highlight-words/-/highlight-words-1.2.2.tgz",
"integrity": "sha512-Mf4xfPXYm8Ay1wTibCrHpNWeR2nUMynMVFkXCi4mbl+TEgmNOe+I4hV7W3OCZcSvzGL6kupaqpfHOemliMTGxQ==",
"engines": {
"node": ">= 16",
"npm": ">= 8"
}
},
"node_modules/history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
@ -15471,6 +15618,33 @@
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz",
"integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA=="
},
"node_modules/material-react-table": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/material-react-table/-/material-react-table-2.13.1.tgz",
"integrity": "sha512-3iWwCa24ogxwllP4+W11euR/GV6f5wQE5FEilJ72/H3hDYHgsN+XehANytaG0G7/qy/OWYE7oXkcsRUU35I/iA==",
"dependencies": {
"@tanstack/match-sorter-utils": "8.15.1",
"@tanstack/react-table": "8.19.3",
"@tanstack/react-virtual": "3.8.3",
"highlight-words": "1.2.2"
},
"engines": {
"node": ">=16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kevinvandy"
},
"peerDependencies": {
"@emotion/react": ">=11.11",
"@emotion/styled": ">=11.11",
"@mui/icons-material": ">=5.11",
"@mui/material": ">=5.13",
"@mui/x-date-pickers": ">=6.15.0",
"react": ">=17.0",
"react-dom": ">=17.0"
}
},
"node_modules/mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@ -19948,6 +20122,11 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/remove-accents": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
"integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="
},
"node_modules/renderkid": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz",
@ -28243,9 +28422,9 @@
"dev": true
},
"@babel/runtime": {
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
"integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
"version": "7.25.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz",
"integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==",
"requires": {
"regenerator-runtime": "^0.14.0"
}
@ -29785,19 +29964,19 @@
}
},
"@mui/private-theming": {
"version": "5.15.14",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz",
"integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==",
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz",
"integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==",
"requires": {
"@babel/runtime": "^7.23.9",
"@mui/utils": "^5.15.14",
"@mui/utils": "^5.16.6",
"prop-types": "^15.8.1"
}
},
"@mui/styled-engine": {
"version": "5.15.14",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz",
"integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==",
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz",
"integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==",
"requires": {
"@babel/runtime": "^7.23.9",
"@emotion/cache": "^11.11.0",
@ -29806,41 +29985,43 @@
}
},
"@mui/system": {
"version": "5.15.15",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.15.tgz",
"integrity": "sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==",
"version": "5.16.7",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz",
"integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==",
"requires": {
"@babel/runtime": "^7.23.9",
"@mui/private-theming": "^5.15.14",
"@mui/styled-engine": "^5.15.14",
"@mui/types": "^7.2.14",
"@mui/utils": "^5.15.14",
"@mui/private-theming": "^5.16.6",
"@mui/styled-engine": "^5.16.6",
"@mui/types": "^7.2.15",
"@mui/utils": "^5.16.6",
"clsx": "^2.1.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
}
},
"@mui/types": {
"version": "7.2.14",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz",
"integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==",
"version": "7.2.15",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz",
"integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==",
"requires": {}
},
"@mui/utils": {
"version": "5.15.14",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz",
"integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==",
"version": "5.16.6",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz",
"integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==",
"requires": {
"@babel/runtime": "^7.23.9",
"@types/prop-types": "^15.7.11",
"@mui/types": "^7.2.15",
"@types/prop-types": "^15.7.12",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
"react-is": "^18.3.1"
},
"dependencies": {
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
}
}
},
@ -29857,6 +30038,20 @@
"reselect": "^4.1.8"
}
},
"@mui/x-date-pickers": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.14.0.tgz",
"integrity": "sha512-3xI3xYVxqPU4//KfE4FcR+Zs7UT4kkDPvA+IDOcQdRUyVwmcXCjBuJZgKgJMqSCNK/KIJZQQrpmy5XGHOKTbdA==",
"requires": {
"@babel/runtime": "^7.25.0",
"@mui/system": "^5.16.7",
"@mui/utils": "^5.16.6",
"@types/react-transition-group": "^4.4.11",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-transition-group": "^4.4.5"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -30266,6 +30461,14 @@
}
}
},
"@tanstack/match-sorter-utils": {
"version": "8.15.1",
"resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.15.1.tgz",
"integrity": "sha512-PnVV3d2poenUM31ZbZi/yXkBu3J7kd5k2u51CGwwNojag451AjTH9N6n41yjXz2fpLeewleyLBmNS6+HcGDlXw==",
"requires": {
"remove-accents": "0.5.0"
}
},
"@tanstack/query-core": {
"version": "5.51.24",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.24.tgz",
@ -30292,6 +30495,32 @@
"@tanstack/query-devtools": "5.51.16"
}
},
"@tanstack/react-table": {
"version": "8.19.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.19.3.tgz",
"integrity": "sha512-MtgPZc4y+cCRtU16y1vh1myuyZ2OdkWgMEBzyjYsoMWMicKZGZvcDnub3Zwb6XF2pj9iRMvm1SO1n57lS0vXLw==",
"requires": {
"@tanstack/table-core": "8.19.3"
}
},
"@tanstack/react-virtual": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.8.3.tgz",
"integrity": "sha512-9ICwbDUUzN99CJIGc373i8NLoj6zFTKI2Hlcmo0+lCSAhPQ5mxq4dGOMKmLYoEFyHcGQ64Bd6ZVbnPpM6lNK5w==",
"requires": {
"@tanstack/virtual-core": "3.8.3"
}
},
"@tanstack/table-core": {
"version": "8.19.3",
"resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.19.3.tgz",
"integrity": "sha512-IqREj9ADoml9zCAouIG/5kCGoyIxPFdqdyoxis9FisXFi5vT+iYfEfLosq4xkU/iDbMcEuAj+X8dWRLvKYDNoQ=="
},
"@tanstack/virtual-core": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.3.tgz",
"integrity": "sha512-vd2A2TnM5lbnWZnHi9B+L2gPtkSeOtJOAw358JqokIH1+v2J7vUAzFVPwB/wrye12RFOurffXu33plm4uQ+JBQ=="
},
"@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@ -30555,9 +30784,9 @@
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
},
"@types/prop-types": {
"version": "15.7.11",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
"version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
},
"@types/qs": {
"version": "6.9.7",
@ -30599,9 +30828,9 @@
}
},
"@types/react-transition-group": {
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz",
"integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==",
"version": "4.4.11",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
"integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
"requires": {
"@types/react": "*"
}
@ -35411,6 +35640,11 @@
"resolved": "https://registry.npmjs.org/headroom.js/-/headroom.js-0.12.0.tgz",
"integrity": "sha512-iXnAafUm3FdzfJ91uixLws2hkKI1jC8bAKK/pt7XYr8Ie1jO7xbK48Ycpl9tUPyBgkzuj1p/PhJS0fy4E/5anA=="
},
"highlight-words": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/highlight-words/-/highlight-words-1.2.2.tgz",
"integrity": "sha512-Mf4xfPXYm8Ay1wTibCrHpNWeR2nUMynMVFkXCi4mbl+TEgmNOe+I4hV7W3OCZcSvzGL6kupaqpfHOemliMTGxQ=="
},
"history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
@ -37050,6 +37284,17 @@
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz",
"integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA=="
},
"material-react-table": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/material-react-table/-/material-react-table-2.13.1.tgz",
"integrity": "sha512-3iWwCa24ogxwllP4+W11euR/GV6f5wQE5FEilJ72/H3hDYHgsN+XehANytaG0G7/qy/OWYE7oXkcsRUU35I/iA==",
"requires": {
"@tanstack/match-sorter-utils": "8.15.1",
"@tanstack/react-table": "8.19.3",
"@tanstack/react-virtual": "3.8.3",
"highlight-words": "1.2.2"
}
},
"mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@ -39886,6 +40131,11 @@
"mdast-util-to-markdown": "^0.6.0"
}
},
"remove-accents": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
"integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="
},
"renderkid": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz",

View file

@ -86,6 +86,7 @@
"@mui/icons-material": "5.15.19",
"@mui/material": "5.15.19",
"@mui/x-data-grid": "7.6.1",
"@mui/x-date-pickers": "7.14.0",
"@react-hook/resize-observer": "2.0.2",
"@tanstack/react-query": "5.51.24",
"@tanstack/react-query-devtools": "5.51.24",
@ -112,6 +113,7 @@
"lodash-es": "4.17.21",
"markdown-it": "14.1.0",
"material-design-icons-iconfont": "6.7.0",
"material-react-table": "2.13.1",
"native-promise-only": "0.8.1",
"pdfjs-dist": "3.11.174",
"react": "18.3.1",

View file

@ -1,5 +1,8 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { getActivityLogApi } from '@jellyfin/sdk/lib/utils/api/activity-log-api';
import { getUserApi } from '@jellyfin/sdk/lib/utils/api/user-api';
import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models/activity-log-entry';
import { LogLevel } from '@jellyfin/sdk/lib/generated-client/models/log-level';
import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto';
import PermMedia from '@mui/icons-material/PermMedia';
import Box from '@mui/material/Box';
@ -7,20 +10,19 @@ import IconButton from '@mui/material/IconButton';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import Typography from '@mui/material/Typography';
import { DataGrid, type GridColDef } from '@mui/x-data-grid';
import { type MRT_Cell, type MRT_ColumnDef, type MRT_Row, MaterialReactTable, useMaterialReactTable } from 'material-react-table';
import { Link, useSearchParams } from 'react-router-dom';
import Page from 'components/Page';
import UserAvatar from 'components/UserAvatar';
import { useLogEntires } from 'hooks/useLogEntries';
import { useUsers } from 'hooks/useUsers';
import { parseISO8601Date, toLocaleDateString, toLocaleTimeString } from 'scripts/datetime';
import { parseISO8601Date, toLocaleString } from 'scripts/datetime';
import globalize from 'lib/globalize';
import { toBoolean } from 'utils/string';
import LogLevelChip from '../components/activityTable/LogLevelChip';
import OverviewCell from '../components/activityTable/OverviewCell';
import GridActionsCellLink from '../components/dataGrid/GridActionsCellLink';
const DEFAULT_PAGE_SIZE = 25;
const VIEW_PARAM = 'useractivity';
@ -37,16 +39,14 @@ const getActivityView = (param: string | null) => {
return ActivityView.System;
};
const getRowId = (row: ActivityLogEntry) => row.Id ?? -1;
const Activity = () => {
const [ searchParams, setSearchParams ] = useSearchParams();
const [ activityView, setActivityView ] = useState(
getActivityView(searchParams.get(VIEW_PARAM)));
const [ paginationModel, setPaginationModel ] = useState({
page: 0,
const [ pagination, setPagination ] = useState({
pageIndex: 0,
pageSize: DEFAULT_PAGE_SIZE
});
@ -68,106 +68,104 @@ const Activity = () => {
}, [usersData]);
const activityParams = useMemo(() => ({
startIndex: paginationModel.page * paginationModel.pageSize,
limit: paginationModel.pageSize,
startIndex: pagination.pageIndex * pagination.pageSize,
limit: pagination.pageSize,
hasUserId: activityView !== ActivityView.All ? activityView === ActivityView.User : undefined
}), [activityView, paginationModel.page, paginationModel.pageSize]);
}), [activityView, pagination.pageIndex, pagination.pageSize]);
const { data: logEntries, isLoading: isLogEntriesLoading } = useLogEntires(activityParams);
const isLoading = isUsersLoading || isLogEntriesLoading;
const userColDef: GridColDef[] = activityView !== ActivityView.System ? [
const columns = useMemo<MRT_ColumnDef<ActivityLogEntry>[]>(() => [
{
field: 'User',
headerName: globalize.translate('LabelUser'),
width: 60,
valueGetter: ( value, row ) => users[row.UserId]?.Name,
renderCell: ({ row }) => (
id: 'Date',
accessorFn: row => parseISO8601Date(row.Date),
header: globalize.translate('LabelTime'),
size: 160,
Cell: ({ cell }) => toLocaleString(cell.getValue<Date>())
},
{
accessorKey: 'Severity',
header: globalize.translate('LabelLevel'),
size: 90,
Cell: ({ cell }: { cell: MRT_Cell<ActivityLogEntry> }) => (
cell.getValue<LogLevel | undefined>() ? (
<LogLevelChip level={cell.getValue<LogLevel>()} />
) : undefined
),
enableResizing: false,
muiTableBodyCellProps: {
align: 'center'
}
},
{
id: 'User',
accessorFn: row => row.UserId && users[row.UserId]?.Name,
header: globalize.translate('LabelUser'),
size: 75,
Cell: ({ row }: { row: MRT_Row<ActivityLogEntry> }) => (
row.original.UserId ? (
<IconButton
size='large'
color='inherit'
sx={{ padding: 0 }}
title={users[row.UserId]?.Name ?? undefined}
title={users[row.original.UserId]?.Name || undefined}
component={Link}
to={`/dashboard/users/profile?userId=${row.UserId}`}
to={`/dashboard/users/profile?userId=${row.original.UserId}`}
>
<UserAvatar user={users[row.UserId]} />
<UserAvatar user={users[row.original.UserId]} />
</IconButton>
)
}
] : [];
const columns: GridColDef[] = [
{
field: 'Date',
headerName: globalize.translate('LabelDate'),
width: 90,
type: 'date',
valueGetter: ( value ) => parseISO8601Date(value),
valueFormatter: ( value ) => toLocaleDateString(value)
},
{
field: 'Time',
headerName: globalize.translate('LabelTime'),
width: 100,
type: 'dateTime',
valueGetter: ( value, row ) => parseISO8601Date(row.Date),
valueFormatter: ( value ) => toLocaleTimeString(value)
},
{
field: 'Severity',
headerName: globalize.translate('LabelLevel'),
width: 110,
renderCell: ({ value }) => (
value ? (
<LogLevelChip level={value} />
) : undefined
)
},
...userColDef,
{
field: 'Name',
headerName: globalize.translate('LabelName'),
width: 300
),
enableResizing: false,
visibleInShowHideMenu: activityView !== ActivityView.System,
muiTableBodyCellProps: {
align: 'center'
}
},
{
field: 'Overview',
headerName: globalize.translate('LabelOverview'),
width: 200,
valueGetter: ( value, row ) => row.ShortOverview ?? row.Overview,
renderCell: ({ row }) => (
<OverviewCell {...row} />
accessorKey: 'Name',
header: globalize.translate('LabelName'),
size: 270
},
{
id: 'Overview',
accessorFn: row => row.ShortOverview || row.Overview,
header: globalize.translate('LabelOverview'),
size: 170,
Cell: ({ row }: { row: MRT_Row<ActivityLogEntry> }) => (
<OverviewCell {...row.original} />
)
},
{
field: 'Type',
headerName: globalize.translate('LabelType'),
width: 180
accessorKey: 'Type',
header: globalize.translate('LabelType'),
size: 150
},
{
field: 'actions',
type: 'actions',
width: 50,
getActions: ({ row }) => {
const actions = [];
if (row.ItemId) {
actions.push(
<GridActionsCellLink
id: 'Actions',
accessorFn: row => row.ItemId,
header: '',
size: 60,
Cell: ({ row }: { row: MRT_Row<ActivityLogEntry> }) => (
row.original.ItemId ? (
<IconButton
size='large'
icon={<PermMedia />}
label={globalize.translate('LabelMediaDetails')}
title={globalize.translate('LabelMediaDetails')}
to={`/details?id=${row.ItemId}`}
/>
);
component={Link}
to={`/details?id=${row.original.ItemId}`}
>
<PermMedia fontSize='inherit' />
</IconButton>
) : undefined
),
enableColumnActions: false,
enableColumnFilter: false,
enableResizing: false,
enableSorting: false
}
return actions;
}
}
];
], [ activityView, users ]);
const onViewChange = useCallback((_e: React.MouseEvent<HTMLElement, MouseEvent>, newView: ActivityView | null) => {
if (newView !== null) {
@ -187,6 +185,58 @@ const Activity = () => {
}
}, [ activityView, searchParams, setSearchParams ]);
const table = useMaterialReactTable({
columns,
data: logEntries?.Items || [],
// Enable custom features
enableColumnPinning: true,
enableColumnResizing: true,
// Sticky header/footer
enableStickyFooter: true,
enableStickyHeader: true,
muiTableContainerProps: {
sx: {
maxHeight: 'calc(100% - 7rem)' // 2 x 3.5rem for header and footer
}
},
// State
state: {
isLoading,
pagination,
columnVisibility: {
User: activityView !== ActivityView.System
}
},
// Server pagination
manualPagination: true,
onPaginationChange: setPagination,
rowCount: logEntries?.TotalRecordCount || 0,
// Custom toolbar contents
renderTopToolbarCustomActions: () => (
<ToggleButtonGroup
size='small'
value={activityView}
onChange={onViewChange}
exclusive
>
<ToggleButton value={ActivityView.All}>
{globalize.translate('All')}
</ToggleButton>
<ToggleButton value={ActivityView.User}>
{globalize.translate('LabelUser')}
</ToggleButton>
<ToggleButton value={ActivityView.System}>
{globalize.translate('LabelSystem')}
</ToggleButton>
</ToggleButtonGroup>
)
});
return (
<Page
id='serverActivityPage'
@ -203,43 +253,14 @@ const Activity = () => {
>
<Box
sx={{
display: 'flex',
alignItems: 'baseline',
marginY: 2
marginBottom: 1
}}
>
<Box sx={{ flexGrow: 1 }}>
<Typography variant='h2'>
{globalize.translate('HeaderActivity')}
</Typography>
</Box>
<ToggleButtonGroup
value={activityView}
onChange={onViewChange}
exclusive
>
<ToggleButton value={ActivityView.All}>
{globalize.translate('All')}
</ToggleButton>
<ToggleButton value={ActivityView.User}>
{globalize.translate('LabelUser')}
</ToggleButton>
<ToggleButton value={ActivityView.System}>
{globalize.translate('LabelSystem')}
</ToggleButton>
</ToggleButtonGroup>
</Box>
<DataGrid
columns={columns}
rows={logEntries?.Items || []}
pageSizeOptions={[ 10, 25, 50, 100 ]}
paginationMode='server'
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
rowCount={logEntries?.TotalRecordCount || 0}
getRowId={getRowId}
loading={isLoading}
/>
<MaterialReactTable table={table} />
</Box>
</Page>
);

View file

@ -186,12 +186,18 @@ const config = {
path.resolve(__dirname, 'node_modules/@jellyfin/libass-wasm'),
path.resolve(__dirname, 'node_modules/@jellyfin/sdk'),
path.resolve(__dirname, 'node_modules/@mui/x-data-grid'),
path.resolve(__dirname, 'node_modules/@mui/x-date-pickers'),
path.resolve(__dirname, 'node_modules/@react-hook/latest'),
path.resolve(__dirname, 'node_modules/@react-hook/passive-layout-effect'),
path.resolve(__dirname, 'node_modules/@react-hook/resize-observer'),
path.resolve(__dirname, 'node_modules/@remix-run/router'),
path.resolve(__dirname, 'node_modules/@tanstack/match-sorter-utils'),
path.resolve(__dirname, 'node_modules/@tanstack/query-core'),
path.resolve(__dirname, 'node_modules/@tanstack/react-query'),
path.resolve(__dirname, 'node_modules/@tanstack/react-table'),
path.resolve(__dirname, 'node_modules/@tanstack/react-virtual'),
path.resolve(__dirname, 'node_modules/@tanstack/table-core'),
path.resolve(__dirname, 'node_modules/@tanstack/virtual-core'),
path.resolve(__dirname, 'node_modules/@uupaa/dynamic-import-polyfill'),
path.resolve(__dirname, 'node_modules/axios'),
path.resolve(__dirname, 'node_modules/blurhash'),
@ -200,14 +206,17 @@ const config = {
path.resolve(__dirname, 'node_modules/dom7'),
path.resolve(__dirname, 'node_modules/epubjs'),
path.resolve(__dirname, 'node_modules/flv.js'),
path.resolve(__dirname, 'node_modules/highlight-words'),
path.resolve(__dirname, 'node_modules/libarchive.js'),
path.resolve(__dirname, 'node_modules/linkify-it'),
path.resolve(__dirname, 'node_modules/markdown-it'),
path.resolve(__dirname, 'node_modules/material-react-table'),
path.resolve(__dirname, 'node_modules/mdurl'),
path.resolve(__dirname, 'node_modules/punycode'),
path.resolve(__dirname, 'node_modules/react-blurhash'),
path.resolve(__dirname, 'node_modules/react-lazy-load-image-component'),
path.resolve(__dirname, 'node_modules/react-router'),
path.resolve(__dirname, 'node_modules/remove-accents'),
path.resolve(__dirname, 'node_modules/screenfull'),
path.resolve(__dirname, 'node_modules/ssr-window'),
path.resolve(__dirname, 'node_modules/swiper'),