暂时的Autoscore

This commit is contained in:
NanGua-QWQ
2026-03-13 22:35:26 +08:00
parent f47b6d483c
commit 77d399ea0f
7 changed files with 294 additions and 85 deletions
+6
View File
@@ -34,10 +34,13 @@
"@capacitor/preferences": "^8.0.1", "@capacitor/preferences": "^8.0.1",
"@electron-toolkit/preload": "^3.0.2", "@electron-toolkit/preload": "^3.0.2",
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
"@react-querybuilder/antd": "^8.14.0",
"@react-querybuilder/dnd": "^8.14.0",
"antd": "^6.3.1", "antd": "^6.3.1",
"antd-mobile": "^5.42.3", "antd-mobile": "^5.42.3",
"better-sqlite3": "^12.6.0", "better-sqlite3": "^12.6.0",
"chokidar": "^5.0.0", "chokidar": "^5.0.0",
"dayjs": "^1.11.20",
"es-object-atoms": "^1.1.1", "es-object-atoms": "^1.1.1",
"express": "^5.2.1", "express": "^5.2.1",
"i18next": "^25.8.14", "i18next": "^25.8.14",
@@ -46,6 +49,9 @@
"os": "^0.1.2", "os": "^0.1.2",
"pg": "^8.19.0", "pg": "^8.19.0",
"pinyin-pro": "^3.27.0", "pinyin-pro": "^3.27.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dnd-touch-backend": "^16.0.1",
"react-i18next": "^16.5.6", "react-i18next": "^16.5.6",
"react-querybuilder": "^8.14.0", "react-querybuilder": "^8.14.0",
"react-router-dom": "^6.28.0", "react-router-dom": "^6.28.0",
+161 -10
View File
@@ -29,6 +29,12 @@ importers:
'@electron-toolkit/utils': '@electron-toolkit/utils':
specifier: ^4.0.0 specifier: ^4.0.0
version: 4.0.0(electron@39.2.7) version: 4.0.0(electron@39.2.7)
'@react-querybuilder/antd':
specifier: ^8.14.0
version: 8.14.0(@ant-design/icons@6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(antd@6.3.1(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(dayjs@1.11.20)(react-querybuilder@8.14.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1))(react@19.2.3)
'@react-querybuilder/dnd':
specifier: ^8.14.0
version: 8.14.0(react-dnd-html5-backend@16.0.1)(react-dnd-touch-backend@16.0.1)(react-dnd@16.0.1(@types/node@22.19.5)(@types/react@19.2.8)(react@19.2.3))(react-querybuilder@8.14.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1))(react@19.2.3)
antd: antd:
specifier: ^6.3.1 specifier: ^6.3.1
version: 6.3.1(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) version: 6.3.1(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -41,6 +47,9 @@ importers:
chokidar: chokidar:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.0.0 version: 5.0.0
dayjs:
specifier: ^1.11.20
version: 1.11.20
es-object-atoms: es-object-atoms:
specifier: ^1.1.1 specifier: ^1.1.1
version: 1.1.1 version: 1.1.1
@@ -63,6 +72,15 @@ importers:
pinyin-pro: pinyin-pro:
specifier: ^3.27.0 specifier: ^3.27.0
version: 3.27.0 version: 3.27.0
react-dnd:
specifier: ^16.0.1
version: 16.0.1(@types/node@22.19.5)(@types/react@19.2.8)(react@19.2.3)
react-dnd-html5-backend:
specifier: ^16.0.1
version: 16.0.1
react-dnd-touch-backend:
specifier: ^16.0.1
version: 16.0.1
react-i18next: react-i18next:
specifier: ^16.5.6 specifier: ^16.5.6
version: 16.5.6(i18next@25.8.14(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) version: 16.5.6(i18next@25.8.14(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)
@@ -1156,6 +1174,24 @@ packages:
react: '>=16.9.0' react: '>=16.9.0'
react-dom: '>=16.9.0' react-dom: '>=16.9.0'
'@react-dnd/asap@5.0.2':
resolution: {integrity: sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==}
'@react-dnd/invariant@4.0.2':
resolution: {integrity: sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==}
'@react-dnd/shallowequal@4.0.2':
resolution: {integrity: sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==}
'@react-querybuilder/antd@8.14.0':
resolution: {integrity: sha512-H6SMCmKtciOIJyXo29oLMMDIG1+ydE7eoIqAIhItsvJN7iLcAPhvKd5+CuHyOWj9tokEAHGpdm4BP+KPFAxTNw==}
peerDependencies:
'@ant-design/icons': '>=5'
antd: '>=5.11.0'
dayjs: '>=1'
react: '>=18'
react-querybuilder: 8.14.0
'@react-querybuilder/core@8.14.0': '@react-querybuilder/core@8.14.0':
resolution: {integrity: sha512-j1pIY0Yyn/dXu9ZST/DVY7TqRmIO1hY/mZ8653DaeHaDzUF37tOdkm/NQDU9RfM0KXIWsJY5zlvYAR1DypZ+7g==} resolution: {integrity: sha512-j1pIY0Yyn/dXu9ZST/DVY7TqRmIO1hY/mZ8653DaeHaDzUF37tOdkm/NQDU9RfM0KXIWsJY5zlvYAR1DypZ+7g==}
peerDependencies: peerDependencies:
@@ -1170,6 +1206,20 @@ packages:
sequelize: sequelize:
optional: true optional: true
'@react-querybuilder/dnd@8.14.0':
resolution: {integrity: sha512-g0BHs9Vtbm7OhnhIq1pxJNY3JXNmSbA7NVTlOuqoAfFl0D46rZfGInVzoBfpwVpoLtQIXPO25Y5N/1/LcWuSNg==}
peerDependencies:
react: '>=18'
react-dnd: '>=14.0.0'
react-dnd-html5-backend: '>=14.0.0'
react-dnd-touch-backend: '>=14.0.0'
react-querybuilder: 8.14.0
peerDependenciesMeta:
react-dnd-html5-backend:
optional: true
react-dnd-touch-backend:
optional: true
'@react-spring/animated@9.6.1': '@react-spring/animated@9.6.1':
resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==} resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==}
peerDependencies: peerDependencies:
@@ -1249,66 +1299,79 @@ packages:
resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.55.1': '@rollup/rollup-linux-arm-musleabihf@4.55.1':
resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.55.1': '@rollup/rollup-linux-arm64-gnu@4.55.1':
resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.55.1': '@rollup/rollup-linux-arm64-musl@4.55.1':
resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.55.1': '@rollup/rollup-linux-loong64-gnu@4.55.1':
resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.55.1': '@rollup/rollup-linux-loong64-musl@4.55.1':
resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.55.1': '@rollup/rollup-linux-ppc64-gnu@4.55.1':
resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.55.1': '@rollup/rollup-linux-ppc64-musl@4.55.1':
resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.55.1': '@rollup/rollup-linux-riscv64-gnu@4.55.1':
resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.55.1': '@rollup/rollup-linux-riscv64-musl@4.55.1':
resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.55.1': '@rollup/rollup-linux-s390x-gnu@4.55.1':
resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.55.1': '@rollup/rollup-linux-x64-gnu@4.55.1':
resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.55.1': '@rollup/rollup-linux-x64-musl@4.55.1':
resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-openbsd-x64@4.55.1': '@rollup/rollup-openbsd-x64@4.55.1':
resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
@@ -1971,8 +2034,8 @@ packages:
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dayjs@1.11.19: dayjs@1.11.20:
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
debug@4.4.3: debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
@@ -2052,6 +2115,9 @@ packages:
os: [darwin] os: [darwin]
hasBin: true hasBin: true
dnd-core@16.0.1:
resolution: {integrity: sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==}
doctrine@2.1.0: doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -2546,6 +2612,9 @@ packages:
hermes-parser@0.25.1: hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
hosted-git-info@4.1.0: hosted-git-info@4.1.0:
resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -3422,6 +3491,27 @@ packages:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true hasBin: true
react-dnd-html5-backend@16.0.1:
resolution: {integrity: sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==}
react-dnd-touch-backend@16.0.1:
resolution: {integrity: sha512-NonoCABzzjyWGZuDxSG77dbgMZ2Wad7eQiCd/ECtsR2/NBLTjGksPUx9UPezZ1nQ/L7iD130Tz3RUshL/ClKLA==}
react-dnd@16.0.1:
resolution: {integrity: sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==}
peerDependencies:
'@types/hoist-non-react-statics': '>= 3.3.1'
'@types/node': '>= 12'
'@types/react': '>= 16'
react: '>= 16.14'
peerDependenciesMeta:
'@types/hoist-non-react-statics':
optional: true
'@types/node':
optional: true
'@types/react':
optional: true
react-dom@19.2.3: react-dom@19.2.3:
resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==}
peerDependencies: peerDependencies:
@@ -3507,6 +3597,9 @@ packages:
peerDependencies: peerDependencies:
redux: ^5.0.0 redux: ^5.0.0
redux@4.2.1:
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
redux@5.0.1: redux@5.0.1:
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
@@ -5157,7 +5250,7 @@ snapshots:
react: 19.2.3 react: 19.2.3
react-dom: 19.2.3(react@19.2.3) react-dom: 19.2.3(react@19.2.3)
'@rc-component/picker@1.9.0(dayjs@1.11.19)(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': '@rc-component/picker@1.9.0(dayjs@1.11.20)(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies: dependencies:
'@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5167,7 +5260,7 @@ snapshots:
react: 19.2.3 react: 19.2.3
react-dom: 19.2.3(react@19.2.3) react-dom: 19.2.3(react@19.2.3)
optionalDependencies: optionalDependencies:
dayjs: 1.11.19 dayjs: 1.11.20
moment: 2.30.1 moment: 2.30.1
'@rc-component/portal@2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': '@rc-component/portal@2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
@@ -5341,6 +5434,20 @@ snapshots:
react: 19.2.3 react: 19.2.3
react-dom: 19.2.3(react@19.2.3) react-dom: 19.2.3(react@19.2.3)
'@react-dnd/asap@5.0.2': {}
'@react-dnd/invariant@4.0.2': {}
'@react-dnd/shallowequal@4.0.2': {}
'@react-querybuilder/antd@8.14.0(@ant-design/icons@6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(antd@6.3.1(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(dayjs@1.11.20)(react-querybuilder@8.14.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1))(react@19.2.3)':
dependencies:
'@ant-design/icons': 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
antd: 6.3.1(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
dayjs: 1.11.20
react: 19.2.3
react-querybuilder: 8.14.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1)
'@react-querybuilder/core@8.14.0': '@react-querybuilder/core@8.14.0':
dependencies: dependencies:
'@ts-jison/lexer': 0.4.1-alpha.1 '@ts-jison/lexer': 0.4.1-alpha.1
@@ -5348,6 +5455,15 @@ snapshots:
immer: 11.1.4 immer: 11.1.4
numeric-quantity: 2.1.0 numeric-quantity: 2.1.0
'@react-querybuilder/dnd@8.14.0(react-dnd-html5-backend@16.0.1)(react-dnd-touch-backend@16.0.1)(react-dnd@16.0.1(@types/node@22.19.5)(@types/react@19.2.8)(react@19.2.3))(react-querybuilder@8.14.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1))(react@19.2.3)':
dependencies:
react: 19.2.3
react-dnd: 16.0.1(@types/node@22.19.5)(@types/react@19.2.8)(react@19.2.3)
react-querybuilder: 8.14.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1)
optionalDependencies:
react-dnd-html5-backend: 16.0.1
react-dnd-touch-backend: 16.0.1
'@react-spring/animated@9.6.1(react@19.2.3)': '@react-spring/animated@9.6.1(react@19.2.3)':
dependencies: dependencies:
'@react-spring/shared': 9.6.1(react@19.2.3) '@react-spring/shared': 9.6.1(react@19.2.3)
@@ -5737,7 +5853,7 @@ snapshots:
dependencies: dependencies:
'@babel/runtime': 7.28.6 '@babel/runtime': 7.28.6
'@types/js-cookie': 3.0.6 '@types/js-cookie': 3.0.6
dayjs: 1.11.19 dayjs: 1.11.20
intersection-observer: 0.12.2 intersection-observer: 0.12.2
js-cookie: 3.0.5 js-cookie: 3.0.5
lodash: 4.17.21 lodash: 4.17.21
@@ -5785,7 +5901,7 @@ snapshots:
antd-mobile-icons: 0.3.0 antd-mobile-icons: 0.3.0
antd-mobile-v5-count: 1.0.1 antd-mobile-v5-count: 1.0.1
classnames: 2.5.1 classnames: 2.5.1
dayjs: 1.11.19 dayjs: 1.11.20
deepmerge: 4.3.1 deepmerge: 4.3.1
nano-memoize: 3.0.16 nano-memoize: 3.0.16
rc-field-form: 1.44.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) rc-field-form: 1.44.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5826,7 +5942,7 @@ snapshots:
'@rc-component/mutate-observer': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/notification': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/notification': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/pagination': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/pagination': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/picker': 1.9.0(dayjs@1.11.19)(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/picker': 1.9.0(dayjs@1.11.20)(moment@2.30.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/progress': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/progress': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/qrcode': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/qrcode': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/rate': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/rate': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5847,7 +5963,7 @@ snapshots:
'@rc-component/upload': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/upload': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/util': 1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
clsx: 2.1.1 clsx: 2.1.1
dayjs: 1.11.19 dayjs: 1.11.20
react: 19.2.3 react: 19.2.3
react-dom: 19.2.3(react@19.2.3) react-dom: 19.2.3(react@19.2.3)
scroll-into-view-if-needed: 3.1.0 scroll-into-view-if-needed: 3.1.0
@@ -6288,7 +6404,7 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
is-data-view: 1.0.2 is-data-view: 1.0.2
dayjs@1.11.19: {} dayjs@1.11.20: {}
debug@4.4.3: debug@4.4.3:
dependencies: dependencies:
@@ -6365,6 +6481,12 @@ snapshots:
verror: 1.10.1 verror: 1.10.1
optional: true optional: true
dnd-core@16.0.1:
dependencies:
'@react-dnd/asap': 5.0.2
'@react-dnd/invariant': 4.0.2
redux: 4.2.1
doctrine@2.1.0: doctrine@2.1.0:
dependencies: dependencies:
esutils: 2.0.3 esutils: 2.0.3
@@ -7096,6 +7218,10 @@ snapshots:
dependencies: dependencies:
hermes-estree: 0.25.1 hermes-estree: 0.25.1
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
hosted-git-info@4.1.0: hosted-git-info@4.1.0:
dependencies: dependencies:
lru-cache: 6.0.0 lru-cache: 6.0.0
@@ -7970,6 +8096,27 @@ snapshots:
minimist: 1.2.8 minimist: 1.2.8
strip-json-comments: 2.0.1 strip-json-comments: 2.0.1
react-dnd-html5-backend@16.0.1:
dependencies:
dnd-core: 16.0.1
react-dnd-touch-backend@16.0.1:
dependencies:
'@react-dnd/invariant': 4.0.2
dnd-core: 16.0.1
react-dnd@16.0.1(@types/node@22.19.5)(@types/react@19.2.8)(react@19.2.3):
dependencies:
'@react-dnd/invariant': 4.0.2
'@react-dnd/shallowequal': 4.0.2
dnd-core: 16.0.1
fast-deep-equal: 3.1.3
hoist-non-react-statics: 3.3.2
react: 19.2.3
optionalDependencies:
'@types/node': 22.19.5
'@types/react': 19.2.8
react-dom@19.2.3(react@19.2.3): react-dom@19.2.3(react@19.2.3):
dependencies: dependencies:
react: 19.2.3 react: 19.2.3
@@ -8049,6 +8196,10 @@ snapshots:
dependencies: dependencies:
redux: 5.0.1 redux: 5.0.1
redux@4.2.1:
dependencies:
'@babel/runtime': 7.28.6
redux@5.0.1: {} redux@5.0.1: {}
reflect-metadata@0.2.2: {} reflect-metadata@0.2.2: {}
@@ -8645,7 +8796,7 @@ snapshots:
ansis: 4.2.0 ansis: 4.2.0
app-root-path: 3.1.0 app-root-path: 3.1.0
buffer: 6.0.3 buffer: 6.0.3
dayjs: 1.11.19 dayjs: 1.11.20
debug: 4.4.3 debug: 4.4.3
dedent: 1.7.1 dedent: 1.7.1
dotenv: 16.6.1 dotenv: 16.6.1
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { PlusOutlined, HolderOutlined, DeleteOutlined } from '@ant-design/icons' import { HolderOutlined, DeleteOutlined } from '@ant-design/icons'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import RuleComponent from './autoScore/ruleComponent' import RuleComponent from './autoScore/ruleComponent'
import { import {
@@ -526,14 +526,16 @@ export const AutoScoreManager: React.FC = () => {
</Form> </Form>
</Card> </Card>
<Card <RuleComponent />
{/* <Card
style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }} style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }}
title={t('autoScore.whenTriggered')} title={t('autoScore.whenTriggered')}
> >
<Space orientation="vertical" style={{ width: '100%' }}> <Space orientation="vertical" style={{ width: '100%' }}>
{/* {triggerList.map((trigger, index) => renderTriggerItem(trigger, index))} {triggerList.map((trigger, index) => renderTriggerItem(trigger, index))}
*/}{' '} {' '}
<RuleComponent />
<Button <Button
type="dashed" type="dashed"
icon={<PlusOutlined />} icon={<PlusOutlined />}
@@ -543,9 +545,9 @@ export const AutoScoreManager: React.FC = () => {
{t('autoScore.addTrigger')} {t('autoScore.addTrigger')}
</Button> </Button>
</Space> </Space>
</Card> </Card> */}
<Card {/* <Card
style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }} style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }}
title={t('autoScore.triggeredActions')} title={t('autoScore.triggeredActions')}
> >
@@ -560,7 +562,7 @@ export const AutoScoreManager: React.FC = () => {
{t('autoScore.addAction')} {t('autoScore.addAction')}
</Button> </Button>
</Space> </Space>
</Card> </Card> */}
<div style={{ marginBottom: '24px', display: 'flex', gap: '12px' }}> <div style={{ marginBottom: '24px', display: 'flex', gap: '12px' }}>
<Button type="primary" onClick={handleSubmit}> <Button type="primary" onClick={handleSubmit}>
+15 -14
View File
@@ -15,6 +15,20 @@ interface TagEditorDialogProps {
title?: string title?: string
} }
export async function fetchAllTags() {
if (!(window as any).api) return []
try {
const res = await (window as any).api.tagsGetAll()
if (res.success && res.data) {
return res.data
}
return []
} catch (e) {
console.error('Failed to fetch tags:', e)
return []
}
}
export const TagEditorDialog: React.FC<TagEditorDialogProps> = ({ export const TagEditorDialog: React.FC<TagEditorDialogProps> = ({
visible, visible,
onClose, onClose,
@@ -28,24 +42,11 @@ export const TagEditorDialog: React.FC<TagEditorDialogProps> = ({
const [selectedTagIds, setSelectedTagIds] = useState<Set<number>>(new Set(initialTagIds)) const [selectedTagIds, setSelectedTagIds] = useState<Set<number>>(new Set(initialTagIds))
const [messageApi, contextHolder] = message.useMessage() const [messageApi, contextHolder] = message.useMessage()
async function fetchAllTags() {
if (!(window as any).api) return
try {
const res = await (window as any).api.tagsGetAll()
if (res.success && res.data) {
setAllTags(res.data)
}
} catch (e) {
console.error('Failed to fetch tags:', e)
messageApi.error(t('tags.fetchFailed'))
}
}
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
setSelectedTagIds(new Set(initialTagIds)) setSelectedTagIds(new Set(initialTagIds))
setInputValue('') setInputValue('')
fetchAllTags() fetchAllTags().then((tags) => setAllTags(tags))
} }
}, [visible, initialTagIds]) }, [visible, initialTagIds])
@@ -1,7 +1,5 @@
.queryBuilder { .queryBuilder {
--querybuilder-font-family: --querybuilder-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
sans-serif;
--querybuilder-background: var(--ss-card-bg, #ffffff); --querybuilder-background: var(--ss-card-bg, #ffffff);
--querybuilder-color: var(--ss-text-main, rgba(0, 0, 0, 0.85)); --querybuilder-color: var(--ss-text-main, rgba(0, 0, 0, 0.85));
--querybuilder-border-radius: 6px; --querybuilder-border-radius: 6px;
@@ -1,4 +1,10 @@
import type { RuleGroupType, Field, Operator } from 'react-querybuilder' import type { RuleGroupType, Field, Operator } from 'react-querybuilder'
import {defaultOperators} from 'react-querybuilder'
import { fetchAllTags } from '../TagEditorDialog'
import type { FullField, RuleType } from 'react-querybuilder';
import { toFullOption } from 'react-querybuilder';
const tags = await fetchAllTags()
export interface AutoScoreTrigger { export interface AutoScoreTrigger {
event: string event: string
@@ -12,52 +18,67 @@ export interface AutoScoreAction {
reason?: string reason?: string
} }
const musicalInstruments = fetchAllTags().then((tags) => tags.map((tag) => tag.name))
export interface AutoScoreRuleData { export interface AutoScoreRuleData {
triggers: AutoScoreTrigger[] triggers: AutoScoreTrigger[]
actions: AutoScoreAction[] actions: AutoScoreAction[]
} }
// i18n key definitions for triggers and actions
export const TRIGGER_TYPE_KEYS = {
interval_time_passed: {
labelKey: 'autoScore.triggerIntervalTime',
descriptionKey: 'triggers.intervalTime.description'
},
student_has_tag: {
labelKey: 'autoScore.triggerStudentTag',
descriptionKey: 'triggers.studentTag.description'
}
}
export const ACTION_TYPE_KEYS = {
add_score: {
labelKey: 'autoScore.actionAddScore',
descriptionKey: 'actions.addScore.description'
},
add_tag: {
labelKey: 'autoScore.actionAddTag',
descriptionKey: 'actions.addTag.description'
}
}
// Function to get fields with i18n support // Function to get fields with i18n support
export const getFields = (t: (key: string) => string): Field[] => [ export const getFields = (t: (key: string) => string): Field[] => [
{ {
name: 'interval_time_passed', name: 'interval_time_passed',
label: t('autoScore.triggerIntervalTime'), label: t('autoScore.triggerIntervalTime'),
placeholder: t('autoScore.intervalMinutesPlaceholder') placeholder: t('autoScore.intervalMinutesPlaceholder'),
inputType: 'date',
datatype: 'timestamp with time zone',
}, },
{ {
name: 'student_has_tag', name: 'student_has_tag',
label: t('autoScore.triggerStudentTag'), label: t('autoScore.triggerStudentTag'),
placeholder: t('autoScore.tagNamesPlaceholder') placeholder: t('autoScore.tagNamesPlaceholder'),
} valueEditorType: 'multiselect',
values: tags.map((tag) => tag.name),
defaultValue: tags.length > 0 ? [tags[0].name] : [],
operators: defaultOperators.filter((op) => op.name === '='),
},
{
name: 'tourStops',
label: 'Tour stops',
matchModes: true,
subproperties: [
{ name: 'date', label: 'Date', inputType: 'date', datatype: 'date' },
{ name: 'time', label: 'Time', inputType: 'time', datatype: 'time' },
],
},
] ]
export const operators: Operator[] = [ /* export const operators: Operator[] = [
{ name: '=', label: '=' }, { name: '=', label: '=' },
{ name: 'contains', label: 'contains' } { name: 'contains', label: 'contains' },
] { name: 'between', label: 'between' }
] */
export const fields: FullField[] = (
[
{
name: 'interval_time_passed',
label: ('autoScore.triggerIntervalTime'),
placeholder: ('autoScore.intervalMinutesPlaceholder')
},
{
name: 'student_has_tag',
label: ('autoScore.triggerStudentTag'),
placeholder: ('autoScore.tagNamesPlaceholder'),
valueEditorType: 'multiselect',
values: tags.map((tag) => tag.name),
defaultValue: 'more_cowbell',
operators: defaultOperators.filter((op) => op.name === 'in'),
}
] satisfies Field[]
).map((o) => toFullOption(o));
export const defaultQuery: RuleGroupType = { export const defaultQuery: RuleGroupType = {
combinator: 'and', combinator: 'and',
@@ -117,3 +138,27 @@ export function autoScoreRuleToQuery(ruleData: AutoScoreRuleData): RuleGroupType
rules: rules.length > 0 ? rules : defaultQuery.rules rules: rules.length > 0 ? rules : defaultQuery.rules
} }
} }
/* import type { Field, FullField, RuleType } from 'react-querybuilder';
import { defaultOperators, toFullOption } from 'react-querybuilder';
import { fetchAllTags } from '../TagEditorDialog'
const tags = await fetchAllTags()
export const fields: FullField[] = (
[
{
name: 'interval_time_passed',
label: ('autoScore.triggerIntervalTime'),
placeholder: ('autoScore.intervalMinutesPlaceholder')
},
{
name: 'student_has_tag',
label: ('autoScore.triggerStudentTag'),
placeholder: ('autoScore.tagNamesPlaceholder'),
valueEditorType: 'multiselect',
values: tags.map((tag) => tag.name),
defaultValue: 'more_cowbell',
operators: defaultOperators.filter((op) => op.name === 'in'),
}
] satisfies Field[]
).map((o) => toFullOption(o)); */
@@ -1,9 +1,14 @@
import { formatQuery, QueryBuilder, RuleGroupType } from 'react-querybuilder' import { formatQuery, QueryBuilder, RuleGroupType } from 'react-querybuilder'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { QueryBuilderDnD } from '@react-querybuilder/dnd';
import * as ReactDnD from 'react-dnd';
import { QueryBuilderAntD } from '@react-querybuilder/antd';
import * as ReactDndHtml5Backend from 'react-dnd-html5-backend';
import * as ReactDndTouchBackend from 'react-dnd-touch-backend';
import { import {
getFields, getFields,
operators, /* operators, */
defaultQuery, defaultQuery,
queryToAutoScoreRule, queryToAutoScoreRule,
autoScoreRuleToQuery, autoScoreRuleToQuery,
@@ -23,9 +28,9 @@ interface RuleComponentProps {
export const RuleComponent: React.FC<RuleComponentProps> = ({ initialData, onChange }) => { export const RuleComponent: React.FC<RuleComponentProps> = ({ initialData, onChange }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [query, setQuery] = useState<RuleGroupType>( const [query, setQuery] = useState<RuleGroupType>(
initialData ? autoScoreRuleToQuery(initialData) : defaultQuery initialData ? autoScoreRuleToQuery(initialData) : defaultQuery
) )
const [actions, setActions] = useState<AutoScoreRuleData['actions']>(initialData?.actions || []) /* const [actions, setActions] = useState<AutoScoreRuleData['actions']>(initialData?.actions || [])
useEffect(() => { useEffect(() => {
if (onChange) { if (onChange) {
@@ -37,10 +42,6 @@ export const RuleComponent: React.FC<RuleComponentProps> = ({ initialData, onCha
} }
}, [query, actions]) }, [query, actions])
const handleQueryChange = (newQuery: RuleGroupType) => {
setQuery(newQuery)
}
const handleAddAction = () => { const handleAddAction = () => {
setActions([...actions, { event: 'add_score', value: '5', reason: '' }]) setActions([...actions, { event: 'add_score', value: '5', reason: '' }])
} }
@@ -54,29 +55,34 @@ export const RuleComponent: React.FC<RuleComponentProps> = ({ initialData, onCha
newActions[index] = { ...newActions[index], [field]: value } newActions[index] = { ...newActions[index], [field]: value }
setActions(newActions) setActions(newActions)
} }
*/
const handleQueryChange = (newQuery: RuleGroupType) => {
setQuery(newQuery)
}
return ( return (
<div> <div>
<Card title={t('autoScore.triggerCondition')} style={{ marginBottom: '16px' }}> <Card title={t('autoScore.triggerCondition')} style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }}>
<QueryBuilder <QueryBuilderDnD dnd={{ ...ReactDnD, ...ReactDndHtml5Backend, ...ReactDndTouchBackend }}>
fields={getFields(t)} <QueryBuilderAntD>
operators={operators} <QueryBuilder
query={query} fields={getFields(t)}
onQueryChange={handleQueryChange} /* operators={operators} */
/> query={query}
/* onQueryChange={handleQueryChange} */
onQueryChange={handleQueryChange} />
</QueryBuilderAntD>
</QueryBuilderDnD>
<div style={{ marginTop: '8px' }}> <div style={{ marginTop: '8px' }}>
<pre style={{ fontSize: '12px', color: '#999' }}>{formatQuery(query, 'json')}</pre> <pre style={{ fontSize: '12px', color: '#999' }}>{ formatQuery(query, 'json') }</pre>
</div> </div>
</Card> </Card>
{/* <Card title={t('autoScore.executeAction')} style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }}>
<Card title={t('autoScore.executeAction')}>
<ActionComponent <ActionComponent
actions={actions} actions={actions}
onAdd={handleAddAction} onAdd={handleAddAction}
onRemove={handleRemoveAction} onRemove={handleRemoveAction}
onChange={handleActionChange} onChange={handleActionChange} />
/> </Card> */}
</Card>
</div> </div>
) )
} }