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 }) => (
- }
- onClick={file && (() => downloadFile(file))}
+export const DownloadLink = memo(({
+ className = '',
+ file,
+ name,
+ icon = ,
+ ...other
+}) => (
+ {name ?? file?.name ?? '-'}
+ 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) => (
- downloadFile(row)} download={name}>
- {name}
-
+
),
},
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={(
+ <>
+ navigate('/')}>Вернуться на главную
+ Загрузить
+ >
+ )}
+ >
+ {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