Merge branch 'release/v0.0.1'
This commit is contained in:
18
ecosystem.config.js.example
Normal file
18
ecosystem.config.js.example
Normal file
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: "rms-v3",
|
||||
script: 'node_modules/next/dist/bin/next', // cluster mode run with node only, not npm
|
||||
args: 'start -p 3000',
|
||||
exec_mode: "cluster", // default fork
|
||||
instances: "max",
|
||||
kill_timeout: 4000,
|
||||
wait_ready: true,
|
||||
autorestart: true,
|
||||
watch: false,
|
||||
max_memory_restart: "1G",
|
||||
log_date_format: "YYYY-MM-DD HH:mm Z",
|
||||
env_prod: {
|
||||
APP_ENV: 'prod' // APP_ENV=prod
|
||||
}
|
||||
}],
|
||||
};
|
||||
@@ -1,7 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
],
|
||||
"^/*": [
|
||||
"./public/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,17 @@
|
||||
"@mui/icons-material": "^5.15.6",
|
||||
"@mui/material": "^5.15.6",
|
||||
"@mui/material-nextjs": "^5.15.6",
|
||||
"@mui/x-date-pickers": "^6.19.5",
|
||||
"date-fns": "^3.3.1",
|
||||
"date-fns-jalali": "^2.13.0-0",
|
||||
"dayjs": "^1.11.10",
|
||||
"formik": "^2.4.5",
|
||||
"jalali-moment": "^3.3.11",
|
||||
"material-react-table": "^2.11.2",
|
||||
"next": "14.1.0",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"sass": "^1.75.0",
|
||||
"stylis": "^4.3.1",
|
||||
"stylis-plugin-rtl": "^2.1.1"
|
||||
},
|
||||
|
||||
176
public/fontiran.scss
Normal file
176
public/fontiran.scss
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
*
|
||||
* Name: IRAN Sans-Serif Font
|
||||
* Version: 5.0
|
||||
* Author: Moslem Ebrahimi (moslemebrahimi.com)
|
||||
* Created on: Dec 25, 2012
|
||||
* Updated on: Sep 01, 2017
|
||||
* Website: http://fontiran.com
|
||||
* Copyright: Commercial/Proprietary Software
|
||||
--------------------------------------------------------------------------------------
|
||||
فونت های ایران سن سریف یک نرم افزار مالکیتی محسوب می شود. جهت آگاهی از قوانین استفاده از این فونت ها لطفا به وب سایت (فونت ایران دات کام) مراجعه نمایید
|
||||
--------------------------------------------------------------------------------------
|
||||
IRAN Sans-serif fonts are considered a proprietary software. To gain information about the laws regarding the use of these fonts, please visit www.fontiran.com
|
||||
--------------------------------------------------------------------------------------
|
||||
This set of fonts are used in this project under the license: (.....)
|
||||
--------------------------------------------------------------------------------------
|
||||
*
|
||||
**/
|
||||
@font-face {
|
||||
font-family: IRANSansFaNum;
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Black.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Black.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb(FaNum)_Black.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb(FaNum)_Black.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb(FaNum)_Black.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSansFaNum;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Bold.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb(FaNum)_Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSansFaNum;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Medium.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Medium.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb(FaNum)_Medium.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSansFaNum;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Light.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_Light.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb(FaNum)_Light.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb(FaNum)_Light.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb(FaNum)_Light.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSansFaNum;
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSansFaNum;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum).eot');
|
||||
src: url('./fonts/eot/IRANSansWeb(FaNum).eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb(FaNum).woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb(FaNum).woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb(FaNum).ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSans;
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url('./fonts/eot/IRANSansWeb_Black.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb_Black.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb_Black.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb_Black.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb_Black.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSans;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: url('./fonts/eot/IRANSansWeb_Bold.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb_Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb_Bold.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb_Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb_Bold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSans;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('./fonts/eot/IRANSansWeb_Medium.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb_Medium.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb_Medium.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb_Medium.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb_Medium.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSans;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('./fonts/eot/IRANSansWeb_Light.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb_Light.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb_Light.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb_Light.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb_Light.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSans;
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url('./fonts/eot/IRANSansWeb_UltraLight.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb_UltraLight.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb_UltraLight.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb_UltraLight.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb_UltraLight.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: IRANSans;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: url('./fonts/eot/IRANSansWeb.eot');
|
||||
src: url('./fonts/eot/IRANSansWeb.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff2/IRANSansWeb.woff2') format('woff2'), /* FF39+,Chrome36+, Opera24+*/
|
||||
url('./fonts/woff/IRANSansWeb.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/IRANSansWeb.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Parastoo;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: url('./fonts/eot/Parastoo.eot');
|
||||
src: url('./fonts/eot/Parastoo.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff/Parastoo.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/Parastoo.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Parastoo;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: url('./fonts/eot/Parastoo-Bold.eot');
|
||||
src: url('./fonts/eot/Parastoo-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-8 */
|
||||
url('./fonts/woff/Parastoo-Bold.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
|
||||
url('./fonts/ttf/Parastoo-Bold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Bnazanin;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: url('./fonts/ttf/BNazanin.ttf') format('truetype');
|
||||
}
|
||||
BIN
public/fonts/eot/IRANSansWeb(FaNum).eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum).eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Black.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Black.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Bold.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Light.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Light.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_Medium.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb(FaNum)_UltraLight.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Black.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Black.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Bold.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Bold.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Light.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Light.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_Medium.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_Medium.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/IRANSansWeb_UltraLight.eot
Normal file
BIN
public/fonts/eot/IRANSansWeb_UltraLight.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/Parastoo-Bold.eot
Normal file
BIN
public/fonts/eot/Parastoo-Bold.eot
Normal file
Binary file not shown.
BIN
public/fonts/eot/Parastoo.eot
Normal file
BIN
public/fonts/eot/Parastoo.eot
Normal file
Binary file not shown.
BIN
public/fonts/ttf/BNazanin.ttf
Normal file
BIN
public/fonts/ttf/BNazanin.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum).ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum).ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Black.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Light.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb(FaNum)_UltraLight.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Black.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Black.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Bold.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Light.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Light.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_Medium.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_Medium.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/IRANSansWeb_UltraLight.ttf
Normal file
BIN
public/fonts/ttf/IRANSansWeb_UltraLight.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/Parastoo-Bold.ttf
Normal file
BIN
public/fonts/ttf/Parastoo-Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/ttf/Parastoo.ttf
Normal file
BIN
public/fonts/ttf/Parastoo.ttf
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum).woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum).woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Black.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Black.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Light.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Light.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_Medium.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb(FaNum)_UltraLight.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Black.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Black.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Bold.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Light.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Light.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_Medium.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_Medium.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/IRANSansWeb_UltraLight.woff
Normal file
BIN
public/fonts/woff/IRANSansWeb_UltraLight.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/Parastoo-Bold.woff
Normal file
BIN
public/fonts/woff/Parastoo-Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff/Parastoo.woff
Normal file
BIN
public/fonts/woff/Parastoo.woff
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum).woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum).woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Black.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Light.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_Medium.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb(FaNum)_UltraLight.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Black.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Black.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Bold.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Light.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Light.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_Medium.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_Medium.woff2
Normal file
Binary file not shown.
BIN
public/fonts/woff2/IRANSansWeb_UltraLight.woff2
Normal file
BIN
public/fonts/woff2/IRANSansWeb_UltraLight.woff2
Normal file
Binary file not shown.
1
public/global.scss
Normal file
1
public/global.scss
Normal file
@@ -0,0 +1 @@
|
||||
@import "fontiran";
|
||||
@@ -1,11 +1,16 @@
|
||||
import {Box, Stack} from "@mui/material";
|
||||
import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo";
|
||||
import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
|
||||
|
||||
const Template = ({children}) => {
|
||||
return (
|
||||
<>
|
||||
header
|
||||
sidebar
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
return (<Stack>
|
||||
<HeaderWithLogo/>
|
||||
<Box>
|
||||
<HeaderWithSidebar>
|
||||
{children}
|
||||
</HeaderWithSidebar>
|
||||
</Box>
|
||||
</Stack>)
|
||||
}
|
||||
|
||||
export default Template
|
||||
@@ -1,11 +1,17 @@
|
||||
import {TableSettingProvider} from "@/lib/contexts/tableSetting";
|
||||
|
||||
export const metadata = {
|
||||
title: 'سامانه جامع راهداری',
|
||||
}
|
||||
|
||||
export default function RootLayout({children}) {
|
||||
return (<html lang="fa" dir={'rtl'}>
|
||||
<body>
|
||||
{children}
|
||||
</body>
|
||||
</html>)
|
||||
return (
|
||||
<html lang="fa" dir={'rtl'}>
|
||||
<body style={{height: '100vh'}}>
|
||||
<TableSettingProvider>
|
||||
{children}
|
||||
</TableSettingProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
149
src/app/page.js
149
src/app/page.js
@@ -1,5 +1,148 @@
|
||||
const Page = () => {
|
||||
return (<></>)
|
||||
'use client'
|
||||
import DataTable from "@/core/components/DataTable";
|
||||
import { useMemo } from "react";
|
||||
|
||||
function Page() {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: 'fullname',
|
||||
header: 'نام کامل',
|
||||
id: "fullname",
|
||||
columns: [
|
||||
{
|
||||
accessorKey: 'name.firstName',
|
||||
header: 'نام',
|
||||
id: "firstName",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
enableClickToCopy: true,
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'name.lastName',
|
||||
header: 'نام خانوادگی',
|
||||
id: "lastName",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
],
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'address',
|
||||
header: 'آدرس',
|
||||
id: "address",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'city',
|
||||
header: 'شهر',
|
||||
id: "city",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains",
|
||||
"lessThan",
|
||||
"greaterThan",
|
||||
"between",
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'وضعیت',
|
||||
id: "state",
|
||||
text: 'نام',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'محدوده',
|
||||
id: "betweenNum",
|
||||
text: 'محدوده',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "betweenNum",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'تاریخ',
|
||||
id: "betweenDate",
|
||||
text: 'تاریخ',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "betweenDate",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'شلکت',
|
||||
id: "select2",
|
||||
text: 'تاریخ',
|
||||
type: 'select2',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'سلکت',
|
||||
id: "select",
|
||||
text: 'تنتنت',
|
||||
type: 'select',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DataTable columns={columns} userId={0} pageName={'testPage'} tableName={'testTable'} />
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default Page
|
||||
export default Page;
|
||||
|
||||
@@ -2,6 +2,7 @@ import cacheProviderRtl from "@/core/utils/cacheRtl";
|
||||
import {CssBaseline, ThemeProvider} from "@mui/material";
|
||||
import theme from "@/core/utils/theme";
|
||||
import {AppRouterCacheProvider} from "@mui/material-nextjs/v14-appRouter";
|
||||
import "^/global.scss"
|
||||
|
||||
const Template = ({children}) => {
|
||||
return (
|
||||
|
||||
31
src/components/BetweenDateFilter.jsx
Normal file
31
src/components/BetweenDateFilter.jsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import {Grid} from '@mui/material';
|
||||
import MuiDatePicker from "@/components/MuiDatePicker";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
const BetWeenDateFilter = ({formik, id , defaultValue}) => {
|
||||
useEffect(() => {
|
||||
formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || '');
|
||||
formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || '');
|
||||
}, []);
|
||||
|
||||
const [dateRange, setDateRange] = useState(defaultValue);
|
||||
|
||||
const handleDateChange = (index, value) => {
|
||||
const newRange = [...dateRange];
|
||||
newRange[index] = value;
|
||||
setDateRange(newRange);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container spacing={1} mt={1} mb={2}>
|
||||
<Grid item xs={6}>
|
||||
<MuiDatePicker label="تاریخ شروع " name={`${id}[0]`} formik={formik} defaultValue={defaultValue?.[0]} minDate={null} maxDate={dateRange[1]} onDateChange={(value) => handleDateChange(0, value)}/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<MuiDatePicker label="تاریخ پایان" name={`${id}[1]`} formik={formik} defaultValue={defaultValue?.[1]} minDate={dateRange[0]} maxDate={null} onDateChange={(value) => handleDateChange(1, value)}/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default BetWeenDateFilter;
|
||||
58
src/components/BetweenNumberFilter.jsx
Normal file
58
src/components/BetweenNumberFilter.jsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import {Grid, TextField} from '@mui/material';
|
||||
import {useEffect} from "react";
|
||||
|
||||
const BetweenNumberFilter = ({formik, id , defaultValue}) => {
|
||||
|
||||
useEffect(() => {
|
||||
formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || '');
|
||||
formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || '');
|
||||
}, []);
|
||||
const handleBlur = (index) => () => {
|
||||
const minValue = formik.values[id][0];
|
||||
const maxValue = formik.values[id][1];
|
||||
|
||||
if (index === 0 && minValue !== '' && maxValue !== '' && parseInt(minValue) > parseInt(maxValue)) {
|
||||
formik.setFieldValue(`${id}[0]`, maxValue);
|
||||
}
|
||||
|
||||
if (index === 1 && minValue !== '' && maxValue !== '' && parseInt(maxValue) < parseInt(minValue)) {
|
||||
formik.setFieldValue(`${id}[1]`, minValue);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
name={`${id}[0]`}
|
||||
label="کمترین رقم"
|
||||
id={`${id}_min`}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={handleBlur(0)}
|
||||
fullWidth
|
||||
value={formik.values[id][0] || ''}
|
||||
margin="normal"
|
||||
sx={{
|
||||
position: 'relative'
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
name={`${id}[1]`}
|
||||
label="بیشترین رقم"
|
||||
id={`${id}_max`}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={handleBlur(1)}
|
||||
fullWidth
|
||||
value={formik.values[id][1] || ''}
|
||||
margin="normal"
|
||||
sx={{
|
||||
position: 'relative'
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default BetweenNumberFilter;
|
||||
20
src/components/CustomToolbar.jsx
Normal file
20
src/components/CustomToolbar.jsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import FilterColumn from "@/components/FilterColumn";
|
||||
|
||||
const CustomToolbar = ({columns}) => {
|
||||
return (
|
||||
<FilterColumn columns={columns}/>
|
||||
)
|
||||
}
|
||||
export default CustomToolbar
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
141
src/components/DataTableMain.jsx
Normal file
141
src/components/DataTableMain.jsx
Normal file
@@ -0,0 +1,141 @@
|
||||
import DataTableTest from "@/components/DataTableTest";
|
||||
import FilterColumn from "@/components/FilterColumn";
|
||||
import {useMemo} from "react";
|
||||
import {Button} from "@mui/material";
|
||||
|
||||
function DataTableMain() {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: 'name.firstName',
|
||||
header: 'نام',
|
||||
size: 150,
|
||||
id: "firstName",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'name.lastName',
|
||||
header: 'نام خانوادگی',
|
||||
size: 150,
|
||||
id: "lastName",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'address',
|
||||
header: 'آدرس',
|
||||
size: 200,
|
||||
id: "address",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'city',
|
||||
header: 'شهر',
|
||||
size: 150,
|
||||
id: "city",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains",
|
||||
"lessThan",
|
||||
"greaterThan",
|
||||
"between",
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'وضعیت',
|
||||
size: 150,
|
||||
id: "state",
|
||||
text:'نام',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "contains",
|
||||
columnFilterModeOptions: [
|
||||
"equals",
|
||||
"notEquals",
|
||||
"contains"
|
||||
],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'محدوده',
|
||||
size: 150,
|
||||
id: "betweenNum",
|
||||
text:'محدوده',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "betweenNum",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'تاریخ',
|
||||
size: 150,
|
||||
id: "betweenDate",
|
||||
text:'تاریخ',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "betweenDate",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'شلکت',
|
||||
size: 150,
|
||||
id: "select2",
|
||||
text:'تاریخ',
|
||||
type: 'select2',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
{
|
||||
accessorKey: 'state',
|
||||
header: 'سلکت',
|
||||
size: 150,
|
||||
id: "select",
|
||||
text:'تنتنت',
|
||||
type: 'select',
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterFn: "equals",
|
||||
columnFilterModeOptions: [],
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<DataTableTest columns={columns}/>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default DataTableMain;
|
||||
104
src/components/DataTableTest.jsx
Normal file
104
src/components/DataTableTest.jsx
Normal file
@@ -0,0 +1,104 @@
|
||||
"use client"
|
||||
import {useMemo, useState} from 'react';
|
||||
import {MaterialReactTable} from 'material-react-table';
|
||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||
import {IconButton, Tooltip, Typography} from "@mui/material";
|
||||
import CustomToolbar from "@/components/CustomToolbar";
|
||||
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
address: '261 Erdman Ford',
|
||||
city: 'East Daphne',
|
||||
state: 'Kentucky',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
address: '769 Dominic Grove',
|
||||
city: 'Columbus',
|
||||
state: 'Ohio',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Joe',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
address: '566 Brakus Inlet',
|
||||
city: 'South Linda',
|
||||
state: 'West Virginia',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Kevin',
|
||||
lastName: 'Vandy',
|
||||
},
|
||||
address: '722 Emie Stream',
|
||||
city: 'Lincoln',
|
||||
state: 'Nebraska',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Joshua',
|
||||
lastName: 'Rolluffs',
|
||||
},
|
||||
address: '32188 Larkin Turnpike',
|
||||
city: 'Charleston',
|
||||
state: 'South Carolina',
|
||||
},
|
||||
];
|
||||
|
||||
function RefreshIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
const TestDataTable = ({columns}) => {
|
||||
const [userId, setUserId] = useState(2);
|
||||
const [pageName, setPageName] = useState('loan');
|
||||
const [tableName, setTableName] = useState('loan_table');
|
||||
const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting();
|
||||
|
||||
const onColumnVisibilityChange = (event) => {
|
||||
const settingValue = event();
|
||||
hideAction(userId, pageName, tableName, settingValue, columns);
|
||||
};
|
||||
const onSortingChange = (event) => {
|
||||
const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []);
|
||||
sortAction(userId, pageName, tableName, settingValue, columns);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography>{settingStore?.[userId]?.[pageName]?.[tableName]?.['summary']}</Typography>
|
||||
<MaterialReactTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
manualSorting={true}
|
||||
renderTopToolbarCustomActions={({table}) => (<>
|
||||
<CustomToolbar
|
||||
columns={columns}
|
||||
/>
|
||||
</>)}
|
||||
initialState={{
|
||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []
|
||||
}}
|
||||
state={{
|
||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []
|
||||
}}
|
||||
onColumnVisibilityChange={onColumnVisibilityChange}
|
||||
onSortingChange={onSortingChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestDataTable;
|
||||
|
||||
30
src/components/FilterBox.jsx
Normal file
30
src/components/FilterBox.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Popper, Paper, List, ListItem, ListItemText, ClickAwayListener } from '@mui/material';
|
||||
|
||||
function FilterBox({anchorEl , open = false, handleClose = () => {} , columnFilterModeOptions , onSelectFilter , defaultFilter}) {
|
||||
|
||||
const id = open ? 'simple-popper' : undefined;
|
||||
const handleSelectFilter = (filterFn) => {
|
||||
onSelectFilter(filterFn);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Popper id={id} open={open} anchorEl={anchorEl} placement="bottom" style={{ zIndex: 1301 }}>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<Paper>
|
||||
<List>
|
||||
{columnFilterModeOptions.map((option, index) => (
|
||||
<ListItem key={index} onClick={() => handleSelectFilter(option)} selected={option === defaultFilter} sx={{ cursor: 'pointer' }}>
|
||||
<ListItemText primary={option} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Paper>
|
||||
</ClickAwayListener>
|
||||
</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterBox;
|
||||
204
src/components/FilterColumn.jsx
Normal file
204
src/components/FilterColumn.jsx
Normal file
@@ -0,0 +1,204 @@
|
||||
"use client"
|
||||
import {
|
||||
Box,
|
||||
Button, Divider, Drawer,
|
||||
FormControl, IconButton, styled, Typography
|
||||
} from '@mui/material';
|
||||
import {useFormik} from 'formik';
|
||||
import TextFieldWithFnBox from "@/components/TextFieldWithFnBox";
|
||||
import {useEffect, useState} from "react";
|
||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||
import BetweenNumberFilter from "@/components/BetweenNumberFilter";
|
||||
import BetWeenDateFilter from "@/components/BetweenDateFilter";
|
||||
import SelectBoxMultiple from "@/components/SelectBoxMultiple";
|
||||
import SelectBox from "@/components/SelectBox";
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
function FilterColumn({ columns }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedFilters, setSelectedFilters] = useState([]);
|
||||
const [userId, setUserId] = useState(2);
|
||||
const [pageName, setPageName] = useState('loan');
|
||||
const [tableName, setTableName] = useState('loan_table');
|
||||
const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting();
|
||||
|
||||
const DrawerHeader = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: theme.spacing(0, 1),
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
const toggleDrawer = (newOpen) => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
const handleDrawerClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
useEffect(() => {
|
||||
const settingValue = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || [];
|
||||
setSelectedFilters(settingValue.length > 0 ? settingValue : []);
|
||||
}, [settingStore]);
|
||||
|
||||
const handleSelectFilter = (fieldName, filterFn) => {
|
||||
const filterIndex = selectedFilters.findIndex(filter => filter.id === fieldName);
|
||||
|
||||
if (filterIndex !== -1) {
|
||||
const updatedFilters = [...selectedFilters];
|
||||
updatedFilters[filterIndex].fn = filterFn;
|
||||
setSelectedFilters(updatedFilters);
|
||||
} else {
|
||||
const newFilter = { id: fieldName, fn: filterFn };
|
||||
const updatedFilters = [...selectedFilters, newFilter];
|
||||
setSelectedFilters(updatedFilters);
|
||||
}
|
||||
};
|
||||
|
||||
const initialValues = columns.reduce((acc, column) => {
|
||||
if (column.enableColumnFilter) {
|
||||
const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters']?.find((filter) => filter.id === column.id);
|
||||
if (column.filterFn === 'betweenNum' || column.filterFn === 'betweenDate') {
|
||||
acc[column.id] = filter?.value || ["", ""];
|
||||
}
|
||||
else if ( column.type === 'select2' ) {
|
||||
acc[column.id] = filter?.value || [];
|
||||
}
|
||||
else {
|
||||
acc[column.id] = filter?.value || '';
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues,
|
||||
onSubmit: (values) => {
|
||||
const updatedFilters = selectedFilters.map(filter => {
|
||||
const value = values[filter.id];
|
||||
if (value !== undefined) {
|
||||
return { ...filter, value };
|
||||
}
|
||||
return filter;
|
||||
});
|
||||
Object.entries(values).forEach(([fieldName, value]) => {
|
||||
const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName);
|
||||
if (filterIndex === -1 && value !== '' && value !== null && value !== undefined) {
|
||||
const column = columns.find(col => col.id === fieldName);
|
||||
updatedFilters.push({ id: fieldName, value, fn: column.filterFn, datatype: column.datatype });
|
||||
}
|
||||
});
|
||||
|
||||
const newArrayFilter = updatedFilters.filter((filter) => {
|
||||
const value = values[filter.id];
|
||||
|
||||
return (
|
||||
value !== '' &&
|
||||
value !== null &&
|
||||
value !== undefined &&
|
||||
!(Array.isArray(value) && (value.length === 0 || (value.length === 2 && value.every((v) => v === ''))))
|
||||
);
|
||||
});
|
||||
|
||||
setSelectedFilters(newArrayFilter);
|
||||
filterAction(userId, pageName, tableName, newArrayFilter, columns);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={toggleDrawer(true)}>Open drawer</Button>
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}
|
||||
sx={{
|
||||
"& .MuiDrawer-paper": {
|
||||
padding: '16px',
|
||||
overflowY: 'auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
scrollbarWidth: 'thin',
|
||||
width:450,
|
||||
"&::-webkit-scrollbar": {
|
||||
width: '8px',
|
||||
},
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: '#ccc',
|
||||
borderRadius: '4px',
|
||||
},
|
||||
"@media (max-width: 600px)": {
|
||||
width: '100%'
|
||||
},
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DrawerHeader>
|
||||
<Typography variant="h6" mb={2}>فیلتر</Typography>
|
||||
<IconButton onClick={handleDrawerClose}>
|
||||
<CloseIcon/>
|
||||
</IconButton>
|
||||
</DrawerHeader>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<FormControl fullWidth>
|
||||
{columns.map((column, index) => (
|
||||
column.enableColumnFilter &&
|
||||
(column.filterFn === 'betweenDate' ?
|
||||
<BetWeenDateFilter
|
||||
key={index}
|
||||
id={column.id}
|
||||
formik={formik}
|
||||
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
||||
/>
|
||||
: column.filterFn === 'betweenNum' ?
|
||||
<BetweenNumberFilter
|
||||
key={index}
|
||||
id={column.id}
|
||||
formik={formik}
|
||||
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ["", ""]}
|
||||
/>
|
||||
: column.type === 'select2' ?
|
||||
<SelectBoxMultiple
|
||||
key={index}
|
||||
id={column.id}
|
||||
formik={formik}
|
||||
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || []}
|
||||
/>
|
||||
: column.type === 'select' ?
|
||||
<SelectBox
|
||||
key={index}
|
||||
id={column.id}
|
||||
formik={formik}
|
||||
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
||||
/>
|
||||
:
|
||||
<TextFieldWithFnBox
|
||||
key={index}
|
||||
id={column.id}
|
||||
header={column.header}
|
||||
formik={formik}
|
||||
defaultFilter={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.fn || column.filterFn}
|
||||
columnFilterModeOptions={column.columnFilterModeOptions}
|
||||
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||
defaultValue={formik.values[column.id] || (settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
||||
/>
|
||||
)
|
||||
))}
|
||||
</FormControl>
|
||||
</Box>
|
||||
<Box sx={{ mt:2 }}>
|
||||
<Divider />
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
|
||||
<Button variant="contained" size="medium" onClick={formik.handleSubmit} sx={{ mt: 1 }}>ثبت</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterColumn;
|
||||
|
||||
|
||||
41
src/components/MapTest.jsx
Normal file
41
src/components/MapTest.jsx
Normal file
@@ -0,0 +1,41 @@
|
||||
"use client"
|
||||
import {Typography} from "@mui/material";
|
||||
|
||||
const data = [
|
||||
{
|
||||
id : "hello",
|
||||
Subitems : [
|
||||
{id : "amin",firstName : "amin", lastName:"ali",Subitems : [{id : "shahrokh",shahrokh : "shahrokh"}], hasSubitems : true, showSubitems : false},
|
||||
{id : "amir",firstName : "amir", lastName:"akbar", hasSubitems : false, showSubitems : false},
|
||||
],
|
||||
hasSubitems : true,
|
||||
showSubitems : false
|
||||
},
|
||||
{
|
||||
id : "hi",
|
||||
Subitems : [
|
||||
{id : "ali",firstName : "ali", lastName:"ali", hasSubitems : false, showSubitems : false},
|
||||
{id : "akbar",firstName : "akbar", lastName:"akbar", hasSubitems : false, showSubitems : false},
|
||||
],
|
||||
hasSubitems : true,
|
||||
showSubitems : false
|
||||
}
|
||||
]
|
||||
const MapTest = () => {
|
||||
const Amin = data.map((item) => {
|
||||
return item.hasSubitems ? {...item, Subitems: item.Subitems.map((subitem) => true ? {
|
||||
...subitem, showSubitems: !item.showSubitems
|
||||
} : subitem)} : item
|
||||
})
|
||||
|
||||
|
||||
console.log(Amin)
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography>hello</Typography>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default MapTest
|
||||
67
src/components/MuiDatePicker.jsx
Normal file
67
src/components/MuiDatePicker.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers";
|
||||
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||
import moment from "jalali-moment";
|
||||
import { faIR } from "@mui/x-date-pickers/locales";
|
||||
import { Box, IconButton, InputAdornment, TextField } from "@mui/material";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function MuiDatePicker({label, name, formik, defaultValue, minDate, maxDate, onDateChange }) {
|
||||
const [pickerValue, setPickerValue] = useState(defaultValue ? new Date(defaultValue) : null);
|
||||
|
||||
return (
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<LocalizationProvider
|
||||
dateAdapter={AdapterDateFnsJalali}
|
||||
localeText={
|
||||
faIR.components.MuiLocalizationProvider.defaultProps.localeText
|
||||
}
|
||||
>
|
||||
<MobileDateTimePicker
|
||||
key={formik.values[name]}
|
||||
ampm={false}
|
||||
onChange={(newValue) => {
|
||||
const date = new Date(newValue);
|
||||
const formattedDate = moment(date)
|
||||
.locale("en")
|
||||
.format("YYYY-MM-DD HH:mm");
|
||||
formik.setFieldValue(name, formattedDate);
|
||||
onDateChange(formattedDate);
|
||||
setPickerValue(newValue);
|
||||
}}
|
||||
slotProps={{
|
||||
textField: {
|
||||
placeholder: "تاریخ خود را وارد کنید",
|
||||
helperText: label,
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
formik.setFieldValue(name, "");
|
||||
setPickerValue(null);
|
||||
}}
|
||||
sx={{
|
||||
color: "#bfbfbf",
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(189, 189, 189, 0.1)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
},
|
||||
},
|
||||
}}
|
||||
value={pickerValue}
|
||||
minDate={minDate ? new Date(minDate) : null}
|
||||
maxDate={maxDate ? new Date(maxDate) : null}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
53
src/components/SelectBox.jsx
Normal file
53
src/components/SelectBox.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import Select from '@mui/material/Select';
|
||||
import {useEffect, useState} from "react";
|
||||
const names = [
|
||||
'Oliver Hansen',
|
||||
'Van Henry',
|
||||
'April Tucker',
|
||||
'Ralph Hubbard',
|
||||
'Omar Alexander',
|
||||
'Carlos Abbott',
|
||||
'Miriam Wagner',
|
||||
'Bradley Wilkerson',
|
||||
'Virginia Andrews',
|
||||
'Kelly Snyder',
|
||||
];
|
||||
const SelectBox = ({ formik, id, defaultValue }) => {
|
||||
|
||||
useEffect(() => {
|
||||
formik.setFieldValue(id, defaultValue || '');
|
||||
}, []);
|
||||
|
||||
const [selectedValue, setSelectedValue] = useState(defaultValue || '');
|
||||
|
||||
const handleChange = (event) => {
|
||||
const { value } = event.target;
|
||||
setSelectedValue(value);
|
||||
formik.setFieldValue(id, value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormControl sx={{ mt: 3 }}>
|
||||
<InputLabel>انتخاب</InputLabel>
|
||||
<Select
|
||||
id={id}
|
||||
value={selectedValue}
|
||||
onChange={handleChange}
|
||||
label="انتخاب"
|
||||
>
|
||||
{names.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectBox;
|
||||
116
src/components/SelectBoxMultiple.jsx
Normal file
116
src/components/SelectBoxMultiple.jsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import {useTheme} from '@mui/material/styles';
|
||||
import Box from '@mui/material/Box';
|
||||
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import Select from '@mui/material/Select';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
const ITEM_HEIGHT = 48;
|
||||
const ITEM_PADDING_TOP = 8;
|
||||
const MenuProps = {
|
||||
PaperProps: {
|
||||
style: {
|
||||
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
||||
width: 250,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const names = [
|
||||
'Oliver Hansen',
|
||||
'Van Henry',
|
||||
'April Tucker',
|
||||
'Ralph Hubbard',
|
||||
'Omar Alexander',
|
||||
'Carlos Abbott',
|
||||
'Miriam Wagner',
|
||||
'Bradley Wilkerson',
|
||||
'Virginia Andrews',
|
||||
'Kelly Snyder',
|
||||
];
|
||||
|
||||
function getStyles(name, personName, theme) {
|
||||
return {
|
||||
fontWeight:
|
||||
personName.indexOf(name) === -1
|
||||
? theme.typography.fontWeightRegular
|
||||
: theme.typography.fontWeightMedium,
|
||||
};
|
||||
}
|
||||
|
||||
const SelectBoxMultiple = ({formik, id, defaultValue}) => {
|
||||
const theme = useTheme();
|
||||
const [personName, setPersonName] = useState(defaultValue || []);
|
||||
|
||||
useEffect(() => {
|
||||
defaultValue.forEach((value, index) => {
|
||||
formik.setFieldValue(`${id}[${index}]`, value || '');
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
const handleChange = (event) => {
|
||||
const {
|
||||
target: {value},
|
||||
} = event;
|
||||
|
||||
const selectedValues = typeof value === 'string' ? value.split(',').filter(item => item.trim() !== '') : value;
|
||||
|
||||
formik.setFieldValue(id, []);
|
||||
|
||||
if (selectedValues.length === 0) {
|
||||
setPersonName([]);
|
||||
formik.setFieldValue(id, []);
|
||||
} else {
|
||||
setPersonName(selectedValues);
|
||||
selectedValues.forEach((selectedValue, index) => {
|
||||
formik.setFieldValue(`${id}[${index}]`, selectedValue);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormControl sx={{width: '100%'}}>
|
||||
<InputLabel id={id}>انتخاب</InputLabel>
|
||||
<Select
|
||||
id={id}
|
||||
multiple
|
||||
value={personName}
|
||||
onChange={handleChange}
|
||||
input={<OutlinedInput label="Chip"/>}
|
||||
renderValue={(selected) => (
|
||||
<Box sx={{display: 'flex', flexWrap: 'wrap', gap: 0.5}}>
|
||||
{selected.map((value) => (
|
||||
<Chip key={value} label={value}/>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
MenuProps={MenuProps}
|
||||
sx={{
|
||||
"&.MuiSelect-select": {
|
||||
minWidth: 0,
|
||||
maxWidth: '100%',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{names.map((name) => (
|
||||
<MenuItem
|
||||
key={name}
|
||||
value={name}
|
||||
style={getStyles(name, personName, theme)}
|
||||
>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectBoxMultiple;
|
||||
51
src/components/TextFieldWithFnBox.jsx
Normal file
51
src/components/TextFieldWithFnBox.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import {IconButton, Paper, TextField} from '@mui/material';
|
||||
import ArtTrackIcon from '@mui/icons-material/ArtTrack';
|
||||
import {useEffect, useState} from "react";
|
||||
import FilterBox from "@/components/FilterBox";
|
||||
|
||||
const TextFieldWithFnBox = ({formik, id , header, defaultValue, defaultFilter , columnFilterModeOptions ,onSelectFilter}) => {
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
formik.setFieldValue(id, defaultValue || '');
|
||||
}, []);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setOpen((prevOpen) => !prevOpen);
|
||||
setAnchorEl(anchorEl ? null : event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextField
|
||||
name={id}
|
||||
label={header}
|
||||
id={id}
|
||||
onChange={formik.handleChange}
|
||||
fullWidth
|
||||
value={formik.values[id]}
|
||||
margin="normal"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<IconButton onClick={handleClick}>
|
||||
<ArtTrackIcon />
|
||||
</IconButton>
|
||||
)
|
||||
}}
|
||||
sx={{
|
||||
position: 'relative'
|
||||
}}
|
||||
/>
|
||||
<FilterBox anchorEl={anchorEl} open={open} handleClose={handleClose} columnFilterModeOptions={columnFilterModeOptions} onSelectFilter={onSelectFilter} defaultFilter={defaultFilter}/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TextFieldWithFnBox;
|
||||
@@ -0,0 +1,9 @@
|
||||
import {Box, Stack} from "@mui/material";
|
||||
|
||||
const HeaderWithLogo = () => {
|
||||
return (<Stack>
|
||||
<Box>header1</Box>
|
||||
<Box>header2</Box>
|
||||
</Stack>)
|
||||
}
|
||||
export default HeaderWithLogo
|
||||
94
src/components/layouts/dashboard/headerWithSidebar/index.jsx
Normal file
94
src/components/layouts/dashboard/headerWithSidebar/index.jsx
Normal file
@@ -0,0 +1,94 @@
|
||||
'use client'
|
||||
import {useState} from "react";
|
||||
import {Box, Drawer, IconButton, Paper, styled, Toolbar, Typography} from "@mui/material";
|
||||
import MuiAppBar from '@mui/material/AppBar';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||
import SidebarMenu from "@/core/components/SidebarMenu";
|
||||
|
||||
const drawerWidth = 260;
|
||||
|
||||
const Main = styled(Paper, {shouldForwardProp: (prop) => prop !== 'open'})(({theme, open}) => ({
|
||||
flexGrow: 1, transition: theme.transitions.create('margin', {
|
||||
easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen,
|
||||
}), marginLeft: `-${drawerWidth}px`, ...(open && {
|
||||
transition: theme.transitions.create('margin', {
|
||||
easing: theme.transitions.easing.easeOut, duration: theme.transitions.duration.enteringScreen,
|
||||
}), marginLeft: 0,
|
||||
}),
|
||||
}),);
|
||||
|
||||
const AppBar = styled(MuiAppBar, {
|
||||
shouldForwardProp: (prop) => prop !== 'open',
|
||||
})(({theme, open}) => ({
|
||||
transition: theme.transitions.create(['margin', 'width'], {
|
||||
easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen,
|
||||
}), ...(open && {
|
||||
width: `calc(100% - ${drawerWidth}px)`,
|
||||
marginLeft: `${drawerWidth}px`,
|
||||
transition: theme.transitions.create(['margin', 'width'], {
|
||||
easing: theme.transitions.easing.easeOut, duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
|
||||
const DrawerHeader = styled('div')(({theme}) => ({
|
||||
display: 'flex', alignItems: 'center', padding: theme.spacing(0, 1), // necessary for content to be below app bar
|
||||
...theme.mixins.toolbar, justifyContent: 'flex-end',
|
||||
}));
|
||||
|
||||
const HeaderWithSidebar = ({children}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleDrawerOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleDrawerClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
return (<Box sx={{display: 'flex'}}>
|
||||
<AppBar sx={{position: 'fixed', top: "unset"}} elevation={0} open={open}>
|
||||
<Toolbar>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="open drawer"
|
||||
onClick={handleDrawerOpen}
|
||||
edge="start"
|
||||
sx={{mr: 2, ...(open && {display: 'none'})}}
|
||||
>
|
||||
<MenuIcon/>
|
||||
</IconButton>
|
||||
<Typography variant="h6" noWrap component="div">
|
||||
menu
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<Drawer
|
||||
sx={{
|
||||
width: drawerWidth, flexShrink: 0, '& .MuiDrawer-paper': {
|
||||
width: drawerWidth,
|
||||
boxSizing: 'border-box',
|
||||
borderTop: 1,
|
||||
borderTopColor: 'divider',
|
||||
top: "unset"
|
||||
},
|
||||
}}
|
||||
variant="persistent"
|
||||
anchor="left"
|
||||
open={open}
|
||||
>
|
||||
<DrawerHeader>
|
||||
<IconButton onClick={handleDrawerClose}>
|
||||
<ChevronRightIcon/>
|
||||
</IconButton>
|
||||
</DrawerHeader>
|
||||
<SidebarMenu />
|
||||
</Drawer>
|
||||
<Main elevation={0} open={open}>
|
||||
<DrawerHeader/>
|
||||
{children}
|
||||
</Main>
|
||||
</Box>)
|
||||
}
|
||||
export default HeaderWithSidebar
|
||||
19
src/core/components/DataTable/Main.js
Normal file
19
src/core/components/DataTable/Main.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useMaterialReactTable } from "material-react-table";
|
||||
import DataTable_Paper from "./table/Paper";
|
||||
|
||||
const isTableInstanceProp = (props) => props.table !== undefined;
|
||||
|
||||
const DataTable_Main = (props) => {
|
||||
let table;
|
||||
|
||||
if (isTableInstanceProp(props)) {
|
||||
table = props.table;
|
||||
} else {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
table = useMaterialReactTable(props);
|
||||
}
|
||||
|
||||
return <DataTable_Paper table={table} />;
|
||||
};
|
||||
|
||||
export default DataTable_Main;
|
||||
207
src/core/components/DataTable/body/TableBody.js
Normal file
207
src/core/components/DataTable/body/TableBody.js
Normal file
@@ -0,0 +1,207 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { TableBody, Typography } from "@mui/material";
|
||||
import { useMRT_RowVirtualizer, useMRT_Rows } from "material-react-table";
|
||||
import { memo, useMemo } from "react";
|
||||
import DataTable_TableBodyRow, { Memo_DataTable_TableBodyRow } from "./TableBodyRow";
|
||||
|
||||
const DataTable_TableBody = ({
|
||||
columnVirtualizer,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getBottomRows,
|
||||
getIsSomeRowsPinned,
|
||||
getRowModel,
|
||||
getState,
|
||||
getTopRows,
|
||||
options: {
|
||||
enableStickyFooter,
|
||||
enableStickyHeader,
|
||||
layoutMode,
|
||||
localization,
|
||||
memoMode,
|
||||
muiTableBodyProps,
|
||||
renderDetailPanel,
|
||||
renderEmptyRowsFallback,
|
||||
rowPinningDisplayMode,
|
||||
},
|
||||
refs: { tableFooterRef, tableHeadRef, tablePaperRef },
|
||||
} = table;
|
||||
const { columnFilters, globalFilter, isFullScreen, rowPinning } = getState();
|
||||
|
||||
const tableBodyProps = {
|
||||
...parseFromValuesOrFunc(muiTableBodyProps, { table }),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const tableHeadHeight =
|
||||
((enableStickyHeader || isFullScreen) &&
|
||||
tableHeadRef.current?.clientHeight) ||
|
||||
0;
|
||||
const tableFooterHeight =
|
||||
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
|
||||
|
||||
const pinnedRowIds = useMemo(() => {
|
||||
if (!rowPinning.bottom?.length && !rowPinning.top?.length) return [];
|
||||
return getRowModel()
|
||||
.rows.filter((row) => row.getIsPinned())
|
||||
.map((r) => r.id);
|
||||
}, [rowPinning, getRowModel().rows]);
|
||||
|
||||
const rows = useMRT_Rows(table);
|
||||
|
||||
const rowVirtualizer = useMRT_RowVirtualizer(table, rows);
|
||||
|
||||
const { virtualRows } = rowVirtualizer ?? {};
|
||||
|
||||
const commonRowProps = {
|
||||
columnVirtualizer,
|
||||
numRows: rows.length,
|
||||
table,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{!rowPinningDisplayMode?.includes('sticky') &&
|
||||
getIsSomeRowsPinned('top') && (
|
||||
<TableBody
|
||||
{...tableBodyProps}
|
||||
sx={(theme) => ({
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
position: 'sticky',
|
||||
top: tableHeadHeight - 1,
|
||||
zIndex: 1,
|
||||
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{getTopRows().map((row, staticRowIndex) => {
|
||||
const props = {
|
||||
...commonRowProps,
|
||||
row,
|
||||
staticRowIndex,
|
||||
};
|
||||
return memoMode === 'rows' ? (
|
||||
<Memo_DataTable_TableBodyRow key={row.id} {...props} />
|
||||
) : (
|
||||
<DataTable_TableBodyRow key={row.id} {...props} />
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
)}
|
||||
<TableBody
|
||||
{...tableBodyProps}
|
||||
sx={(theme) => ({
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
height: rowVirtualizer
|
||||
? `${rowVirtualizer.getTotalSize()}px`
|
||||
: undefined,
|
||||
minHeight: !rows.length ? '100px' : undefined,
|
||||
position: 'relative',
|
||||
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{tableBodyProps?.children ??
|
||||
(!rows.length ? (
|
||||
<tr
|
||||
style={{
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
}}
|
||||
>
|
||||
<td
|
||||
colSpan={table.getVisibleLeafColumns().length}
|
||||
style={{
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
}}
|
||||
>
|
||||
{renderEmptyRowsFallback?.({ table }) ?? (
|
||||
<Typography
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
fontStyle: 'italic',
|
||||
maxWidth: `min(100vw, ${tablePaperRef.current?.clientWidth ?? 360
|
||||
}px)`,
|
||||
py: '2rem',
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{globalFilter || columnFilters.length
|
||||
? localization.noResultsFound
|
||||
: localization.noRecordsToDisplay}
|
||||
</Typography>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<>
|
||||
{(virtualRows ?? rows).map((rowOrVirtualRow, staticRowIndex) => {
|
||||
let row = rowOrVirtualRow;
|
||||
if (rowVirtualizer) {
|
||||
if (renderDetailPanel) {
|
||||
if (rowOrVirtualRow.index % 2 === 1) {
|
||||
return null;
|
||||
} else {
|
||||
staticRowIndex = rowOrVirtualRow.index / 2;
|
||||
}
|
||||
} else {
|
||||
staticRowIndex = rowOrVirtualRow.index;
|
||||
}
|
||||
row = rows[staticRowIndex];
|
||||
}
|
||||
const props = {
|
||||
...commonRowProps,
|
||||
pinnedRowIds,
|
||||
row,
|
||||
rowVirtualizer,
|
||||
staticRowIndex,
|
||||
virtualRow: rowVirtualizer
|
||||
? (rowOrVirtualRow)
|
||||
: undefined,
|
||||
};
|
||||
const key = `${row.id}-${row.index}`;
|
||||
return memoMode === 'rows' ? (
|
||||
<Memo_DataTable_TableBodyRow key={key} {...props} />
|
||||
) : (
|
||||
<DataTable_TableBodyRow key={key} {...props} />
|
||||
);
|
||||
})}
|
||||
</>
|
||||
))}
|
||||
</TableBody>
|
||||
{!rowPinningDisplayMode?.includes('sticky') &&
|
||||
getIsSomeRowsPinned('bottom') && (
|
||||
<TableBody
|
||||
{...tableBodyProps}
|
||||
sx={(theme) => ({
|
||||
bottom: tableFooterHeight - 1,
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
position: 'sticky',
|
||||
zIndex: 1,
|
||||
...(parseFromValuesOrFunc(tableBodyProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{getBottomRows().map((row, staticRowIndex) => {
|
||||
const props = {
|
||||
...commonRowProps,
|
||||
row,
|
||||
staticRowIndex,
|
||||
};
|
||||
return memoMode === 'rows' ? (
|
||||
<Memo_DataTable_TableBodyRow key={row.id} {...props} />
|
||||
) : (
|
||||
<DataTable_TableBodyRow key={row.id} {...props} />
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableBody
|
||||
|
||||
export const Memo_DataTable_TableBody = memo(
|
||||
DataTable_TableBody,
|
||||
(prev, next) => prev.table.options.data === next.table.options.data,
|
||||
);
|
||||
306
src/core/components/DataTable/body/TableBodyCell.js
Normal file
306
src/core/components/DataTable/body/TableBodyCell.js
Normal file
@@ -0,0 +1,306 @@
|
||||
import { isCellEditable, openEditingCell } from "material-react-table";
|
||||
|
||||
const { parseFromValuesOrFunc, getCommonMRTCellStyles } = require("@/core/utils/utils");
|
||||
const { useTheme } = require("@emotion/react");
|
||||
const { TableCell, Skeleton } = require("@mui/material");
|
||||
const { useState, useEffect, useMemo, memo } = require("react");
|
||||
const { default: DataTable_CopyButton } = require("../buttons/CopyButton");
|
||||
const { default: DataTable_TableBodyCellValue } = require("./TableBodyCellValue");
|
||||
|
||||
const DataTable_TableBodyCell = ({
|
||||
cell,
|
||||
numRows,
|
||||
rowRef,
|
||||
staticColumnIndex,
|
||||
staticRowIndex,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
columnResizeDirection,
|
||||
columnResizeMode,
|
||||
createDisplayMode,
|
||||
editDisplayMode,
|
||||
enableCellActions,
|
||||
enableClickToCopy,
|
||||
enableColumnOrdering,
|
||||
enableColumnPinning,
|
||||
enableGrouping,
|
||||
layoutMode,
|
||||
mrtTheme: { draggingBorderColor },
|
||||
muiSkeletonProps,
|
||||
muiTableBodyCellProps,
|
||||
},
|
||||
setHoveredColumn,
|
||||
} = table;
|
||||
const {
|
||||
actionCell,
|
||||
columnSizingInfo,
|
||||
creatingRow,
|
||||
density,
|
||||
draggingColumn,
|
||||
draggingRow,
|
||||
editingCell,
|
||||
editingRow,
|
||||
hoveredColumn,
|
||||
hoveredRow,
|
||||
isLoading,
|
||||
showSkeletons,
|
||||
} = getState();
|
||||
const { column, row } = cell;
|
||||
const { columnDef } = column;
|
||||
const { columnDefType } = columnDef;
|
||||
|
||||
const args = { cell, column, row, table };
|
||||
const tableCellProps = {
|
||||
...parseFromValuesOrFunc(muiTableBodyCellProps, args),
|
||||
...parseFromValuesOrFunc(columnDef.muiTableBodyCellProps, args),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const skeletonProps = parseFromValuesOrFunc(muiSkeletonProps, {
|
||||
cell,
|
||||
column,
|
||||
row,
|
||||
table,
|
||||
});
|
||||
|
||||
const [skeletonWidth, setSkeletonWidth] = useState(100);
|
||||
useEffect(() => {
|
||||
if ((!isLoading && !showSkeletons) || skeletonWidth !== 100) return;
|
||||
const size = column.getSize();
|
||||
setSkeletonWidth(
|
||||
columnDefType === 'display'
|
||||
? size / 2
|
||||
: Math.round(Math.random() * (size - size / 3) + size / 3),
|
||||
);
|
||||
}, [isLoading, showSkeletons]);
|
||||
|
||||
const draggingBorders = useMemo(() => {
|
||||
const isDraggingColumn = draggingColumn?.id === column.id;
|
||||
const isHoveredColumn = hoveredColumn?.id === column.id;
|
||||
const isDraggingRow = draggingRow?.id === row.id;
|
||||
const isHoveredRow = hoveredRow?.id === row.id;
|
||||
const isFirstColumn = column.getIsFirstColumn();
|
||||
const isLastColumn = column.getIsLastColumn();
|
||||
const isLastRow = numRows && staticRowIndex === numRows - 1;
|
||||
const isResizingColumn = columnSizingInfo.isResizingColumn === column.id;
|
||||
const showResizeBorder =
|
||||
isResizingColumn && columnResizeMode === 'onChange';
|
||||
|
||||
const borderStyle = showResizeBorder
|
||||
? `2px solid ${draggingBorderColor} !important`
|
||||
: isDraggingColumn || isDraggingRow
|
||||
? `1px dashed ${theme.palette.grey[500]} !important`
|
||||
: isHoveredColumn || isHoveredRow || isResizingColumn
|
||||
? `2px dashed ${draggingBorderColor} !important`
|
||||
: undefined;
|
||||
|
||||
if (showResizeBorder) {
|
||||
return columnResizeDirection === 'ltr'
|
||||
? { borderRight: borderStyle }
|
||||
: { borderLeft: borderStyle };
|
||||
}
|
||||
|
||||
return borderStyle
|
||||
? {
|
||||
borderBottom:
|
||||
isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn)
|
||||
? borderStyle
|
||||
: undefined,
|
||||
borderLeft:
|
||||
isDraggingColumn ||
|
||||
isHoveredColumn ||
|
||||
((isDraggingRow || isHoveredRow) && isFirstColumn)
|
||||
? borderStyle
|
||||
: undefined,
|
||||
borderRight:
|
||||
isDraggingColumn ||
|
||||
isHoveredColumn ||
|
||||
((isDraggingRow || isHoveredRow) && isLastColumn)
|
||||
? borderStyle
|
||||
: undefined,
|
||||
borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined,
|
||||
}
|
||||
: undefined;
|
||||
}, [
|
||||
columnSizingInfo.isResizingColumn,
|
||||
draggingColumn,
|
||||
draggingRow,
|
||||
hoveredColumn,
|
||||
hoveredRow,
|
||||
staticRowIndex,
|
||||
]);
|
||||
|
||||
const isColumnPinned =
|
||||
enableColumnPinning &&
|
||||
columnDef.columnDefType !== 'group' &&
|
||||
column.getIsPinned();
|
||||
|
||||
const isEditable = isCellEditable({ cell, table });
|
||||
|
||||
const isEditing =
|
||||
isEditable &&
|
||||
!['custom', 'modal'].includes(editDisplayMode) &&
|
||||
(editDisplayMode === 'table' ||
|
||||
editingRow?.id === row.id ||
|
||||
editingCell?.id === cell.id) &&
|
||||
!row.getIsGrouped();
|
||||
|
||||
const isCreating =
|
||||
isEditable && createDisplayMode === 'row' && creatingRow?.id === row.id;
|
||||
|
||||
const showClickToCopyButton =
|
||||
(parseFromValuesOrFunc(enableClickToCopy, cell) === true ||
|
||||
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) === true) &&
|
||||
!['context-menu', false].includes(
|
||||
// @ts-ignore
|
||||
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell),
|
||||
);
|
||||
|
||||
const isRightClickable = parseFromValuesOrFunc(enableCellActions, cell);
|
||||
|
||||
const cellValueProps = {
|
||||
cell,
|
||||
table,
|
||||
};
|
||||
|
||||
const handleDoubleClick = (event) => {
|
||||
tableCellProps?.onDoubleClick?.(event);
|
||||
openEditingCell({ cell, table });
|
||||
};
|
||||
|
||||
const handleDragEnter = (e) => {
|
||||
tableCellProps?.onDragEnter?.(e);
|
||||
if (enableGrouping && hoveredColumn?.id === 'drop-zone') {
|
||||
setHoveredColumn(null);
|
||||
}
|
||||
if (enableColumnOrdering && draggingColumn) {
|
||||
setHoveredColumn(
|
||||
columnDef.enableColumnOrdering !== false ? column : null,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (e) => {
|
||||
if (columnDef.enableColumnOrdering !== false) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
const handleContextMenu = (e) => {
|
||||
tableCellProps?.onContextMenu?.(e);
|
||||
if (isRightClickable) {
|
||||
e.preventDefault();
|
||||
table.setActionCell(cell);
|
||||
table.refs.actionCellRef.current = e.currentTarget;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TableCell
|
||||
data-index={staticColumnIndex}
|
||||
data-pinned={!!isColumnPinned || undefined}
|
||||
{...tableCellProps}
|
||||
onContextMenu={handleContextMenu}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={handleDragOver}
|
||||
sx={(theme) => ({
|
||||
'&:hover': {
|
||||
outline:
|
||||
actionCell?.id === cell.id ||
|
||||
(editDisplayMode === 'cell' && isEditable) ||
|
||||
(editDisplayMode === 'table' && (isCreating || isEditing))
|
||||
? `1px solid ${theme.palette.grey[500]}`
|
||||
: undefined,
|
||||
textOverflow: 'clip',
|
||||
},
|
||||
alignItems: layoutMode?.startsWith('grid') ? 'center' : undefined,
|
||||
cursor: isRightClickable
|
||||
? 'context-menu'
|
||||
: isEditable && editDisplayMode === 'cell'
|
||||
? 'pointer'
|
||||
: 'inherit',
|
||||
outline:
|
||||
actionCell?.id === cell.id
|
||||
? `1px solid ${theme.palette.grey[500]}`
|
||||
: undefined,
|
||||
outlineOffset: '-1px',
|
||||
overflow: 'hidden',
|
||||
p:
|
||||
density === 'compact'
|
||||
? columnDefType === 'display'
|
||||
? '0 0.5rem'
|
||||
: '0.5rem'
|
||||
: density === 'comfortable'
|
||||
? columnDefType === 'display'
|
||||
? '0.5rem 0.75rem'
|
||||
: '1rem'
|
||||
: columnDefType === 'display'
|
||||
? '1rem 1.25rem'
|
||||
: '1.5rem',
|
||||
|
||||
textOverflow: columnDefType !== 'display' ? 'ellipsis' : undefined,
|
||||
whiteSpace:
|
||||
row.getIsPinned() || density === 'compact' ? 'nowrap' : 'normal',
|
||||
...getCommonMRTCellStyles({
|
||||
column,
|
||||
table,
|
||||
tableCellProps,
|
||||
theme,
|
||||
}),
|
||||
...draggingBorders,
|
||||
})}
|
||||
>
|
||||
{tableCellProps.children ?? (
|
||||
<>
|
||||
{cell.getIsPlaceholder() ? (
|
||||
columnDef.PlaceholderCell?.({ cell, column, row, table }) ?? null
|
||||
) : showSkeletons !== false && (isLoading || showSkeletons) ? (
|
||||
<Skeleton
|
||||
animation="wave"
|
||||
height={20}
|
||||
width={skeletonWidth}
|
||||
{...skeletonProps}
|
||||
/>
|
||||
) : columnDefType === 'display' &&
|
||||
(['mrt-row-expand', 'mrt-row-numbers', 'mrt-row-select'].includes(
|
||||
column.id,
|
||||
) ||
|
||||
!row.getIsGrouped()) ? (
|
||||
columnDef.Cell?.({
|
||||
cell,
|
||||
column,
|
||||
renderedCellValue: cell.renderValue(),
|
||||
row,
|
||||
rowRef,
|
||||
staticColumnIndex,
|
||||
staticRowIndex,
|
||||
table,
|
||||
})
|
||||
) : showClickToCopyButton && columnDef.enableClickToCopy !== false ? (
|
||||
<DataTable_CopyButton cell={cell} table={table}>
|
||||
<DataTable_TableBodyCellValue {...cellValueProps} />
|
||||
</DataTable_CopyButton>
|
||||
) : (
|
||||
<DataTable_TableBodyCellValue {...cellValueProps} />
|
||||
)}
|
||||
{cell.getIsGrouped() && !columnDef.GroupedCell && (
|
||||
<> ({row.subRows?.length})</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</TableCell>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableBodyCell;
|
||||
|
||||
export const Memo_DataTable_TableBodyCell = memo(
|
||||
DataTable_TableBodyCell,
|
||||
(prev, next) => next.cell === prev.cell,
|
||||
);
|
||||
112
src/core/components/DataTable/body/TableBodyCellValue.js
Normal file
112
src/core/components/DataTable/body/TableBodyCellValue.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
const allowedTypes = ["string", "number"];
|
||||
|
||||
const DataTable_TableBodyCellValue = ({
|
||||
cell,
|
||||
rowRef,
|
||||
staticColumnIndex,
|
||||
staticRowIndex,
|
||||
table,
|
||||
}) => {
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
enableFilterMatchHighlighting,
|
||||
mrtTheme: { matchHighlightColor },
|
||||
},
|
||||
} = table;
|
||||
const { column, row } = cell;
|
||||
const { columnDef } = column;
|
||||
const { globalFilter, globalFilterFn } = getState();
|
||||
const filterValue = column.getFilterValue();
|
||||
|
||||
let renderedCellValue =
|
||||
cell.getIsAggregated() && columnDef.AggregatedCell
|
||||
? columnDef.AggregatedCell({
|
||||
cell,
|
||||
column,
|
||||
row,
|
||||
table,
|
||||
})
|
||||
: row.getIsGrouped() && !cell.getIsGrouped()
|
||||
? null
|
||||
: cell.getIsGrouped() && columnDef.GroupedCell
|
||||
? columnDef.GroupedCell({
|
||||
cell,
|
||||
column,
|
||||
row,
|
||||
table,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const isGroupedValue = renderedCellValue !== undefined;
|
||||
|
||||
if (!isGroupedValue) {
|
||||
renderedCellValue = cell.renderValue();
|
||||
}
|
||||
|
||||
if (
|
||||
enableFilterMatchHighlighting &&
|
||||
columnDef.enableFilterMatchHighlighting !== false &&
|
||||
String(renderedCellValue) &&
|
||||
allowedTypes.includes(typeof renderedCellValue) &&
|
||||
((filterValue &&
|
||||
allowedTypes.includes(typeof filterValue) &&
|
||||
["autocomplete", "text"].includes(columnDef.filterVariant)) ||
|
||||
(globalFilter &&
|
||||
allowedTypes.includes(typeof globalFilter) &&
|
||||
column.getCanGlobalFilter()))
|
||||
) {
|
||||
const chunks = highlightWords?.({
|
||||
matchExactly:
|
||||
(filterValue ? columnDef._filterFn : globalFilterFn) !== "fuzzy",
|
||||
query: (filterValue ?? globalFilter ?? "").toString(),
|
||||
text: renderedCellValue?.toString(),
|
||||
});
|
||||
if (chunks?.length > 1 || chunks?.[0]?.match) {
|
||||
renderedCellValue = (
|
||||
<span aria-label={renderedCellValue} role="note">
|
||||
{chunks?.map(({ key, match, text }) => (
|
||||
<Box
|
||||
aria-hidden="true"
|
||||
component="span"
|
||||
key={key}
|
||||
sx={
|
||||
match
|
||||
? {
|
||||
backgroundColor: matchHighlightColor,
|
||||
borderRadius: "2px",
|
||||
color: (theme) =>
|
||||
theme.palette.mode === "dark"
|
||||
? theme.palette.common.white
|
||||
: theme.palette.common.black,
|
||||
padding: "2px 1px",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{text}
|
||||
</Box>
|
||||
)) ?? renderedCellValue}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (columnDef.Cell && !isGroupedValue) {
|
||||
renderedCellValue = columnDef.Cell({
|
||||
cell,
|
||||
column,
|
||||
renderedCellValue,
|
||||
row,
|
||||
rowRef,
|
||||
staticColumnIndex,
|
||||
staticRowIndex,
|
||||
table,
|
||||
});
|
||||
}
|
||||
|
||||
return renderedCellValue;
|
||||
};
|
||||
export default DataTable_TableBodyCellValue;
|
||||
254
src/core/components/DataTable/body/TableBodyRow.js
Normal file
254
src/core/components/DataTable/body/TableBodyRow.js
Normal file
@@ -0,0 +1,254 @@
|
||||
import { commonCellBeforeAfterStyles, getCommonPinnedCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { TableRow, alpha, darken, lighten } from "@mui/material";
|
||||
import { getIsRowSelected } from "material-react-table";
|
||||
import { memo, useMemo, useRef } from "react";
|
||||
import DataTable_TableBodyCell, { Memo_DataTable_TableBodyCell } from "./TableBodyCell";
|
||||
import DataTable_TableDetailPanel from "./TableDetailPanel";
|
||||
|
||||
const DataTable_TableBodyRow = ({
|
||||
columnVirtualizer,
|
||||
numRows,
|
||||
pinnedRowIds,
|
||||
row,
|
||||
rowVirtualizer,
|
||||
staticRowIndex,
|
||||
table,
|
||||
virtualRow,
|
||||
...rest
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
enableRowOrdering,
|
||||
enableRowPinning,
|
||||
enableStickyFooter,
|
||||
enableStickyHeader,
|
||||
layoutMode,
|
||||
memoMode,
|
||||
mrtTheme: {
|
||||
baseBackgroundColor,
|
||||
pinnedRowBackgroundColor,
|
||||
selectedRowBackgroundColor,
|
||||
},
|
||||
muiTableBodyRowProps,
|
||||
renderDetailPanel,
|
||||
rowPinningDisplayMode,
|
||||
},
|
||||
refs: { tableFooterRef, tableHeadRef },
|
||||
setHoveredRow,
|
||||
} = table;
|
||||
const {
|
||||
density,
|
||||
draggingColumn,
|
||||
draggingRow,
|
||||
editingCell,
|
||||
editingRow,
|
||||
hoveredRow,
|
||||
isFullScreen,
|
||||
rowPinning,
|
||||
} = getState();
|
||||
|
||||
const visibleCells = row.getVisibleCells();
|
||||
|
||||
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } =
|
||||
columnVirtualizer ?? {};
|
||||
|
||||
const isRowSelected = getIsRowSelected({ row, table });
|
||||
const isRowPinned = enableRowPinning && row.getIsPinned();
|
||||
const isDraggingRow = draggingRow?.id === row.id;
|
||||
const isHoveredRow = hoveredRow?.id === row.id;
|
||||
|
||||
const tableRowProps = {
|
||||
...parseFromValuesOrFunc(muiTableBodyRowProps, {
|
||||
row,
|
||||
staticRowIndex,
|
||||
table,
|
||||
}),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const [bottomPinnedIndex, topPinnedIndex] = useMemo(() => {
|
||||
if (
|
||||
!enableRowPinning ||
|
||||
!rowPinningDisplayMode?.includes('sticky') ||
|
||||
!pinnedRowIds ||
|
||||
!row.getIsPinned()
|
||||
)
|
||||
return [];
|
||||
return [
|
||||
[...pinnedRowIds].reverse().indexOf(row.id),
|
||||
pinnedRowIds.indexOf(row.id),
|
||||
];
|
||||
}, [pinnedRowIds, rowPinning]);
|
||||
|
||||
const tableHeadHeight =
|
||||
((enableStickyHeader || isFullScreen) &&
|
||||
tableHeadRef.current?.clientHeight) ||
|
||||
0;
|
||||
const tableFooterHeight =
|
||||
(enableStickyFooter && tableFooterRef.current?.clientHeight) || 0;
|
||||
|
||||
const sx = parseFromValuesOrFunc(tableRowProps?.sx, theme);
|
||||
|
||||
const defaultRowHeight =
|
||||
density === 'compact' ? 37 : density === 'comfortable' ? 53 : 69;
|
||||
|
||||
const customRowHeight =
|
||||
// @ts-ignore
|
||||
parseInt(tableRowProps?.style?.height ?? sx?.height, 10) || undefined;
|
||||
|
||||
const rowHeight = customRowHeight || defaultRowHeight;
|
||||
|
||||
const handleDragEnter = (_e) => {
|
||||
if (enableRowOrdering && draggingRow) {
|
||||
setHoveredRow(row);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (e) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const rowRef = useRef(null);
|
||||
|
||||
const cellHighlightColor = isRowSelected
|
||||
? selectedRowBackgroundColor
|
||||
: isRowPinned
|
||||
? pinnedRowBackgroundColor
|
||||
: undefined;
|
||||
|
||||
const cellHighlightColorHover =
|
||||
tableRowProps?.hover !== false
|
||||
? isRowSelected
|
||||
? cellHighlightColor
|
||||
: theme.palette.mode === 'dark'
|
||||
? `${lighten(baseBackgroundColor, 0.3)}`
|
||||
: `${darken(baseBackgroundColor, 0.3)}`
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow
|
||||
data-index={renderDetailPanel ? staticRowIndex * 2 : staticRowIndex}
|
||||
data-pinned={!!isRowPinned || undefined}
|
||||
data-selected={isRowSelected || undefined}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={handleDragOver}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
rowRef.current = node;
|
||||
rowVirtualizer?.measureElement(node);
|
||||
}
|
||||
}}
|
||||
selected={isRowSelected}
|
||||
{...tableRowProps}
|
||||
style={{
|
||||
transform: virtualRow
|
||||
? `translateY(${virtualRow.start}px)`
|
||||
: undefined,
|
||||
...tableRowProps?.style,
|
||||
}}
|
||||
sx={(theme) => ({
|
||||
'&:hover td:after': cellHighlightColorHover
|
||||
? {
|
||||
backgroundColor: alpha(cellHighlightColorHover, 0.3),
|
||||
...commonCellBeforeAfterStyles,
|
||||
}
|
||||
: undefined,
|
||||
backgroundColor: `${baseBackgroundColor} !important`,
|
||||
bottom:
|
||||
!virtualRow && bottomPinnedIndex !== undefined && isRowPinned
|
||||
? `${bottomPinnedIndex * rowHeight +
|
||||
(enableStickyFooter ? tableFooterHeight - 1 : 0)
|
||||
}px`
|
||||
: undefined,
|
||||
boxSizing: 'border-box',
|
||||
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
|
||||
opacity: isRowPinned ? 0.97 : isDraggingRow || isHoveredRow ? 0.5 : 1,
|
||||
position: virtualRow
|
||||
? 'absolute'
|
||||
: rowPinningDisplayMode?.includes('sticky') && isRowPinned
|
||||
? 'sticky'
|
||||
: 'relative',
|
||||
td: {
|
||||
...getCommonPinnedCellStyles({ table, theme }),
|
||||
},
|
||||
'td:after': cellHighlightColor
|
||||
? {
|
||||
backgroundColor: cellHighlightColor,
|
||||
...commonCellBeforeAfterStyles,
|
||||
}
|
||||
: undefined,
|
||||
top: virtualRow
|
||||
? 0
|
||||
: topPinnedIndex !== undefined && isRowPinned
|
||||
? `${topPinnedIndex * rowHeight +
|
||||
(enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0)
|
||||
}px`
|
||||
: undefined,
|
||||
transition: virtualRow ? 'none' : 'all 150ms ease-in-out',
|
||||
width: '100%',
|
||||
zIndex:
|
||||
rowPinningDisplayMode?.includes('sticky') && isRowPinned ? 2 : 0,
|
||||
...(sx),
|
||||
})}
|
||||
>
|
||||
{virtualPaddingLeft ? (
|
||||
<td style={{ display: 'flex', width: virtualPaddingLeft }} />
|
||||
) : null}
|
||||
{(virtualColumns ?? visibleCells).map(
|
||||
(cellOrVirtualCell, staticColumnIndex) => {
|
||||
let cell = cellOrVirtualCell;
|
||||
if (columnVirtualizer) {
|
||||
staticColumnIndex = (cellOrVirtualCell).index;
|
||||
cell = visibleCells[staticColumnIndex];
|
||||
}
|
||||
const props = {
|
||||
cell,
|
||||
numRows,
|
||||
rowRef,
|
||||
staticColumnIndex,
|
||||
staticRowIndex,
|
||||
table,
|
||||
};
|
||||
return cell ? (
|
||||
memoMode === 'cells' &&
|
||||
cell.column.columnDef.columnDefType === 'data' &&
|
||||
!draggingColumn &&
|
||||
!draggingRow &&
|
||||
editingCell?.id !== cell.id &&
|
||||
editingRow?.id !== row.id ? (
|
||||
<Memo_DataTable_TableBodyCell key={cell.id} {...props} />
|
||||
) : (
|
||||
<DataTable_TableBodyCell key={cell.id} {...props} />
|
||||
)
|
||||
) : null;
|
||||
},
|
||||
)}
|
||||
{virtualPaddingRight ? (
|
||||
<td style={{ display: 'flex', width: virtualPaddingRight }} />
|
||||
) : null}
|
||||
</TableRow>
|
||||
{renderDetailPanel && !row.getIsGrouped() && (
|
||||
<DataTable_TableDetailPanel
|
||||
parentRowRef={rowRef}
|
||||
row={row}
|
||||
rowVirtualizer={rowVirtualizer}
|
||||
staticRowIndex={staticRowIndex}
|
||||
table={table}
|
||||
virtualRow={virtualRow}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default DataTable_TableBodyRow
|
||||
|
||||
export const Memo_DataTable_TableBodyRow = memo(
|
||||
DataTable_TableBodyRow,
|
||||
(prev, next) =>
|
||||
prev.row === next.row && prev.staticRowIndex === next.staticRowIndex,
|
||||
);
|
||||
93
src/core/components/DataTable/body/TableDetailPanel.js
Normal file
93
src/core/components/DataTable/body/TableDetailPanel.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { Collapse, TableCell, TableRow } from "@mui/material";
|
||||
|
||||
const DataTable_TableDetailPanel = ({
|
||||
parentRowRef,
|
||||
row,
|
||||
rowVirtualizer,
|
||||
staticRowIndex,
|
||||
table,
|
||||
virtualRow,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getState,
|
||||
getVisibleLeafColumns,
|
||||
options: {
|
||||
layoutMode,
|
||||
mrtTheme: { baseBackgroundColor },
|
||||
muiDetailPanelProps,
|
||||
muiTableBodyRowProps,
|
||||
renderDetailPanel,
|
||||
},
|
||||
} = table;
|
||||
const { isLoading } = getState();
|
||||
|
||||
|
||||
const tableRowProps = parseFromValuesOrFunc(muiTableBodyRowProps, {
|
||||
isDetailPanel: true,
|
||||
row,
|
||||
staticRowIndex,
|
||||
table,
|
||||
});
|
||||
|
||||
const tableCellProps = {
|
||||
...parseFromValuesOrFunc(muiDetailPanelProps, {
|
||||
row,
|
||||
table,
|
||||
}),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const DetailPanel = !isLoading && renderDetailPanel?.({ row, table });
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
className="Mui-TableBodyCell-DetailPanel"
|
||||
data-index={renderDetailPanel ? staticRowIndex * 2 + 1 : staticRowIndex}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
rowVirtualizer?.measureElement?.(node);
|
||||
}
|
||||
}}
|
||||
{...tableRowProps}
|
||||
sx={(theme) => ({
|
||||
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
|
||||
position: virtualRow ? 'absolute' : undefined,
|
||||
top: virtualRow
|
||||
? `${parentRowRef.current?.getBoundingClientRect()?.height}px`
|
||||
: undefined,
|
||||
transform: virtualRow
|
||||
? `translateY(${virtualRow?.start}px)`
|
||||
: undefined,
|
||||
width: '100%',
|
||||
...(parseFromValuesOrFunc(tableRowProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
<TableCell
|
||||
className="Mui-TableBodyCell-DetailPanel"
|
||||
colSpan={getVisibleLeafColumns().length}
|
||||
{...tableCellProps}
|
||||
sx={(theme) => ({
|
||||
backgroundColor: virtualRow ? baseBackgroundColor : undefined,
|
||||
borderBottom: !row.getIsExpanded() ? 'none' : undefined,
|
||||
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
|
||||
py: !!DetailPanel && row.getIsExpanded() ? '1rem' : 0,
|
||||
transition: !virtualRow ? 'all 150ms ease-in-out' : undefined,
|
||||
width: `100%`,
|
||||
...(parseFromValuesOrFunc(tableCellProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{virtualRow ? (
|
||||
row.getIsExpanded() && DetailPanel
|
||||
) : (
|
||||
<Collapse in={row.getIsExpanded()} mountOnEnter unmountOnExit>
|
||||
{DetailPanel}
|
||||
</Collapse>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableDetailPanel
|
||||
75
src/core/components/DataTable/buttons/CopyButton.js
Normal file
75
src/core/components/DataTable/buttons/CopyButton.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { Button, Tooltip } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
|
||||
const DataTable_CopyButton = ({
|
||||
cell,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
options: { localization, muiCopyButtonProps },
|
||||
} = table;
|
||||
const { column, row } = cell;
|
||||
const { columnDef } = column;
|
||||
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const handleCopy = (event, text) => {
|
||||
event.stopPropagation();
|
||||
navigator.clipboard.writeText(text);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 4000);
|
||||
};
|
||||
|
||||
const buttonProps = {
|
||||
...parseFromValuesOrFunc(muiCopyButtonProps, {
|
||||
cell,
|
||||
column,
|
||||
row,
|
||||
table,
|
||||
}),
|
||||
...parseFromValuesOrFunc(columnDef.muiCopyButtonProps, {
|
||||
cell,
|
||||
column,
|
||||
row,
|
||||
table,
|
||||
}),
|
||||
...rest,
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
{...getCommonTooltipProps('top')}
|
||||
title={
|
||||
buttonProps?.title ??
|
||||
(copied ? localization.copiedToClipboard : localization.clickToCopy)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
onClick={(e) => handleCopy(e, cell.getValue())}
|
||||
size="small"
|
||||
type="button"
|
||||
variant="text"
|
||||
{...buttonProps}
|
||||
sx={(theme) => ({
|
||||
backgroundColor: 'transparent',
|
||||
border: 'none',
|
||||
color: 'inherit',
|
||||
cursor: 'copy',
|
||||
fontFamily: 'inherit',
|
||||
fontSize: 'inherit',
|
||||
letterSpacing: 'inherit',
|
||||
m: '-0.25rem',
|
||||
minWidth: 'unset',
|
||||
py: 0,
|
||||
textAlign: 'inherit',
|
||||
textTransform: 'inherit',
|
||||
...(parseFromValuesOrFunc(buttonProps?.sx, theme)),
|
||||
})}
|
||||
title={undefined}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
export default DataTable_CopyButton
|
||||
54
src/core/components/DataTable/buttons/GrabHandleButton.js
Normal file
54
src/core/components/DataTable/buttons/GrabHandleButton.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { IconButton, Tooltip } from "@mui/material";
|
||||
|
||||
const DataTable_GrabHandleButton = ({
|
||||
location,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
options: {
|
||||
icons: { DragHandleIcon },
|
||||
localization,
|
||||
},
|
||||
} = table;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
{...getCommonTooltipProps('top')}
|
||||
title={rest?.title ?? localization.move}
|
||||
>
|
||||
<IconButton
|
||||
aria-label={rest.title ?? localization.move}
|
||||
disableRipple
|
||||
draggable="true"
|
||||
size="small"
|
||||
{...rest}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
rest?.onClick?.(e);
|
||||
}}
|
||||
sx={(theme) => ({
|
||||
'&:active': {
|
||||
cursor: 'grabbing',
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: 'transparent',
|
||||
opacity: 1,
|
||||
},
|
||||
cursor: 'grab',
|
||||
m: '0 -0.1rem',
|
||||
opacity: location === 'row' ? 1 : 0.5,
|
||||
p: '2px',
|
||||
transition: 'all 150ms ease-in-out',
|
||||
...(parseFromValuesOrFunc(rest?.sx, theme)),
|
||||
})}
|
||||
title={undefined}
|
||||
>
|
||||
<DragHandleIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_GrabHandleButton
|
||||
@@ -0,0 +1,41 @@
|
||||
import { IconButton, Tooltip } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import DataTable_ShowHideColumnsMenu from "../menus/ShowHideColumnsMenu";
|
||||
|
||||
const DataTable_ShowHideColumnsButton = ({ table, ...rest }) => {
|
||||
const {
|
||||
options: {
|
||||
icons: { ViewColumnIcon },
|
||||
localization,
|
||||
},
|
||||
} = table;
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={rest?.title ?? localization.showHideColumns}>
|
||||
<IconButton
|
||||
aria-label={localization.showHideColumns}
|
||||
onClick={handleClick}
|
||||
{...rest}
|
||||
title={undefined}
|
||||
>
|
||||
<ViewColumnIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{anchorEl && (
|
||||
<DataTable_ShowHideColumnsMenu
|
||||
anchorEl={anchorEl}
|
||||
setAnchorEl={setAnchorEl}
|
||||
table={table}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default DataTable_ShowHideColumnsButton
|
||||
@@ -0,0 +1,4 @@
|
||||
const DataTable_ToggleFiltersButton = ({ table, ...rest }) => {
|
||||
return <></>
|
||||
}
|
||||
export default DataTable_ToggleFiltersButton
|
||||
63
src/core/components/DataTable/head/TableHead.js
Normal file
63
src/core/components/DataTable/head/TableHead.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { TableHead } from "@mui/material";
|
||||
import DataTable_TableHeadRow from "./TableHeadRow";
|
||||
|
||||
const DataTable_TableHead = ({
|
||||
columnVirtualizer,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
enableStickyHeader,
|
||||
layoutMode,
|
||||
muiTableHeadProps,
|
||||
positionToolbarAlertBanner,
|
||||
},
|
||||
refs: { tableHeadRef },
|
||||
} = table;
|
||||
const { isFullScreen, showAlertBanner } = getState();
|
||||
|
||||
const tableHeadProps = {
|
||||
...parseFromValuesOrFunc(muiTableHeadProps, { table }),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const stickyHeader = enableStickyHeader || isFullScreen;
|
||||
|
||||
return (
|
||||
<TableHead
|
||||
{...tableHeadProps}
|
||||
ref={(ref) => {
|
||||
tableHeadRef.current = ref;
|
||||
if (tableHeadProps?.ref) {
|
||||
// @ts-ignore
|
||||
tableHeadProps.ref.current = ref;
|
||||
}
|
||||
}}
|
||||
sx={(theme) => ({
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
opacity: 0.97,
|
||||
position: stickyHeader ? 'sticky' : 'relative',
|
||||
top: stickyHeader && layoutMode?.startsWith('grid') ? 0 : undefined,
|
||||
zIndex: stickyHeader ? 2 : undefined,
|
||||
...(parseFromValuesOrFunc(tableHeadProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{table
|
||||
.getHeaderGroups()
|
||||
.map((headerGroup) => (
|
||||
<DataTable_TableHeadRow
|
||||
columnVirtualizer={columnVirtualizer}
|
||||
headerGroup={headerGroup}
|
||||
key={headerGroup.id}
|
||||
table={table}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</TableHead>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableHead
|
||||
283
src/core/components/DataTable/head/TableHeadCell.js
Normal file
283
src/core/components/DataTable/head/TableHeadCell.js
Normal file
@@ -0,0 +1,283 @@
|
||||
import { getCommonMRTCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Box, TableCell } from "@mui/material";
|
||||
import { MRT_TableHeadCellSortLabel } from "material-react-table";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const DataTable_TableHeadCell = ({
|
||||
columnVirtualizer,
|
||||
header,
|
||||
staticColumnIndex,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
columnResizeDirection,
|
||||
columnResizeMode,
|
||||
enableColumnActions,
|
||||
enableColumnDragging,
|
||||
enableColumnOrdering,
|
||||
enableColumnPinning,
|
||||
enableGrouping,
|
||||
enableMultiSort,
|
||||
layoutMode,
|
||||
mrtTheme: { draggingBorderColor },
|
||||
muiTableHeadCellProps,
|
||||
},
|
||||
refs: { tableHeadCellRefs },
|
||||
setHoveredColumn,
|
||||
} = table;
|
||||
const {
|
||||
columnSizingInfo,
|
||||
density,
|
||||
draggingColumn,
|
||||
grouping,
|
||||
hoveredColumn,
|
||||
showColumnFilters,
|
||||
} = getState();
|
||||
const { column } = header;
|
||||
const { columnDef } = column;
|
||||
const { columnDefType } = columnDef;
|
||||
|
||||
const tableCellProps = {
|
||||
...parseFromValuesOrFunc(muiTableHeadCellProps, { column, table }),
|
||||
...parseFromValuesOrFunc(columnDef.muiTableHeadCellProps, {
|
||||
column,
|
||||
table,
|
||||
}),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const isColumnPinned =
|
||||
enableColumnPinning &&
|
||||
columnDef.columnDefType !== 'group' &&
|
||||
column.getIsPinned();
|
||||
|
||||
const showColumnActions =
|
||||
(enableColumnActions || columnDef.enableColumnActions) &&
|
||||
columnDef.enableColumnActions !== false;
|
||||
|
||||
const showDragHandle =
|
||||
enableColumnDragging !== false &&
|
||||
columnDef.enableColumnDragging !== false &&
|
||||
(enableColumnDragging ||
|
||||
(enableColumnOrdering && columnDef.enableColumnOrdering !== false) ||
|
||||
(enableGrouping &&
|
||||
columnDef.enableGrouping !== false &&
|
||||
!grouping.includes(column.id)));
|
||||
|
||||
const headerPL = useMemo(() => {
|
||||
let pl = 0;
|
||||
if (column.getCanSort()) pl += 1;
|
||||
if (showColumnActions) pl += 1.75;
|
||||
if (showDragHandle) pl += 1.5;
|
||||
return pl;
|
||||
}, [showColumnActions, showDragHandle]);
|
||||
|
||||
const draggingBorders = useMemo(() => {
|
||||
const showResizeBorder =
|
||||
columnSizingInfo.isResizingColumn === column.id &&
|
||||
columnResizeMode === 'onChange' &&
|
||||
!header.subHeaders.length;
|
||||
|
||||
const borderStyle = showResizeBorder
|
||||
? `2px solid ${draggingBorderColor} !important`
|
||||
: draggingColumn?.id === column.id
|
||||
? `1px dashed ${theme.palette.grey[500]}`
|
||||
: hoveredColumn?.id === column.id
|
||||
? `2px dashed ${draggingBorderColor}`
|
||||
: undefined;
|
||||
|
||||
if (showResizeBorder) {
|
||||
return columnResizeDirection === 'ltr'
|
||||
? { borderRight: borderStyle }
|
||||
: { borderLeft: borderStyle };
|
||||
}
|
||||
const draggingBorders = borderStyle
|
||||
? {
|
||||
borderLeft: borderStyle,
|
||||
borderRight: borderStyle,
|
||||
borderTop: borderStyle,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return draggingBorders;
|
||||
}, [draggingColumn, hoveredColumn, columnSizingInfo.isResizingColumn]);
|
||||
|
||||
const handleDragEnter = (_e) => {
|
||||
if (enableGrouping && hoveredColumn?.id === 'drop-zone') {
|
||||
setHoveredColumn(null);
|
||||
}
|
||||
if (enableColumnOrdering && draggingColumn && columnDefType !== 'group') {
|
||||
setHoveredColumn(
|
||||
columnDef.enableColumnOrdering !== false ? column : null,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (e) => {
|
||||
if (columnDef.enableColumnOrdering !== false) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const HeaderElement =
|
||||
parseFromValuesOrFunc(columnDef.Header, {
|
||||
column,
|
||||
header,
|
||||
table,
|
||||
}) ?? columnDef.header;
|
||||
|
||||
|
||||
const columnRelativeDepth = header.depth - column.depth;
|
||||
|
||||
if (
|
||||
columnRelativeDepth > 1
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let rowSpan = 1;
|
||||
if (header.isPlaceholder) {
|
||||
const leafs = header.getLeafHeaders();
|
||||
rowSpan = leafs[leafs.length - 1].depth - header.depth;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableCell
|
||||
align={
|
||||
columnDefType === 'group'
|
||||
? 'center'
|
||||
: theme.direction === 'rtl'
|
||||
? 'right'
|
||||
: 'left'
|
||||
}
|
||||
colSpan={header.colSpan}
|
||||
rowSpan={rowSpan}
|
||||
data-index={staticColumnIndex}
|
||||
data-pinned={!!isColumnPinned || undefined}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={handleDragOver}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
tableHeadCellRefs.current[column.id] = node;
|
||||
if (columnDefType !== 'group') {
|
||||
columnVirtualizer?.measureElement?.(node);
|
||||
}
|
||||
}
|
||||
}}
|
||||
{...tableCellProps}
|
||||
sx={(theme) => ({
|
||||
'& :hover': {
|
||||
'.MuiButtonBase-root': {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
flexDirection: layoutMode?.startsWith('grid') ? 'column' : undefined,
|
||||
fontWeight: 'bold',
|
||||
overflow: 'visible',
|
||||
p:
|
||||
density === 'compact'
|
||||
? '0.5rem'
|
||||
: density === 'comfortable'
|
||||
? columnDefType === 'display'
|
||||
? '0.75rem'
|
||||
: '1rem'
|
||||
: columnDefType === 'display'
|
||||
? '1rem 1.25rem'
|
||||
: '1.5rem',
|
||||
pb:
|
||||
columnDefType === 'display'
|
||||
? 0
|
||||
: showColumnFilters || density === 'compact'
|
||||
? '0.4rem'
|
||||
: '0.6rem',
|
||||
pt:
|
||||
columnDefType === 'group' || density === 'compact'
|
||||
? '0.25rem'
|
||||
: density === 'comfortable'
|
||||
? '.75rem'
|
||||
: '1.25rem',
|
||||
userSelect: enableMultiSort && column.getCanSort() ? 'none' : undefined,
|
||||
verticalAlign: 'middle',
|
||||
...getCommonMRTCellStyles({
|
||||
column,
|
||||
header,
|
||||
table,
|
||||
tableCellProps,
|
||||
theme,
|
||||
}),
|
||||
...draggingBorders,
|
||||
}
|
||||
)}
|
||||
>
|
||||
{tableCellProps.children ?? (
|
||||
<Box
|
||||
className="Mui-TableHeadCell-Content"
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection:
|
||||
tableCellProps?.align === 'right' ? 'row-reverse' : 'row',
|
||||
justifyContent:
|
||||
columnDefType === 'group' ||
|
||||
tableCellProps?.align === 'center'
|
||||
? 'center'
|
||||
: column.getCanResize()
|
||||
? 'space-between'
|
||||
: 'flex-start',
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
className="Mui-TableHeadCell-Content-Labels"
|
||||
onClick={column.getToggleSortingHandler()}
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
cursor:
|
||||
column.getCanSort() && columnDefType !== 'group'
|
||||
? 'pointer'
|
||||
: undefined,
|
||||
display: 'flex',
|
||||
flexDirection:
|
||||
tableCellProps?.align === 'right' ? 'row-reverse' : 'row',
|
||||
overflow: columnDefType === 'data' ? 'hidden' : undefined,
|
||||
pl:
|
||||
tableCellProps?.align === 'center'
|
||||
? `${headerPL}rem`
|
||||
: undefined,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
className="Mui-TableHeadCell-Content-Wrapper"
|
||||
sx={{
|
||||
'&:hover': {
|
||||
textOverflow: 'clip',
|
||||
},
|
||||
minWidth: `${Math.min(columnDef.header?.length ?? 0, 4)}ch`,
|
||||
overflow: columnDefType === 'data' ? 'hidden' : undefined,
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace:
|
||||
(columnDef.header?.length ?? 0) < 20
|
||||
? 'nowrap'
|
||||
: 'normal',
|
||||
}}
|
||||
>
|
||||
{HeaderElement}
|
||||
</Box>
|
||||
{(column.getCanSort() && columnDefType !== 'group') && (
|
||||
<MRT_TableHeadCellSortLabel sx={{ width: 20 }} header={header} table={table} />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</TableCell>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableHeadCell;
|
||||
76
src/core/components/DataTable/head/TableHeadRow.js
Normal file
76
src/core/components/DataTable/head/TableHeadRow.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { TableRow } from "@mui/material";
|
||||
import DataTable_TableHeadCell from "./TableHeadCell";
|
||||
|
||||
const DataTable_TableHeadRow = ({
|
||||
columnVirtualizer,
|
||||
headerGroup,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
options: {
|
||||
enableStickyHeader,
|
||||
layoutMode,
|
||||
mrtTheme: { baseBackgroundColor },
|
||||
muiTableHeadRowProps,
|
||||
},
|
||||
} = table;
|
||||
|
||||
const { virtualColumns, virtualPaddingLeft, virtualPaddingRight } =
|
||||
columnVirtualizer ?? {};
|
||||
|
||||
const tableRowProps = {
|
||||
...parseFromValuesOrFunc(muiTableHeadRowProps, {
|
||||
headerGroup,
|
||||
table,
|
||||
}),
|
||||
...rest,
|
||||
};
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
{...tableRowProps}
|
||||
sx={(theme) => ({
|
||||
backgroundColor: baseBackgroundColor,
|
||||
display: layoutMode?.startsWith('grid') ? 'flex' : undefined,
|
||||
position:
|
||||
enableStickyHeader && layoutMode === 'semantic'
|
||||
? 'sticky'
|
||||
: 'relative',
|
||||
top: 0,
|
||||
...(parseFromValuesOrFunc(tableRowProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{virtualPaddingLeft ? (
|
||||
<th style={{ display: 'flex', width: virtualPaddingLeft }} />
|
||||
) : null}
|
||||
{(virtualColumns ?? headerGroup.headers).map(
|
||||
(headerOrVirtualHeader, staticColumnIndex) => {
|
||||
let header = headerOrVirtualHeader;
|
||||
|
||||
if (columnVirtualizer) {
|
||||
staticColumnIndex = (headerOrVirtualHeader)
|
||||
.index;
|
||||
header = headerGroup.headers[staticColumnIndex];
|
||||
}
|
||||
|
||||
return header ? (
|
||||
<DataTable_TableHeadCell
|
||||
columnVirtualizer={columnVirtualizer}
|
||||
header={header}
|
||||
key={header.id}
|
||||
staticColumnIndex={staticColumnIndex}
|
||||
table={table}
|
||||
/>
|
||||
) : null;
|
||||
},
|
||||
)}
|
||||
{virtualPaddingRight ? (
|
||||
<th style={{ display: 'flex', width: virtualPaddingRight }} />
|
||||
) : null}
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableHeadRow
|
||||
123
src/core/components/DataTable/index.js
Normal file
123
src/core/components/DataTable/index.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import { useMaterialReactTable } from "material-react-table";
|
||||
import DataTable_Main from "./Main";
|
||||
import { FA_DATATABLE_LOCALIZATION } from "./localization/fa/datatable";
|
||||
import CustomToolbar from "@/components/CustomToolbar";
|
||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||
import {flattenArrayOfObjects} from "@/core/utils/flattenArrayOfObjects";
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
address: '261 Erdman Ford',
|
||||
city: 'East Daphne',
|
||||
state: 'Kentucky',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
address: '769 Dominic Grove',
|
||||
city: 'Columbus',
|
||||
state: 'Ohio',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Joe',
|
||||
lastName: 'Doe',
|
||||
},
|
||||
address: '566 Brakus Inlet',
|
||||
city: 'South Linda',
|
||||
state: 'West Virginia',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Kevin',
|
||||
lastName: 'Vandy',
|
||||
},
|
||||
address: '722 Emie Stream',
|
||||
city: 'Lincoln',
|
||||
state: 'Nebraska',
|
||||
},
|
||||
{
|
||||
name: {
|
||||
firstName: 'Joshua',
|
||||
lastName: 'Rolluffs',
|
||||
},
|
||||
address: '32188 Larkin Turnpike',
|
||||
city: 'Charleston',
|
||||
state: 'South Carolina',
|
||||
},
|
||||
];
|
||||
|
||||
const DataTable = (props) => {
|
||||
const { userId, pageName, tableName, columns, initialStateProps } = props
|
||||
const { settingStore, hideAction, sortAction } = useTableSetting();
|
||||
const flatColumns = flattenArrayOfObjects(columns,'columns')
|
||||
|
||||
const onColumnVisibilityChange = (event) => {
|
||||
const settingValue = event();
|
||||
hideAction(userId, pageName, tableName, settingValue, flatColumns);
|
||||
};
|
||||
const onSortingChange = (event) => {
|
||||
const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []);
|
||||
sortAction(userId, pageName, tableName, settingValue, flatColumns);
|
||||
}
|
||||
|
||||
|
||||
const table = useMaterialReactTable({
|
||||
localization: FA_DATATABLE_LOCALIZATION,
|
||||
columns,
|
||||
data: data,
|
||||
// manualSorting: true,
|
||||
renderTopToolbarCustomActions: ({ table }) => (<>
|
||||
<CustomToolbar
|
||||
columns={flatColumns}
|
||||
/>
|
||||
</>),
|
||||
initialState: {
|
||||
density: 'compact',
|
||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [],
|
||||
...initialStateProps
|
||||
},
|
||||
state: {
|
||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []
|
||||
},
|
||||
muiTableHeadProps: {
|
||||
sx: {
|
||||
borderTop: "1px solid #e1e1e1",
|
||||
borderBottom: "2px solid #e1e1e1",
|
||||
}
|
||||
},
|
||||
muiTableHeadCellProps: {
|
||||
sx: {
|
||||
color: "primary.main",
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset"
|
||||
}
|
||||
},
|
||||
},
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset"
|
||||
}
|
||||
},
|
||||
},
|
||||
onColumnVisibilityChange: onColumnVisibilityChange,
|
||||
onSortingChange: onSortingChange,
|
||||
...props
|
||||
})
|
||||
|
||||
|
||||
return <DataTable_Main table={table} />;
|
||||
};
|
||||
|
||||
export default DataTable;
|
||||
92
src/core/components/DataTable/localization/fa/datatable.js
Normal file
92
src/core/components/DataTable/localization/fa/datatable.js
Normal file
@@ -0,0 +1,92 @@
|
||||
export const FA_DATATABLE_LOCALIZATION = {
|
||||
actions: "عملیات",
|
||||
and: "و",
|
||||
cancel: "لغو",
|
||||
changeFilterMode: "تغییر حالت فیلتر",
|
||||
changeSearchMode: "تغییر حالت جستجو",
|
||||
clearFilter: "پاک کردن فیلتر",
|
||||
clearSearch: "پاک کردن جستجو",
|
||||
clearSort: "پاک کردن مرتب سازی",
|
||||
clickToCopy: "کلیک برای کپی",
|
||||
collapse: "جمع شدن",
|
||||
collapseAll: "جمع شدن همه",
|
||||
columnActions: "عملیات ستون",
|
||||
copiedToClipboard: "کپی شد",
|
||||
dropToGroupBy: "رها کردن برای گروه بندی بر اساس {column}",
|
||||
edit: "ویرایش",
|
||||
expand: "باز شدن",
|
||||
expandAll: "باز شدن همه",
|
||||
filterArrIncludes: "شامل",
|
||||
filterArrIncludesAll: "شامل همه",
|
||||
filterArrIncludesSome: "شامل",
|
||||
filterBetween: "میان",
|
||||
filterBetweenInclusive: "میان با احتساب هر دو",
|
||||
filterByColumn: "فیلتر بر اساس {column}",
|
||||
filterContains: "شامل",
|
||||
filterEmpty: "خالی",
|
||||
filterEndsWith: "به پایان میرسد با",
|
||||
filterEquals: "برابر",
|
||||
filterEqualsString: "برابر",
|
||||
filterFuzzy: "نزدیک",
|
||||
filterGreaterThan: "بزرگتر از",
|
||||
filterGreaterThanOrEqualTo: "بزرگتر یا مساوی",
|
||||
filterInNumberRange: "میان",
|
||||
filterIncludesString: "شامل",
|
||||
filterIncludesStringSensitive: "شامل",
|
||||
filterLessThan: "کوچکتر از",
|
||||
filterLessThanOrEqualTo: "کوچکتر یا مساوی",
|
||||
filterMode: "حالت فیلتر: {filterType}",
|
||||
filterNotEmpty: "غیر خالی",
|
||||
filterNotEquals: "نا برابر",
|
||||
filterStartsWith: "شروع میشود با",
|
||||
filterWeakEquals: "برابر",
|
||||
filteringByColumn: "فیلتر بر اساس {column} - {filterType} {filterValue}",
|
||||
goToFirstPage: "رفتن به صفحه اول",
|
||||
goToLastPage: "رفتن به صفحه آخر",
|
||||
goToNextPage: "رفتن به صفحه بعدی",
|
||||
goToPreviousPage: "رفتن به صفحه قبلی",
|
||||
grab: "گرفتن",
|
||||
groupByColumn: "گروه بندی بر اساس {column}",
|
||||
groupedBy: "گروه بندی شده بر اساس",
|
||||
hideAll: "پنهان کردن همه",
|
||||
hideColumn: "پنهان کردن ستون {column}",
|
||||
max: "حداکثر",
|
||||
min: "حداقل",
|
||||
move: "انتقال",
|
||||
noRecordsToDisplay: "هیچ رکوردی برای نمایش وجود ندارد",
|
||||
noResultsFound: "نتیجهای یافت نشد",
|
||||
of: "از",
|
||||
or: "یا",
|
||||
pinToLeft: "چسباندن به سمت چپ",
|
||||
pinToRight: "چسباندن به سمت راست",
|
||||
resetColumnSize: "بازنشانی اندازه ستون",
|
||||
resetOrder: "بازنشانی ترتیب",
|
||||
rowActions: "عملیات ردیف",
|
||||
rowNumber: "#",
|
||||
rowNumbers: "شماره ردیف",
|
||||
rowsPerPage: "ردیف در هر صفحه",
|
||||
save: "ذخیره",
|
||||
search: "جستجو",
|
||||
selectedCountOfRowCountRowsSelected:
|
||||
"{selectedCount} از {rowCount} ردیف انتخاب شده",
|
||||
select: "انتخاب",
|
||||
showAll: "نمایش همه",
|
||||
showAllColumns: "نمایش همه ستونها",
|
||||
showHideColumns: "نمایش/مخفی کردن ستونها",
|
||||
showHideFilters: "نمایش/مخفی کردن فیلترها",
|
||||
showHideSearch: "نمایش/مخفی کردن جستجو",
|
||||
sortByColumnAsc: "مرتب سازی بر اساس {column} صعودی",
|
||||
sortByColumnDesc: "مرتب سازی بر اساس {column} نزولی",
|
||||
sortedByColumnAsc: "مرتب شده بر اساس {column} صعودی",
|
||||
sortedByColumnDesc: "مرتب شده بر اساس {column} نزولی",
|
||||
thenBy: "، سپس بر اساس ",
|
||||
toggleDensity: "تغییر تراکم",
|
||||
toggleFullScreen: "تغییر حالت تمام صفحه",
|
||||
toggleSelectAll: "انتخاب/عدم انتخاب همه",
|
||||
toggleSelectRow: "انتخاب/عدم انتخاب ردیف",
|
||||
toggleVisibility: "تغییر پیدا/پنهان",
|
||||
ungroupByColumn: "لغو گروه بندی بر اساس {column}",
|
||||
unpin: "رها کردن",
|
||||
unpinAll: "رها کردن همه",
|
||||
unsorted: "بدون مرتب سازی",
|
||||
};
|
||||
50
src/core/components/DataTable/menus/ActionMenuItem.js
Normal file
50
src/core/components/DataTable/menus/ActionMenuItem.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Box, IconButton, ListItemIcon, MenuItem } from "@mui/material";
|
||||
|
||||
const DataTable_ActionMenuItem = ({
|
||||
icon,
|
||||
label,
|
||||
onOpenSubMenu,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
options: {
|
||||
icons: { ArrowRightIcon },
|
||||
},
|
||||
} = table;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
minWidth: '120px',
|
||||
my: 0,
|
||||
py: '6px',
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>{icon}</ListItemIcon>
|
||||
{label}
|
||||
</Box>
|
||||
{onOpenSubMenu && (
|
||||
<IconButton
|
||||
onClick={onOpenSubMenu}
|
||||
onMouseEnter={onOpenSubMenu}
|
||||
size="small"
|
||||
sx={{ p: 0 }}
|
||||
>
|
||||
<ArrowRightIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_ActionMenuItem
|
||||
100
src/core/components/DataTable/menus/CellActionMenu.js
Normal file
100
src/core/components/DataTable/menus/CellActionMenu.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { Menu } from "@mui/material";
|
||||
import DataTable_ActionMenuItem from "./ActionMenuItem";
|
||||
|
||||
const DataTable_CellActionMenu = ({
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
editDisplayMode,
|
||||
enableClickToCopy,
|
||||
enableEditing,
|
||||
icons: { ContentCopy, EditIcon },
|
||||
localization,
|
||||
mrtTheme: { menuBackgroundColor },
|
||||
renderCellActionMenuItems,
|
||||
},
|
||||
refs: { actionCellRef },
|
||||
} = table;
|
||||
const { actionCell, density } = getState();
|
||||
const cell = actionCell || null;
|
||||
const { row } = cell;
|
||||
const { column } = cell;
|
||||
const { columnDef } = column;
|
||||
|
||||
const handleClose = (event) => {
|
||||
event?.stopPropagation();
|
||||
table.setActionCell(null);
|
||||
actionCellRef.current = null;
|
||||
};
|
||||
|
||||
const internalMenuItems = [
|
||||
(parseFromValuesOrFunc(enableClickToCopy, cell) === 'context-menu' ||
|
||||
parseFromValuesOrFunc(columnDef.enableClickToCopy, cell) ===
|
||||
'context-menu') && (
|
||||
<DataTable_ActionMenuItem
|
||||
icon={<ContentCopy />}
|
||||
key={'mrt-copy'}
|
||||
label={localization.copy}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
navigator.clipboard.writeText(cell.getValue());
|
||||
handleClose();
|
||||
}}
|
||||
table={table}
|
||||
/>
|
||||
),
|
||||
parseFromValuesOrFunc(enableEditing, row) && editDisplayMode === 'cell' && (
|
||||
<DataTable_ActionMenuItem
|
||||
icon={<EditIcon />}
|
||||
key={'mrt-edit'}
|
||||
label={localization.edit}
|
||||
onClick={() => {
|
||||
openEditingCell({ cell, table });
|
||||
handleClose();
|
||||
}}
|
||||
table={table}
|
||||
/>
|
||||
),
|
||||
].filter(Boolean);
|
||||
|
||||
const renderActionProps = {
|
||||
cell,
|
||||
closeMenu: handleClose,
|
||||
column,
|
||||
internalMenuItems,
|
||||
row,
|
||||
table,
|
||||
};
|
||||
|
||||
const menuItems =
|
||||
columnDef.renderCellActionMenuItems?.(renderActionProps) ??
|
||||
renderCellActionMenuItems?.(renderActionProps);
|
||||
|
||||
return (
|
||||
(!!menuItems?.length || !!internalMenuItems?.length) && (
|
||||
<Menu
|
||||
MenuListProps={{
|
||||
dense: density === 'compact',
|
||||
sx: {
|
||||
backgroundColor: menuBackgroundColor,
|
||||
},
|
||||
}}
|
||||
anchorEl={actionCellRef.current}
|
||||
disableScrollLock
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onClose={handleClose}
|
||||
open={!!cell}
|
||||
transformOrigin={{ horizontal: -100, vertical: 8 }}
|
||||
{...rest}
|
||||
>
|
||||
{menuItems ?? internalMenuItems}
|
||||
</Menu>
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_CellActionMenu
|
||||
140
src/core/components/DataTable/menus/ShowHideColumnsMenu.js
Normal file
140
src/core/components/DataTable/menus/ShowHideColumnsMenu.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import { Box, Button, Divider, Menu } from "@mui/material";
|
||||
import { useMemo, useState } from "react";
|
||||
import DataTable_ShowHideColumnsMenuItems from "./ShowHideColumnsMenuItems";
|
||||
|
||||
const DataTable_ShowHideColumnsMenu = ({ anchorEl,
|
||||
setAnchorEl,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getAllColumns,
|
||||
getAllLeafColumns,
|
||||
getCenterLeafColumns,
|
||||
getIsAllColumnsVisible,
|
||||
getIsSomeColumnsPinned,
|
||||
getIsSomeColumnsVisible,
|
||||
getLeftLeafColumns,
|
||||
getRightLeafColumns,
|
||||
getState,
|
||||
options: {
|
||||
enableColumnOrdering,
|
||||
enableColumnPinning,
|
||||
enableHiding,
|
||||
localization,
|
||||
mrtTheme: { menuBackgroundColor },
|
||||
},
|
||||
} = table;
|
||||
|
||||
const { columnOrder, columnPinning, density } = getState();
|
||||
|
||||
const handleToggleAllColumns = (value) => {
|
||||
getAllLeafColumns()
|
||||
.filter((col) => col.columnDef.enableHiding !== false)
|
||||
.forEach((col) => col.toggleVisibility(value));
|
||||
};
|
||||
|
||||
const allColumns = useMemo(() => {
|
||||
const columns = getAllColumns();
|
||||
if (
|
||||
columnOrder.length > 0 &&
|
||||
!columns.some((col) => col.columnDef.columnDefType === 'group')
|
||||
) {
|
||||
return [
|
||||
...getLeftLeafColumns(),
|
||||
...Array.from(new Set(columnOrder)).map((colId) =>
|
||||
getCenterLeafColumns().find((col) => col?.id === colId),
|
||||
),
|
||||
...getRightLeafColumns(),
|
||||
].filter(Boolean);
|
||||
}
|
||||
return columns;
|
||||
}, [
|
||||
columnOrder,
|
||||
columnPinning,
|
||||
getAllColumns(),
|
||||
getCenterLeafColumns(),
|
||||
getLeftLeafColumns(),
|
||||
getRightLeafColumns(),
|
||||
]);
|
||||
|
||||
const isNestedColumns = allColumns.some(
|
||||
(col) => col.columnDef.columnDefType === 'group',
|
||||
);
|
||||
|
||||
const [hoveredColumn, setHoveredColumn] = useState(null);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
MenuListProps={{
|
||||
dense: density === 'compact',
|
||||
sx: {
|
||||
backgroundColor: menuBackgroundColor,
|
||||
},
|
||||
}}
|
||||
anchorEl={anchorEl}
|
||||
disableScrollLock
|
||||
onClose={() => setAnchorEl(null)}
|
||||
open={!!anchorEl}
|
||||
{...rest}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
p: '0.5rem',
|
||||
pt: 0,
|
||||
}}
|
||||
>
|
||||
{enableHiding && (
|
||||
<Button
|
||||
disabled={!getIsSomeColumnsVisible()}
|
||||
onClick={() => handleToggleAllColumns(false)}
|
||||
>
|
||||
{localization.hideAll}
|
||||
</Button>
|
||||
)}
|
||||
{enableColumnOrdering && (
|
||||
<Button
|
||||
onClick={() =>
|
||||
table.setColumnOrder(
|
||||
getDefaultColumnOrderIds(table.options, true),
|
||||
)
|
||||
}
|
||||
>
|
||||
{localization.resetOrder}
|
||||
</Button>
|
||||
)}
|
||||
{enableColumnPinning && (
|
||||
<Button
|
||||
disabled={!getIsSomeColumnsPinned()}
|
||||
onClick={() => table.resetColumnPinning(true)}
|
||||
>
|
||||
{localization.unpinAll}
|
||||
</Button>
|
||||
)}
|
||||
{enableHiding && (
|
||||
<Button
|
||||
disabled={getIsAllColumnsVisible()}
|
||||
onClick={() => handleToggleAllColumns(true)}
|
||||
>
|
||||
{localization.showAll}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
<Divider />
|
||||
{allColumns.map((column, index) => (
|
||||
<DataTable_ShowHideColumnsMenuItems
|
||||
allColumns={allColumns}
|
||||
column={column}
|
||||
hoveredColumn={hoveredColumn}
|
||||
isNestedColumns={isNestedColumns}
|
||||
key={`${index}-${column.id}`}
|
||||
setHoveredColumn={setHoveredColumn}
|
||||
table={table}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
export default DataTable_ShowHideColumnsMenu
|
||||
160
src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js
Normal file
160
src/core/components/DataTable/menus/ShowHideColumnsMenuItems.js
Normal file
@@ -0,0 +1,160 @@
|
||||
import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { Box, FormControlLabel, MenuItem, Switch, Tooltip, Typography } from "@mui/material";
|
||||
import { useRef, useState } from "react";
|
||||
import DataTable_GrabHandleButton from "../buttons/GrabHandleButton";
|
||||
|
||||
const DataTable_ShowHideColumnsMenuItems = ({
|
||||
allColumns,
|
||||
column,
|
||||
hoveredColumn,
|
||||
isNestedColumns,
|
||||
setHoveredColumn,
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
enableColumnOrdering,
|
||||
enableHiding,
|
||||
localization,
|
||||
mrtTheme: { draggingBorderColor },
|
||||
},
|
||||
setColumnOrder,
|
||||
} = table;
|
||||
|
||||
const { columnOrder } = getState();
|
||||
const { columnDef } = column;
|
||||
const { columnDefType } = columnDef;
|
||||
|
||||
const switchChecked = column.getIsVisible();
|
||||
|
||||
const handleToggleColumnHidden = (column) => {
|
||||
if (columnDefType === 'group') {
|
||||
column?.columns?.forEach?.((childColumn) => {
|
||||
childColumn.toggleVisibility(!switchChecked);
|
||||
});
|
||||
} else {
|
||||
column.toggleVisibility();
|
||||
}
|
||||
};
|
||||
|
||||
const menuItemRef = useRef(null);
|
||||
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const handleDragStart = (e) => {
|
||||
setIsDragging(true);
|
||||
try {
|
||||
e.dataTransfer.setDragImage(menuItemRef.current, 0, 0);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragEnd = (_e) => {
|
||||
setIsDragging(false);
|
||||
setHoveredColumn(null);
|
||||
if (hoveredColumn) {
|
||||
setColumnOrder(reorderColumn(column, hoveredColumn, columnOrder));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragEnter = (_e) => {
|
||||
if (!isDragging && columnDef.enableColumnOrdering !== false) {
|
||||
setHoveredColumn(column);
|
||||
}
|
||||
};
|
||||
|
||||
if (!columnDef.header || columnDef.visibleInShowHideMenu === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem
|
||||
disableRipple
|
||||
onDragEnter={handleDragEnter}
|
||||
ref={menuItemRef}
|
||||
{...rest}
|
||||
sx={(theme) => ({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
my: 0,
|
||||
opacity: isDragging ? 0.5 : 1,
|
||||
outline: isDragging
|
||||
? `2px dashed ${theme.palette.grey[500]}`
|
||||
: hoveredColumn?.id === column.id
|
||||
? `2px dashed ${draggingBorderColor}`
|
||||
: 'none',
|
||||
outlineOffset: '-2px',
|
||||
pl: `${(column.depth + 0.5) * 2}rem`,
|
||||
py: '6px',
|
||||
...(parseFromValuesOrFunc(rest?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexWrap: 'nowrap',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
{columnDefType !== 'group' &&
|
||||
enableColumnOrdering &&
|
||||
!isNestedColumns &&
|
||||
(columnDef.enableColumnOrdering !== false ? (
|
||||
<DataTable_GrabHandleButton
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragStart={handleDragStart}
|
||||
table={table}
|
||||
/>
|
||||
) : (
|
||||
<Box sx={{ width: '28px' }} />
|
||||
))}
|
||||
{enableHiding ? (
|
||||
<FormControlLabel
|
||||
checked={switchChecked}
|
||||
componentsProps={{
|
||||
typography: {
|
||||
sx: {
|
||||
mb: 0,
|
||||
opacity: columnDefType !== 'display' ? 1 : 0.5,
|
||||
},
|
||||
},
|
||||
}}
|
||||
control={
|
||||
<Tooltip
|
||||
{...getCommonTooltipProps()}
|
||||
title={localization.toggleVisibility}
|
||||
>
|
||||
<Switch />
|
||||
</Tooltip>
|
||||
}
|
||||
disabled={!column.getCanHide()}
|
||||
label={columnDef.header}
|
||||
onChange={() => handleToggleColumnHidden(column)}
|
||||
/>
|
||||
) : (
|
||||
<Typography sx={{ alignSelf: 'center' }}>
|
||||
{columnDef.header}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</MenuItem>
|
||||
{column.columns?.map((c, i) => (
|
||||
<DataTable_ShowHideColumnsMenuItems
|
||||
allColumns={allColumns}
|
||||
column={c}
|
||||
hoveredColumn={hoveredColumn}
|
||||
isNestedColumns={isNestedColumns}
|
||||
key={`${i}-${c.id}`}
|
||||
setHoveredColumn={setHoveredColumn}
|
||||
table={table}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_ShowHideColumnsMenuItems;
|
||||
78
src/core/components/DataTable/table/Paper.js
Normal file
78
src/core/components/DataTable/table/Paper.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { Paper } from "@mui/material";
|
||||
import DataTable_BottomToolbar from "../toolbar/BottomToolbar";
|
||||
import DataTable_TopToolbar from "../toolbar/TopToolbar";
|
||||
import DataTable_TableContainer from "./TableContainer";
|
||||
|
||||
const DataTable_Paper = ({ table, ...rest }) => {
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
enableBottomToolbar,
|
||||
enableTopToolbar,
|
||||
mrtTheme: { baseBackgroundColor },
|
||||
muiTablePaperProps,
|
||||
renderBottomToolbar,
|
||||
renderTopToolbar,
|
||||
},
|
||||
refs: { tablePaperRef },
|
||||
} = table;
|
||||
|
||||
const { isFullScreen } = getState();
|
||||
|
||||
const paperProps = {
|
||||
...parseFromValuesOrFunc(muiTablePaperProps, { table }),
|
||||
...rest,
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={0}
|
||||
{...paperProps}
|
||||
ref={(ref) => {
|
||||
tablePaperRef.current = ref;
|
||||
if (paperProps?.ref) {
|
||||
//@ts-ignore
|
||||
paperProps.ref.current = ref;
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
...(isFullScreen
|
||||
? {
|
||||
bottom: 0,
|
||||
height: '100dvh',
|
||||
left: 0,
|
||||
margin: 0,
|
||||
maxHeight: '100dvh',
|
||||
maxWidth: '100dvw',
|
||||
padding: 0,
|
||||
position: 'fixed',
|
||||
right: 0,
|
||||
top: 0,
|
||||
width: '100dvw',
|
||||
zIndex: 999,
|
||||
}
|
||||
: {}),
|
||||
...paperProps?.style,
|
||||
}}
|
||||
sx={(theme) => ({
|
||||
backgroundColor: baseBackgroundColor,
|
||||
backgroundImage: 'unset',
|
||||
overflow: 'hidden',
|
||||
transition: 'all 100ms ease-in-out',
|
||||
...(parseFromValuesOrFunc(paperProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{enableTopToolbar &&
|
||||
(parseFromValuesOrFunc(renderTopToolbar, { table }) ?? (
|
||||
<DataTable_TopToolbar table={table} />
|
||||
))}
|
||||
<DataTable_TableContainer table={table} />
|
||||
{enableBottomToolbar &&
|
||||
(parseFromValuesOrFunc(renderBottomToolbar, { table }) ?? (
|
||||
<DataTable_BottomToolbar table={table} />
|
||||
))}
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
export default DataTable_Paper;
|
||||
77
src/core/components/DataTable/table/Table.js
Normal file
77
src/core/components/DataTable/table/Table.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import { parseCSSVarId, parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { Table } from "@mui/material";
|
||||
import { useMRT_ColumnVirtualizer } from "material-react-table";
|
||||
import { useMemo } from "react";
|
||||
import DataTable_TableBody, { Memo_DataTable_TableBody } from "../body/TableBody";
|
||||
import DataTable_TableHead from "../head/TableHead";
|
||||
|
||||
const DataTable_Table = ({
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getFlatHeaders,
|
||||
getState,
|
||||
options: {
|
||||
columns,
|
||||
enableStickyHeader,
|
||||
enableTableFooter,
|
||||
enableTableHead,
|
||||
layoutMode,
|
||||
memoMode,
|
||||
muiTableProps,
|
||||
renderCaption,
|
||||
},
|
||||
} = table;
|
||||
const { columnSizing, columnSizingInfo, columnVisibility, isFullScreen } =
|
||||
getState();
|
||||
|
||||
const tableProps = {
|
||||
...parseFromValuesOrFunc(muiTableProps, { table }),
|
||||
...rest,
|
||||
};
|
||||
|
||||
const Caption = parseFromValuesOrFunc(renderCaption, { table });
|
||||
|
||||
const columnSizeVars = useMemo(() => {
|
||||
const headers = getFlatHeaders();
|
||||
const colSizes = {};
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
const header = headers[i];
|
||||
const colSize = header.getSize();
|
||||
colSizes[`--header-${parseCSSVarId(header.id)}-size`] = colSize;
|
||||
colSizes[`--col-${parseCSSVarId(header.column.id)}-size`] = colSize;
|
||||
}
|
||||
return colSizes;
|
||||
}, [columns, columnSizing, columnSizingInfo, columnVisibility]);
|
||||
|
||||
const columnVirtualizer = useMRT_ColumnVirtualizer(table);
|
||||
|
||||
const commonTableGroupProps = {
|
||||
columnVirtualizer,
|
||||
table,
|
||||
};
|
||||
|
||||
return (
|
||||
<Table
|
||||
stickyHeader={enableStickyHeader || isFullScreen}
|
||||
{...tableProps}
|
||||
style={{ ...columnSizeVars, ...tableProps?.style }}
|
||||
sx={(theme) => ({
|
||||
display: layoutMode?.startsWith('grid') ? 'grid' : undefined,
|
||||
position: 'relative',
|
||||
...(parseFromValuesOrFunc(tableProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{!!Caption && <caption>{Caption}</caption>}
|
||||
{enableTableHead && <DataTable_TableHead {...commonTableGroupProps} />}
|
||||
{memoMode === 'table-body' || columnSizingInfo.isResizingColumn ? (
|
||||
<Memo_DataTable_TableBody {...commonTableGroupProps} />
|
||||
) : (
|
||||
<DataTable_TableBody {...commonTableGroupProps} />
|
||||
)}
|
||||
{/* {enableTableFooter && <MRT_TableFooter {...commonTableGroupProps} />} */}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
export default DataTable_Table
|
||||
94
src/core/components/DataTable/table/TableContainer.js
Normal file
94
src/core/components/DataTable/table/TableContainer.js
Normal file
@@ -0,0 +1,94 @@
|
||||
import { parseFromValuesOrFunc } from "@/core/utils/utils";
|
||||
import { TableContainer } from "@mui/material";
|
||||
import { useEffect, useLayoutEffect, useState } from "react";
|
||||
import DataTable_CellActionMenu from "../menus/CellActionMenu";
|
||||
import DataTable_Table from "./Table";
|
||||
import DataTable_TableLoadingOverlay from "./TableLoadingOverlay";
|
||||
|
||||
const useIsomorphicLayoutEffect =
|
||||
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||
|
||||
const DataTable_TableContainer = ({
|
||||
table,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
getState,
|
||||
options: {
|
||||
enableCellActions,
|
||||
enableStickyHeader,
|
||||
muiTableContainerProps,
|
||||
},
|
||||
refs: { bottomToolbarRef, tableContainerRef, topToolbarRef },
|
||||
} = table;
|
||||
const {
|
||||
actionCell,
|
||||
isFullScreen,
|
||||
isLoading,
|
||||
showLoadingOverlay,
|
||||
} = getState();
|
||||
|
||||
const loading =
|
||||
showLoadingOverlay !== false && (isLoading || showLoadingOverlay);
|
||||
|
||||
const [totalToolbarHeight, setTotalToolbarHeight] = useState(0);
|
||||
|
||||
const tableContainerProps = {
|
||||
...parseFromValuesOrFunc(muiTableContainerProps, {
|
||||
table,
|
||||
}),
|
||||
...rest,
|
||||
};
|
||||
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const topToolbarHeight =
|
||||
typeof document !== 'undefined'
|
||||
? topToolbarRef.current?.offsetHeight ?? 0
|
||||
: 0;
|
||||
|
||||
const bottomToolbarHeight =
|
||||
typeof document !== 'undefined'
|
||||
? bottomToolbarRef?.current?.offsetHeight ?? 0
|
||||
: 0;
|
||||
|
||||
setTotalToolbarHeight(topToolbarHeight + bottomToolbarHeight);
|
||||
});
|
||||
|
||||
return (
|
||||
<TableContainer
|
||||
aria-busy={loading}
|
||||
aria-describedby={loading ? 'mrt-progress' : undefined}
|
||||
{...tableContainerProps}
|
||||
ref={(node) => {
|
||||
if (node) {
|
||||
tableContainerRef.current = node;
|
||||
if (tableContainerProps?.ref) {
|
||||
//@ts-ignore
|
||||
tableContainerProps.ref.current = node;
|
||||
}
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
maxHeight: isFullScreen
|
||||
? `calc(100vh - ${totalToolbarHeight}px)`
|
||||
: undefined,
|
||||
...tableContainerProps?.style,
|
||||
}}
|
||||
sx={(theme) => ({
|
||||
maxHeight: enableStickyHeader
|
||||
? `clamp(350px, calc(100vh - ${totalToolbarHeight}px), 9999px)`
|
||||
: undefined,
|
||||
maxWidth: '100%',
|
||||
overflow: 'auto',
|
||||
position: 'relative',
|
||||
...(parseFromValuesOrFunc(tableContainerProps?.sx, theme)),
|
||||
})}
|
||||
>
|
||||
{loading ? <DataTable_TableLoadingOverlay table={table} /> : null}
|
||||
<DataTable_Table table={table} />
|
||||
{enableCellActions && actionCell && <DataTable_CellActionMenu table={table} />}
|
||||
</TableContainer>
|
||||
);
|
||||
|
||||
}
|
||||
export default DataTable_TableContainer
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user