diff --git a/package-lock.json b/package-lock.json index 97a86f45..9894e7c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -456,9 +456,9 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", - "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.28.6", @@ -904,9 +904,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -938,9 +938,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -1161,9 +1161,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -1186,9 +1186,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -1308,9 +1308,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -1333,9 +1333,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -1516,9 +1516,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -1547,9 +1547,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -1696,9 +1696,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -1727,9 +1727,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -1991,9 +1991,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -2022,9 +2022,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -2119,9 +2119,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -2160,9 +2160,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -2290,9 +2290,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -2375,9 +2375,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -2477,9 +2477,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -2562,9 +2562,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -2668,9 +2668,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -2738,9 +2738,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -2852,9 +2852,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -2911,9 +2911,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -2942,9 +2942,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -3179,9 +3179,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -3210,9 +3210,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -3412,9 +3412,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -3443,9 +3443,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -3629,9 +3629,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -3660,9 +3660,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -3756,9 +3756,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -3817,9 +3817,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -3965,9 +3965,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -4050,9 +4050,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -4153,9 +4153,9 @@ } }, "@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { "@babel/parser": "^7.29.0", @@ -4238,9 +4238,9 @@ "dev": true }, "@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "requires": { "@babel/types": "^7.29.0" @@ -4787,9 +4787,9 @@ } }, "@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", + "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", "dev": true, "requires": { "@babel/compat-data": "^7.29.0", @@ -4924,9 +4924,9 @@ } }, "@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==" + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==" }, "@babel/template": { "version": "7.12.13", @@ -7807,13 +7807,13 @@ "dev": true }, "axios": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", - "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", "requires": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" }, "dependencies": { "es-define-property": { @@ -8069,13 +8069,13 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", - "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", "dev": true, "requires": { "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", "semver": "^6.3.1" }, "dependencies": { @@ -8088,22 +8088,22 @@ } }, "babel-plugin-polyfill-corejs3": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", - "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", "core-js-compat": "^3.48.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", - "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.6.6" + "@babel/helper-define-polyfill-provider": "^0.6.8" } }, "babel-plugin-syntax-jsx": { @@ -9161,42 +9161,48 @@ } }, "core-js": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", - "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==" + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==" }, "core-js-compat": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", - "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", "dev": true, "requires": { "browserslist": "^4.28.1" }, "dependencies": { + "baseline-browser-mapping": { + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.13.tgz", + "integrity": "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==", + "dev": true + }, "browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "requires": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" } }, "caniuse-lite": { - "version": "1.0.30001766", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", - "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "version": "1.0.30001784", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001784.tgz", + "integrity": "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==", "dev": true }, "electron-to-chromium": { - "version": "1.5.283", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz", - "integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==", + "version": "1.5.330", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.330.tgz", + "integrity": "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA==", "dev": true }, "escalade": { @@ -9206,9 +9212,9 @@ "dev": true }, "node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "dev": true }, "picocolors": { @@ -17424,9 +17430,9 @@ } }, "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==" }, "prr": { "version": "1.0.1", @@ -17620,9 +17626,9 @@ } }, "react-dropzone": { - "version": "14.4.0", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.4.0.tgz", - "integrity": "sha512-8VvsHqg9WGAr+wAnP0oVErK5HOwAoTOzRsxLPzbBXrtXtFfukkxMyuvdI/lJ+5OxtsrzmvWE5Eoo3Y4hMsaxpA==", + "version": "14.4.1", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.4.1.tgz", + "integrity": "sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==", "requires": { "attr-accept": "^2.2.4", "file-selector": "^2.1.0", @@ -17779,9 +17785,9 @@ } }, "react-virtuoso": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.1.tgz", - "integrity": "sha512-KF474cDwaSb9+SJ380xruBB4P+yGWcVkcu26HtMqYNMTYlYbrNy8vqMkE+GpAApPPufJqgOLMoWMFG/3pJMXUA==" + "version": "4.18.4", + "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.4.tgz", + "integrity": "sha512-DNM4Wy2tMA/J6ejMaDdqecOug31rOwgSRg4C/Dw6Iox4dJe9qwcx32M8HdhkE5uHEVVZh7h0koYwAsCSNdxGfQ==" }, "react-window": { "version": "1.8.11", diff --git a/package.json b/package.json index 017bf365..bfa7690a 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "@mui/material": "5.14.5", "@mui/styles": "5.14.5", "@mui/x-date-pickers": "^5.0.20", - "axios": "^1.13.4", - "core-js": "^3.48.0", + "axios": "^1.14.0", + "core-js": "^3.49.0", "i18next": "^22.4.9", "jquery": "^3.7.1", "lodash": "^4.17.23", @@ -23,7 +23,7 @@ "react-beautiful-dnd": "^13.1.1", "react-diff-viewer": "^3.1.1", "react-dom": "^18.3.1", - "react-dropzone": "^14.4.0", + "react-dropzone": "^14.4.1", "react-ga4": "^2.1.0", "react-google-recaptcha": "^2.1.0", "react-hotjar": "^5.5.0", @@ -34,7 +34,7 @@ "react-password-strength-bar": "^0.3.5", "react-quill": "^2.0.0", "react-router-dom": "^5.3.4", - "react-virtuoso": "^4.18.1", + "react-virtuoso": "^4.18.4", "react-window": "^1.8.11", "stacktrace-js": "^2.0.2", "xlsx": "^0.18.5" @@ -49,9 +49,9 @@ "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-object-rest-spread": "^7.20.7", "@babel/polyfill": "^7.12.1", - "@babel/preset-env": "^7.29.0", + "@babel/preset-env": "^7.29.2", "@babel/preset-react": "^7.28.5", - "@babel/runtime": "^7.28.6", + "@babel/runtime": "^7.29.2", "babel-eslint": "^10.1.0", "babel-loader": "^8.4.1", "copy-webpack-plugin": "^4.6.0", diff --git a/src/components/common/AddToCollectionDialog.jsx b/src/components/common/AddToCollectionDialog.jsx new file mode 100644 index 00000000..5474ac22 --- /dev/null +++ b/src/components/common/AddToCollectionDialog.jsx @@ -0,0 +1,329 @@ +import React from 'react' +import { TextField, CircularProgress, Divider, DialogContent, DialogActions } from '@mui/material' +import Autocomplete from '@mui/material/Autocomplete' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import Box from '@mui/material/Box' +import Alert from '@mui/material/Alert' +import Table from '@mui/material/Table' +import TableHead from '@mui/material/TableHead' +import TableBody from '@mui/material/TableBody' +import TableRow from '@mui/material/TableRow' +import TableCell from '@mui/material/TableCell' +import { includes, toLower } from 'lodash' +import APIService from '../../services/APIService' +import { getCurrentUserCollections, dropVersion } from '../../common/utils' +import Dialog from './Dialog' +import DialogTitle from './DialogTitle' +import GroupHeader from './GroupHeader' +import GroupItems from './GroupItems' +import AutocompleteLoading from './AutocompleteLoading' +import CascadeSelector from './CascadeSelector' +import RepoChip from '../repos/RepoChip' +import RepoTooltip from '../repos/RepoTooltip' + +// Extract "[id] [name]" from an expression URL like /orgs/CIEL/sources/CIEL/concepts/1234/ +const extractConceptLabel = expression => { + if (!expression) return expression + const parts = expression.replace(/\/$/, '').split('/') + const conceptsIdx = parts.lastIndexOf('concepts') + if (conceptsIdx !== -1 && parts[conceptsIdx + 1]) { + return parts[conceptsIdx + 1] + } + return expression +} + +// Format one error entry object { description, conflicting_references, conflicting_concept_id, ... } +const formatErrorEntry = entry => { + if (!entry || typeof entry !== 'object') return String(entry) + const lines = [] + if (entry.description) lines.push(entry.description) + if (entry.conflicting_references && entry.conflicting_references.length) { + const refs = entry.conflicting_references.map(r => { + // extract the reference ID from the URI e.g. /users/.../references/14957106/ + const m = r.match(/\/references\/([^/]+)\/?$/) + return m ? `Reference #${m[1]}` : r + }) + lines.push(`Conflicting: ${refs.join(', ')}`) + } + if (entry.conflicting_concept_id) { + const label = entry.conflicting_concept_name + ? `${entry.conflicting_concept_id} ${entry.conflicting_concept_name}` + : entry.conflicting_concept_id + lines.push(`Conflicting concept: ${label}`) + } + if (entry.conflicting_name) lines.push(`Conflicting name: "${entry.conflicting_name}"`) + return lines.join(' — ') || JSON.stringify(entry) +} + +// The API returns message as { expressionUrl: { errors: [...] } } +const formatErrorMessage = message => { + if (!message) return '—' + if (typeof message === 'string') return message + + // Unwrap the expression-keyed envelope + const allErrors = [] + Object.values(message).forEach(val => { + if (val && Array.isArray(val.errors)) { + val.errors.forEach(e => allErrors.push(formatErrorEntry(e))) + } else if (val && typeof val === 'object') { + allErrors.push(formatErrorEntry(val)) + } + }) + return allErrors.length ? allErrors.join('\n') : JSON.stringify(message) +} + +const AddToCollectionDialog = ({ open, onClose, concept }) => { + const [collections, setCollections] = React.useState([]) + const [selected, setSelected] = React.useState(null) + const [input, setInput] = React.useState('') + const [loadingCollections, setLoadingCollections] = React.useState(false) + const [cascadeParams, setCascadeParams] = React.useState({}) + const [submitting, setSubmitting] = React.useState(false) + const [results, setResults] = React.useState(null) // array of { added, expression, message } + const [error, setError] = React.useState(null) + + React.useEffect(() => { + if (open) { + setLoadingCollections(true) + setSelected(null) + setResults(null) + setError(null) + setCascadeParams({}) + const seen = new Set() + getCurrentUserCollections(batch => { + setCollections(prev => { + const merged = [ + ...prev, + ...batch.filter(c => { + if (seen.has(c.url)) return false + seen.add(c.url) + return true + }) + ] + return merged + }) + setLoadingCollections(false) + }) + } else { + setCollections([]) + } + }, [open]) + + const handleInputChange = (_, value) => setInput(value || '') + + const filterCollectionOptions = (options, { inputValue }) => { + if (!inputValue) return options + const q = toLower(inputValue) + return options.filter(o => + includes(toLower(o.name), q) || + includes(toLower(o.id), q) || + includes(toLower(o.short_code), q) || + includes(toLower(o.owner), q) + ) + } + + const conceptUrl = concept + ? dropVersion(concept.url) || concept.url + : null + + const handleSubmit = () => { + if (!selected || !conceptUrl) return + setSubmitting(true) + setError(null) + setResults(null) + + const collectionOwnerType = selected.owner_type && selected.owner_type.toLowerCase() === 'organization' ? 'orgs' : 'users' + const queryParams = Object.keys(cascadeParams).length + ? cascadeParams + : undefined + + APIService[collectionOwnerType](selected.owner) + .collections(selected.short_code || selected.id) + .appendToUrl('references/') + .put( + { data: { expressions: [conceptUrl] }, cascade: cascadeParams.method || '' }, + null, + {}, + queryParams + ) + .then(response => { + setSubmitting(false) + if (response && (response.status === 200 || response.status === 201)) { + setResults(Array.isArray(response.data) ? response.data : []) + } else { + const msg = (response && (response.detail || response.error)) || 'Something went wrong' + setError(msg) + } + }) + } + + const addedCount = results ? results.filter(r => r.added).length : 0 + const failedCount = results ? results.filter(r => !r.added).length : 0 + const done = results !== null + + return ( + + Add to Collection + + + {/* Concept being added */} + {concept && ( + + Adding: {concept.display_name || concept.id} + {concept.source && from {concept.source}} + + )} + + {/* Collection selector */} + option.url === value.url} + getOptionLabel={option => option ? `${option.name || option.id} (${option.owner})` : ''} + groupBy={option => option.owner} + onInputChange={handleInputChange} + onChange={(_, item) => setSelected(item)} + disabled={submitting || done} + renderInput={params => ( + + {loadingCollections ? : null} + {params.InputProps.endAdornment} + + ), + }} + /> + )} + loadingText={} + noOptionsText="No editable collections found" + renderGroup={params => ( +
  • + {params.group} + {params.children} +
  • + )} + renderOption={(props, option) => ( + +
  • + + {option.name || option.id} + + + + + + +
  • + +
    + )} + /> + + {/* Cascade selector */} + + + {/* Submitting spinner */} + {submitting && ( + + + Adding reference… + + )} + + {/* Request error */} + {error && {error}} + + {/* Results */} + {done && ( + + + {addedCount > 0 && failedCount === 0 && `${addedCount} reference${addedCount !== 1 ? 's' : ''} added`} + {addedCount > 0 && failedCount > 0 && `${addedCount} added, ${failedCount} failed`} + {addedCount === 0 && failedCount > 0 && `${failedCount} reference${failedCount !== 1 ? 's' : ''} failed`} + {addedCount === 0 && failedCount === 0 && 'No references added'} + + + {/* Successes */} + {addedCount > 0 && ( + 0 ? 2 : 0, border: '1px solid', borderColor: 'divider', borderRadius: 1, overflow: 'hidden' }}> + {results.filter(r => r.added).map((item, idx, arr) => ( + + + + {item.conceptId || extractConceptLabel(item.expression)} + + + {typeof item.message === 'string' ? item.message : ''} + + + {idx < arr.length - 1 && } + + ))} + + )} + + {/* Failures */} + {failedCount > 0 && ( + + + + Reference + Error + + + + {results.filter(r => !r.added).map((item, idx) => ( + + + {extractConceptLabel(item.expression)} + + + {formatErrorMessage(item.message)} + + + ))} + +
    + )} +
    + )} +
    + + + + {!done && ( + + )} + +
    + ) +} + +export default AddToCollectionDialog diff --git a/src/components/common/CascadeSelector.jsx b/src/components/common/CascadeSelector.jsx new file mode 100644 index 00000000..b24f87f2 --- /dev/null +++ b/src/components/common/CascadeSelector.jsx @@ -0,0 +1,228 @@ +import React from 'react' +import Box from '@mui/material/Box' +import TextField from '@mui/material/TextField' +import Collapse from '@mui/material/Collapse' +import FormControl from '@mui/material/FormControl' +import InputLabel from '@mui/material/InputLabel' +import Select from '@mui/material/Select' +import MenuItem from '@mui/material/MenuItem' +import Checkbox from '@mui/material/Checkbox' +import FormControlLabel from '@mui/material/FormControlLabel' +import Chip from '@mui/material/Chip' +import Tooltip from '@mui/material/Tooltip' +import IconButton from '@mui/material/IconButton' +import HelpOutlineIcon from '@mui/icons-material/HelpOutline' +import CodeIcon from '@mui/icons-material/CodeOutlined' + +const PRESETS = [ + { + id: 'none', + label: 'None', + params: {}, + }, + { + id: 'sourcemappings', + label: 'Source Mappings', + params: { method: 'sourcemappings' }, + }, + { + id: 'sourcetoconcepts', + label: 'OpenMRS', + params: { method: 'sourcetoconcepts', mapTypes: 'Q-AND-A,CONCEPT-SET', cascadeLevels: '*', returnMapTypes: '*' }, + }, + { + id: 'custom', + label: 'Custom', + params: null, + }, +] + +const DEFAULT_CUSTOM_PARAMS = { + method: 'sourcetoconcepts', + mapTypes: '', + excludeMapTypes: '', + cascadeLevels: '*', + returnMapTypes: '*', +} + +const buildQueryString = (params, transform) => { + if (!params || Object.keys(params).length === 0) return '' + const parts = [] + if (params.method) parts.push(`method=${params.method}`) + if (params.mapTypes) parts.push(`mapTypes=${params.mapTypes}`) + if (params.excludeMapTypes) parts.push(`excludeMapTypes=${params.excludeMapTypes}`) + if (params.cascadeLevels) parts.push(`cascadeLevels=${params.cascadeLevels}`) + if (params.returnMapTypes) parts.push(`returnMapTypes=${params.returnMapTypes}`) + if (transform) parts.push('transformReferences=openmrs_concept_reference') + return parts.length ? `?${parts.join('&')}` : '' +} + +const CascadeSelector = ({ onChange, conceptUrl, collectionUrl, showPreviewDefault = false }) => { + const [selectedPresetId, setSelectedPresetId] = React.useState('none') + const [transform, setTransform] = React.useState(false) + const [customParams, setCustomParams] = React.useState(DEFAULT_CUSTOM_PARAMS) + const [showPreview, setShowPreview] = React.useState(showPreviewDefault) + + const selectedPreset = PRESETS.find(p => p.id === selectedPresetId) + const baseParams = selectedPresetId === 'custom' ? customParams : (selectedPreset.params || {}) + const currentParams = transform + ? { ...baseParams, transformReferences: 'openmrs_concept_reference' } + : baseParams + + React.useEffect(() => { + if (onChange) onChange(currentParams) + }, [selectedPresetId, customParams, transform]) // eslint-disable-line react-hooks/exhaustive-deps + + const handleCustomParamChange = field => event => { + setCustomParams(prev => ({ ...prev, [field]: event.target.value })) + } + + const queryString = buildQueryString(baseParams, transform) + const collectionBase = (collectionUrl || '/:owner/collections/:collection').replace(/\/$/, '') + const endpoint = `${collectionBase}/references/${queryString}` + const conceptExpr = conceptUrl || '/:owner/sources/:source/concepts/:id/' + const requestBody = JSON.stringify({ data: { expressions: [conceptExpr] }, cascade: baseParams.method || '' }, null, 2) + + return ( + + {/* Cascade dropdown + Transform checkbox on same row */} + + + Cascade + + + + + setTransform(e.target.checked)} + /> + } + label="Transform" + sx={{ mr: 0, '& .MuiFormControlLabel-label': { fontSize: '0.875rem' } }} + /> + + + + + + + + + {/* Custom params form */} + + + + Method + + + + + + + + + + + + + + {/* API call preview */} + + } + label={showPreview ? 'Hide API call' : 'Preview API call'} + variant="outlined" + clickable + onClick={() => setShowPreview(v => !v)} + sx={{ fontSize: '0.7rem' }} + /> + + + + + {`PUT ${endpoint}\n\n${requestBody}`} + + + + ) +} + +export default CascadeSelector diff --git a/src/components/concepts/ConceptHeader.jsx b/src/components/concepts/ConceptHeader.jsx index baae222f..b775c943 100644 --- a/src/components/concepts/ConceptHeader.jsx +++ b/src/components/concepts/ConceptHeader.jsx @@ -5,16 +5,19 @@ import Typography from '@mui/material/Typography' import Skeleton from '@mui/material/Skeleton'; import Button from '@mui/material/Button'; import DownIcon from '@mui/icons-material/ArrowDropDown'; +import AddIcon from '@mui/icons-material/PlaylistAddOutlined'; import CloseIconButton from '../common/CloseIconButton'; import { toOwnerURI, currentUserHasAccess } from '../../common/utils'; import Breadcrumbs from '../common/Breadcrumbs' import { BLACK } from '../../common/colors' import ConceptManagementList from './ConceptManagementList' +import AddToCollectionDialog from '../common/AddToCollectionDialog' const ConceptHeader = ({concept, repo, onClose, repoURL, onEdit, onRetire, nested, loading}) => { const { t } = useTranslation() const [menu, setMenu] = React.useState(false) const [menuAnchorEl, setMenuAnchorEl] = React.useState(false) + const [addToCollectionOpen, setAddToCollectionOpen] = React.useState(false) const onMenuOpen = event => { setMenuAnchorEl(event.currentTarget) setMenu(true) @@ -69,17 +72,36 @@ const ConceptHeader = ({concept, repo, onClose, repoURL, onEdit, onRetire, neste } { - currentUserHasAccess() && repo?.version === 'HEAD' && has(repo, 'source_type') && !loading && + !loading &&
    - + + {currentUserHasAccess() && ( + + )} + + {currentUserHasAccess() && repo?.version === 'HEAD' && has(repo, 'source_type') && ( + )}
    } + setAddToCollectionOpen(false)} + concept={concept} + /> ) } diff --git a/src/components/repos/RepoTooltip.jsx b/src/components/repos/RepoTooltip.jsx index a63213f8..2ae7d4d6 100644 --- a/src/components/repos/RepoTooltip.jsx +++ b/src/components/repos/RepoTooltip.jsx @@ -121,7 +121,7 @@ const TooltipTitle = ({ repo }) => { ) } -const RepoTooltip = ({ repo, basicTooltip, children, spanStyle }) => { +const RepoTooltip = ({ repo, basicTooltip, children, spanStyle, enterDelay, enterNextDelay }) => { return basicTooltip ? ( @@ -135,6 +135,8 @@ const RepoTooltip = ({ repo, basicTooltip, children, spanStyle }) => { maxWidth: 400 } }} + enterDelay={enterDelay} + enterNextDelay={enterNextDelay} title={