diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.vscode/launch.json b/.vscode/launch.json old mode 100644 new mode 100755 diff --git a/.vscode/settings.json b/.vscode/settings.json old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index e940f42..de49569 --- a/README.md +++ b/README.md @@ -1 +1,62 @@ -Проект веб части ASB cloud \ No newline at end of file +![ASB Logo](concept/ImagesSrc/logo_Asb.svg) +# Проект веб части ASB cloud + +# Порядок запуска +## 1. Установка пакетов +Для запуска установки необходимо иметь уже установленый [NPM](https://www.npmjs.com). + +Установка выполняется одной командой: +```bash +npm i +``` + +## 2. Автогенерация сервисов +Для корректной работы веб-приложения необходимо наличие сервисов работы с RestAPI. + +Для их автогенерации требуется уже запущенная серверная часть. + +Автогенерацию можно запустить с помощью уже прописанных в [package.json](package.json) скриптов, либо вручную. + +Если сервер запущен на текущей машине достаточно написать: +```bash +npm run update_openapi +``` + +Для получения сервисов с основного сервера: +```bash +npm run update_openapi_server +``` + +или же ручной вариант: +```bash +npx openapi -i http://{IP_ADDRESS}:{PORT}/swagger/v1/swagger.json -o src/services/api +``` + +где ***IP_ADDRESS*** и ***PORT*** это соответственно IP-адрес и порт сервера. + +На данный момент имеются следующие IP-адреса: + +| IP-адрес | Описание | +|:-|:-| +| 127.0.0.1:5000 | Локальный адрес вашей машины (привязан к `update_openapi`) | +| 192.168.1.70:5000 | Локальный адрес development-сервера (привязан к `update_openapi_server`) | +| 46.146.209.148:89 | Внешний адрес development-сервера | +| 46.146.209.148 | Внешний адрес production-сервера | + +## 3. Компиляция production-версии приложения +После выполнения вышеописанных пунктов приложение готово к компиляции. + +Для компиляции досточно выполнить команду: +```bash +npm run build +``` + +После завершения этой команды скомпилированное приложение будет находиться в появившейся директории [build/](build/). + +## 4. Запуск development-версии приложения +В [package.json](package.json) необходимо проверить и при необходимости изменить значение в поле ***proxy*** (пара адрес-порт сервера с RestAPI) на актуальное. + +После чего выполнить запуск командой: +```bash +npm start +``` diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 3d2733d..0000000 --- a/TODO.md +++ /dev/null @@ -1 +0,0 @@ -env params prod/dev \ No newline at end of file diff --git a/concept/ImagesSrc/logo_32_Asb.png b/concept/ImagesSrc/logo_32_Asb.png old mode 100644 new mode 100755 diff --git a/concept/ImagesSrc/logo_32_naftagaz.png b/concept/ImagesSrc/logo_32_naftagaz.png old mode 100644 new mode 100755 diff --git a/concept/ImagesSrc/logo_Asb.svg b/concept/ImagesSrc/logo_Asb.svg old mode 100644 new mode 100755 diff --git a/concept/SludgeDiagram.jsx b/concept/SludgeDiagram.jsx old mode 100644 new mode 100755 diff --git a/concept/Smbo/EquipmentDetails.jsx b/concept/Smbo/EquipmentDetails.jsx old mode 100644 new mode 100755 index 5178236..24b18a7 --- a/concept/Smbo/EquipmentDetails.jsx +++ b/concept/Smbo/EquipmentDetails.jsx @@ -1,8 +1,10 @@ import {Row, Col} from 'antd' -import Documents from '../Documents/DocumentsTemplate' -import '../../styles/equipment_details.css' -export default function EquipmentDetails({id, equipmentTimers, equipmentSensors}) { +import Documents from '../Documents/DocumentsTemplate' + +import '@styles/equipment_details.css' + +export default function EquipmentDetails({ id, equipmentTimers, equipmentSensors }) { let stateOfEquipmentDetails = equipmentTimers.map(timer => { return(

{timer.label}: {timer.value} {timer.unit}

