diff --git a/package-lock.json b/package-lock.json index df506d6..c0c39b1 100755 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "chartjs-plugin-datalabels": "^2.0.0", "chartjs-plugin-zoom": "^1.2.1", "d3": "^7.4.4", - "less": "^4.1.2", "moment": "^2.29.3", "pigeon-maps": "^0.21.0", "react": "^18.1.0", @@ -46,6 +45,7 @@ "html-webpack-plugin": "^5.5.0", "interpolate-html-plugin": "^4.0.0", "jest": "^28.1.0", + "less": "^4.1.3", "less-loader": "^11.0.0", "openapi-typescript": "^5.4.0", "openapi-typescript-codegen": "^0.23.0", @@ -4855,6 +4855,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, "dependencies": { "is-what": "^3.14.1" }, @@ -5445,6 +5446,7 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "optional": true, "dependencies": { "ms": "^2.1.1" @@ -5751,6 +5753,7 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, "optional": true, "dependencies": { "prr": "~1.0.1" @@ -6453,7 +6456,7 @@ "version": "4.2.9", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "devOptional": true + "dev": true }, "node_modules/hammerjs": { "version": "2.0.8", @@ -6751,7 +6754,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "devOptional": true, + "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -6775,6 +6778,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, "optional": true, "bin": { "image-size": "bin/image-size.js" @@ -7031,7 +7035,8 @@ "node_modules/is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true }, "node_modules/is-wsl": { "version": "2.2.0", @@ -8274,9 +8279,10 @@ } }, "node_modules/less": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", - "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -8294,7 +8300,7 @@ "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "needle": "^2.5.2", + "needle": "^3.1.0", "source-map": "~0.6.0" } }, @@ -8430,6 +8436,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, "optional": true, "dependencies": { "pify": "^4.0.1", @@ -8443,6 +8450,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, "optional": true, "bin": { "semver": "bin/semver" @@ -8527,7 +8535,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "devOptional": true, + "dev": true, "bin": { "mime": "cli.js" }, @@ -8610,7 +8618,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "devOptional": true + "dev": true }, "node_modules/multicast-dns": { "version": "7.2.4", @@ -8644,13 +8652,14 @@ "dev": true }, "node_modules/needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", + "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "dev": true, "optional": true, "dependencies": { "debug": "^3.2.6", - "iconv-lite": "^0.4.4", + "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, "bin": { @@ -8660,6 +8669,19 @@ "node": ">= 4.4.x" } }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -9030,6 +9052,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, "engines": { "node": ">= 0.10" } @@ -9129,6 +9152,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, "optional": true, "engines": { "node": ">=6" @@ -9361,6 +9385,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, "optional": true }, "node_modules/psl": { @@ -10402,6 +10427,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, "optional": true }, "node_modules/scheduler": { @@ -10706,7 +10732,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -15779,6 +15805,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, "requires": { "is-what": "^3.14.1" } @@ -16209,6 +16236,7 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "optional": true, "requires": { "ms": "^2.1.1" @@ -16439,6 +16467,7 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, "optional": true, "requires": { "prr": "~1.0.1" @@ -16965,7 +16994,7 @@ "version": "4.2.9", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "devOptional": true + "dev": true }, "hammerjs": { "version": "2.0.8", @@ -17192,7 +17221,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "devOptional": true, + "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -17208,6 +17237,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, "optional": true }, "import-fresh": { @@ -17379,7 +17409,8 @@ "is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true }, "is-wsl": { "version": "2.2.0", @@ -18334,9 +18365,10 @@ "dev": true }, "less": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", - "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, "requires": { "copy-anything": "^2.0.1", "errno": "^0.1.1", @@ -18344,7 +18376,7 @@ "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "needle": "^2.5.2", + "needle": "^3.1.0", "parse-node-version": "^1.0.1", "source-map": "~0.6.0", "tslib": "^2.3.0" @@ -18450,6 +18482,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, "optional": true, "requires": { "pify": "^4.0.1", @@ -18460,6 +18493,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, "optional": true } } @@ -18531,7 +18565,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "devOptional": true + "dev": true }, "mime-db": { "version": "1.52.0", @@ -18590,7 +18624,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "devOptional": true + "dev": true }, "multicast-dns": { "version": "7.2.4", @@ -18615,14 +18649,27 @@ "dev": true }, "needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", + "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "dev": true, "optional": true, "requires": { "debug": "^3.2.6", - "iconv-lite": "^0.4.4", + "iconv-lite": "^0.6.3", "sax": "^1.2.4" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } } }, "negotiator": { @@ -18896,7 +18943,8 @@ "parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true }, "parseurl": { "version": "1.3.3", @@ -18972,6 +19020,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, "optional": true }, "pigeon-maps": { @@ -19131,6 +19180,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, "optional": true }, "psl": { @@ -19905,6 +19955,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, "optional": true }, "scheduler": { @@ -20166,7 +20217,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true + "dev": true }, "source-map-js": { "version": "1.0.2", diff --git a/package.json b/package.json index f46e169..4273022 100755 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "chartjs-plugin-datalabels": "^2.0.0", "chartjs-plugin-zoom": "^1.2.1", "d3": "^7.4.4", - "less": "^4.1.2", "moment": "^2.29.3", "pigeon-maps": "^0.21.0", "react": "^18.1.0", @@ -93,6 +92,7 @@ "html-webpack-plugin": "^5.5.0", "interpolate-html-plugin": "^4.0.0", "jest": "^28.1.0", + "less": "^4.1.3", "less-loader": "^11.0.0", "openapi-typescript": "^5.4.0", "openapi-typescript-codegen": "^0.23.0", diff --git a/src/App.tsx b/src/App.tsx index 09c58ad..d788656 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import Login from '@pages/Login' import Cluster from '@pages/Cluster' import Deposit from '@pages/Deposit' import Register from '@pages/Register' +import FileDownload from '@pages/FileDownload' import '@styles/App.less' @@ -39,6 +40,7 @@ export const App = memo(() => ( } /> } /> } /> + } /> diff --git a/src/components/DownloadLink.tsx b/src/components/DownloadLink.tsx index 906dc40..a62559b 100755 --- a/src/components/DownloadLink.tsx +++ b/src/components/DownloadLink.tsx @@ -1,22 +1,43 @@ -import { memo } from 'react' -import { Button, ButtonProps } from 'antd' +import { memo, ReactNode } from 'react' +import { Link, LinkProps } from 'react-router-dom' import { FileWordOutlined } from '@ant-design/icons' import { FileInfoDto } from '@api' import { downloadFile } from './factory' -export type DownloadLinkProps = ButtonProps & { +import { getLinkToFile } from '@pages/FileDownload' + +import '@styles/index.css' + +export type DownloadLinkProps = LinkProps & { file?: FileInfoDto name?: string + icon?: ReactNode } -export const DownloadLink = memo(({ file, name, ...other }) => ( - + className={`download-link ${className}`} + + to={getLinkToFile(file)} + onClick={(e) => { + if (file) + downloadFile(file) + e.preventDefault() + return false + }} + > + {icon} + {name ?? file?.name ?? '-'} + )) export default DownloadLink diff --git a/src/components/factory.ts b/src/components/factory.ts index 399aba2..077ea3e 100755 --- a/src/components/factory.ts +++ b/src/components/factory.ts @@ -37,6 +37,21 @@ export const notify = (body?: ReactNode, notifyType: NotifyType = 'info', other? type asyncFunction = (...args: any) => Promise +const parseApiEror = (err: unknown, actionName?: string) => { + if (!(err instanceof ApiError)) return false + + switch (err.status) { + case 403: + if (actionName) + notify(`Недостаточно прав для выполнения действия "${actionName}"`, 'error') + else + notify('Недостаточно прав для выполнения действия', 'error') + return true + case 204: return true + default: return false + } +} + export const invokeWebApiWrapperAsync = async ( funcAsync: asyncFunction, setShowLoader?: Dispatch>, @@ -49,14 +64,8 @@ export const invokeWebApiWrapperAsync = async ( } catch (ex) { if(isDev()) console.error(ex) - if (ex instanceof ApiError && ex.status === 403) { - if (actionName) - notify(`Недостаточно прав для выполнения действия "${actionName}"`, 'error') - else - notify('Недостаточно прав для выполнения действия', 'error') - } else { + if (!parseApiEror(ex, actionName)) notify(getFunctionalValue(errorNotifyText)(ex), 'error') - } } finally { setShowLoader?.(false) } @@ -104,9 +113,11 @@ export const upload = async (url: string, formData: FormData) => { export const downloadFile = async (fileInfo: FileInfoDto) => { try { await download(`/api/well/${fileInfo.idWell}/files/${fileInfo.id}`) + return true } catch (error) { - notify(`Не удалось скачать файл ${fileInfo.name} по скважине (${fileInfo.idWell})`, 'error') + notify(`Не удалось скачать файл "${fileInfo.name}" по скважине №${fileInfo.idWell}`, 'error') console.log(error) + return false } } diff --git a/src/pages/AccessDenied.jsx b/src/pages/AccessDenied.jsx index 285c64e..7484f03 100755 --- a/src/pages/AccessDenied.jsx +++ b/src/pages/AccessDenied.jsx @@ -28,7 +28,7 @@ export const AccessDenied = memo(() => {  Страницы не существует.  - Вернуться назад > + navigate(-1)}>Вернуться назад > diff --git a/src/pages/Documents/DocumentsTemplate.jsx b/src/pages/Documents/DocumentsTemplate.jsx index 6bc1829..840db5c 100755 --- a/src/pages/Documents/DocumentsTemplate.jsx +++ b/src/pages/Documents/DocumentsTemplate.jsx @@ -1,11 +1,12 @@ import { useState, useEffect, useMemo, useCallback } from 'react' -import { DatePicker, Button, Input } from 'antd' +import { DatePicker, Input } from 'antd' import { useIdWell } from '@asb/context' +import DownloadLink from '@components/DownloadLink' import LoaderPortal from '@components/LoaderPortal' import { UploadForm } from '@components/UploadForm' import { CompanyView, UserView } from '@components/views' -import { invokeWebApiWrapperAsync, downloadFile, formatBytes } from '@components/factory' +import { invokeWebApiWrapperAsync, formatBytes } from '@components/factory' import { EditableTable, makeColumn, makeDateColumn, makeNumericColumn, makePaginationObject } from '@components/Table' import { unique } from '@utils/filters' import { hasPermission } from '@utils' @@ -21,9 +22,7 @@ const columns = [ key: 'document', dataIndex: 'name', render: (name, row) => ( - + ), }, makeDateColumn('Дата загрузки', 'uploadDate'), diff --git a/src/pages/FileDownload.jsx b/src/pages/FileDownload.jsx new file mode 100644 index 0000000..f557a95 --- /dev/null +++ b/src/pages/FileDownload.jsx @@ -0,0 +1,107 @@ +import { Link, useNavigate, useParams } from 'react-router-dom' +import { memo, useCallback, useEffect, useState } from 'react' +import { InfoCircleFilled, CloseCircleOutlined } from '@ant-design/icons' +import { Button, Result, Typography } from 'antd' + +import { downloadFile, invokeWebApiWrapperAsync } from '@components/factory' +import { wrapPrivateComponent } from '@utils' +import { FileService, WellService } from '@api' + +import AccessDenied from './AccessDenied' + +const { Paragraph, Text } = Typography + +export const getLinkToFile = (fileInfo) => `/file_download/${fileInfo.idWell}/${fileInfo.id}` + +const FileDownload = memo(function FileDownload() { + const { idWell, idFile } = useParams() + const [well, setWell] = useState({}) + const [file, setFile] = useState({}) + const [isError, setIsError] = useState(false) + + const navigate = useNavigate() + + useEffect(() => { + invokeWebApiWrapperAsync( + async () => setWell(await WellService.get(idWell)), + null, + 'Не удалось получить информацию о скважине', + 'Получение данных о скважине', + ) + }, [idWell]) + + useEffect(() => { + invokeWebApiWrapperAsync( + async () => { + const files = await FileService.getFilesInfo(idWell) + // TODO Получается только одна категория файлов. + // Поменять при появлении метода получения инфы о конкретном файле + setFile(files.items.find((file) => file.id === idFile) ?? { id: idFile, idWell, name: `File_${idWell}_${idFile}` }) + }, + null, + () => { + setIsError(true) + return 'Не удалось получить информацию о файле' + }, + 'Получение информации о файле' + ) + }, [idWell, idFile]) + + const download = useCallback(async () => { + if (!await downloadFile(file)) + setIsError(true) + }, [file]) + + + return ( + } + title={( + <> + Вы перешли к странице загрузки файла! +
+ Файл "{file.name ?? ('№' + idFile)}", скважина "{well.caption ?? ('№' + idWell)}". + + )} + // subTitle={} + extra={( + <> + + + + )} + > + {isError && ( +
+ + Возможные причины ошибки при попытке скачивания файла: + + + +  У вас отсутствует доступ к файлу.  + + Обратиться в поддержку > + + + + +  Файла не существует.  + navigate(-1)}>Вернуться назад > + + + +  Разрешения не обновились.  + Перезайти в аккаунт > + +
+ )} +
+ ) +}) + +FileDownload.displayName = 'FileDownloadMemo' + +export default wrapPrivateComponent(FileDownload, { + requirements: ['File.get'], + route: 'file_download/:idWell/:idFile*', +}, ) diff --git a/src/styles/index.css b/src/styles/index.css index c87c9bc..b095532 100755 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -127,3 +127,18 @@ code { position: relative; padding: 16px 0; } + +.noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome, Edge, Opera and Firefox */ +} + +.download-link { + height: 32px; + padding: 4px 15px; +} \ No newline at end of file