diff --git a/concept/Smbo/SmboPlate.jsx b/concept/Smbo/SmboPlate.jsx old mode 100644 new mode 100755 diff --git a/concept/Smbo/images/RigPlan2.png b/concept/Smbo/images/RigPlan2.png old mode 100644 new mode 100755 diff --git a/concept/Smbo/images/TopDrive_Dummy.png b/concept/Smbo/images/TopDrive_Dummy.png old mode 100644 new mode 100755 diff --git a/concept/Smbo/index.jsx b/concept/Smbo/index.jsx old mode 100644 new mode 100755 diff --git a/concept/TelemetryAnalysis.jsx b/concept/TelemetryAnalysis.jsx old mode 100644 new mode 100755 diff --git a/concept/WellStat.jsx b/concept/WellStat.jsx old mode 100644 new mode 100755 diff --git a/concept/WellTelemetryAnalysis.jsx b/concept/WellTelemetryAnalysis.jsx deleted file mode 100644 index e0505b9..0000000 --- a/concept/WellTelemetryAnalysis.jsx +++ /dev/null @@ -1,163 +0,0 @@ -import { Table, Select, DatePicker } from "antd"; -import { TelemetryAnalyticsService } from "../src/services/api"; -import { useState, useEffect } from "react"; -import { useParams } from "react-router-dom"; -import notify from "../src/components/notify"; -import LoaderPortal from "../src/components/LoaderPortal"; -import moment from "moment"; -import "../styles/message.css"; - -const { Option } = Select; -const pageSize = 26; -const { RangePicker } = DatePicker; - -const columns = [ - { - title: "Название операции", - key: "name", - dataIndex: "name", - }, - { - title: "Дата начала операции", - key: "beginDate", - dataIndex: "beginDate", - render: (item) => moment.utc(item).local().format("DD MMM YYYY, HH:mm:ss"), - }, - { - title: "Дата окончания операции", - key: "endDate", - dataIndex: "endDate", - render: (item) => moment.utc(item).local().format("DD MMM YYYY, HH:mm:ss"), - }, - { - title: "Глубина скважины в начале операции", - key: "beginWellDepth", - dataIndex: "startWellDepth", - }, - { - title: "Глубина скважины в конце операции", - key: "endWellDepth", - dataIndex: "endWellDepth", - }, -]; - -const filterOptions = [ - { label: "Невозможно определить операцию", value: 1 }, - { label: "Роторное бурение", value: 2 }, - { label: "Слайдирование", value: 3 }, - { label: "Подъем с проработкой", value: 4 }, - { label: "Спуск с проработкой", value: 5 }, - { label: "Подъем с промывкой", value: 6 }, - { label: "Спуск с промывкой", value: 7 }, - { label: "Спуск в скважину", value: 8 }, - { label: "Спуск с вращением", value: 9 }, - { label: "Подъем из скважины", value: 10 }, - { label: "Подъем с вращением", value: 11 }, - { label: "Промывка в покое", value: 12 }, - { label: "Промывка с вращением", value: 13 }, - { label: "Удержание в клиньях", value: 14 }, - { label: "Неподвижное состояние", value: 15 }, - { label: "Вращение без циркуляции", value: 16 }, - { label: "На поверхности", value: 17 }, -]; - -export default function WellTelemetryAnalysis() { - let { id } = useParams(); - - const [page, setPage] = useState(1); - const [range, setRange] = useState([]); - const [categories, setCategories] = useState([]); - const [pagination, setPagination] = useState(null); - const [operations, setOperations] = useState([]); - - const [loader, setLoader] = useState(false); - - const children = filterOptions.map((line) => ( - - )); - - const onChangeRange = (range) => { - setRange(range); - }; - - useEffect(() => { - const GetOperations = async () => { - setLoader(true); - try { - let begin = null; - let end = null; - if (range?.length > 1) { - begin = range[0].toISOString(); - end = range[1].toISOString(); - } - - await TelemetryAnalyticsService.getOperationsByWell( - `${id}`, - (page - 1) * pageSize, - pageSize, - categories, - begin, - end - ).then((paginatedOperations) => { - setOperations( - paginatedOperations?.items.map((o) => { - return { - key: o.id, - begin: o.date, - ...o, - }; - }) - ); - - setPagination({ - total: paginatedOperations?.count, - current: Math.floor(paginatedOperations?.skip / pageSize), - }); - }); - } catch (ex) { - notify(`Не удалось загрузить операции по скважине "${id}"`, "error"); - console.log(ex); - } - setLoader(false); - }; - GetOperations(); - }, [id, categories, range, page]); - - return ( - <> -
-

Фильтр операций

- - -
- - setPage(page), - }} - rowKey={(record) => record.id} - /> - - - ); -} diff --git a/concept/readme.md b/concept/readme.md old mode 100644 new mode 100755 diff --git a/craco.config.js b/craco.config.js old mode 100644 new mode 100755 diff --git a/doc/MSE_and_torqueStab_info.txt b/doc/MSE_and_torqueStab_info.txt deleted file mode 100644 index 7950584..0000000 --- a/doc/MSE_and_torqueStab_info.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Вопрос Олегу: Какой бит и в каком регистре (или значение регистра) контроллера спинмастера сигнализирует что система спинмастер активана/работает? -Ответ: Такого бита нет, но можно понять если etap %MW1600: INT; не равен 6 и не равен 0 тогда система в работе - -# Вопрос Олегу: Какой бит и в каком регистре (или значение регистра) контроллера спинмастера сигнализирует что система стабилизации крутящего момента активна/работает? -Ответ: Такого бита по сути тоже нет но можно понять что -когда stik_sleep %MX2802.01: BOOL; =true -и -etap %MW1600: INT; =7 -тогда торк мастер работает \ No newline at end of file diff --git a/package-lock.json b/package-lock.json old mode 100644 new mode 100755 index c0e2227..5851375 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,18 @@ "version": "0.1.0", "dependencies": { "@craco/craco": "^6.1.2", - "@microsoft/signalr": "^5.0.5", + "@microsoft/signalr": "^6.0.4", "@testing-library/jest-dom": "^5.11.10", "@testing-library/react": "^11.2.6", "@testing-library/user-event": "^12.8.3", + "@types/react-dom": "^18.0.3", "antd": "^4.15.0", "chart.js": "^3.6.0", "chartjs-adapter-moment": "^1.0.0", "chartjs-plugin-datalabels": "^2.0.0-rc.1", "chartjs-plugin-zoom": "^1.1.1", "craco-less": "^1.17.1", + "d3": "^7.4.4", "moment": "^2.29.1", "pigeon-maps": "^0.19.7", "react": "^17.0.2", @@ -30,11 +32,12 @@ "web-vitals": "^1.1.1" }, "devDependencies": { + "@types/d3": "^7.1.0", "@types/react": "^17.0.3", "@types/react-router-dom": "^5.3.2", "craco-alias": "^3.0.1", "openapi-typescript": "^3.4.1", - "openapi-typescript-codegen": "^0.9.3" + "openapi-typescript-codegen": "^0.21.0" } }, "node_modules/@ampproject/remapping": { @@ -2631,15 +2634,35 @@ "dev": true }, "node_modules/@microsoft/signalr": { - "version": "5.0.14", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-5.0.14.tgz", - "integrity": "sha512-TdATUaBcJu0UB4BmhHzJ/JeUMocKNg/P2/NlFvY6re8DNoINCsVjYDqWfW3mvXz16uFlIH1p8hdJlzt8caVdVA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.4.tgz", + "integrity": "sha512-YeWRh4LxfYnq4I5CKw17/HOq8rY+ouTv6Bq+s55122StE3pK29j8j2OpP+1PA3D1ksHPfy7dFIgC33yr/E+01A==", "dependencies": { "abort-controller": "^3.0.0", "eventsource": "^1.0.7", - "fetch-cookie": "^0.7.3", - "node-fetch": "^2.6.0", - "ws": "^6.0.0" + "fetch-cookie": "^0.11.0", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + } + }, + "node_modules/@microsoft/signalr/node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@nodelib/fs.scandir": { @@ -3186,6 +3209,259 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/d3": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.1.0.tgz", + "integrity": "sha512-gYWvgeGjEl+zmF8c+U1RNIKqe7sfQwIXeLXO5Os72TjDjCEtgpvGBvZ8dXlAuSS1m6B90Y1Uo6Bm36OGR/OtCA==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.2.tgz", + "integrity": "sha512-5mjGjz6XOXKOCdTajXTZ/pMsg236RdiwKPrRPWAEf/2S/+PzwY+LLYShUpeysWaMvsdS7LArh6GdUefoxpchsQ==", + "dev": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", + "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", + "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==", + "dev": true + }, + "node_modules/@types/d3-color": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.0.2.tgz", + "integrity": "sha512-WVx6zBiz4sWlboCy7TCgjeyHpNjMsoF36yaagny1uXfbadc9f+5BeBf7U+lRmQqY3EHbGQpP8UdW8AC+cywSwQ==", + "dev": true + }, + "node_modules/@types/d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.0.tgz", + "integrity": "sha512-iGm7ZaGLq11RK3e69VeMM6Oqj2SjKUB9Qhcyd1zIcqn2uE8w9GFB445yCY46NOQO3ByaNyktX1DK+Etz7ZaX+w==", + "dev": true + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==", + "dev": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", + "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", + "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==", + "dev": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", + "dev": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", + "dev": true, + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", + "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==", + "dev": true + }, + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "dev": true + }, + "node_modules/@types/d3-geo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", + "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.0.2.tgz", + "integrity": "sha512-+krnrWOZ+aQB6v+E+jEkmkAx9HvsNAD+1LCD0vlBY3t+HwjKnsBFbpVLx6WWzDzCIuiTWdAxXMEnGnVXpB09qQ==", + "dev": true + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "dev": true, + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", + "dev": true + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", + "dev": true + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", + "dev": true + }, + "node_modules/@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", + "dev": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "dev": true, + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", + "dev": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.2.tgz", + "integrity": "sha512-d29EDd0iUBrRoKhPndhDY6U/PYxOWqgIZwKTooy2UkBfU7TNZNpRho0yLWPxlatQrFWk2mnTu71IZQ4+LRgKlQ==", + "dev": true + }, + "node_modules/@types/d3-shape": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.0.2.tgz", + "integrity": "sha512-5+ButCmIfNX8id5seZ7jKj3igdcxx+S9IDBiT35fQGTLZUfkFgTv+oBH34xgeoWDKpWcMITSzBILWQtBoN5Piw==", + "dev": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "dev": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", + "dev": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", + "dev": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-Sv4qEI9uq3bnZwlOANvYK853zvpdKEm1yz9rcc8ZTsxvRklcs9Fx4YFuGA3gXoQN/c/1T6QkVNjhaRO/cWj94g==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", + "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", + "dev": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/eslint": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", @@ -3200,6 +3476,12 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" }, + "node_modules/@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", + "dev": true + }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -3302,8 +3584,7 @@ "node_modules/@types/prop-types": { "version": "15.7.4", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", - "dev": true + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "node_modules/@types/q": { "version": "1.5.5", @@ -3314,13 +3595,20 @@ "version": "17.0.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.3.tgz", + "integrity": "sha512-1RRW9kst+67gveJRYPxGmVy8eVJ05O43hg77G2j5m76/RFJtMbcfAs2viQ2UNsvvDg8F7OfQZx8qQcl6ymygaQ==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-router": { "version": "5.1.18", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", @@ -3353,8 +3641,7 @@ "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "node_modules/@types/source-list-map": { "version": "0.1.2", @@ -5739,7 +6026,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, "engines": { "node": ">= 10" } @@ -6588,8 +6874,7 @@ "node_modules/csstype": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==", - "dev": true + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" }, "node_modules/cyclist": { "version": "1.0.1", @@ -6605,6 +6890,387 @@ "type": "^1.0.1" } }, + "node_modules/d3": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.4.4.tgz", + "integrity": "sha512-97FE+MYdAlV3R9P74+R3Uar7wUKkIFu89UWMjEaDhiJ9VxKvqaMxauImy8PC2DdBkdM2BxJOIoLxPrcZUyrKoQ==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "3", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.1.6.tgz", + "integrity": "sha512-DCbBBNuKOeiR9h04ySRBMW52TFVc91O9wJziuyXw6Ztmy8D3oZbmCkOO3UHKC7ceNJsN2Mavo9+vwV8EAEUXzA==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-0Oc4D0KyhwhM7ZL0RMnfGycLN7hxHB8CMmwZ3+H26PWAG0ozNuYG5hXSDNgmP1SgJkQMrlG6cP20HoaSbvcJTQ==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/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==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", + "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -6962,6 +7628,14 @@ "rimraf": "bin.js" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -7471,11 +8145,6 @@ "next-tick": "~1.0.0" } }, - "node_modules/es6-denodeify": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz", - "integrity": "sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8=" - }, "node_modules/es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", @@ -8867,12 +9536,14 @@ } }, "node_modules/fetch-cookie": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.7.3.tgz", - "integrity": "sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", "dependencies": { - "es6-denodeify": "^0.1.1", - "tough-cookie": "^2.3.3" + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/figgy-pudding": { @@ -10477,6 +11148,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -12116,19 +12795,6 @@ "node": ">=0.4.0" } }, - "node_modules/jsdom/node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/jsdom/node_modules/tr46": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", @@ -12140,14 +12806,6 @@ "node": ">=8" } }, - "node_modules/jsdom/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/jsdom/node_modules/whatwg-url": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", @@ -13634,18 +14292,15 @@ } }, "node_modules/openapi-typescript-codegen": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.9.3.tgz", - "integrity": "sha512-/ZQL1wpWqwruVGxI5EDsKS7C+AMjLEEwnH73keEM6Gy91pcUGDbBbX2e5APf0hDSQs9TX+hQnHdGu7ZUu6HIcQ==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.21.0.tgz", + "integrity": "sha512-wohx5b03jNfPVKocNoyzu7zVscPoRjyq/G/P5Bdtsjeze2BkXiLxd8uwkVCESQx6Sid4xihohKUgDy4MO09nsg==", "dev": true, "dependencies": { - "camelcase": "^6.2.0", - "commander": "^7.0.0", - "handlebars": "^4.7.6", - "js-yaml": "^4.0.0", - "json-schema-ref-parser": "^9.0.7", - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "camelcase": "^6.3.0", + "commander": "^9.0.0", + "handlebars": "^4.7.7", + "json-schema-ref-parser": "^9.0.9" }, "bin": { "openapi": "bin/index.js" @@ -13663,6 +14318,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-typescript-codegen/node_modules/commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/openapi-typescript/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -17509,6 +18173,11 @@ "inherits": "^2.0.1" } }, + "node_modules/robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, "node_modules/rollup": { "version": "1.32.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", @@ -17641,6 +18310,11 @@ "aproba": "^1.1.1" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, "node_modules/rxjs": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", @@ -19799,15 +20473,24 @@ } }, "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" }, "engines": { - "node": ">=0.8" + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" } }, "node_modules/tr46": { @@ -24130,15 +24813,23 @@ "dev": true }, "@microsoft/signalr": { - "version": "5.0.14", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-5.0.14.tgz", - "integrity": "sha512-TdATUaBcJu0UB4BmhHzJ/JeUMocKNg/P2/NlFvY6re8DNoINCsVjYDqWfW3mvXz16uFlIH1p8hdJlzt8caVdVA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.4.tgz", + "integrity": "sha512-YeWRh4LxfYnq4I5CKw17/HOq8rY+ouTv6Bq+s55122StE3pK29j8j2OpP+1PA3D1ksHPfy7dFIgC33yr/E+01A==", "requires": { "abort-controller": "^3.0.0", "eventsource": "^1.0.7", - "fetch-cookie": "^0.7.3", - "node-fetch": "^2.6.0", - "ws": "^6.0.0" + "fetch-cookie": "^0.11.0", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + }, + "dependencies": { + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "requires": {} + } } }, "@nodelib/fs.scandir": { @@ -24525,6 +25216,259 @@ "@babel/types": "^7.3.0" } }, + "@types/d3": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.1.0.tgz", + "integrity": "sha512-gYWvgeGjEl+zmF8c+U1RNIKqe7sfQwIXeLXO5Os72TjDjCEtgpvGBvZ8dXlAuSS1m6B90Y1Uo6Bm36OGR/OtCA==", + "dev": true, + "requires": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "@types/d3-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.2.tgz", + "integrity": "sha512-5mjGjz6XOXKOCdTajXTZ/pMsg236RdiwKPrRPWAEf/2S/+PzwY+LLYShUpeysWaMvsdS7LArh6GdUefoxpchsQ==", + "dev": true + }, + "@types/d3-axis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", + "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-brush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", + "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==", + "dev": true + }, + "@types/d3-color": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.0.2.tgz", + "integrity": "sha512-WVx6zBiz4sWlboCy7TCgjeyHpNjMsoF36yaagny1uXfbadc9f+5BeBf7U+lRmQqY3EHbGQpP8UdW8AC+cywSwQ==", + "dev": true + }, + "@types/d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", + "dev": true, + "requires": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "@types/d3-delaunay": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.0.tgz", + "integrity": "sha512-iGm7ZaGLq11RK3e69VeMM6Oqj2SjKUB9Qhcyd1zIcqn2uE8w9GFB445yCY46NOQO3ByaNyktX1DK+Etz7ZaX+w==", + "dev": true + }, + "@types/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==", + "dev": true + }, + "@types/d3-drag": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", + "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-dsv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", + "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==", + "dev": true + }, + "@types/d3-ease": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==", + "dev": true + }, + "@types/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", + "dev": true, + "requires": { + "@types/d3-dsv": "*" + } + }, + "@types/d3-force": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", + "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==", + "dev": true + }, + "@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "dev": true + }, + "@types/d3-geo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", + "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", + "dev": true, + "requires": { + "@types/geojson": "*" + } + }, + "@types/d3-hierarchy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.0.2.tgz", + "integrity": "sha512-+krnrWOZ+aQB6v+E+jEkmkAx9HvsNAD+1LCD0vlBY3t+HwjKnsBFbpVLx6WWzDzCIuiTWdAxXMEnGnVXpB09qQ==", + "dev": true + }, + "@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "dev": true, + "requires": { + "@types/d3-color": "*" + } + }, + "@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==", + "dev": true + }, + "@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==", + "dev": true + }, + "@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==", + "dev": true + }, + "@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==", + "dev": true + }, + "@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "dev": true, + "requires": { + "@types/d3-time": "*" + } + }, + "@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==", + "dev": true + }, + "@types/d3-selection": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.2.tgz", + "integrity": "sha512-d29EDd0iUBrRoKhPndhDY6U/PYxOWqgIZwKTooy2UkBfU7TNZNpRho0yLWPxlatQrFWk2mnTu71IZQ4+LRgKlQ==", + "dev": true + }, + "@types/d3-shape": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.0.2.tgz", + "integrity": "sha512-5+ButCmIfNX8id5seZ7jKj3igdcxx+S9IDBiT35fQGTLZUfkFgTv+oBH34xgeoWDKpWcMITSzBILWQtBoN5Piw==", + "dev": true, + "requires": { + "@types/d3-path": "*" + } + }, + "@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "dev": true + }, + "@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==", + "dev": true + }, + "@types/d3-timer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==", + "dev": true + }, + "@types/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-Sv4qEI9uq3bnZwlOANvYK853zvpdKEm1yz9rcc8ZTsxvRklcs9Fx4YFuGA3gXoQN/c/1T6QkVNjhaRO/cWj94g==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-zoom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", + "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", + "dev": true, + "requires": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "@types/eslint": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", @@ -24539,6 +25483,12 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" }, + "@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", + "dev": true + }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -24641,8 +25591,7 @@ "@types/prop-types": { "version": "15.7.4", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", - "dev": true + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "@types/q": { "version": "1.5.5", @@ -24653,13 +25602,20 @@ "version": "17.0.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", - "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.3.tgz", + "integrity": "sha512-1RRW9kst+67gveJRYPxGmVy8eVJ05O43hg77G2j5m76/RFJtMbcfAs2viQ2UNsvvDg8F7OfQZx8qQcl6ymygaQ==", + "requires": { + "@types/react": "*" + } + }, "@types/react-router": { "version": "5.1.18", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", @@ -24692,8 +25648,7 @@ "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "@types/source-list-map": { "version": "0.1.2", @@ -26573,8 +27528,7 @@ "commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" }, "common-tags": { "version": "1.8.2", @@ -27232,8 +28186,7 @@ "csstype": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==", - "dev": true + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" }, "cyclist": { "version": "1.0.1", @@ -27249,6 +28202,279 @@ "type": "^1.0.1" } }, + "d3": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.4.4.tgz", + "integrity": "sha512-97FE+MYdAlV3R9P74+R3Uar7wUKkIFu89UWMjEaDhiJ9VxKvqaMxauImy8PC2DdBkdM2BxJOIoLxPrcZUyrKoQ==", + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "3", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + } + }, + "d3-array": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.1.6.tgz", + "integrity": "sha512-DCbBBNuKOeiR9h04ySRBMW52TFVc91O9wJziuyXw6Ztmy8D3oZbmCkOO3UHKC7ceNJsN2Mavo9+vwV8EAEUXzA==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + } + }, + "d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-0Oc4D0KyhwhM7ZL0RMnfGycLN7hxHB8CMmwZ3+H26PWAG0ozNuYG5hXSDNgmP1SgJkQMrlG6cP20HoaSbvcJTQ==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "requires": { + "delaunator": "5" + } + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "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==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "requires": { + "d3-dsv": "1 - 3" + } + }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-geo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", + "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", + "requires": { + "d3-array": "2.5.0 - 3" + } + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" + }, + "d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" + }, + "d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, + "d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -27525,6 +28751,14 @@ } } }, + "delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "requires": { + "robust-predicates": "^3.0.0" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -27938,11 +29172,6 @@ "next-tick": "~1.0.0" } }, - "es6-denodeify": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz", - "integrity": "sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8=" - }, "es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", @@ -28961,12 +30190,11 @@ } }, "fetch-cookie": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.7.3.tgz", - "integrity": "sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", "requires": { - "es6-denodeify": "^0.1.1", - "tough-cookie": "^2.3.3" + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" } }, "figgy-pudding": { @@ -30185,6 +31413,11 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -31419,16 +32652,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, "tr46": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", @@ -31437,11 +32660,6 @@ "punycode": "^2.1.1" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, "whatwg-url": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", @@ -32584,18 +33802,15 @@ } }, "openapi-typescript-codegen": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.9.3.tgz", - "integrity": "sha512-/ZQL1wpWqwruVGxI5EDsKS7C+AMjLEEwnH73keEM6Gy91pcUGDbBbX2e5APf0hDSQs9TX+hQnHdGu7ZUu6HIcQ==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.21.0.tgz", + "integrity": "sha512-wohx5b03jNfPVKocNoyzu7zVscPoRjyq/G/P5Bdtsjeze2BkXiLxd8uwkVCESQx6Sid4xihohKUgDy4MO09nsg==", "dev": true, "requires": { - "camelcase": "^6.2.0", - "commander": "^7.0.0", - "handlebars": "^4.7.6", - "js-yaml": "^4.0.0", - "json-schema-ref-parser": "^9.0.7", - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "camelcase": "^6.3.0", + "commander": "^9.0.0", + "handlebars": "^4.7.7", + "json-schema-ref-parser": "^9.0.9" }, "dependencies": { "camelcase": { @@ -32603,6 +33818,12 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true + }, + "commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "dev": true } } }, @@ -35579,6 +36800,11 @@ "inherits": "^2.0.1" } }, + "robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, "rollup": { "version": "1.32.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", @@ -35678,6 +36904,11 @@ "aproba": "^1.1.1" } }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, "rxjs": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", @@ -37395,12 +38626,20 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "dependencies": { + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } } }, "tr46": { diff --git a/package.json b/package.json old mode 100644 new mode 100755 index c785414..0787000 --- a/package.json +++ b/package.json @@ -4,16 +4,18 @@ "private": true, "dependencies": { "@craco/craco": "^6.1.2", - "@microsoft/signalr": "^5.0.5", + "@microsoft/signalr": "^6.0.4", "@testing-library/jest-dom": "^5.11.10", "@testing-library/react": "^11.2.6", "@testing-library/user-event": "^12.8.3", + "@types/react-dom": "^18.0.3", "antd": "^4.15.0", "chart.js": "^3.6.0", "chartjs-adapter-moment": "^1.0.0", "chartjs-plugin-datalabels": "^2.0.0-rc.1", "chartjs-plugin-zoom": "^1.1.1", "craco-less": "^1.17.1", + "d3": "^7.4.4", "moment": "^2.29.1", "pigeon-maps": "^0.19.7", "react": "^17.0.2", @@ -28,8 +30,10 @@ "start": "craco start", "build": "craco build", "test": "craco test", - "update_openapi": "npx openapi -i http://127.0.0.1:5000/swagger/v1/swagger.json -o src/services/api", - "update_openapi_server": "npx openapi -i http://192.168.1.70:5000/swagger/v1/swagger.json -o src/services/api", + "oul": "npx openapi -i http://127.0.0.1:5000/swagger/v1/swagger.json -o src/services/api", + "oud": "npx openapi -i http://192.168.1.70:5000/swagger/v1/swagger.json -o src/services/api", + "oug": "npx openapi -i http://46.146.209.148/swagger/v1/swagger.json -o src/services/api", + "oug_dev": "npx openapi -i http://46.146.209.148:89/swagger/v1/swagger.json -o src/services/api", "react_start": "react-scripts start", "react_build": "react-scripts build", "react_test": "react-scripts test", @@ -55,10 +59,11 @@ ] }, "devDependencies": { + "@types/d3": "^7.1.0", "@types/react": "^17.0.3", "@types/react-router-dom": "^5.3.2", "craco-alias": "^3.0.1", "openapi-typescript": "^3.4.1", - "openapi-typescript-codegen": "^0.9.3" + "openapi-typescript-codegen": "^0.21.0" } } diff --git a/public/favicon.ico b/public/favicon.ico old mode 100644 new mode 100755 diff --git a/public/images/logo_32.png b/public/images/logo_32.png old mode 100644 new mode 100755 diff --git a/public/index.html b/public/index.html old mode 100644 new mode 100755 index aeeddf7..affdf4a --- a/public/index.html +++ b/public/index.html @@ -1,13 +1,15 @@ - + - + + + АСБ Vision diff --git a/public/manifest.json b/public/manifest.json old mode 100644 new mode 100755 diff --git a/public/robots.txt b/public/robots.txt old mode 100644 new mode 100755 diff --git a/src/App.js b/src/App.tsx similarity index 95% rename from src/App.js rename to src/App.tsx index 18b2b83..5349dab 100644 --- a/src/App.js +++ b/src/App.tsx @@ -3,22 +3,22 @@ import { Switch, Route } from 'react-router-dom' +import { memo } from 'react' import { ConfigProvider } from 'antd' import locale from 'antd/lib/locale/ru_RU' -import { OpenAPI } from '@api' -import { getUserToken } from '@utils/storage' import { PrivateRoute } from '@components/Private' +import { getUserToken } from '@utils/storage' +import { OpenAPI } from '@api' import Main from '@pages/Main' import Login from '@pages/Login' import Register from '@pages/Register' import '@styles/App.less' -import { memo } from 'react' //OpenAPI.BASE = 'http://localhost:3000' -OpenAPI.TOKEN = async () => getUserToken() +OpenAPI.TOKEN = async () => getUserToken() ?? '' OpenAPI.HEADERS = {'Content-Type': 'application/json'} export const App = memo(() => ( diff --git a/src/components/AnalysisOperationTime.jsx b/src/components/AnalysisOperationTime.jsx deleted file mode 100644 index 89a9209..0000000 --- a/src/components/AnalysisOperationTime.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import moment from 'moment' -import { DatePicker } from 'antd' -import { useState, useEffect } from 'react' -import { useParams } from 'react-router-dom' - -import LoaderPortal from '@components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '@components/factory' -import { TelemetryAnalyticsService } from '@api' -import { ChartOperationTime } from './charts/ChartOperationTime' - -const { RangePicker } = DatePicker - -const lines = [{ labelAccessorName: 'processName', pieceAccessorName: 'duration' }] - -export const AnalysisOperationTime = () => { - const { id } = useParams() - const [operationTimeData, setOperationTimeData] = useState([]) - const [loader, setLoader] = useState(false) - const [range, setRange] = useState([moment().subtract(1,'days'), moment()]) - - useEffect(() => invokeWebApiWrapperAsync( - async () => { - const begin = range?.length > 1 ? range[0].toISOString() : null - const end = range?.length > 1 ? range[1].toISOString() : null - const summary = await TelemetryAnalyticsService.getOperationsSummary(id, begin, end) - setOperationTimeData(summary) - }, - setLoader, - `Не удалось получить данные для анализа Операция-Время по скважине '${id}' за период с ${begin} по ${end}`, - 'Получение данных для анализа Операция-Время по скважине' - ), [id, range]) - - return ( - - setRange(range)} /> - - - ) -} - -export default AnalysisOperationTime diff --git a/src/components/ChangePassword.tsx b/src/components/ChangePassword.tsx old mode 100644 new mode 100755 index fb2ef0e..92725ab --- a/src/components/ChangePassword.tsx +++ b/src/components/ChangePassword.tsx @@ -1,5 +1,5 @@ -import { memo, useState } from 'react' -import { useForm } from 'antd/lib/form/Form' +import { memo, useCallback, useMemo, useState } from 'react' +import { Rule } from 'antd/lib/form' import { Form, Input, Modal, FormProps } from 'antd' import { AuthService, UserDto } from '@api' @@ -21,12 +21,19 @@ export type ChangePasswordProps = { const fieldRules = [...passwordRules, ...createPasswordRules] +const confirmPasswordRules: Rule[] = [({ getFieldValue }) => ({ validator(_, value: string) { + if (value !== getFieldValue('new-password')) + return Promise.reject('Пароли не совпадают!') + return Promise.resolve() +}})] + export const ChangePassword = memo(({ user, visible, onCancel, onOk }) => { const [showLoader, setShowLoader] = useState(false) - const [password, setPassword] = useState('') const [isDisabled, setIsDisabled] = useState(true) - const [form] = useForm() + const userData = useMemo(() => user ?? { id: getUserId(), login: getUserLogin() } as UserDto, [user]) + + const [form] = Form.useForm() const onFormChange = async () => await form.validateFields() .then(() => setIsDisabled(false)) @@ -37,15 +44,15 @@ export const ChangePassword = memo(({ user, visible, onCanc onCancel?.() } - const onFormFinish = () => invokeWebApiWrapperAsync( + const onFormFinish = useCallback((values: any) => invokeWebApiWrapperAsync( async() => { - await AuthService.changePassword(user?.id ?? getUserId() ?? -1, `"${password}"`) + await AuthService.changePassword(userData.id ?? -1, `${values['new-password']}`) onOk?.() }, setShowLoader, - `Не удалось сменить пароль пользователя ${getUserLogin()}`, + `Не удалось сменить пароль пользователя ${userData.login}`, 'Смена пароля пользователя' - ) + ), [userData, onOk]) return ( (({ user, visible, onCanc okButtonProps={{ disabled: isDisabled }} + // getContainer={false} // Исправляет ошибку с формой, но портит вид модалки при вызове из user menu + // TODO: разобраться >
(({ user, visible, onCanc onFinish={onFormFinish} onChange={onFormChange} > - - setPassword(e.target.value)} value={password} /> + + - ({ validator(_, value: string) { - if (value !== password) - return Promise.reject('Пароли не совпадают!') - return Promise.resolve() - }})]} - > + diff --git a/src/components/Display.jsx b/src/components/Display.tsx similarity index 65% rename from src/components/Display.jsx rename to src/components/Display.tsx index 77d1a1b..1ae6709 100644 --- a/src/components/Display.jsx +++ b/src/components/Display.tsx @@ -1,19 +1,33 @@ import moment from 'moment' -import { useState, useEffect, memo } from 'react' +import { useState, useEffect, memo, ReactNode } from 'react' import {CaretUpOutlined, CaretDownOutlined, CaretRightOutlined} from '@ant-design/icons' import '@styles/display.css' -export const formatNumber = (value, format) => +export const formatNumber = (value?: unknown, format?: number) => Number.isInteger(format) && Number.isFinite(value) - ? (+value).toFixed(format) - : (+value).toPrecision(4) + ? Number(value).toFixed(format) + : Number(value).toPrecision(4) const iconStyle = { color:'#0008' } const displayValueStyle = { display: 'flex', flexGrow: 1 } -export const ValueDisplay = ({ prefix, value, suffix, isArrowVisible, format, enumeration }) => { - const [val, setVal] = useState('---') +export type ValueDisplayProps = { + prefix?: ReactNode + suffix?: ReactNode + format?: number | string + isArrowVisible?: boolean + enumeration?: Record + value: string +} + +export type DisplayProps = ValueDisplayProps & { + className?: string + label?: ReactNode +} + +export const ValueDisplay = memo(({ prefix, value, suffix, isArrowVisible, format, enumeration }) => { + const [val, setVal] = useState('---') const [arrowState, setArrowState] = useState({ preVal: NaN, preTimestamp: Date.now(), @@ -28,25 +42,25 @@ export const ValueDisplay = ({ prefix, value, suffix, isArrowVisible, format, en if (Number.isFinite(+value)) { if (isArrowVisible && (arrowState.preTimestamp + 1000 < Date.now())) { let direction = 0 - if (value > arrowState.preVal) + if (+value > arrowState.preVal) direction = 1 - if (value < arrowState.preVal) + if (+value < arrowState.preVal) direction = -1 setArrowState({ - preVal: value, + preVal: +value, preTimestamp: Date.now(), direction: direction, }) } - return formatNumber(value, format) + return formatNumber(value, Number(format)) } if (value.length > 4) { const valueDate = moment(value) if (valueDate.isValid()) - return valueDate.format(format) + return valueDate.format(String(format)) } return value @@ -74,9 +88,9 @@ export const ValueDisplay = ({ prefix, value, suffix, isArrowVisible, format, en {prefix} {val} {suffix}{arrow} ) -} +}) -export const Display = memo(({ className, label, ...other })=> ( +export const Display = memo(({ className, label, ...other })=> (
{label}
diff --git a/src/components/DownloadLink.tsx b/src/components/DownloadLink.tsx old mode 100644 new mode 100755 diff --git a/src/components/ErrorFetch.js b/src/components/ErrorFetch.ts similarity index 66% rename from src/components/ErrorFetch.js rename to src/components/ErrorFetch.ts index b4f2bed..68993f1 100644 --- a/src/components/ErrorFetch.js +++ b/src/components/ErrorFetch.ts @@ -1,5 +1,7 @@ export class ErrorFetch extends Error { - constructor(status, message) { + public status: number + + constructor(status: number, message?: string) { super(message) this.name = 'ErrorFetch' this.status = status diff --git a/src/components/Grid.tsx b/src/components/Grid.tsx old mode 100644 new mode 100755 diff --git a/src/components/Layout/AdminLayoutPortal.tsx b/src/components/Layout/AdminLayoutPortal.tsx old mode 100644 new mode 100755 diff --git a/src/components/Layout/LayoutPortal.tsx b/src/components/Layout/LayoutPortal.tsx old mode 100644 new mode 100755 diff --git a/src/components/Layout/index.ts b/src/components/Layout/index.ts old mode 100644 new mode 100755 diff --git a/src/components/LoaderPortal.tsx b/src/components/LoaderPortal.tsx old mode 100644 new mode 100755 diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx old mode 100644 new mode 100755 diff --git a/src/components/Private/PrivateContent.tsx b/src/components/Private/PrivateContent.tsx old mode 100644 new mode 100755 diff --git a/src/components/Private/PrivateDefaultRoute.tsx b/src/components/Private/PrivateDefaultRoute.tsx old mode 100644 new mode 100755 diff --git a/src/components/Private/PrivateMenu.tsx b/src/components/Private/PrivateMenu.tsx new file mode 100644 index 0000000..8ecc6ab --- /dev/null +++ b/src/components/Private/PrivateMenu.tsx @@ -0,0 +1,49 @@ +import { join } from 'path' +import { Menu, MenuItemProps, MenuProps } from 'antd' +import { Children, cloneElement, memo, ReactElement, useContext, useMemo } from 'react' +import { Link, useLocation } from 'react-router-dom' + +import { RootPathContext } from '@asb/context' +import { isURLAvailable } from '@utils/permissions' + +export type PrivateMenuProps = MenuProps & { root?: string } + +export type PrivateMenuLinkProps = MenuItemProps & { + tabName?: string + path?: string + title: string + visible?: boolean +} + +export const PrivateMenuLink = memo(({ tabName = '', path = '', title, ...other }) => { + const location = useLocation() + return ( + + {title} + + ) +}) + +const PrivateMenuMain = memo(({ root, children, ...other }) => { + const rootContext = useContext(RootPathContext) + const rootPath = useMemo(() => root ?? rootContext ?? '', [root, rootContext]) + + const items = useMemo(() => Children.toArray(children).map((child) => { + const element = child as ReactElement + let key = element.key?.toString() + const visible: boolean | undefined = element.props.visible + if (key && visible !== false) { + key = key.slice(key.lastIndexOf('$') + 1) // Ключ автоматический преобразуется в "(.+)\$ключ" + const path = join(rootPath, key) + if (visible || isURLAvailable(path)) + return cloneElement(element, { key, path, tabName: key }) + } + return null + }), [children, rootPath]) + + return +}) + +export const PrivateMenu = Object.assign(PrivateMenuMain, { Link: PrivateMenuLink }) + +export default PrivateMenu diff --git a/src/components/Private/PrivateMenuItem.tsx b/src/components/Private/PrivateMenuItem.tsx old mode 100644 new mode 100755 index fd48ee9..1d0d101 --- a/src/components/Private/PrivateMenuItem.tsx +++ b/src/components/Private/PrivateMenuItem.tsx @@ -1,22 +1,22 @@ import { join } from 'path' import { Menu, MenuItemProps } from 'antd' import { memo, NamedExoticComponent } from 'react' +import { Link, useLocation } from 'react-router-dom' import { isURLAvailable } from '@utils/permissions' -import { Link, useLocation } from 'react-router-dom' export type PrivateMenuItemProps = MenuItemProps & { root: string path: string } -export type PrivateMenuLinkProps = MenuItemProps & { +export type PrivateMenuItemLinkProps = MenuItemProps & { root?: string path: string title: string } -export const PrivateMenuItemLink = memo(({ root = '', path, title, ...other }) => { +export const PrivateMenuItemLink = memo(({ root = '', path, title, ...other }) => { const location = useLocation() return ( @@ -26,9 +26,9 @@ export const PrivateMenuItemLink = memo(({ root = '', path }) export const PrivateMenuItem: NamedExoticComponent & { - Link: NamedExoticComponent + Link: NamedExoticComponent } = Object.assign(memo(({ root, path, ...other }) => - isURLAvailable(join(root, path)) ? : null +
+ + + + ) +}) + +export default NewParamsTable diff --git a/src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx b/src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx index 0c55a33..c44f472 100644 --- a/src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx +++ b/src/pages/Analytics/WellCompositeEditor/WellCompositeSections.jsx @@ -1,13 +1,14 @@ import { Link, useLocation } from 'react-router-dom' -import { useState, useEffect, memo, useCallback, useMemo } from 'react' +import { useState, useEffect, memo, useMemo } from 'react' import { LineChartOutlined, ProfileOutlined } from '@ant-design/icons' -import { Table, Tag, Button, Badge, Divider, Modal, Row, Col, Popconfirm } from 'antd' +import { Table, Tag, Button, Badge, Divider, Modal, Row, Col } from 'antd' +import { useIdWell } from '@asb/context' import { CompanyView } from '@components/views' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { makeTextColumn, makeNumericColumnPlanFact } from '@components/Table' -import { DrillParamsService, WellCompositeService } from '@api' +import { makeTextColumn, makeNumericColumnPlanFact, makeNumericColumn } from '@components/Table' +import { WellCompositeService } from '@api' import { hasPermission } from '@utils/permissions' import { calcAndUpdateStatsBySections, @@ -16,31 +17,29 @@ import { } from '@utils/functions' import { Tvd } from '@pages/WellOperations/Tvd' -import { getColumns } from '@pages/WellOperations/WellDrillParams' import WellOperationsTable from '@pages/Cluster/WellOperationsTable' - +import NewParamsTable from './NewParamsTable' const filtersMinMax = [ { text: 'min', value: 'min' }, { text: 'max', value: 'max' }, ] +const sortBySectionId = (a, b) => a?.sectionId - b?.sectionId + const filtersSectionsType = [] const DAY_IN_MS = 1000 * 60 * 60 * 24 -export const WellCompositeSections = memo(({ idWell, statsWells, selectedSections }) => { - const [params, setParams] = useState([]) +export const WellCompositeSections = memo(({ statsWells, selectedSections }) => { const [selectedWells, setSelectedWells] = useState([]) const [wellOperations, setWellOperations] = useState([]) const [selectedWellsKeys, setSelectedWellsKeys] = useState([]) const [selectedWellId, setSelectedWellId] = useState(0) const [showLoader, setShowLoader] = useState(false) - const [showParamsLoader, setShowParamsLoader] = useState(false) const [isTVDModalVisible, setIsTVDModalVisible] = useState(false) const [isOpsModalVisible, setIsOpsModalVisible] = useState(false) - const [isParamsModalVisible, setIsParamsModalVisible] = useState(false) - const [paramsColumns, setParamsColumns] = useState([]) + const idWell = useIdWell() const location = useLocation() const rows = useMemo(() => { @@ -70,8 +69,7 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection sectionBhaUpSpeedFact: section.fact?.bhaUpSpeed, sectionCasingDownSpeedPlan: section.plan?.casingDownSpeed, sectionCasingDownSpeedFact: section.fact?.casingDownSpeed, - nonProductiveTimePlan: section.plan?.nonProductiveHours, - nonProductiveTimeFact: section.fact?.nonProductiveHours, + nonProductiveHours: section.fact?.nonProductiveHours, companies: well.companies, } @@ -101,10 +99,6 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection return rows }, [statsWells]) - useEffect(() => invokeWebApiWrapperAsync( - async () => setParamsColumns(await getColumns(idWell)) - ), [idWell]) - useEffect(() => { if (isOpsModalVisible || selectedWellId <= 0) return invokeWebApiWrapperAsync( @@ -126,11 +120,27 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection setSelectedWellsKeys(selected.map((row) => row.key)) }, [rows, selectedSections]) + const rowSelection = useMemo(() => hasPermission('WellOperation.edit') && { + selectedRowKeys: selectedWellsKeys, + onChange: (keys, items) => invokeWebApiWrapperAsync( + async () => { + const selectedSections = items.map((row) => ({idWell, idWellSrc: row.id, idWellSectionType: row.sectionId})) + await WellCompositeService.save(idWell, selectedSections) + + setSelectedWells(items) + setSelectedWellsKeys(keys) + }, + setShowLoader, + `Не удалось сохранить изменения выбранных секций для композитной скважины "${idWell}"`, + 'Изменение выбранных секций скважины' + ) + }, [idWell, selectedWellsKeys]) + const columns = useMemo(() => [ makeTextColumn('скв №', 'caption', null, null, (text, item) => {text ?? '-'} ), - makeTextColumn('Секция', 'sectionType', filtersSectionsType, null, (text) => text ?? '-'), + makeTextColumn('Секция', 'sectionType', filtersSectionsType, sortBySectionId, (text) => text ?? '-'), makeNumericColumnPlanFact('Глубина, м', 'sectionWellDepth', filtersMinMax, makeFilterMinMaxFunction), makeNumericColumnPlanFact('Продолжительность, ч', 'sectionBuildDays', filtersMinMax, makeFilterMinMaxFunction), makeNumericColumnPlanFact('МСП, м/ч', 'sectionRateOfPenetration', filtersMinMax, makeFilterMinMaxFunction), @@ -138,7 +148,7 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection makeNumericColumnPlanFact('Спуск КНБК, м/ч', 'sectionBhaDownSpeed', filtersMinMax, makeFilterMinMaxFunction), makeNumericColumnPlanFact('Подъем КНБК, м/ч', 'sectionBhaUpSpeed', filtersMinMax, makeFilterMinMaxFunction), makeNumericColumnPlanFact('Скорость спуска ОК, м/ч', 'sectionCasingDownSpeed', filtersMinMax, makeFilterMinMaxFunction), - makeNumericColumnPlanFact('НПВ, сут', 'nonProductiveTime', filtersMinMax, makeFilterMinMaxFunction, null, '70px'), + makeNumericColumn('НПВ, ч', 'nonProductiveHours', filtersMinMax, makeFilterMinMaxFunction, null, '80px'), { title: 'TVD', render: (value) => ( @@ -174,43 +184,6 @@ export const WellCompositeSections = memo(({ idWell, statsWells, selectedSection }, ], [location.pathname]) - const rowSelection = useMemo(() => hasPermission('WellOperation.edit') && { - selectedRowKeys: selectedWellsKeys, - onChange: (keys, items) => invokeWebApiWrapperAsync( - async () => { - const selectedSections = items.map((row) => ({idWell, idWellSrc: row.id, idWellSectionType: row.sectionId})) - await WellCompositeService.save(idWell, selectedSections) - - setSelectedWells(items) - setSelectedWellsKeys(keys) - }, - setShowParamsLoader, - `Не удалось сохранить изменения выбранных секций для композитной скважины "${idWell}"`, - 'Изменение выбранных секций скважины' - ) - }, [idWell, selectedWellsKeys]) - - const onParamButtonClick = useCallback(() => invokeWebApiWrapperAsync( - async () => { - setIsParamsModalVisible(true) - const params = await DrillParamsService.getCompositeAll(idWell) - setParams(params) - }, - setShowParamsLoader, - `Не удалось загрузить список режимов для скважины "${idWell}"`, - 'Получение списка режимов скважины' - ), [idWell]) - - const onParamsAddClick = useCallback(() => invokeWebApiWrapperAsync( - async () => { - await DrillParamsService.save(idWell, params) - setIsParamsModalVisible(false) - }, - setShowLoader, - `Не удалось добавить режимы в список скважины "${idWell}"`, - 'Добавление режима скважины' - ), [idWell, params]) - return ( <>
- - - + - - setIsParamsModalVisible(false)} - width={1700} - footer={( - - - - )} - > - -
- - ) }) diff --git a/src/pages/Analytics/WellCompositeEditor/index.jsx b/src/pages/Analytics/WellCompositeEditor/index.jsx old mode 100644 new mode 100755 index cd2de0d..9725994 --- a/src/pages/Analytics/WellCompositeEditor/index.jsx +++ b/src/pages/Analytics/WellCompositeEditor/index.jsx @@ -1,24 +1,23 @@ -import { useState, useEffect, memo } from 'react' -import { Switch, useParams } from 'react-router-dom' -import { Col, Layout, Menu, Row } from 'antd' +import { useState, useEffect, memo, useContext } from 'react' +import { useParams } from 'react-router-dom' +import { Col, Layout, Row } from 'antd' -import { - OperationStatService, - WellCompositeService, -} from '@api' -import { arrayOrDefault } from '@utils' +import { IdWellContext } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import WellSelector from '@components/selectors/WellSelector' import { invokeWebApiWrapperAsync } from '@components/factory' -import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private' +import { PrivateMenu, PrivateSwitch } from '@components/Private' +import { arrayOrDefault } from '@utils' +import { OperationStatService, WellCompositeService } from '@api' import ClusterWells from '@pages/Cluster/ClusterWells' import { WellCompositeSections } from './WellCompositeSections' const { Content } = Layout -export const WellCompositeEditor = memo(({ idWell, rootPath }) => { +export const WellCompositeEditor = memo(({ rootPath }) => { const { tab } = useParams() + const idWell = useContext(IdWellContext) const [statsWells, setStatsWells] = useState([]) const [showLoader, setShowLoader] = useState(false) @@ -42,13 +41,14 @@ export const WellCompositeEditor = memo(({ idWell, rootPath }) => { useEffect(() => { const wellIds = selectedSections.map((value) => value.idWellSrc) + .filter((id, idx, arr) => arr.lastIndexOf(id) === idx) setSelectedIdWells(wellIds) }, [selectedSections]) useEffect(() => invokeWebApiWrapperAsync( async () => { - const stats = await OperationStatService.getWellsStat(selectedIdWells) - setStatsWells(arrayOrDefault(stats)) + const stats = arrayOrDefault(await OperationStatService.getWellsStat(selectedIdWells)) + setStatsWells(stats) }, setShowTabLoader, 'Не удалось загрузить статистику по скважинам/секциям', @@ -66,28 +66,19 @@ export const WellCompositeEditor = memo(({ idWell, rootPath }) => { /> - - - - + + + + - - - - - - - - - + + + + diff --git a/src/pages/Analytics/index.jsx b/src/pages/Analytics/index.jsx old mode 100644 new mode 100755 index bac5683..33834a4 --- a/src/pages/Analytics/index.jsx +++ b/src/pages/Analytics/index.jsx @@ -1,36 +1,35 @@ -import { memo, useMemo } from 'react' -import { Layout, Menu } from 'antd' -import { Switch, useParams } from 'react-router-dom' +import { memo, useContext, useMemo } from 'react' +import { useParams } from 'react-router-dom' +import { Layout } from 'antd' -import { PrivateDefaultRoute, PrivateMenuItemLink, PrivateRoute } from '@components/Private' +import { RootPathContext } from '@asb/context' +import { PrivateMenu, PrivateSwitch } from '@components/Private' -import WellCompositeEditor from './WellCompositeEditor' import Statistics from './Statistics' +import WellCompositeEditor from './WellCompositeEditor' -export const Analytics = memo(({ idWell }) => { +export const Analytics = memo(() => { const { tab } = useParams() - const rootPath = useMemo(() => `/well/${idWell}/analytics`, [idWell]) + const root = useContext(RootPathContext) + const rootPath = useMemo(() => `${root}/analytics`, [root]) return ( - - - - - + - - - - - - - - - - - + + + + + + + + + + + + - + ) }) diff --git a/src/pages/Cluster/ClusterWells.jsx b/src/pages/Cluster/ClusterWells.jsx old mode 100644 new mode 100755 index f919f2f..1c48058 --- a/src/pages/Cluster/ClusterWells.jsx +++ b/src/pages/Cluster/ClusterWells.jsx @@ -11,6 +11,7 @@ import { makeNumericColumnPlanFact, Table, makeNumericRender, + makeNumericColumn, } from '@components/Table' import { CompanyView } from '@components/views' import LoaderPortal from '@components/LoaderPortal' @@ -36,6 +37,7 @@ const DAY_IN_MS = 86_400_000 const ONLINE_DEADTIME = 600_000 const getDate = (str) => isRawDate(str) ? new Date(str).toLocaleString() : '-' +const numericRender = makeNumericRender(1) export const ClusterWells = memo(({ statsWells }) => { const [selectedWellId, setSelectedWellId] = useState(0) @@ -127,38 +129,23 @@ export const ClusterWells = memo(({ statsWells }) => { makeColumn('начало', 'factStart', { sorter: makeDateSorter('factStart'), render: getDate }), makeColumn('окончание', 'factEnd', { sorter: makeDateSorter('factEnd'), render: getDate }), ]), - makeNumericColumnPlanFact('Продолжительность, сут', 'period', filtersMinMax, makeFilterMinMaxFunction, makeNumericRender(1)), - makeNumericColumnPlanFact('МСП, м/ч', 'rateOfPenetration', filtersMinMax, makeFilterMinMaxFunction, makeNumericRender(1)), - makeNumericColumnPlanFact('Рейсовая скорость, м/ч', 'routeSpeed', filtersMinMax, makeFilterMinMaxFunction, makeNumericRender(1)), - makeNumericColumnPlanFact('НПВ, сут', 'notProductiveTime', filtersMinMax, makeFilterMinMaxFunction, makeNumericRender(1)), - { - title: 'TVD', - key: 'tvd', - render: (value) => , - align: 'center' - }, - { - title: 'Операции', - key: 'operations', - render: (value) => , - align: 'center' - }, - { - title: 'Участники', - key: 'companies', - dataIndex: 'companies', + makeNumericColumnPlanFact('Продолжительность, сут', 'period', filtersMinMax, makeFilterMinMaxFunction, numericRender), + makeNumericColumnPlanFact('МСП, м/ч', 'rateOfPenetration', filtersMinMax, makeFilterMinMaxFunction, numericRender), + makeNumericColumnPlanFact('Рейсовая скорость, м/ч', 'routeSpeed', filtersMinMax, makeFilterMinMaxFunction, numericRender), + makeNumericColumn('НПВ, ч', 'notProductiveTimeFact', filtersMinMax, makeFilterMinMaxFunction, numericRender), + makeColumn('TVD', 'tvd', { align: 'center', render: (_, value) => ( + + + + + + } /> + + + } /> + + +
+ +
+
+
+ Отправить заявку на регистрацию
- -
- Отправить заявку на регистрацию -
- -
+ + +
- + ) }) diff --git a/src/pages/Main.jsx b/src/pages/Main.jsx old mode 100644 new mode 100755 index e090edf..67a39fb --- a/src/pages/Main.jsx +++ b/src/pages/Main.jsx @@ -1,6 +1,7 @@ import { memo } from 'react' import { Route, Switch } from 'react-router-dom' +import { RootPathContext } from '@asb/context' import { AdminLayoutPortal, LayoutPortal } from '@components/Layout' import { PrivateDefaultRoute, PrivateRoute } from '@components/Private' @@ -11,32 +12,34 @@ import AdminPanel from './AdminPanel' import AccessDenied from './AccessDenied' export const Main = memo(() => ( - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + )) export default Main diff --git a/src/pages/Measure/InclinometryTable.jsx b/src/pages/Measure/InclinometryTable.jsx old mode 100644 new mode 100755 diff --git a/src/pages/Measure/MeasureTable.jsx b/src/pages/Measure/MeasureTable.jsx old mode 100644 new mode 100755 index 25e7fd5..6f858dd --- a/src/pages/Measure/MeasureTable.jsx +++ b/src/pages/Measure/MeasureTable.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, memo, useMemo, useCallback } from 'react' +import { useState, useEffect, memo, useMemo, useCallback, useContext } from 'react' import { Button, Form, Input, Popconfirm, Timeline } from 'antd' import { CheckSquareOutlined, @@ -9,6 +9,7 @@ import { DeleteOutlined } from '@ant-design/icons' +import { IdWellContext } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { hasPermission } from '@utils/permissions' @@ -25,13 +26,15 @@ const createEditingColumns = (cols, renderDelegate) => const disabled = !hasPermission('Measure.edit') -export const MeasureTable = memo(({ idWell, group, updateMeasuresFunc, additionalButtons }) => { +export const MeasureTable = memo(({ group, updateMeasuresFunc, additionalButtons }) => { const [showLoader, setShowLoader] = useState(false) const [displayedValues, setDisplayedValues] = useState({}) const [editingColumns, setEditingColumns] = useState(group.columns) const [isTableEditing, setIsTableEditing] = useState(false) const [editingActionName, setEditingActionName] = useState('') + const idWell = useContext(IdWellContext) + const [measuresForm] = Form.useForm() const data = useMemo(() => group?.values?.length > 0 ? group.values : [group?.defaultValue], [group?.defaultValue, group?.values]) diff --git a/src/pages/Measure/View.jsx b/src/pages/Measure/View.jsx old mode 100644 new mode 100755 diff --git a/src/pages/Measure/columnsCommon.js b/src/pages/Measure/columnsCommon.js old mode 100644 new mode 100755 diff --git a/src/pages/Measure/drillingFluidData.js b/src/pages/Measure/drillingFluidData.js old mode 100644 new mode 100755 diff --git a/src/pages/Measure/index.jsx b/src/pages/Measure/index.jsx old mode 100644 new mode 100755 index adf6b4c..ecc1e6d --- a/src/pages/Measure/index.jsx +++ b/src/pages/Measure/index.jsx @@ -1,10 +1,11 @@ import { Button } from 'antd' -import { useState, useEffect, memo } from 'react' +import { useState, useEffect, memo, useContext } from 'react' import { TableOutlined } from '@ant-design/icons' -import { MeasureService } from '@api' +import { IdWellContext } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' +import { MeasureService } from '@api' import { MeasureTable } from './MeasureTable' import { InclinometryTable } from './InclinometryTable' @@ -41,12 +42,14 @@ const defaultData = [ } ] -export const Measure = memo(({ idWell }) => { +export const Measure = memo(() => { const [showLoader, setShowLoader] = useState(false) const [isMeasuresUpdating, setIsMeasuresUpdating] = useState(true) const [data, setData] = useState(defaultData) const [tableIdx, setTableIdx] = useState(-1) + const idWell = useContext(IdWellContext) + useEffect(() => invokeWebApiWrapperAsync( async () => { if (!isMeasuresUpdating) return @@ -73,7 +76,6 @@ export const Measure = memo(({ idWell }) => { {data.map((group, idx) => ( setIsMeasuresUpdating(true)} additionalButtons={group.additionalButtons?.(group, idx, setTableIdx)} diff --git a/src/pages/Measure/mudDiagramData.js b/src/pages/Measure/mudDiagramData.js old mode 100644 new mode 100755 diff --git a/src/pages/Measure/nnbData.js b/src/pages/Measure/nnbData.js old mode 100644 new mode 100755 diff --git a/src/pages/Register.jsx b/src/pages/Register.jsx old mode 100644 new mode 100755 diff --git a/src/pages/Reports/DailyReport/ReportEditor.jsx b/src/pages/Reports/DailyReport/ReportEditor.jsx new file mode 100644 index 0000000..ffea880 --- /dev/null +++ b/src/pages/Reports/DailyReport/ReportEditor.jsx @@ -0,0 +1,295 @@ +import moment from 'moment' +import { DatePicker, Descriptions, Divider, Form, Input, InputNumber, Modal, Select, Space, Table } from 'antd' +import { memo, useCallback, useContext, useEffect, useState } from 'react' + +import { IdWellContext } from '@asb/context' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { makeColumn, makeGroupColumn } from '@components/Table' +import { DailyReportService } from '@api' + + +const { Item: RawItem } = Form +const { Summary } = Table + +const Item = memo(({ style, ...other }) => ) + +const table1Columns = [ + makeGroupColumn('Отчётный период', [ + makeColumn('От (дата, время)', 'dateStart', { width: 200, render: (_, { disabled, onChange, checkIsDateBusy }) => ( + + + + )}), + ]), + makeGroupColumn('Забой за отчётный период, м', [ + makeColumn('От', 'depthStart', { width: 200, render: () => ( + + + + )}), + makeColumn('До', 'depthEnd', { width: 200, render: () => ( + + + + )}), + ]) +] + +const cellData = { + width: 200, + render: (name) => ( + + + + ) +} + +const table2Columns = [ + makeColumn('Работа модулей САУБ', 'label', { width: 400 }), + makeColumn('Часов:', 'hours', cellData), + makeColumn('Метров:', 'meters', cellData), +] + +const table2Data = [ + { key: '1', label: 'АПД (автоматическая подача долота), ч/м:', hours: 'workTimeSAUB', meters: 'penetrationSAUB' }, + { key: '2', label: 'Спин Мастер (осцилляция), ч/м:', hours: 'workTimeSpinMaster', meters: 'penetrationSpinMaster' }, + { key: '3', label: 'Торк Мастер (демпфирование), ч/м:', hours: 'workTimeTorkMaster', meters: 'penetrationTorkMaster' }, +] + +const table3Columns = [ + makeGroupColumn('Бурение в роторе (за отчётный период) с использованием САУБ-1', [ + makeColumn('Проходка', 'sinking', cellData), + makeColumn('Часы бурения', 'hours', cellData), + makeColumn('Среднее диф. Давление', 'pressure', cellData), + ]), +] + +const table3Data = [{ key: '', sinking: 'penetrationInRotor', hours: 'numberDrillingHours', pressure: 'avgDiffDropRotor' }] + +const table4Columns = [ + makeGroupColumn('Бурение в слайде (за отчётный период) с использованием САУБ-1', [ + makeColumn('Проходка', 'sinking', cellData), + makeColumn('Часы бурения', 'hours', cellData), + makeColumn('Среднее диф. Давление', 'pressure', cellData), + ]), +] + +const table4Data = [{ key: '', sinking: 'penetrationInSlide', hours: 'drillingTimeInRotor', pressure: 'avgDiffPressureSlide' }] + +const table6Columns = [ + makeGroupColumn('БЕЗМЕТРАЖНЫЕ РАБОТЫ', [ + makeColumn('Подготовка ствола скважины к наращиванию', 'l_label', { colSpan: 2, width: 200 }), + makeColumn('', 'l_value', { colSpan: 0, ...cellData }), + makeColumn('Наращивание', 'r_label', { colSpan: 2, width: 200 }), + makeColumn('', 'r_value', { colSpan: 0, ...cellData }), + ]), +] + +const table6Data = [{ + key: '1', + l_label: 'Норматив на одну операцию, (мин):', + r_label: 'Норматив на одну операцию, (мин):', + l_value: 'standardTimeBarrelPreparation', + r_value: 'standardTimeExtension' +}, { + key: '2', + l_label: 'Проработка при бур, факт (ч):', + r_label: 'Наращивание, факт (ч):', + l_value: 'actualTimeBarrelPreparation', + r_value: 'actualTimeExtension' +}] + +const table6Summary = () => ( + + + Краткие причины: доп проработки при переходе из слайда в ротор, в середине свечи. + + + Краткие причины: нехватка пальцев на обоих руках у первого помощника бурильщика. + + +) + +const table2Summary = () => ( + + МСЕ, колличество запусков, раз: + + + + + + +) + +export const ReportEditor = memo(({ visible, data, onDone, onCancel, checkIsDateBusy }) => { + const [form] = Form.useForm() + const [isInvalid, setIsInvalid] = useState(false) + const [isLoading, setIsLoading] = useState(false) + + const idWell = useContext(IdWellContext) + + const setFields = useCallback((data) => form.setFieldsValue(data ? { + ...data, + rotorDrillingModes: Array.isArray(data.rotorDrillingModes) ? data.rotorDrillingModes ?? [] : [], + slideDrillingModes: Array.isArray(data.slideDrillingModes) ? data.slideDrillingModes ?? [] : [], + reportDate: moment.utc(data.reportDate).local(), + } : {}), [form]) + + useEffect(() => setFields(data), [data, setFields]) + + const onFormChange = useCallback(async () => await form.validateFields() + .then(() => setIsInvalid(false)) + .catch(() => setIsInvalid(true)) + , [form]) + + const onFormFinish = useCallback((formData) => invokeWebApiWrapperAsync( + async () => { + if (data) + await DailyReportService.update(idWell, data.reportDate, formData) + else + await DailyReportService.add(idWell, formData) + onDone?.(formData) + form.resetFields() + }, + setIsLoading, + 'Не удалось сохранить суточный рапорт', + 'Сохранение суточного рапорта', + ), [data, onDone, idWell, form]) + + const onDateChange = useCallback((date) => invokeWebApiWrapperAsync( + async () => { + if (data) return + const newData = await DailyReportService.getOrGenerate(idWell, date.format('YYYY-MM-DD') + 'Z') + if (checkIsDateBusy(moment(newData.reportDate))) + throw new Error('Рапорт на данную дату уже существует') + setFields(newData) + }, + setIsLoading, + (e) => `Не удалось загрузить автозаполняемые данные для нового рапорта: ${e}`, + 'Получение автозаполняемых данных суточного рапорта', + ), [idWell, data, setFields, checkIsDateBusy]) + + return ( + Суточная сводка бурения скважины № {data?.wellName} куст № {data?.clusterName} : + <>Новая cуточная сводка бурения скважины + } + onOk={form.submit} + okButtonProps={{ + disabled: isInvalid, + loading: isLoading, + }} + > + +
+ + + + + + + +
+ + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +}) + +export default ReportEditor diff --git a/src/pages/Reports/DailyReport/index.jsx b/src/pages/Reports/DailyReport/index.jsx new file mode 100644 index 0000000..cbb0c97 --- /dev/null +++ b/src/pages/Reports/DailyReport/index.jsx @@ -0,0 +1,114 @@ +import moment from 'moment' +import { Button } from 'antd' +import { FileExcelOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons' +import { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react' + +import { IdWellContext } from '@asb/context' +import LoaderPortal from '@components/LoaderPortal' +import { DateRangeWrapper, Table, makeDateColumn, makeColumn } from '@components/Table' +import { download, invokeWebApiWrapperAsync } from '@components/factory' +import { DailyReportService } from '@api' +import { arrayOrDefault } from '@utils' + +import ReportEditor from './ReportEditor' + +export const DailyReport = memo(() => { + const [data, setData] = useState([]) + const [isLoading, setIsLoading] = useState(false) + const [searchDate, setSearchDate] = useState([moment().subtract(1, 'week'), moment()]) + const [selectedReport, setSelectedReport] = useState(null) + const [isEditorVisible, setIsEditorVisible] = useState(false) + + const idWell = useContext(IdWellContext) + + const updateTable = useCallback(() => invokeWebApiWrapperAsync( + async () => { + const data = arrayOrDefault(await DailyReportService.getList(idWell)) + setData(data) + }, + setIsLoading, + 'Не удалось загрузить список суточных рапортов', + 'Получение списка суточных рапортов', + ), [idWell]) + + useEffect(updateTable, [updateTable]) + + const checkIsDateBusy = useCallback((current) => current.isAfter(moment(), 'day') || data.some((row) => moment(row.reportDate).isSame(current, 'day')), [data]) + + const columns = useMemo(() => [ + makeDateColumn('Дата', 'reportDate', undefined, 'DD.MM.YYYY', { width: 300 }), + makeColumn('', '', { width: 200, render: (_, report) => ( + <> +
+ + setIsEditorVisible(false)} + onDone={() => { + setIsEditorVisible(false) + updateTable() + }} + checkIsDateBusy={checkIsDateBusy} + /> + + ) +}) + +export default DailyReport diff --git a/src/pages/Report/ReportCreationNotify.jsx b/src/pages/Reports/DiagramReport/ReportCreationNotify.jsx similarity index 100% rename from src/pages/Report/ReportCreationNotify.jsx rename to src/pages/Reports/DiagramReport/ReportCreationNotify.jsx diff --git a/src/pages/Report/Reports.jsx b/src/pages/Reports/DiagramReport/Reports.jsx similarity index 93% rename from src/pages/Report/Reports.jsx rename to src/pages/Reports/DiagramReport/Reports.jsx index cf44431..9d0609f 100644 --- a/src/pages/Report/Reports.jsx +++ b/src/pages/Reports/DiagramReport/Reports.jsx @@ -1,12 +1,13 @@ import { Button, Tooltip } from 'antd' -import { useState, useEffect, memo } from 'react' +import { useState, useEffect, memo, useContext } from 'react' import { FilePdfOutlined, FileTextOutlined } from '@ant-design/icons' -import { ReportService } from '@api' -import { formatDate, periodToString } from '@utils' +import { IdWellContext } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { Table, makeDateSorter, makeNumericSorter } from '@components/Table' import { invokeWebApiWrapperAsync, downloadFile } from '@components/factory' +import { formatDate, periodToString } from '@utils' +import { ReportService } from '@api' const imgPaths = { '.pdf': , @@ -55,10 +56,12 @@ const columns = [ }, ] -export const Reports = memo(({ idWell }) => { +export const Reports = memo(() => { const [reports, setReports] = useState([]) const [showLoader, setShowLoader] = useState(false) + const idWell = useContext(IdWellContext) + useEffect(() => invokeWebApiWrapperAsync( async () => { const reportsResponse = await ReportService.getAllReportsNamesByWell(idWell) diff --git a/src/pages/Report/index.jsx b/src/pages/Reports/DiagramReport/index.jsx similarity index 92% rename from src/pages/Report/index.jsx rename to src/pages/Reports/DiagramReport/index.jsx index ce8a0d4..6462abd 100644 --- a/src/pages/Report/index.jsx +++ b/src/pages/Reports/DiagramReport/index.jsx @@ -1,13 +1,14 @@ import 'moment/locale/ru' import moment from 'moment' -import { useState, useEffect, memo, useCallback } from 'react' +import { useState, useEffect, memo, useCallback, useContext } from 'react' import { Radio, Button, Select, notification } from 'antd' -import { ReportService } from '@api' -import { Subscribe } from '@services/signalr' +import { IdWellContext } from '@asb/context' +import { DateRangeWrapper } from 'components/Table' import { LoaderPortal } from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { DateRangeWrapper } from 'components/Table/DateRangeWrapper' +import { Subscribe } from '@services/signalr' +import { ReportService } from '@api' import { Reports } from './Reports' import { ReportCreationNotify } from './ReportCreationNotify' @@ -32,7 +33,7 @@ const reportFormats = [ { value: 1, label: 'LAS' }, ] -export const Report = memo(({ idWell }) => { +export const DiagramReport = memo(() => { const [aviableDateRange, setAviableDateRange] = useState([moment(), moment()]) const [filterDateRange, setFilterDateRange] = useState([ moment().subtract(1, 'days').startOf('day'), @@ -43,6 +44,8 @@ export const Report = memo(({ idWell }) => { const [pagesCount, setPagesCount] = useState(0) const [showLoader, setShowLoader] = useState(false) + const idWell = useContext(IdWellContext) + const handleReportCreation = useCallback(async () => await invokeWebApiWrapperAsync( async () => { const taskId = await ReportService.createReport( @@ -69,12 +72,10 @@ export const Report = memo(({ idWell }) => { } } - const unSubscribeReportHub = Subscribe( - 'hubs/reports', - 'GetReportProgress', - `Report_${taskId}`, - handleReportProgress - ) + const unSubscribeReportHub = Subscribe('hubs/reports', `Report_${taskId}`, { + methodName: 'GetReportProgress', + handler: handleReportProgress, + }) }, setShowLoader, `Не удалось создать отчет по скважине (${idWell}) c @@ -168,9 +169,9 @@ export const Report = memo(({ idWell }) => { - + ) }) -export default Report +export default DiagramReport diff --git a/src/pages/Reports/index.jsx b/src/pages/Reports/index.jsx new file mode 100644 index 0000000..6bd29c0 --- /dev/null +++ b/src/pages/Reports/index.jsx @@ -0,0 +1,41 @@ +import { useParams } from 'react-router-dom' +import { memo, useContext, useMemo } from 'react' +import { FilePdfOutlined } from '@ant-design/icons' +import { Layout } from 'antd' + +import { RootPathContext } from '@asb/context' +import { PrivateMenu, PrivateSwitch } from '@components/Private' + +import DailyReport from './DailyReport' +import DiagramReport from './DiagramReport' + +const { Content } = Layout + +export const Reports = memo(() => { + const { tab } = useParams() + + const root = useContext(RootPathContext) + const rootPath = useMemo(() => `${root}/reports`, [root]) + + return ( + + + + } title={'Диаграмма'}/> + + + + + + + + + + + + + + ) +}) + +export default Reports diff --git a/src/pages/SuspenseFallback.tsx b/src/pages/SuspenseFallback.tsx old mode 100644 new mode 100755 diff --git a/src/pages/Archive/ArchiveColumn.jsx b/src/pages/Telemetry/Archive/ArchiveColumn.jsx old mode 100644 new mode 100755 similarity index 100% rename from src/pages/Archive/ArchiveColumn.jsx rename to src/pages/Telemetry/Archive/ArchiveColumn.jsx diff --git a/src/pages/Archive/ArchiveDisplay.jsx b/src/pages/Telemetry/Archive/ArchiveDisplay.jsx old mode 100644 new mode 100755 similarity index 97% rename from src/pages/Archive/ArchiveDisplay.jsx rename to src/pages/Telemetry/Archive/ArchiveDisplay.jsx index c4bae7e..c3310ba --- a/src/pages/Archive/ArchiveDisplay.jsx +++ b/src/pages/Telemetry/Archive/ArchiveDisplay.jsx @@ -2,7 +2,7 @@ import { memo, useMemo } from 'react' import { Grid, GridItem } from '@components/Grid' -import { paramsGroups } from '@pages/TelemetryView' +import { paramsGroups } from '../TelemetryView' import { ArchiveColumn } from './ArchiveColumn' const interpolationSearch = (data, begin, end, accessor) => { diff --git a/src/pages/Archive/index.jsx b/src/pages/Telemetry/Archive/index.jsx old mode 100644 new mode 100755 similarity index 93% rename from src/pages/Archive/index.jsx rename to src/pages/Telemetry/Archive/index.jsx index f969709..318272e --- a/src/pages/Archive/index.jsx +++ b/src/pages/Telemetry/Archive/index.jsx @@ -1,14 +1,16 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { useState, useEffect, memo, useCallback } from 'react' +import { useState, useEffect, memo, useCallback, useContext } from 'react' +import { IdWellContext } from '@asb/context' import { Flex } from '@components/Grid' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { DatePickerWrapper, makeDateSorter } from '@components/Table' import { PeriodPicker, defaultPeriod } from '@components/selectors/PeriodPicker' import { TelemetryDataSaubService } from '@api' +import { range } from '@utils' -import { normalizeData } from '@pages/TelemetryView' +import { normalizeData } from '../TelemetryView' import { ArchiveDisplay, cutData } from './ArchiveDisplay' const DATA_COUNT = 2048 // Колличество точек на подгрузку графика @@ -54,14 +56,7 @@ const getLoadingInterval = (loaded, startDate, interval) => { } } -const range = (start, end) => { - const result = [] - for (let i = start; i < end; i++) - result.push(i) - return result -} - -export const Archive = memo(({ idWell }) => { +export const Archive = memo(() => { const [dataSaub, setDataSaub] = useState([]) const [dateLimit, setDateLimit] = useState({ from: 0, to: new Date() }) const [chartInterval, setChartInterval] = useState(parseInt(defaultPeriod) * 1000) @@ -69,6 +64,8 @@ export const Archive = memo(({ idWell }) => { const [showLoader, setShowLoader] = useState(false) const [loaded, setLoaded] = useState(null) + const idWell = useContext(IdWellContext) + const onGraphWheel = useCallback((e) => { if (loaded && dateLimit.from && dateLimit.to) { setStartDate((prevStartDate) => { @@ -88,17 +85,17 @@ export const Archive = memo(({ idWell }) => { }, [dateLimit]) const isDateTimeDisabled = useCallback((date) => ({ - disabledHours: () => range(0, 24).filter(h => { + disabledHours: () => range(24).filter(h => { if (!date) return false const dt = +new Date(date).setHours(h) return dt < dateLimit.from || dt > +dateLimit.to - chartInterval }), - disabledMinutes: () => range(0, 60).filter(m => { + disabledMinutes: () => range(60).filter(m => { if (!date) return false const dt = +new Date(date).setMinutes(m) return dt < dateLimit.from || dt > +dateLimit.to - chartInterval }), - disabledSeconds: () => range(0, 60).filter(s => { + disabledSeconds: () => range(60).filter(s => { if (!date) return false const dt = +new Date(date).setSeconds(s) return dt < dateLimit.from || dt > +dateLimit.to - chartInterval diff --git a/src/pages/Telemetry/DashboardNNB/AddGroupWindow.jsx b/src/pages/Telemetry/DashboardNNB/AddGroupWindow.jsx new file mode 100644 index 0000000..96ce88e --- /dev/null +++ b/src/pages/Telemetry/DashboardNNB/AddGroupWindow.jsx @@ -0,0 +1,18 @@ +import { PlusOutlined } from '@ant-design/icons' +import { Form, Input } from 'antd' +import { memo } from 'react' + +import Poprompt from '@components/selectors/Poprompt' + +const addGroupRules = [{ required: true, message: 'Пожалуйста, введите название группы' }] +const addGroupButtonProps = { type: 'link', className: 'add_group', icon: } + +export const AddGroupWindow = memo(({ addGroup, initialValue = 'Новая группа' }) => ( + + + + + +)) + +export default AddGroupWindow diff --git a/src/pages/Telemetry/DashboardNNB/AddWidgetWindow.jsx b/src/pages/Telemetry/DashboardNNB/AddWidgetWindow.jsx new file mode 100644 index 0000000..1cd15cd --- /dev/null +++ b/src/pages/Telemetry/DashboardNNB/AddWidgetWindow.jsx @@ -0,0 +1,52 @@ +import { PlusOutlined } from '@ant-design/icons' +import { Form, Select } from 'antd' +import { memo, useCallback, useMemo } from 'react' + +import Poprompt from '@components/selectors/Poprompt' + +export const createWidgetId = (witsRecord, dt = false) => `${witsRecord.recordId}_${witsRecord.itemId}` + (dt ? `_${Date.now()}` : '') + +export const makeWidgetFromWits = (witsRecord) => ({ + id: createWidgetId(witsRecord, true), + witsId: witsRecord.longMnemonic.toLowerCase(), + recordId: witsRecord.recordId, + unit: witsRecord.metricUnits, + label: witsRecord.longMnemonic, +}) + +const addWidgetRules = [{ required: true, message: 'Пожалуйста, выберите виджет' }] +const addWidgetButtonProps = { type: 'link', className: 'add_group', icon: } + +export const AddWidgetWindow = memo(({ witsInfo, onAdded }) => { + const options = useMemo(() => witsInfo?.map((witsRecord) => ({ + label: `Record #${witsRecord.recordId}: ${witsRecord.longMnemonic}`, + value: createWidgetId(witsRecord), + })) ?? [], [witsInfo]) + + const onFormFinish = useCallback((value) => { + if (!value?.widget) return + const record = witsInfo.find((witsRecord) => createWidgetId(witsRecord) === value.widget) + if (record) + onAdded?.(makeWidgetFromWits(record)) + }, [onAdded, witsInfo]) + + return ( + + +
+ +)) + +export default OperationsTable diff --git a/src/pages/Telemetry/Operations/index.jsx b/src/pages/Telemetry/Operations/index.jsx new file mode 100644 index 0000000..f6f57fc --- /dev/null +++ b/src/pages/Telemetry/Operations/index.jsx @@ -0,0 +1,91 @@ +import { memo, useCallback, useContext, useEffect, useState } from 'react' +import { InputNumber } from 'antd' +import moment from 'moment' + +import { IdWellContext } from '@asb/context' +import LoaderPortal from '@components/LoaderPortal' +import { DateRangeWrapper } from '@components/Table' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { DetectedOperationService, TelemetryDataSaubService } from '@api' +import { range } from '@utils' + +import OperationsChart from './OperationsChart' +import OperationsTable from './OperationsTable' + +import '@styles/detected_operations.less' + +export const Operations = memo(() => { + const [isLoading, setIsLoading] = useState(false) + const [dateRange, setDateRange] = useState([]) + const [yDomain, setYDomain] = useState(20) + const [dates, setDates] = useState() + const [data, setData] = useState([]) + + const idWell = useContext(IdWellContext) + + const disabledDates = useCallback((current) => current && !moment(current).isBetween(...dateRange, 'day', '[]'), [dateRange]) + + const disabledTimes = useCallback((date) => ({ + disabledHours: () => range(24).filter(h => date && !moment(date).hours(h).isBetween(...dateRange, 'hour', '[]')), + disabledMinutes: () => range(60).filter(m => date && !moment(date).minutes(m).isBetween(...dateRange, 'minute', '[]')), + disabledSeconds: () => range(60).filter(s => date && !moment(date).seconds(s).isBetween(...dateRange, 'second', '[]')) + }), [dateRange]) + + useEffect(() => invokeWebApiWrapperAsync( + async () => { + const dates = await TelemetryDataSaubService.getDataDatesRange(idWell) + if (dates) { + const dt = [moment(dates.from), moment(dates.to)] + setDateRange(dt) + setDates(dt) + } + }, + setIsLoading, + 'Не удалось загрузить диапазон доступных дат', + 'Получение дапазона доступних дат', + ), [idWell]) + + useEffect(() => invokeWebApiWrapperAsync( + async () => { + if (!dates) return + const data = await DetectedOperationService.get(idWell, undefined, dates[0].toISOString(), dates[1].toISOString()) + setData(data) + }, + setIsLoading, + 'Не удалось загрузить список определённых операций', + 'Получение списка определённых операций', + ), [idWell, dates]) + + return ( +
+
+ + +
+ +
+ + +
+
+
+ ) +}) + +export default Operations diff --git a/src/pages/TelemetryView/ActiveMessagesOnline.jsx b/src/pages/Telemetry/TelemetryView/ActiveMessagesOnline.jsx old mode 100644 new mode 100755 similarity index 77% rename from src/pages/TelemetryView/ActiveMessagesOnline.jsx rename to src/pages/Telemetry/TelemetryView/ActiveMessagesOnline.jsx index ec888ea..3e9ea0b --- a/src/pages/TelemetryView/ActiveMessagesOnline.jsx +++ b/src/pages/Telemetry/TelemetryView/ActiveMessagesOnline.jsx @@ -1,19 +1,22 @@ import { Table } from 'antd' -import { useState, useEffect, useCallback, memo } from 'react' +import { useState, useEffect, useCallback, memo, useContext } from 'react' +import { IdWellContext } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { Subscribe } from '@services/signalr' import { MessageService } from '@api' -import { columns } from '@pages/Messages' +import { columns } from '../Messages' import '@styles/message.css' -export const ActiveMessagesOnline = memo(({ idWell }) => { +export const ActiveMessagesOnline = memo(() => { const [messages, setMessages] = useState([]) const [loader, setLoader] = useState(false) + const idWell = useContext(IdWellContext) + const handleReceiveMessages = useCallback((messages) => { if (messages) setMessages(messages.items.splice(0, 4)) @@ -29,7 +32,10 @@ export const ActiveMessagesOnline = memo(({ idWell }) => { `Не удалось загрузить сообщения по скважине "${idWell}"`, 'Получение списка сообщений' ) - return Subscribe('hubs/telemetry','ReceiveMessages', `well_${idWell}`, handleReceiveMessages) + return Subscribe('hubs/telemetry',`well_${idWell}`, { + methodName: 'ReceiveMessages', + handler: handleReceiveMessages, + }) }, [idWell, handleReceiveMessages]) return ( diff --git a/src/pages/TelemetryView/ChartTimeOnlineFooter.jsx b/src/pages/Telemetry/TelemetryView/ChartTimeOnlineFooter.jsx old mode 100644 new mode 100755 similarity index 100% rename from src/pages/TelemetryView/ChartTimeOnlineFooter.jsx rename to src/pages/Telemetry/TelemetryView/ChartTimeOnlineFooter.jsx diff --git a/src/pages/TelemetryView/CustomColumn.jsx b/src/pages/Telemetry/TelemetryView/CustomColumn.jsx old mode 100644 new mode 100755 similarity index 90% rename from src/pages/TelemetryView/CustomColumn.jsx rename to src/pages/Telemetry/TelemetryView/CustomColumn.jsx index f3ac368..9da3fea --- a/src/pages/TelemetryView/CustomColumn.jsx +++ b/src/pages/Telemetry/TelemetryView/CustomColumn.jsx @@ -11,6 +11,7 @@ const params = [ { label: 'Расход, м³/ч', accessorName: 'flow', isArrowVisible: true }, { label: 'Расход х.х., м³/ч', accessorName: 'flowIdle', isArrowVisible: true }, { label: 'Время', accessorName: 'date', format: 'HH:mm:ss' }, + { label: 'MSE, %', accessorName: 'mse', format: 2 }, ] export const CustomColumn = memo(({ data }) => { @@ -26,8 +27,8 @@ export const CustomColumn = memo(({ data }) => { label={param.label} value={param.value} suffix={param.units} - format = {param.format} - isArrowVisible = {param.isArrowVisible} + format={param.format} + isArrowVisible={param.isArrowVisible} /> ))} { const addPointData = (point) => ({ depth: point.wellDepth }) +const ChartValues = memo(({ pv }) => pv?.map((v, idx) => { + const text = `${v.value?.toFixed(2) ?? '--'} ${v.unit}` + return ( + + ) +})) + export const MonitoringColumn = memo(({ lineGroup, data, flowChartData, interval, showBorder, style, headerHeight, pointCount = 2048, additionalLabels }) => { const [dataStore, setDataStore] = useState([]) - const [lineGroupWithoutShapes, setLineGroupWithoutShapes] = useState([]) - const dataLast = data?.[data.length - 1] - const yStart = new Date((dataLast?.date ? +new Date(dataLast.date) : Date.now()) - interval * 0.97) - let pv = lineGroup.filter(line => line.showLabels).map(line => ({ + const dataLast = useMemo(() => data?.[data.length - 1], [data]) + const yStart = useMemo(() => new Date((dataLast?.date ? +new Date(dataLast.date) : Date.now()) - interval * 0.97), [dataLast, interval]) + const pv = useMemo(() => lineGroup.filter(line => line.showLabels).map(line => ({ color: line.color, label: line.label, unit: line.units, value: dataLast?.[line.xAccessorName] - })) + })), [lineGroup, dataLast]) + + const lineGroupWithoutShapes = useMemo(() => lineGroup.filter(cfg => !cfg.isShape), [lineGroup]) const postParsing = useCallback((data) => { lineGroupWithoutShapes.forEach(lineCfg => { @@ -67,10 +83,6 @@ export const MonitoringColumn = memo(({ lineGroup, data, flowChartData, interval }) }, [data, pointCount]) - useEffect(() => { - setLineGroupWithoutShapes(lineGroup.filter(cfg => !cfg.isShape)) - }, [lineGroup]) - return (
@@ -80,20 +92,7 @@ export const MonitoringColumn = memo(({ lineGroup, data, flowChartData, interval
- {pv?.map((v, idx) => { - const text = `${v.value?.toFixed(2) ?? '--'} ${v.unit}` - return ( - - ) - })} + {additionalLabels?.map((label, idx) => ( { + +export const SetpointSender = memo(({ onClose, visible, setpointNames }) => { const [expirePeriod, setExpirePeriod] = useState(defaultPeriod) const [comment, setComment] = useState('') const [setpoints, setSetpoints] = useState([]) const [isLoading, setIsLoading] = useState(false) - const addingColumns = [ + const idWell = useContext(IdWellContext) + + const addingColumns = useMemo(() => [ { title: 'Наименование уставки', dataIndex: 'name', @@ -33,27 +37,26 @@ export const SetpointSender = ({ idWell, onClose, visible, setpointNames }) => { render: makeNumericRender(1), align: 'right' } - ] + ], [setpointNames]) - const onAdd = async (sp) => setSetpoints((prevSp) => { + const onAdd = useCallback(async (sp) => setSetpoints((prevSp) => { sp.key = Date.now() - prevSp.push(sp) - return prevSp - }) + return [...prevSp, sp] + }), []) - const onEdit = async (sp) => setSetpoints((prevSp) => { + const onEdit = useCallback(async (sp) => setSetpoints((prevSp) => { const idx = prevSp.findIndex((val) => val.key === sp.key) prevSp[idx] = sp - return prevSp - }) + return [...prevSp] + }), []) - const onDelete = async (sp) => setSetpoints((prevSp) => { + const onDelete = useCallback(async (sp) => setSetpoints((prevSp) => { const idx = prevSp.findIndex((val) => val.key === sp.key) prevSp.splice(idx, 1) - return prevSp - }) + return [...prevSp] + }), []) - const onModalOk = () => invokeWebApiWrapperAsync( + const onModalOk = useCallback(() => invokeWebApiWrapperAsync( async () => { const setpointsObject = setpoints.reduce((obj, sp) => { obj[sp.name] = sp.value @@ -66,12 +69,12 @@ export const SetpointSender = ({ idWell, onClose, visible, setpointNames }) => { comment: comment } await SetpointsService.insert(idWell, request) - onClose(true) + await onClose(true) }, setIsLoading, `Не удалось отправить уставки по скважине "${idWell}"`, `Рекомендация новыой уставки` - ) + ), [idWell, setpoints, comment, expirePeriod, onClose]) return ( { onCancel={onClose} onOk={onModalOk} okText={'Отправить'} + okButtonProps={{ disabled: setpoints.length <= 0 }} > @@ -115,4 +119,6 @@ export const SetpointSender = ({ idWell, onClose, visible, setpointNames }) => { ) -} +}) + +export default SetpointSender diff --git a/src/pages/TelemetryView/SetpointViewer.jsx b/src/pages/Telemetry/TelemetryView/Setpoints/SetpointViewer.jsx old mode 100644 new mode 100755 similarity index 98% rename from src/pages/TelemetryView/SetpointViewer.jsx rename to src/pages/Telemetry/TelemetryView/Setpoints/SetpointViewer.jsx index 7a0fa75..d22ccf2 --- a/src/pages/TelemetryView/SetpointViewer.jsx +++ b/src/pages/Telemetry/TelemetryView/Setpoints/SetpointViewer.jsx @@ -72,3 +72,5 @@ export const SetpointViewer = memo(({ setpoint, visible, onClose, setpointNames ) }) + +export default SetpointViewer diff --git a/src/pages/TelemetryView/Setpoints.jsx b/src/pages/Telemetry/TelemetryView/Setpoints/index.jsx old mode 100644 new mode 100755 similarity index 82% rename from src/pages/TelemetryView/Setpoints.jsx rename to src/pages/Telemetry/TelemetryView/Setpoints/index.jsx index a74f9e5..7cf4901 --- a/src/pages/TelemetryView/Setpoints.jsx +++ b/src/pages/Telemetry/TelemetryView/Setpoints/index.jsx @@ -1,19 +1,20 @@ -import moment from 'moment' import { Button, Modal } from 'antd' -import { useState, useEffect } from 'react' +import { useState, useEffect, memo, useCallback, useMemo, useContext } from 'react' +import { IdWellContext } from '@asb/context' import { Table } from '@components/Table' import { UserView } from '@components/views' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' +import { hasPermission } from '@utils/permissions' import { makeStringCutter } from '@utils/string' +import { formatDate } from '@utils' import { SetpointsService } from '@api' -import { SetpointSender } from './SetpointSender' +import SetpointSender from './SetpointSender' import { SetpointViewer, getSetpointStatus } from './SetpointViewer' -import { hasPermission } from '@asb/utils/permissions' -export const Setpoints = ({ idWell, ...other }) => { +export const Setpoints = memo(({ ...other }) => { const [isModalVisible, setIsModalVisible] = useState(false) const [isSenderVisible, setIsSenderVisible] = useState(false) const [isViewerVisible, setIsViewerVisible] = useState(false) @@ -22,6 +23,8 @@ export const Setpoints = ({ idWell, ...other }) => { const [selected, setSelected] = useState(null) const [setpointNames, setSetpointNames] = useState([]) + const idWell = useContext(IdWellContext) + useEffect(() => invokeWebApiWrapperAsync( async () => { const names = await SetpointsService.getSetpointsNamesByIdWell(idWell) @@ -37,21 +40,21 @@ export const Setpoints = ({ idWell, ...other }) => { 'Получение списка имён уставок' ), [idWell]) - const showMore = (id) => { + const showMore = useCallback((id) => { const selected = setpoints.find((sp) => sp.id === id) setSelected(selected ?? {}) setIsViewerVisible(true) - } + }, [setpoints]) - const historyColumns = [ - { title: 'Дата', dataIndex: 'uploadDate', render: item => moment(item).format('DD MMM YYYY, HH:mm:ss') }, + const historyColumns = useMemo(() => [ + { title: 'Дата', dataIndex: 'uploadDate', render: item => formatDate(item) }, { title: 'Автор', dataIndex: 'author', render: (user) => }, { title: 'Комментарий', dataIndex: 'comment', render: makeStringCutter() }, { title: 'Статус', dataIndex: 'idState', render: (id) => getSetpointStatus(parseInt(id)) }, { dataIndex: 'id', render: (id) => }, - ] + ], [showMore]) - const updateTable = async () => await invokeWebApiWrapperAsync( + const updateTable = useCallback(async () => await invokeWebApiWrapperAsync( async () => { const setpoints = await SetpointsService.getByIdWell(idWell) setSetpoints(setpoints) @@ -59,19 +62,19 @@ export const Setpoints = ({ idWell, ...other }) => { setIsLoading, `Не удалось загрузить список для скважины "${idWell}"`, 'Получение списка скважин' - ) + ), [idWell]) - const onOpenClick = async () => { + const onOpenClick = useCallback(async () => { await updateTable() setIsModalVisible(true) - } + }, [updateTable]) - const onSenderClose = (pushed) => { - if (pushed) updateTable() + const onSenderClose = useCallback(async (pushed) => { + if (pushed) await updateTable() setIsSenderVisible(false) - } + }, [updateTable]) - return hasPermission('Setpoints.get') && ( + return !hasPermission('Setpoints.get') ? null : (
) -} +}) + +export default Setpoints diff --git a/src/pages/TelemetryView/UserOfWells.jsx b/src/pages/Telemetry/TelemetryView/UserOfWells.jsx old mode 100644 new mode 100755 similarity index 100% rename from src/pages/TelemetryView/UserOfWells.jsx rename to src/pages/Telemetry/TelemetryView/UserOfWells.jsx diff --git a/src/pages/Telemetry/TelemetryView/WirelineRunOut.jsx b/src/pages/Telemetry/TelemetryView/WirelineRunOut.jsx new file mode 100644 index 0000000..a6fc188 --- /dev/null +++ b/src/pages/Telemetry/TelemetryView/WirelineRunOut.jsx @@ -0,0 +1,39 @@ +import { memo, useCallback, useContext, useEffect, useState } from 'react' + +import { IdWellContext } from '@asb/context' +import { WirelineView } from '@components/views' +import { invokeWebApiWrapperAsync } from '@components/factory' +import { TelemetryWirelineRunOutService } from '@api' + + +export const WirelineRunOut = memo(() => { + const [twro, setTwro] = useState({}) + const [isLoading, setIsLoading] = useState(false) + + const idWell = useContext(IdWellContext) + + const update = useCallback(() => invokeWebApiWrapperAsync( + async () => { + const twro = await TelemetryWirelineRunOutService.getData(idWell) + setTwro(twro) + }, + setIsLoading, + 'Не удалось получить данные по талевому канату' + ), [idWell]) + + const onTooltipVisibleChanged = useCallback((visible) => { + if (visible) update() + }, [update]) + + useEffect(update, [update]) + + return ( + + ) +}) + +export default WirelineRunOut diff --git a/src/pages/TelemetryView/index.jsx b/src/pages/Telemetry/TelemetryView/index.jsx old mode 100644 new mode 100755 similarity index 95% rename from src/pages/TelemetryView/index.jsx rename to src/pages/Telemetry/TelemetryView/index.jsx index 3a9f28e..2189da5 --- a/src/pages/TelemetryView/index.jsx +++ b/src/pages/Telemetry/TelemetryView/index.jsx @@ -1,5 +1,5 @@ import { Select } from 'antd' -import { useState, useEffect, useCallback } from 'react' +import { useState, useEffect, useCallback, useContext } from 'react' import { DrillFlowChartService, @@ -8,6 +8,7 @@ import { TelemetryDataSpinService, WellService } from '@api' +import { IdWellContext } from '@asb/context' import { makeDateSorter } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { Grid, GridItem, Flex } from '@components/Grid' @@ -22,6 +23,7 @@ import ActiveMessagesOnline from './ActiveMessagesOnline' import { ModeDisplay } from './ModeDisplay' import { UserOfWell } from './UserOfWells' import { Setpoints } from './Setpoints' +import WirelineRunOut from './WirelineRunOut' import MomentStabPicEnabled from '@images/DempherOn.png' import MomentStabPicDisabled from '@images/DempherOff.png' @@ -302,7 +304,7 @@ export const normalizeData = (data) => data?.map(item => ({ blockSpeed: Math.abs(item.blockSpeed) })) ?? [] -export default function TelemetryView({ idWell }) { +export default function TelemetryView() { const [dataSaub, setDataSaub] = useState([]) const [dataSpin, setDataSpin] = useState([]) const [chartInterval, setChartInterval] = useState(defaultPeriod) @@ -311,6 +313,8 @@ export default function TelemetryView({ idWell }) { const [flowChartData, setFlowChartData] = useState([]) const [rop, setRop] = useState(null) + const idWell = useContext(IdWellContext) + const handleDataSaub = useCallback((data) => { if (data) { const dataSaub = normalizeData(data) @@ -322,8 +326,11 @@ export default function TelemetryView({ idWell }) { const handleDataSpin = useCallback((data) => data && setDataSpin(data), []) useEffect(() => { - const unsubscribeSaub = Subscribe('hubs/telemetry', 'ReceiveDataSaub', `well_${idWell}`, handleDataSaub) - const unsubscribeSpin = Subscribe('hubs/telemetry', 'ReceiveDataSpin', `well_${idWell}`, handleDataSpin) + const unsubscribe = Subscribe( + 'hubs/telemetry', `well_${idWell}`, + { methodName: 'ReceiveDataSaub', handler: handleDataSaub }, + { methodName: 'ReceiveDataSpin', handler: handleDataSpin } + ) invokeWebApiWrapperAsync( async () => { const flowChart = await DrillFlowChartService.get(idWell) @@ -337,10 +344,7 @@ export default function TelemetryView({ idWell }) { `Не удалось получить данные по скважине "${idWell}"`, 'Получение данных по скважине' ) - return () => { - unsubscribeSaub() - unsubscribeSpin() - } + return unsubscribe }, [idWell, chartInterval, handleDataSpin, handleDataSaub]) useEffect(() => invokeWebApiWrapperAsync( @@ -391,8 +395,9 @@ export default function TelemetryView({ idWell }) {
- +   + {'TorqueMaster'} {'SpinMaster'}

MSE

diff --git a/src/pages/Telemetry/index.jsx b/src/pages/Telemetry/index.jsx new file mode 100755 index 0000000..8207810 --- /dev/null +++ b/src/pages/Telemetry/index.jsx @@ -0,0 +1,51 @@ +import { useParams } from 'react-router-dom' +import { memo, useContext, useMemo } from 'react' +import { Layout } from 'antd' +import { AlertOutlined, FundViewOutlined, DatabaseOutlined } from '@ant-design/icons' + +import { RootPathContext } from '@asb/context' +import { PrivateSwitch, PrivateMenu } from '@components/Private' + +import Archive from './Archive' +import Messages from './Messages' +import DashboardNNB from './DashboardNNB' +import TelemetryView from './TelemetryView' + +import '@styles/index.css' +import Operations from './Operations' + +const { Content } = Layout + +export const Telemetry = memo(() => { + const { tab } = useParams() + const root = useContext(RootPathContext) + const rootPath = useMemo(() => `${root}/telemetry`, [root]) + + return ( + + + + } title={'Мониторинг'}/> + } title={'Сообщения'} /> + } title={'Архив'} /> + + + + + + + + + + + + + + + + + + ) +}) + +export default Telemetry diff --git a/src/pages/TelemetryAnalysis/TelemetryAnalysisDepthToDay.jsx b/src/pages/TelemetryAnalysis/TelemetryAnalysisDepthToDay.jsx deleted file mode 100644 index 904b966..0000000 --- a/src/pages/TelemetryAnalysis/TelemetryAnalysisDepthToDay.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useState, useEffect, memo } from 'react' - -import { TelemetryAnalyticsService } from '@api' -import LoaderPortal from '@components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '@components/factory' -import { ChartTelemetryDepthToDay } from '@components/charts/ChartTelemetryDepthToDay' - -export const TelemetryAnalysisDepthToDay = memo(({ idWell }) => { - const [depthData, setDepthData] = useState([]) - const [bitPositionData, setBitPositionData] = useState([]) - const [loader, setLoader] = useState(false) - - useEffect(() => invokeWebApiWrapperAsync( - async () => { - const depthToDayData = await TelemetryAnalyticsService.getWellDepthToDay(idWell) - - const depths = depthToDayData.map(el => ({depth: el.wellDepth, date: el.date})) - .sort((a, b) => new Date(a.date) - new Date(b.date)) - setDepthData(depths) - - const bitPositions = depthToDayData.map(el => ({depth: el.bitDepth, date: el.date})) - .sort((a, b) => new Date(a.date) - new Date(b.date)) - setBitPositionData(bitPositions) - }, - setLoader, - `Не удалось получить данные для анализа Глубина-День по скважине "${idWell}"`, - 'Получение данных для анализа Глубина-День' - ), [idWell]) - - return ( - -
- -
-
- ) -}) - -export default TelemetryAnalysisDepthToDay diff --git a/src/pages/TelemetryAnalysis/TelemetryAnalysisDepthToInterval.jsx b/src/pages/TelemetryAnalysis/TelemetryAnalysisDepthToInterval.jsx deleted file mode 100644 index 989165f..0000000 --- a/src/pages/TelemetryAnalysis/TelemetryAnalysisDepthToInterval.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Select } from 'antd' -import { useState, useEffect, memo } from 'react' - -import { arrayOrDefault } from '@utils' -import { TelemetryAnalyticsService } from '@api' -import LoaderPortal from '@components/LoaderPortal' -import { invokeWebApiWrapperAsync } from '@components/factory' -import { ChartTelemetryDepthToInterval } from '@components/charts/ChartTelemetryDepthToInterval' - -const timePeriodCollection = [ - { value: '3600', label: '1 час' }, - { value: '21600', label: '6 часов' }, - { value: '43200', label: '12 часов' }, - { value: '86400', label: '24 часа' } -] - -export const TelemetryAnalysisDepthToInterval = memo(({ idWell }) => { - const [depthToIntervalData, setDepthToIntervalData] = useState([]) - const [chartInterval, setChartInterval] = useState(86400) - const [loader, setLoader] = useState(false) - - useEffect(() => invokeWebApiWrapperAsync( - async () => { - const depthToIntervalData = await TelemetryAnalyticsService.getWellDepthToInterval(idWell, chartInterval) - setDepthToIntervalData(arrayOrDefault(depthToIntervalData)) - }, - setLoader, - `Не удалось получить данные для анализа скорость проходки-интервал "${idWell}"`, - 'Получение данных для анализа скорость проходки-интервал' - ), [idWell, chartInterval]) - - return ( - -
-
({ borderDash, }) -export const Tvd = memo(({ idWell, title, ...other }) => { +export const Tvd = memo(({ idWell: wellId, title, ...other }) => { const [chart, setChart] = useState() const [xLabel, setXLabel] = useState('day') const [operations, setOperations] = useState({}) const [tableVisible, setTableVisible] = useState(false) const [isLoading, setIsLoading] = useState(false) + const idWellContext = useContext(IdWellContext) + const idWell = useMemo(() => wellId ?? idWellContext, [wellId, idWellContext]) + const chartRef = useRef(null) const history = useHistory() diff --git a/src/pages/WellOperations/WellDrillParams.jsx b/src/pages/WellOperations/WellDrillParams.jsx old mode 100644 new mode 100755 index 8db51b6..5a4570b --- a/src/pages/WellOperations/WellDrillParams.jsx +++ b/src/pages/WellOperations/WellDrillParams.jsx @@ -1,10 +1,12 @@ -import { useState, useEffect, useCallback, memo, useMemo } from 'react' +import { useState, useEffect, useCallback, memo, useMemo, useContext } from 'react' +import { IdWellContext } from '@asb/context' import { EditableTable, makeSelectColumn, makeActionHandler, makeNumericAvgRange, + makeNumericSorter, } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' @@ -12,17 +14,19 @@ import { DrillParamsService, WellOperationService } from '@api' import { hasPermission } from '@utils/permissions' import { arrayOrDefault } from '@utils' + export const getColumns = async (idWell) => { let sectionTypes = await WellOperationService.getSectionTypes(idWell) - sectionTypes = Object.keys(sectionTypes).map((id) => ({ - label: sectionTypes[id], - value: id, + sectionTypes = Object.entries(sectionTypes).map(([id, value]) => ({ + label: value, + value: parseInt(id), })) return [ makeSelectColumn('Конструкция секции','idWellSectionType', sectionTypes, null, { editable: true, width: 160, + sorter: makeNumericSorter('idWellSectionType'), }), makeNumericAvgRange('Нагрузка, т', 'axialLoad', 1), makeNumericAvgRange('Давление, атм', 'pressure', 1), @@ -32,11 +36,13 @@ export const getColumns = async (idWell) => { ] } -export const WellDrillParams = memo(({ idWell }) => { +export const WellDrillParams = memo(() => { const [params, setParams] = useState([]) const [showLoader, setShowLoader] = useState(false) const [columns, setColumns] = useState([]) + const idWell = useContext(IdWellContext) + const updateParams = useCallback(async () => await invokeWebApiWrapperAsync( async () => { const params = arrayOrDefault(await DrillParamsService.getAll(idWell)) diff --git a/src/pages/WellOperations/WellOperationsEditor.jsx b/src/pages/WellOperations/WellOperationsEditor.jsx old mode 100644 new mode 100755 index 033a6f0..11b0298 --- a/src/pages/WellOperations/WellOperationsEditor.jsx +++ b/src/pages/WellOperations/WellOperationsEditor.jsx @@ -1,8 +1,9 @@ import moment from 'moment' import { Input } from 'antd' import { useLocation } from 'react-router-dom' -import { useState, useEffect, memo, useMemo, useCallback } from 'react' +import { useState, useEffect, memo, useMemo, useCallback, useContext } from 'react' +import { IdWellContext } from '@asb/context' import { EditableTable, makeColumn, @@ -21,6 +22,7 @@ import { hasPermission } from '@utils/permissions' import { arrayOrDefault } from '@utils' import { WellOperationService } from '@api' + const { TextArea } = Input const basePageSize = 160 @@ -52,12 +54,14 @@ const generateColumns = (showNpt = false, categories = [], sectionTypes = []) => makeTextColumn('Комментарий', 'comment', null, null, null, { editable: true, input: