diff --git a/.dockerignore b/.dockerignore index 7c8736819..72840736e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,22 +1,28 @@ -**/.classpath -**/.dockerignore -**/.git -**/.gitignore -**/.project -**/.settings -**/.toolstarget -**/.vs -**/.vscode -**/*.*proj.user -**/*.dbmdl -**/*.jfm -**/charts -**/docker-compose* -**/compose* -**/Dockerfile* -**/node_modules -**/npm-debug.log -**/obj -**/secrets.dev.yaml -**/values.dev.yaml -README.md +# Version control and CI +.git +.github + +# Dependencies and Yarn state, reinstalled in the image +node_modules +.yarn/cache +.yarn/install-state.gz + +# Build and test output +build +coverage + +# Local environment and runtime config, never baked into the image +*.local +public/config.js + +# Not part of the build +.dockerignore +Dockerfile* +terraform +*.md + +# Editors and tools +**/.DS_Store +.idea +.vscode +.claude diff --git a/.env b/.env index b6170d570..17cdd0bec 100644 --- a/.env +++ b/.env @@ -1,6 +1,3 @@ -# add env-driven feature flags with the `REACT_APP_FF_` prefix -# example: REACT_APP_FF_MAJOR_FEATURE=true or REACT_APP_FF_EXPERIMENTAL_THING=false - REACT_APP_MAPBOX_TOKEN=pk.eyJ1IjoidmpvZWxtIiwiYSI6ImNpZ3RzNXdmeDA4cm90N2tuZzhsd3duZm0ifQ.YcHUz9BmCk2oVOsL48VgVQ REACT_APP_DAS_HOST='' REACT_APP_DAS_AUTH_TOKEN_URL=/oauth2/token/ @@ -10,8 +7,4 @@ REACT_APP_ROUTE_PREFIX=/ REACT_APP_BASE_MAP_STYLES='mapbox://styles/vjoelm/clthqjb7400z101ptatvj7s1h' REACT_APP_DEFAULT_EVENT_FILTER_FROM_DAYS=31 REACT_APP_DEFAULT_PATROL_FILTER_FROM_DAYS=1 - -# Overrides the Otus URL reported by the server, for local development REACT_APP_OTUS_URL='' - -# Feature flags diff --git a/.env.development b/.env.development index 6ddc2e652..589df2c5e 100644 --- a/.env.development +++ b/.env.development @@ -1,5 +1,2 @@ -REACT_APP_DAS_HOST='' REACT_APP_GA4_TRACKING_ID=G-1MVMZ0CMWF -REACT_APP_MOCK_EVENTS_API=false -REACT_APP_MOCK_EVENTTYPES_V2_API=false PORT=9000 diff --git a/.env.production b/.env.production index dda5aa030..dcb54eff4 100644 --- a/.env.production +++ b/.env.production @@ -1,4 +1 @@ -GENERATE_SOURCEMAP=false -REACT_APP_DAS_HOST='' -REACT_APP_ROUTE_PREFIX=/ REACT_APP_GA4_TRACKING_ID=G-B9CJEDN0BN diff --git a/.gitconfig b/.gitconfig deleted file mode 100644 index 1c8d4a7e3..000000000 --- a/.gitconfig +++ /dev/null @@ -1,2 +0,0 @@ -[core] - hooksPath = .githooks diff --git a/.gitignore b/.gitignore index ae5bd8d86..5d6b1ddf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,24 @@ -.DS_Store +# Dependencies +/node_modules -/.idea +# Yarn: keep the pinned release and its config, ignore the cache and install state /.yarn/* +!/.yarn/patches +!/.yarn/plugins +!/.yarn/releases +!/.yarn/sdks +!/.yarn/versions + +# Build and test output /build /coverage -/node_modules -/.vscode -/.idea - -public/config.js -.env.local -.env.development.local -.env.test.local -.env.production.local -.claude/settings.local.json -.idea +# Local environment and runtime config +*.local +/public/config.js -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions +# Editors and tools +.DS_Store +/.idea +/.vscode +/.claude/settings.local.json diff --git a/.stylelintrc.json b/.stylelintrc.json deleted file mode 100644 index 098e065fb..000000000 --- a/.stylelintrc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": [ - "stylelint-config-standard", - "stylelint-config-css-modules" - ], - "plugins": [ - "stylelint-scss" - ], - "rules": { - "selector-pseudo-class-no-unknown": [ - true, - { - "ignorePseudoClasses": [ - "global", - "export" - ] - } - ] - } -} diff --git a/AGENTS.md b/AGENTS.md index 8d76dedcd..431143800 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -324,7 +324,19 @@ Either way the client gets an access token, Auth0's used as is, kept in a cookie ### Otus -**Otus** is EarthRanger's field-intelligence chat agent, a separate web app rather than part of this client. The client embeds it in an iframe whose URL comes from the system status payload (`otus_settings.url`), overridden for local development by `REACT_APP_OTUS_URL`. +**Otus** is EarthRanger's field-intelligence agent: a chat where users ask operational questions about their site, such as which collars went quiet or how a patrol covered its area, and get answers drawn from the site's live data, sometimes with a map, chart, table or file. It is a separate web app with its own repository and deployment; the client only embeds it, as it does the alerts page. + +**Connection.** Each cluster runs one Otus, and the server sends its URL in the system status's `otus_settings.url` only where the `otus` preview feature is on; `REACT_APP_OTUS_URL` overrides it for local development. The client frames that URL in embedded mode and, once Otus says it is ready, hands it the site URL and the user's access token over `postMessage`, again whenever the token is renewed. Otus then reads the site as the signed-in user, never as an active profile, and never writes to it. Otus accepts being framed only by origins it allows, so an embed that stays blank is usually Otus's configuration, not this client's. + +**Conversations** belong to Otus, per user and site, so they survive a reload. Since Otus starts a sandbox per user, the frame loads on the tab's first visit, then stays alive while the user switches tabs. + +**UI** +- **Otus tab** (`/otus`): the client's own header, whose New conversation and Recent buttons it relays to the frame, above the Otus frame. On medium layouts and up the panel resizes by drag or keyboard, its width survives a reload, and the map's padding follows it. + +**Key files** +- `SideBar/OtusTab/`: the frame, the handshake, the resizing, and the header. +- `ducks/system-config/`: the Otus URL. +- `selectors/otus/`, `utils/otus.js`: the panel width and its bounds. ### App Chrome @@ -342,7 +354,7 @@ The map fills the screen, framed by a top bar, a sidebar and a global menu. On s | **Patrols** | `PATROL_MANAGEMENT` flag + patrol read permission | | **Gear** | the site has gear | | **Map Layers** | `ANALYZERS`, `SPATIAL_FEATURES`, `SUBJECTS` or `EVENTS` flag | -| **Otus** | an Otus URL in the system status payload, which the server sends only where the `otus` preview feature is on | +| **Otus** | an Otus URL; see Otus | | **Settings** | always | **Map Layers** has Subjects, Features, Analyzers and Events sub-tabs, each behind its own flag; the first three share one search. Events shows or hides events on the map and toggles their heatmap. What a user hides survives a reload only if they chose to restore map layers in Settings → General. @@ -397,7 +409,7 @@ All application source is `.js`, including JSX — Vite compiles every source `. ### Routing -The app is mounted under `REACT_APP_ROUTE_PREFIX`. `constants/routes.js` holds the top-level routes: login, EULA and community sit above the shell, and everything else falls through to the authenticated app. Inside it, `SideBar/` routes each tab by its `TAB_KEYS` segment (`events`, `patrols`, `gear`, `layers`, `settings`), and the Events and Patrols managers nest their own routes. Elsewhere, read the tab and item from the URL with `getCurrentTabFromURL` / `getCurrentIdFromURL` in `utils/navigation.js`. +The app is mounted under `REACT_APP_ROUTE_PREFIX`. `constants/routes.js` holds the top-level routes: login, EULA and community sit above the shell, and everything else falls through to the authenticated app. Inside it, `SideBar/` routes each tab by its `TAB_KEYS` segment (`events`, `patrols`, `gear`, `layers`, `otus`, `settings`), and the Events and Patrols managers nest their own routes. Elsewhere, read the tab and item from the URL with `getCurrentTabFromURL` / `getCurrentIdFromURL` in `utils/navigation.js`. Navigate with the app's `hooks/useNavigate`, not React Router's, so a form with unsaved changes can prompt before the user leaves. @@ -453,7 +465,7 @@ The repository favors code that reads the same everywhere. ESLint and Stylelint Group imports into blocks separated by a blank line, in this order: -1. External packages, `React` first. +1. External packages, `react` first. 2. SVG icons: `import { ReactComponent as CalendarIcon } from '../common/images/icons/calendar.svg';` 3. Internal non-components: constants, ducks, selectors, hooks, utils, and the module's own `./utils` helpers. 4. Components: app components, subcomponents, and lazily imported ones. @@ -516,7 +528,7 @@ Function parameters follow the call's own logic, not the alphabet. - Component-specific styles go in a co-located `styles.module.scss`; global partials live in `src/common/styles/`; a subtree that repeats a pattern across its components keeps its own `_shared.scss` of mixins at its root. - Pull colors, layout breakpoints and mixins from those partials with `@use`; never hard-code a value that already exists as a variable. -- Class names in camelCase, naming the element's role inside the component rather than how it looks: `.menuItemOption`, `.legTableWrapper`, `.titleBarMain`. +- Class names name the element's role inside the component rather than how it looks: `.menuItemOption`, `.legTableWrapper`, `.titleBarMain`. - Nest selectors to mirror the component's own DOM structure; keep media queries at the end of the block they modify. - Sizes, spacing and radii in `rem`. `px` is for hairlines only — borders, outlines and shadows. - Derive a hover, active or disabled shade from the variable with `color.adjust`; never introduce a second hex for it. @@ -538,7 +550,7 @@ Comment only what the code cannot say — a non-obvious *why*, a caveat, an exte - **One line, one reason.** Take a second line only when the first cannot carry the reason, never a third, and cut any sentence that argues the same point again. `//` only, each line at most 80 columns, however wide the code nearby. - **Directly above the line it explains**, as a full sentence ending in a period. A comment above a function is for a caveat that governs the whole of it, never a summary of what it does — if a function needs that summary, its name is wrong or it is doing too much. -- An `eslint-disable` line always carries the reason it is there. +- An `eslint-disable` or `stylelint-disable` line always carries the reason it is there. - A `TODO` is only for a blocker outside this repository, and says what it is waiting on. Otherwise, never leave working notes behind: no narrating the change (`// now using X instead of Y`, `// this fixes the bug`), no ticket numbers, no references to plans or conversations that exist only on your machine. The diff and the commit message are for that. - None at all in `styles.module.scss` or test files, even for the subtle case. Test intent goes in the `describe` / `test` names: rename or split instead. Why production code is surprising belongs in the production file. @@ -570,8 +582,7 @@ Comment only what the code cannot say — a non-obvious *why*, a caveat, an exte - `yarn start`: Vite dev server on port 9000, against the development backend at https://root.dev.pamdas.org. Each developer configures it in `.env.development`. - `yarn build`: production bundle, then the service worker - `yarn test `: Jest. It pins `TZ=UTC`; a bare `jest` invocation will fail datetime tests on any other machine timezone. -- `yarn lint`: ESLint over all of `src`, which carries pre-existing problems. To see only yours, run `npx eslint` on the files you touched. -- `yarn stylelint`: Stylelint over the SCSS modules +- `yarn format`: ESLint, then Stylelint, with fixes, over the whole repository. - `yarn check-i18n-files-version`: verifies the translation cache version was bumped ### Scope @@ -595,7 +606,7 @@ Before you call the work done, reread what you wrote — every changed hunk, not ### Before You Commit -- Run `yarn lint`, and `yarn stylelint` if you touched SCSS. Fix every problem you introduced. +- Run `yarn format`, and fix every problem you introduced. - Run `yarn test` over the areas you changed and make sure they pass. - If you changed anything under `public/locales/`, bump `I18N_FILES_VERSION` in `src/i18n.js` above develop's and verify with `yarn check-i18n-files-version`. - Update this file only under the terms in **Maintaining This File**. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 15ce4a2b8..64592540a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,8 +48,8 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue] * Contributions to EarthRanger require documentation and test coverage. * Documentation can be in the form of self-describing code, with comments, or proposal documents included in the pull request. * Project-wide test coverage should never regress as the result of a contribution, only maintain or increase overall coverage. -* Our codebase enforces code styles driven by ESLint, which generally follow best practices as per the Airbnb JavaScript code style guidelines and React best practices. - * You can try running `npm run lint` to analyze and fix your code styles as necessary. +* Our codebase enforces code styles driven by ESLint and Stylelint, which generally follow their recommended rules and React best practices. + * You can try running `yarn format` to analyze and fix your code styles as necessary. * The ultimate assessment of code standards is at the discretion of the EarthRanger team. diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index 997c6bd40..000000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,8 +0,0 @@ -# check=skip=InvalidDefaultArgInFrom -ARG NODE_VERSION -FROM node:${NODE_VERSION}-alpine -COPY . /app -WORKDIR /app -RUN yarn install --immutable -EXPOSE 9000 -CMD ["yarn", "start"] diff --git a/Dockerfile.test b/Dockerfile.test deleted file mode 100644 index fbacdd0c7..000000000 --- a/Dockerfile.test +++ /dev/null @@ -1,7 +0,0 @@ -# check=skip=InvalidDefaultArgInFrom -ARG NODE_VERSION -FROM node:${NODE_VERSION}-alpine -COPY . /app -WORKDIR /app -RUN yarn install --immutable -CMD ["yarn", "test"] diff --git a/README.md b/README.md index 108e8be0f..d3e6ffa82 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ Base element styles, such as fonts and headings, are in `src/index.scss`. #### Public assets -Files in `public/`, such as `favicon.ico`, `manifest.json`, the translation files and `config.js`, are served as they are from the site's root. +Files in `public/`, such as the app icons, `manifest.json`, the translation files and `config.js`, are served as they are from the site's root. #### SVG icons @@ -443,22 +443,22 @@ yarn test #### Tools -- **[ESLint](https://eslint.org/):** JavaScript linting, with the recommended rules of `@eslint/js`, `eslint-plugin-react`, `eslint-plugin-react-hooks` and, for tests, `eslint-plugin-jest`. Configured in `eslint.config.js`. -- **[Stylelint](https://stylelint.io/):** SCSS linting, with `stylelint-config-standard`, `stylelint-config-css-modules` and `stylelint-scss`. Configured in `.stylelintrc.json`. +- **[ESLint](https://eslint.org/):** JavaScript linting, with the recommended rules of `@eslint/js`, `eslint-plugin-react`, `eslint-plugin-react-hooks` and, for tests, `eslint-plugin-jest`. Configured in `eslint.config.mjs`. +- **[Stylelint](https://stylelint.io/):** SCSS linting, with `stylelint-config-standard-scss` and `stylelint-config-css-modules`, and camelCase class names. Configured in `stylelint.config.mjs`. #### Commands -- Lint the JavaScript and the SCSS: +- Lint and fix all files: ```bash -yarn lint -yarn stylelint +yarn format ``` - Lint and fix only the files you touched: ```bash npx eslint --fix +npx stylelint --fix ``` ### VS Code Extensions diff --git a/VERSION b/VERSION deleted file mode 100644 index d00491fd7..000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index a75a9b52e..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,43 +0,0 @@ -services: - web: - build: - context: . - dockerfile: Dockerfile.dev - args: - NODE_VERSION: ${NODE_VERSION:?NODE_VERSION must be set (e.g. export NODE_VERSION=$(cat .node-version))} - volumes: - - .:/app - restart: on-failure - # mock_api: - # build: - # context: ./mock-api - # dockerfile: Dockerfile.dev - # args: - # NODE_VERSION: ${NODE_VERSION:?NODE_VERSION must be set (e.g. export NODE_VERSION=$(cat .node-version))} - # volumes: - # - /app/node_modules - # - ./mock-api:/app - # web_test: - # build: - # context: . - # dockerfile: Dockerfile.dev - # args: - # NODE_VERSION: ${NODE_VERSION:?NODE_VERSION must be set (e.g. export NODE_VERSION=$(cat .node-version))} - # volumes: - # - /app/node_modules - # - .:/app - # # environment: - # # - CI=true - # command: yarn test - # restart: on-failure - nginx: - build: - context: ./nginx - dockerfile: Dockerfile.dev - restart: always - depends_on: - - "web" - # - "mock_api" - ports: - - '9000:80' - - '35729:35729' \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 0534e090b..000000000 --- a/eslint.config.js +++ /dev/null @@ -1,117 +0,0 @@ -import { defineConfig, globalIgnores } from 'eslint/config'; -import globals from 'globals'; -import jest from 'eslint-plugin-jest'; -import js from '@eslint/js'; -import react from 'eslint-plugin-react'; -import reactHooks from 'eslint-plugin-react-hooks'; - -export default defineConfig([ - globalIgnores([ - '.github/', - '.yarn/', - 'build/', - 'jest-config/', - 'mock-api/', - 'nginx/', - 'node_modules/', - 'public/', - 'terraform/', - ]), - - { - name: 'src/javascript', - files: ['**/*.{js,jsx}'], - extends: [ - js.configs.recommended, - react.configs.flat.recommended, - react.configs.flat['jsx-runtime'], - reactHooks.configs.flat.recommended, - ], - languageOptions: { - ecmaVersion: 'latest', - globals: { - ...globals.browser, - ...globals.node, - }, - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - sourceType: 'module', - }, - settings: { - react: { - // `version: "detect"` still uses APIs removed in ESLint 10. - version: '19.2.5', - }, - }, - rules: { - 'keyword-spacing': [ - 'error', - { before: true, after: true }, - ], - 'comma-spacing': [ - 'error', - { before: false, after: true }, - ], - 'arrow-spacing': [ - 'error', - { before: true, after: true }, - ], - 'key-spacing': [ - 'error', - { afterColon: true }, - ], - 'object-curly-spacing': ['error', 'always'], - indent: [ - 'error', - 2, - { ignoredNodes: ['TemplateLiteral', 'JSXElement *'] }, - ], - 'template-curly-spacing': 'off', - 'react/jsx-indent': [ - 'error', - 2, - ], - 'linebreak-style': [ - 'error', - 'unix', - ], - quotes: [ - 'error', - 'single', - ], - semi: [ - 'error', - 'always', - ], - 'react/prop-types': 'off', - strict: 'off', - 'max-len': 'off', - 'no-trailing-spaces': [ - 'error', - { ignoreComments: true }, - ], - 'no-prototype-builtins': 'off', - 'no-underscore-dangle': 'off', - 'no-unused-vars': [ - 'warn', - { - argsIgnorePattern: '^_', - caughtErrorsIgnorePattern: '^_', - varsIgnorePattern: 'React|^_', - }, - ], - camelcase: 'off', - 'func-names': 'off', - 'react/no-this-in-sfc': 'off', - }, - }, - - { - name: 'src/jest', - files: ['**/*.test.{js,jsx}', '**/setupTests.js', '**/src/__test-helpers/**/*.js'], - extends: [jest.configs['flat/recommended']], - }, -]); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..8026614f4 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,76 @@ +import { defineConfig, globalIgnores } from 'eslint/config'; +import globals from 'globals'; +import jest from 'eslint-plugin-jest'; +import js from '@eslint/js'; +import react from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; + +export default defineConfig([ + globalIgnores([ + '.claude/', + '.yarn/', + 'build/', + 'coverage/', + 'jest-config/', + 'public/', + ]), + + { + extends: [ + js.configs.recommended, + react.configs.flat.recommended, + react.configs.flat['jsx-runtime'], + reactHooks.configs.flat.recommended, + ], + files: ['**/*.{js,jsx,mjs}'], + languageOptions: { + globals: globals.browser, + }, + name: 'javascript', + rules: { + 'no-unused-vars': [ + 'warn', + { + argsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + 'react/prop-types': 'off', + }, + settings: { + react: { + // `version: "detect"` still uses APIs removed in ESLint 10. + version: '19.3.0', + }, + }, + }, + + { + files: ['*.{js,mjs}', 'src/sw-build.js'], + languageOptions: { + globals: globals.node, + }, + name: 'node', + }, + + { + files: ['src/sw-custom.js'], + languageOptions: { + globals: { + ...globals.serviceworker, + workbox: 'readonly', + }, + }, + name: 'service-worker', + }, + + { + extends: [jest.configs['flat/recommended']], + files: ['**/*.test.{js,jsx}', 'src/setupTests.js', 'src/__test-helpers/**'], + languageOptions: { + globals: globals.node, + }, + name: 'jest', + }, +]); diff --git a/index.html b/index.html index f27db7802..c5922c1d5 100644 --- a/index.html +++ b/index.html @@ -3,13 +3,15 @@ - - + + - + + + EarthRanger @@ -19,7 +21,7 @@
- + diff --git a/mock-api/.dockerignore b/mock-api/.dockerignore deleted file mode 100644 index 3c3629e64..000000000 --- a/mock-api/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/mock-api/.gitignore b/mock-api/.gitignore deleted file mode 100644 index 069e07f96..000000000 --- a/mock-api/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.DS_Store - -/.yarn/* -/node_modules - -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions diff --git a/mock-api/Dockerfile.dev b/mock-api/Dockerfile.dev deleted file mode 100644 index bab458ecd..000000000 --- a/mock-api/Dockerfile.dev +++ /dev/null @@ -1,16 +0,0 @@ -# check=skip=InvalidDefaultArgInFrom -ARG NODE_VERSION -FROM node:${NODE_VERSION}-alpine -WORKDIR /app - -RUN yarn global add nodemon - -COPY package.json . -COPY yarn.lock . -RUN yarn --ignore-scripts - -COPY . . - -EXPOSE 8080 - -CMD ["nodemon", "app.js"] diff --git a/mock-api/api/v1.0/activity/events/index.js b/mock-api/api/v1.0/activity/events/index.js deleted file mode 100644 index 9b6a37e31..000000000 --- a/mock-api/api/v1.0/activity/events/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const express = require('express'); - -const { generateEvent } = require('./utils'); - -const events = express.Router(); - -events.get('/', (_, res) => { - res.json({ - data: { - results: Array.from({ length: 25 }, generateEvent), - next: null, - count: 25, - }, - }); -}); - -module.exports = events; diff --git a/mock-api/api/v1.0/activity/events/utils.js b/mock-api/api/v1.0/activity/events/utils.js deleted file mode 100644 index b229721e8..000000000 --- a/mock-api/api/v1.0/activity/events/utils.js +++ /dev/null @@ -1,104 +0,0 @@ -const { faker } = require('@faker-js/faker'); -const { featureCollection, polygon, rewind } = require('@turf/turf'); - -const generateArrayofCoordinatePairs = (length = 5) => { - const baseLat = Number.parseFloat(faker.location.latitude()) / 2; - const baseLon = Number.parseFloat(faker.location.longitude()) / 2; - - const getRandomBetweenMinusOneAndOne = () => Math.random() * (Math.random() > 0.5 ? 1 : -1); - - return Array.from({ length }, () => - [baseLon + getRandomBetweenMinusOneAndOne(), baseLat + getRandomBetweenMinusOneAndOne()] - ); -}; - -const createPolygonFeatureCollection = () => { - const numberOfPolygons = 1; // change this to randomInteger() when you want to support multi-feature featurecollections for the geometry prop - - const polygonCoordinateSets = Array.from({ length: numberOfPolygons }, () => { - let coordinates = generateArrayofCoordinatePairs(faker.number.int({ max: 8, min: 4 })); - coordinates = [[...coordinates, coordinates[0]]]; /* close the polygon by adding a final point identical to the first */ - - return coordinates; - }); - - return createFeatureCollectionOfGeometryTypeFromCoords(polygonCoordinateSets); -}; - -const createFeatureCollectionOfGeometryTypeFromCoords = (arrayOfCoords = [], geometryType = polygon) => - featureCollection( - arrayOfCoords.map(coords => - rewind( - geometryType(coords, { datetime: new Date().toISOString() }) - ) - ) - ); - -const geometryOptions = [createPolygonFeatureCollection, null]; -const priorityOptions = [ - { value: 0, label: 'Gray' }, - { value: 100, label: 'Green' }, - { value: 200, label: 'Amber' }, - { value: 300, label: 'Red' }, -]; - -const generateEvent = (override) => { - const geometry = faker.helpers.arrayElement(geometryOptions)?.(); - - const location = !!geometry ? null : { - latitude: Number.parseFloat(faker.location.latitude()), - longitude: Number.parseFloat(faker.location.longitude()), - }; - - const priority = faker.helpers.arrayElement(priorityOptions); - const timestamp = faker.date.recent(); - const id = faker.string.uuid(); - - return { - id, - is_collection: false, - geometry, - location, - time: timestamp, - serial_number: faker.number.int(), - message: '', - provenance: '', - ...override, - event_type: 'carcass_rep', - priority: priority.value, - priority_label: priority.label, - attributes: {}, - comment: null, - title: faker.lorem.words(3), - notes: [], - reported_by: null, - state: 'active', - contains: [], - is_linked_to: [], - is_contained_in: [], - sort_at: timestamp, - geojson: location ? { - type: 'Feature', - geometry: { - type: 'Point', - coordinates: [location.longitude, location.latitude], - }, - properties: { - image: null, - }, - } : geometry, - patrol_segments: [], - updated_at: timestamp, - created_at: timestamp, - icon_id: 'silence_source_rep', - event_details: {}, - files: [], - event_category: 'analyzer_event', - url: `/api/v1.0/activity/event/${id}`, - image_url: 'https://develop.pamdas.org/static/generic-gray.svg', - patrols: [], - updates: [], - }; -}; - -module.exports = { generateEvent }; diff --git a/mock-api/api/v1.0/activity/eventtypes/index.js b/mock-api/api/v1.0/activity/eventtypes/index.js deleted file mode 100644 index 9ac4e4e61..000000000 --- a/mock-api/api/v1.0/activity/eventtypes/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const express = require('express'); - -const eventtypes = express.Router(); - -eventtypes.get('/:eventTypeValue/schema', (_, res) => { - res.json({ data: {} }); -}); - -module.exports = eventtypes; diff --git a/mock-api/api/v1.0/index.js b/mock-api/api/v1.0/index.js deleted file mode 100644 index 0eccf2a49..000000000 --- a/mock-api/api/v1.0/index.js +++ /dev/null @@ -1,11 +0,0 @@ -const express = require('express'); - -const events = require('./activity/events'); -const eventtypes = require('./activity/eventtypes'); - -const apiv1 = express.Router(); - -apiv1.use('/activity/events', events); -apiv1.use('/activity/eventtypes', eventtypes); - -module.exports = apiv1; diff --git a/mock-api/api/v2.0/activity/eventtypes/fixtures.js b/mock-api/api/v2.0/activity/eventtypes/fixtures.js deleted file mode 100644 index 543377b99..000000000 --- a/mock-api/api/v2.0/activity/eventtypes/fixtures.js +++ /dev/null @@ -1,309 +0,0 @@ -const eventtypesFixture = { - data: [ - { - id: '29736bf4-c1eb-4cb7-bdb2-3b6464108517', - has_events_assigned: true, - icon: 'animal_control_rep', - value: 'animal_control_v2', - display: 'Animal Control v2', - ordernum: 1, - is_collection: false, - category: 'security', - icon_id: 'animal_control_rep', - is_active: true, - default_priority: 0, - default_state: 'active', - geometry_type: 'Point', - resolve_time: null, - auto_resolve: false, - url: 'https://stage.pamdas.org/api/v2.0/activity/eventtypes/animal_control_v2', - }, - { - id: 'bbd64930-a029-4d89-98f2-f94e269f8fe6', - has_events_assigned: true, - icon: 'fire_rep', - value: 'fire_v2', - display: 'Fire v2', - ordernum: 2, - is_collection: false, - category: 'monitoring', - icon_id: 'fire_rep', - is_active: true, - default_priority: 300, - default_state: 'active', - geometry_type: 'Polygon', - resolve_time: null, - auto_resolve: false, - url: 'https://stage.pamdas.org/api/v2.0/activity/eventtypes/fire_v2', - }, - { - id: '551d9203-a74c-4107-b727-681cc10c6f3e', - has_events_assigned: false, - icon: 'light_rep', - value: 'light_v2', - display: 'Light v2', - ordernum: 3, - is_collection: false, - category: 'security', - icon_id: 'light_rep', - is_active: true, - default_priority: 100, - default_state: 'active', - geometry_type: 'Point', - resolve_time: 2, - auto_resolve: true, - url: 'https://stage.pamdas.org/api/v2.0/activity/eventtypes/light_v2', - }, - ], - status: { - code: 200, - message: 'OK', - }, -}; - -const eventtypeSchemaFixtures = { - animal_control_v2: { - json: { - $schema: 'https://json-schema.org/draft/2020-12/schema', - properties: { - number_of_shots_fired: { - deprecated: false, - description: '', - title: 'Number of Shots Fired', - type: 'number', - }, - animal_species: { - default: '', - deprecated: false, - description: '', - title: 'Animal Species', - type: 'string', - }, - number_of_animals: { - deprecated: false, - description: '', - minimum: 1, - title: 'Number of Animals', - type: 'number', - }, - reason_animal_control_needed: { - default: '', - deprecated: false, - description: 'Brief description of the decision', - title: 'Reason Animal Control Needed', - type: 'string', - }, - }, - required: ['animal_species', 'number_of_animals'], - type: 'object', - unevaluatedProperties: false, - }, - ui: { - fields: { - number_of_shots_fired: { - placeholder: '', - type: 'NUMERIC', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - animal_species: { - inputType: 'SHORT_TEXT', - placeholder: 'Rhino', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - number_of_animals: { - placeholder: '', - type: 'NUMERIC', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - reason_animal_control_needed: { - inputType: 'LONG_TEXT', - placeholder: '', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - }, - headers: {}, - order: ['section-9ytDR-VkTZeTXwgT08_65'], - sections: { - 'section-9ytDR-VkTZeTXwgT08_65': { - columns: 2, - isActive: true, - label: '', - leftColumn: [ - { name: 'animal_species', type: 'field' }, - { name: 'reason_animal_control_needed', type: 'field' }, - ], - rightColumn: [ - { name: 'number_of_animals', type: 'field' }, - { name: 'number_of_shots_fired', type: 'field' }, - ], - }, - }, - }, - }, - fire_v2: { - json: { - $schema: 'https://json-schema.org/draft/2020-12/schema', - properties: { - direction_fire_is_moving: { - default: '', - deprecated: false, - description: '', - title: 'Direction Fire is Moving', - type: 'string', - }, - status: { - default: 'Active', - deprecated: false, - description: '', - title: 'Status', - type: 'string', - }, - cause: { - default: '', - deprecated: false, - description: 'Probable cause of the fire', - title: 'Cause', - type: 'string', - }, - }, - required: ['direction_fire_is_moving', 'status'], - type: 'object', - unevaluatedProperties: false, - }, - ui: { - fields: { - direction_fire_is_moving: { - inputType: 'SHORT_TEXT', - placeholder: 'Norht, East, South, West...', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - status: { - inputType: 'SHORT_TEXT', - placeholder: 'Active, Inactive', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - cause: { - inputType: 'LONG_TEXT', - placeholder: '', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - }, - headers: {}, - order: ['section-9ytDR-VkTZeTXwgT08_65'], - sections: { - 'section-9ytDR-VkTZeTXwgT08_65': { - columns: 2, - isActive: true, - label: '', - leftColumn: [ - { name: 'status', type: 'field' }, - { name: 'direction_fire_is_moving', type: 'field' }, - ], - rightColumn: [{ name: 'cause', type: 'field' }], - }, - }, - }, - }, - light_v2: { - json: { - $schema: 'https://json-schema.org/draft/2020-12/schema', - properties: { - what_was_detected: { - default: '', - deprecated: false, - description: '', - title: 'What was detected', - type: 'string', - }, - bearing: { - deprecated: false, - description: '0-360', - maximum: 360, - minimum: 0, - title: 'Bearing', - type: 'number', - }, - distance: { - deprecated: false, - description: 'In meters', - title: 'Distance', - type: 'number', - }, - description_of_activity: { - default: '', - deprecated: false, - description: '', - title: 'Description of activity', - type: 'string', - }, - 'patrols_response_/_intent': { - default: '', - deprecated: false, - description: '', - title: 'Patrols response / intent', - type: 'string', - }, - }, - required: ['what_was_detected'], - type: 'object', - unevaluatedProperties: false, - }, - ui: { - fields: { - what_was_detected: { - inputType: 'SHORT_TEXT', - placeholder: 'Camp fire, smoke, torch...', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - bearing: { - placeholder: '', - type: 'NUMERIC', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - distance: { - placeholder: '', - type: 'NUMERIC', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - description_of_activity: { - inputType: 'LONG_TEXT', - placeholder: '', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - 'patrols_response_/_intent': { - inputType: 'SHORT_TEXT', - placeholder: '', - type: 'TEXT', - parent: 'section-9ytDR-VkTZeTXwgT08_65', - }, - }, - headers: {}, - order: ['section-9ytDR-VkTZeTXwgT08_65'], - sections: { - 'section-9ytDR-VkTZeTXwgT08_65': { - columns: 2, - isActive: true, - label: '', - leftColumn: [ - { name: 'what_was_detected', type: 'field' }, - { name: 'distance', type: 'field' }, - { name: 'patrols_response_/_intent', type: 'field' }, - ], - rightColumn: [ - { name: 'bearing', type: 'field' }, - { name: 'description_of_activity', type: 'field' }, - ], - }, - }, - }, - }, -}; - -module.exports = { eventtypesFixture, eventtypeSchemaFixtures }; diff --git a/mock-api/api/v2.0/activity/eventtypes/index.js b/mock-api/api/v2.0/activity/eventtypes/index.js deleted file mode 100644 index b249bd6d0..000000000 --- a/mock-api/api/v2.0/activity/eventtypes/index.js +++ /dev/null @@ -1,19 +0,0 @@ -const express = require('express'); - -const { eventtypesFixture, eventtypeSchemaFixtures } = require('./fixtures'); - -const eventtypes = express.Router(); - -eventtypes.get('/', (_, res) => { - res.json(eventtypesFixture); -}); - -eventtypes.get('/:eventTypeValue/schema', (req, res) => { - if (eventtypeSchemaFixtures[req.params.eventTypeValue]) { - res.json(eventtypeSchemaFixtures[req.params.eventTypeValue]); - } else { - res.sendStatus(404); - } -}); - -module.exports = eventtypes; diff --git a/mock-api/api/v2.0/index.js b/mock-api/api/v2.0/index.js deleted file mode 100644 index ce4478ab7..000000000 --- a/mock-api/api/v2.0/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const express = require('express'); - -const eventtypes = require('./activity/eventtypes'); - -const apiV2 = express.Router(); - -apiV2.use('/activity/eventtypes', eventtypes); - -module.exports = apiV2; diff --git a/mock-api/app.js b/mock-api/app.js deleted file mode 100644 index 26fcceb45..000000000 --- a/mock-api/app.js +++ /dev/null @@ -1,16 +0,0 @@ -const express = require('express'); - -const apiV1 = require('./api/v1.0'); -const apiV2 = require('./api/v2.0'); - -const HOST = '0.0.0.0'; -const PORT = 8080; - -const app = express(); - -app.use('/api/v1.0', apiV1); -app.use('/api/v2.0', apiV2); - -app.listen(PORT, HOST, () => { - console.log(`Mock API listening on ${HOST}:${PORT}`); -}); diff --git a/mock-api/package.json b/mock-api/package.json deleted file mode 100644 index 42e9fb2bd..000000000 --- a/mock-api/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "mock-api", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "nodemon app.js" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@faker-js/faker": "^10.6.0", - "@turf/turf": "^7.4.0", - "express": "^5.2.1", - "nodemon": "^3.1.14" - } -} diff --git a/mock-api/yarn.lock b/mock-api/yarn.lock deleted file mode 100644 index b5bcf0fcd..000000000 --- a/mock-api/yarn.lock +++ /dev/null @@ -1,3062 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 10 - cacheKey: 10c0 - -"@faker-js/faker@npm:^10.6.0": - version: 10.6.0 - resolution: "@faker-js/faker@npm:10.6.0" - checksum: 10c0/ee285d597249a019f3a11b6705d1908616ea9e880207ca4f89e6205dbf7e98abd1129f025f5da19484f5e88f556b0629a4363745ff0bbaf1984ebf54cffde6e3 - languageName: node - linkType: hard - -"@isaacs/fs-minipass@npm:^4.0.0": - version: 4.0.1 - resolution: "@isaacs/fs-minipass@npm:4.0.1" - dependencies: - minipass: "npm:^7.0.4" - checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 - languageName: node - linkType: hard - -"@turf/along@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/along@npm:7.4.0" - dependencies: - "@turf/bearing": "npm:7.4.0" - "@turf/destination": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/2ee79998a6208ac58ce5d24ce6834589d1cdd9bd39e396819fadee1ccb9b5e60f377b0061af71adfc99df39802688a83874c7151fac41e3eb0245796f01e7746 - languageName: node - linkType: hard - -"@turf/angle@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/angle@npm:7.4.0" - dependencies: - "@turf/bearing": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/rhumb-bearing": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/125d85e3506cbb5d8de8d5ae8a21fd3d002112d97f6ca27ac374b1bd132e0966310b482332bdbd32aff6ba1fc7a49a000f1492e147aa366c511ee8d975dde73b - languageName: node - linkType: hard - -"@turf/area@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/area@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/528205051e01f9c87935f79955e660126da6d63958c8340f39573ecf5d88c1394f3c8b02e29d86bda0036ce57f7ab4d27e4409c14ad504db8938a82b1b801e73 - languageName: node - linkType: hard - -"@turf/bbox-clip@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/bbox-clip@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/2abd3cebde4ec173f0851aa6d854aef91bf1968f5058fec7064e84774adf7121b452752e7ed4794db19493f0d81824fc0f765be93db85b85fa47726d2971b945 - languageName: node - linkType: hard - -"@turf/bbox-polygon@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/bbox-polygon@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/fa20421ef2bc81ef8b8aef8fd14a466e771b2c9b0113dfc770d1e1c74824178ad5af41d7683b2a141863b04407dbca062460562bafe985fc2bac80ce560142ed - languageName: node - linkType: hard - -"@turf/bbox@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/bbox@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/3828964cf0d7269a2e63a427420d8ad97237f82389157deaac50e660301ab354178cb2d96a6aa3ce2399ab60d11298a420dbda15a74d1bc21ebfbec0e4aa5793 - languageName: node - linkType: hard - -"@turf/bearing@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/bearing@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/9c1a25f7f492e039fa9fc9f563210f3c2442594a848cacc35e39e180f7221fc7777a5d22946720afb2d1707890fb69d81547130c5e8f78b626e0fa8b5ce8c007 - languageName: node - linkType: hard - -"@turf/bezier-spline@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/bezier-spline@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/6218899a1d5d18f19084aee0a533c0c6791b9f3a89d9bfcb7315542113188183ea3b602851fff12661c389c737248bfb1dd3caec78ab6e68284f4f647080d79a - languageName: node - linkType: hard - -"@turf/boolean-clockwise@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-clockwise@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/8279d21980c5686602ffd7ce9d2619b8884c74b5b041be328c56366d30fa8ee58b39377774e65666e21a6abb2945053da751508d6df9101ce30dbd3b4c94c0f8 - languageName: node - linkType: hard - -"@turf/boolean-concave@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-concave@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/fd476626597c63c9d4211f4b6201d7dd028b0ab6af1fb64d4338af3f05ce22d4885bc53b30b33a884a5b0f97469f7666947e772df88d4352a16b6fccbab94be6 - languageName: node - linkType: hard - -"@turf/boolean-contains@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-contains@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/boolean-point-on-line": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-split": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/2fa6633e5ff8c0cee2e6293eb83507f0d47cae96ba36d2f6a6b46967af0dda9f021e6dfd9d68d154b0cd03e6c4852577e6a28ebfd1de6bbb8ea1638fd46c22b7 - languageName: node - linkType: hard - -"@turf/boolean-crosses@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-crosses@npm:7.4.0" - dependencies: - "@turf/boolean-equal": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-intersect": "npm:7.4.0" - "@turf/polygon-to-line": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/c438a21ace6aad944ea37bab952bc3844c12fe7a32faf632196632546e61e38818fc0bb92a1629ae436d742701ab0fc9e467dcb97200661a8f9c5b07efa28d2c - languageName: node - linkType: hard - -"@turf/boolean-disjoint@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-disjoint@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/line-intersect": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/polygon-to-line": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/fe52efd592fa8756c5428c005a9a4e81f531f7b1b9014184db117e11b396f8da940424cdcf4cb4a771238263d14ea477c45543408c3e880d71b670e46036d68f - languageName: node - linkType: hard - -"@turf/boolean-equal@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-equal@npm:7.4.0" - dependencies: - "@turf/clean-coords": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - geojson-equality-ts: "npm:^1.0.2" - tslib: "npm:^2.8.1" - checksum: 10c0/afda26b4025bac9c9bbca8389f085faa224775e09891341175c5fc62d970665ff0985eb6fcc9673ad999e58e719095c21350771e12c551352b451c70a5c794de - languageName: node - linkType: hard - -"@turf/boolean-intersects@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-intersects@npm:7.4.0" - dependencies: - "@turf/boolean-disjoint": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/699e54f4b397c8f5a6874ac84c98861483f163937cd9b24cff1dc12f30303f1caf5f6d7c3c21e82b008318079cb3bbe99e86fc07a11fd14c29686bb5b9b6852c - languageName: node - linkType: hard - -"@turf/boolean-overlap@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-overlap@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-intersect": "npm:7.4.0" - "@turf/line-overlap": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - geojson-equality-ts: "npm:^1.0.2" - tslib: "npm:^2.8.1" - checksum: 10c0/0abb26cf794e534f4e9e3400a147ada0dea30d357646acf8bcbb15216444caca1c6f1bcbce2ce925deb1ffdf1b0cbe0f51c8e56675fcbbc7c7e5ab6267285b27 - languageName: node - linkType: hard - -"@turf/boolean-parallel@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-parallel@npm:7.4.0" - dependencies: - "@turf/clean-coords": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/line-segment": "npm:7.4.0" - "@turf/rhumb-bearing": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/adba3ee86d629e5fcaee8bed12e19f98fa659f283cb5c589eba88a2ea70c821bf5b86ab8c46fc3ba79c2f865b5caa58ea33a7423318064cce7f9ac29d2544367 - languageName: node - linkType: hard - -"@turf/boolean-point-in-polygon@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-point-in-polygon@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - point-in-polygon-hao: "npm:^1.1.0" - tslib: "npm:^2.8.1" - checksum: 10c0/c4d92534d6e2de4602a6507bf35626a2fc825bb0edb7643908978d98069a14aee1e9cce41812a0575fc08039716b2c74def3bb6f530121f54d86fc2062964b84 - languageName: node - linkType: hard - -"@turf/boolean-point-on-line@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-point-on-line@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/7cb6b6c70e3cea967eccdcb7cfa4c38b0f66450630665e7cc8906ee1f4eb8cfc58ba804d88b5b8768de630ce6059870ee29b6e109e900afd2b88a95984d9e8bd - languageName: node - linkType: hard - -"@turf/boolean-touches@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-touches@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/boolean-point-on-line": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/5f92f92d3547b9fe063cfeebf4b17d3c6a10d83a327b47ca0c402997fdea8964d3bc0b6843a2cd1f9c92133e08848a566713f5a12db16b069251f550063d853a - languageName: node - linkType: hard - -"@turf/boolean-valid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-valid@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/boolean-crosses": "npm:7.4.0" - "@turf/boolean-disjoint": "npm:7.4.0" - "@turf/boolean-overlap": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/boolean-point-on-line": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-intersect": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - geojson-polygon-self-intersections: "npm:^1.2.1" - tslib: "npm:^2.8.1" - checksum: 10c0/af4807e4dee1b13100f1cfe097ab67b44aa8342df92cf7424b46e5d6ef765c63f910772683d2709787d972c0e68704c8e72821657e2a6c7ade0c88c02832c98d - languageName: node - linkType: hard - -"@turf/boolean-within@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/boolean-within@npm:7.4.0" - dependencies: - "@turf/boolean-contains": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/06bca91dfd06e2a56c807eccbcf0d8ebe5564e1e5be4da1ad4da3c4c56c6c97a25054bb28886379cf4114fcfb071e393ebada0b1043a1c18ec31ec6e2709ada8 - languageName: node - linkType: hard - -"@turf/buffer@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/buffer@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/center": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/jsts": "npm:^2.7.1" - "@turf/meta": "npm:7.4.0" - "@turf/projection": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - d3-geo: "npm:^2.0.2" - tslib: "npm:^2.8.1" - checksum: 10c0/6720084a5f4444e857d44541dfe13b1dd1cba6fa77aedbe2b63ff1cf2b51a992ba682c69efb440806bd647c92f2923352c3ca989e39e01cd209c947037b61fb0 - languageName: node - linkType: hard - -"@turf/center-mean@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/center-mean@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/b8af8b9166ebcacfd6d5d795c2d0adafb76ab66ec41b6fbde790029f6ec642da39d87ea801ce16ffa4f287e9f9a6133caafe75a48a296df356753a92ff55e649 - languageName: node - linkType: hard - -"@turf/center-median@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/center-median@npm:7.4.0" - dependencies: - "@turf/center-mean": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/4ddb17222d3645d6f63d49667dd6c0f7a50552ec16a2b80dbdee8cfaf4e0ea0398e9005eaf784d006d89ed5bdfe9dfa1738aa5626f74e0800c695444cfb65921 - languageName: node - linkType: hard - -"@turf/center-of-mass@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/center-of-mass@npm:7.4.0" - dependencies: - "@turf/centroid": "npm:7.4.0" - "@turf/convex": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/ac9cd37c1a0b2ecf7ca49f3f45fa302fdf827f79269c76ce23caad4c41af3ed5dd8e9080706dcbbe6a0277fc826e51cf776ee0f3cd311ece1e50ca1701ab661b - languageName: node - linkType: hard - -"@turf/center@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/center@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/bfa143251d8bb58085e4e41701bb93fc23baf7b42f08f08b95f663b324624992ccb1f034f906833a418416fe5ab37047acb10b44bfde1931f43e3c3397e66938 - languageName: node - linkType: hard - -"@turf/centroid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/centroid@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/5a643bef7303e05aa70e96a891229edf010c74ba2912340c4c2058c7ad2285e2f722cfe1fe0688bcc78802d18170e0930c86bbecc9ee4b27cdbde10c66ce3a8d - languageName: node - linkType: hard - -"@turf/circle@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/circle@npm:7.4.0" - dependencies: - "@turf/destination": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/439147da3e49c6d5b7951eabdf67fac4aa1d3c7ab8ac81b4e267452a4f0a5bcfa28aa6f00001d67d0940ff5c1ff7e1f24c0852bde5d8884556d241c09794600a - languageName: node - linkType: hard - -"@turf/clean-coords@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/clean-coords@npm:7.4.0" - dependencies: - "@turf/boolean-point-on-line": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/2572c0df64eed37c885bd6b427c169afd8673e2e833ae35f9308f9df34afe21bf5928a064a29466164fd2953e939c13738bf61eb2ff243c7c6d4da0cf5a8497b - languageName: node - linkType: hard - -"@turf/clone@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/clone@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/f71b291f9131677c09edc688149b6bd7d8174bc991071314d382ff2197a8939c70470db6d6d7b034bf57e5925c7a41d2072c94feefdfae9cdfc7c6d84764de72 - languageName: node - linkType: hard - -"@turf/clusters-dbscan@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/clusters-dbscan@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - rbush: "npm:^3.0.1" - tslib: "npm:^2.8.1" - checksum: 10c0/3f25903225bea6df4c264999acc4dec75b5f43f66d82e14be0d1caed54bebfc5f0c643e0de25dd9386ebdba34daef6805a5db91ac91adc65ba582e4cbde04e2b - languageName: node - linkType: hard - -"@turf/clusters-kmeans@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/clusters-kmeans@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - skmeans: "npm:0.9.7" - tslib: "npm:^2.8.1" - checksum: 10c0/a893ecd72e1adcfd7ad2b2a3fc056c3056672fe7c72f7b96d8a898d099675ff8ca84fd5c9e0fb02298418b07694ac21d48875fa0d004f994c676ddf8ae033375 - languageName: node - linkType: hard - -"@turf/clusters@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/clusters@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/f52c9b8eb86a69a5745f90115bca72848d671c29f28897cade3b40aa952016385dda903c17729a8cecdd9812cafa99b1d200b0b4c3e50a370d2a12066d62fb15 - languageName: node - linkType: hard - -"@turf/collect@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/collect@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - rbush: "npm:^3.0.1" - tslib: "npm:^2.8.1" - checksum: 10c0/bf7ad2b9a1dcf602951c51b94f1a89e3ea1602788cac80560a4231bbab7188d0f645de7077d56ac7dd49310a2201010933968cd4e00c4c7f79669e47020b639f - languageName: node - linkType: hard - -"@turf/combine@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/combine@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/7c5ace7b05b3b2141305e0362fadfe311b1c1c69a929747ebaac8bf9da9aeec993486d09358b24b7f48062d7e9850bf3cf7d08cd0e461254da1f74c817aed0be - languageName: node - linkType: hard - -"@turf/concave@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/concave@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/tin": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - topojson-client: "npm:3.x" - topojson-server: "npm:3.x" - tslib: "npm:^2.8.1" - checksum: 10c0/52107d7f7d8a857e32553bf406572cdf1e1be7731f3bd2ca64e65ebb66a5b545ba3f18f4b30188cc66937ad17bd3ae7242eed22b663e74bb2a8872d0766fdb02 - languageName: node - linkType: hard - -"@turf/convex@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/convex@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - concaveman: "npm:^1.2.1" - tslib: "npm:^2.8.1" - checksum: 10c0/fbd3a5f8dc68e35bec52ede2b12b3f33331215f116c8723ae259b4a250687bf5c67a52db80c99df85b1c4715e2430705ab86e71b7deb8127c44bc57d26e0384e - languageName: node - linkType: hard - -"@turf/destination@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/destination@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/249e73fd7a4dad3356c398a65ec99d181e649115e856e22f12c5d10ddf643b20d1c3e3fb8f0e407aeca3400314b947df0a7c8e0a9f817f1667b1d78bdbc44954 - languageName: node - linkType: hard - -"@turf/difference@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/difference@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - polyclip-ts: "npm:^0.16.8" - tslib: "npm:^2.8.1" - checksum: 10c0/660a59789fe1412785f7073faee2fb3c8daf266963cbe68aab3fde98bc20f7a81079257c6322ec6393199bd23b619854cf2f4e6c2f82e1f7f06a96ec53dd7eaf - languageName: node - linkType: hard - -"@turf/directional-mean@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/directional-mean@npm:7.4.0" - dependencies: - "@turf/bearing": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/destination": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/length": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/f6d6efb10fc8f8ef2e73346b92aac7655f0fecd0591f707dc041b373e199101c512d6f6bbb943a45cea513d653fbd4a93b884f0a864ebaedb35a8529078567be - languageName: node - linkType: hard - -"@turf/dissolve@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/dissolve@npm:7.4.0" - dependencies: - "@turf/flatten": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - polyclip-ts: "npm:^0.16.8" - tslib: "npm:^2.8.1" - checksum: 10c0/dcac1bad6254f869f1e227be5aeb5ab967433e56880f767e37b43bb2f998b326679b62537de99d3e929cc8c003486eb4191c7e5840e66068201611fe484ac69a - languageName: node - linkType: hard - -"@turf/distance-weight@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/distance-weight@npm:7.4.0" - dependencies: - "@turf/centroid": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/c6d5325066427b0dcb395b88b2b38d9f87b038cd143c9fa68450acebc078e3d3281c7f09cd447bdf98c45b1d514fef56eecb8d679a6bcf831fb1c6275828a2dc - languageName: node - linkType: hard - -"@turf/distance@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/distance@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/0f372ede39894995df9a98383769411b86be1c4f23ca746bf00d138073c464f36e35b40265189a1b3dfc9559592b3b20458389176102a5045c2f67d3cf685227 - languageName: node - linkType: hard - -"@turf/ellipse@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/ellipse@npm:7.4.0" - dependencies: - "@turf/destination": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/transform-rotate": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/7cbe58d3c3172599de8c98d4ba393c9dd424457caf7ed0b7c64bd2e34d8e30ac9ab836149e83d8a1327ceb5e5724584ca6c70681bfdcdde9c9079ffd369bc25b - languageName: node - linkType: hard - -"@turf/envelope@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/envelope@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/bbox-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/c430cb1fe7c80402c71f36bb54eaf175574717b123f3aebde469f5dec5fbd519418f119bb025bd01034a9b20a2c2ca4a51797e10c81a2f66434dbe4a39bcae1e - languageName: node - linkType: hard - -"@turf/explode@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/explode@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e51b6423a914b9f72e4dc333560dd3534c76bfc41447fd99ca2062451c7b7393113dff2b3d153d7efd9cb796392d7644828fbe87846b3eb623f3b05b8f0e2308 - languageName: node - linkType: hard - -"@turf/flatten@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/flatten@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/a2b884615d3df924784ffc984214c0b99bdef934e75608779f34f819231bf2b451363a37397e3109b3dae08b9bf5447c4c7e595470442de93f920929786cb44f - languageName: node - linkType: hard - -"@turf/flip@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/flip@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e4909681d48301b37966bc6b0fcc96ccf30aba734060fcb711f34a0e697ff9b583b980df47f36332a8ae500aa04728146c4aa63551149fca29b6865a0bc3886f - languageName: node - linkType: hard - -"@turf/geojson-rbush@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/geojson-rbush@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - rbush: "npm:^3.0.1" - tslib: "npm:^2.8.1" - checksum: 10c0/a73f4f79c49c10444702dc98b20e75d24312b321b066fc214231f4ce508195c5aea53fa724a8aa0ab2f9ab2ab9927d5fdf35fce80b82fdbf429c406dd4a53d70 - languageName: node - linkType: hard - -"@turf/great-circle@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/great-circle@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - arc: "npm:^0.2.0" - tslib: "npm:^2.8.1" - checksum: 10c0/c66913541543305606e9aab388d91d102d98afbe0e027d14d3e310f00218612a6f26cea1a95b4e6de9cd8f94f8652a90fea4a788adc6b8a76d4858934102f6b4 - languageName: node - linkType: hard - -"@turf/helpers@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/helpers@npm:7.4.0" - dependencies: - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/2fb850f41deb834260e655cae29bc3c0efd53614c8444737bd0bba64121cb183b8f641556b4e97d235c5ef5066e56bdb25b83b5b54ba563f60462dd21aac2273 - languageName: node - linkType: hard - -"@turf/hex-grid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/hex-grid@npm:7.4.0" - dependencies: - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/intersect": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/fca2c840e718947f078609ae9eb16b9d4fd10ccc377631a77815005129071f6af84d483f9c3053a7164f781d65d224d2861569b3183b64a4a1c3c50613eb7655 - languageName: node - linkType: hard - -"@turf/interpolate@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/interpolate@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/hex-grid": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/point-grid": "npm:7.4.0" - "@turf/square-grid": "npm:7.4.0" - "@turf/triangle-grid": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/a274cc33eb857c11b30154fae5034a51f394cf32ca5ec7d676121f85816da1f9f9fe1add361a9ef01f5c74ff5401b0549aab6107b1d4640a2381438cb840519f - languageName: node - linkType: hard - -"@turf/intersect@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/intersect@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - polyclip-ts: "npm:^0.16.8" - tslib: "npm:^2.8.1" - checksum: 10c0/16b71e37817c16fcccb2ff7c0d0ff09a2c12330dbe0636294fe45f8c56caff9eff62601fd3b9817e1fc1a937b64cdf7b9427b5691296d645b879be086684229b - languageName: node - linkType: hard - -"@turf/invariant@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/invariant@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/d8ddc9883699471cf578a41fb269aa0538f91fc2425ad0f79c1627cdaa717d23b3f0f5b803ee7052a054e9de79a7e31a83476850f4ab4a78679af4ef6f17b7b3 - languageName: node - linkType: hard - -"@turf/isobands@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/isobands@npm:7.4.0" - dependencies: - "@turf/area": "npm:7.4.0" - "@turf/bbox": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/explode": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/9b55dd15bc319e8f495ae238fb594fed728a3fd53c413bfa0d053b543cb5e1f4f7da389bdd6b9f48831d4abf21c4bc16093aa6a568bfa6d66c1993c2b2e3ea5d - languageName: node - linkType: hard - -"@turf/isolines@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/isolines@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/a68b372373d630eb9d323ab3b98e904f526c4ecf386d107611e42faca0eb3e7c468cdd643b1de0662878978fbbee2724c48d0522903b4a5d407c56a4c6beb7fe - languageName: node - linkType: hard - -"@turf/jsts@npm:^2.7.1": - version: 2.7.2 - resolution: "@turf/jsts@npm:2.7.2" - dependencies: - jsts: "npm:2.7.1" - checksum: 10c0/19eab63e7e26a613e7186de170d9f96c32759769a0268acac3da4c5cefc8f9f5a1274f9fc73b0cb85c5d52c9d9516167c98a42d1635e03c3a712e2a784e192c7 - languageName: node - linkType: hard - -"@turf/kinks@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/kinks@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e4c9bd283f0377a2e50619bd9c4c0e90736135aaec787e3bbb0397ba02aaddfb91a1d6720caa3c6cc73b57d89abcb165fe6a3f6bca8c0b0df89c3c9a9e14076a - languageName: node - linkType: hard - -"@turf/length@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/length@npm:7.4.0" - dependencies: - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/bb05418ec46abae522014f5b9ec32b8be77708ba7d8e774096a2288d4ac0e897675c002a7cb5a65c284c0cf3c66603c39ad7a30df57936684898fc4ee657913f - languageName: node - linkType: hard - -"@turf/line-arc@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-arc@npm:7.4.0" - dependencies: - "@turf/circle": "npm:7.4.0" - "@turf/destination": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/659817139aac6180c6a2d3ad3484864ac621d78ce66aeb284aee2b4b4cb712321867fbcd54c34068b22afdbf7332f2908a03732ff7b603b80e0ad3147af6f187 - languageName: node - linkType: hard - -"@turf/line-chunk@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-chunk@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/length": "npm:7.4.0" - "@turf/line-slice-along": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/33eff40c9f63f40d23972cdae2e47463b8103cb7a5b5d80d4a5453458ca5f014cb6477486f1a6ed2e57efa34611647ce2f45f2aa511718e0b3f1f705cf390b43 - languageName: node - linkType: hard - -"@turf/line-intersect@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-intersect@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - robust-predicates: "npm:^2.0.4" - tinyqueue: "npm:^2.0.3" - tslib: "npm:^2.8.1" - checksum: 10c0/02945aab639a8ae3b735f9d68dcf2a0b4885ceac95ec9dc6d34b5311e4771041ed133e2aeb0d4cf848b2839403a7059df639761a9f675315ae2fa190046912c3 - languageName: node - linkType: hard - -"@turf/line-offset@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-offset@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/28dd785d98054aadfa09b7f2f7e58161aca17beb937b4257ea48171aed9f45dfeefe2a1a659f704a46917956a1532bf323666af896d135ae45d8c8ae9de72727 - languageName: node - linkType: hard - -"@turf/line-overlap@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-overlap@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/boolean-point-on-line": "npm:7.4.0" - "@turf/geojson-rbush": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-segment": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/nearest-point-on-line": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - fast-deep-equal: "npm:^3.1.3" - tslib: "npm:^2.8.1" - checksum: 10c0/4dfc8cf8fc30d6a63faf07c254eff149141b2c4a8307bfbc202530ca8b8d0f5f1b7dd46ab439126c391ba7efdf5af87f476dd82e6fb64a5368aee6a9a9f965c5 - languageName: node - linkType: hard - -"@turf/line-segment@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-segment@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/7ea8036858adf78da867242d39bc34533c5d663255fee5bb638fd2729c8c3c0265ef5d763aa6b4f1b806c3f2b3a7223666592a85635d6d981a4e90fbd410ae4a - languageName: node - linkType: hard - -"@turf/line-slice-along@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-slice-along@npm:7.4.0" - dependencies: - "@turf/bearing": "npm:7.4.0" - "@turf/destination": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/a59c1ec05878ec5bed13315150a168fc425496201a3479b9d90aefda159e73a9d8e155b44a9db61080ce73288ae5cd7a79186e208f8a5d680ed796eb1ab26840 - languageName: node - linkType: hard - -"@turf/line-slice@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-slice@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/nearest-point-on-line": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/34f53566143658343d8ee27aa2ddb67239342f2103f4d192d4f278c9d220fc954dde842593812054e3143ff8362900dcd2ba545e32befa15a9467526ba22da1c - languageName: node - linkType: hard - -"@turf/line-split@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-split@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/geojson-rbush": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-intersect": "npm:7.4.0" - "@turf/line-segment": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/nearest-point-on-line": "npm:7.4.0" - "@turf/truncate": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/2fdb0f93298a166cf13350274ca9fecb209b05c33efa5b54e516bbf907d242ef4c58cc729b8948a57709ee6c1422529580f812ff5236fff2e41ec259f87a2269 - languageName: node - linkType: hard - -"@turf/line-to-polygon@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/line-to-polygon@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/cb637576454536ae3572fbf0e6ba5621b2d2d083895a5984cb39f703c3395f5070e060ea4664000dc097cf1c4370b0c2e99acd06cfa6e15877fbcb0d87294698 - languageName: node - linkType: hard - -"@turf/mask@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/mask@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - polyclip-ts: "npm:^0.16.8" - tslib: "npm:^2.8.1" - checksum: 10c0/80ae3933890bbf10544ba5449b636a7f4a5da51459f6cb35412318c60e8028065f1433c544b6d870c9334fba21848c1585377848a19765e35a4d665f9fca90b8 - languageName: node - linkType: hard - -"@turf/meta@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/meta@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/6d08c84c6573757d6f6df1272ea07d3f8daf4a81e83aa1fea2ed85cdc8047d984bcbc4ae3cc7708d374108c2cba92c78d6e885c475ff32a23ef54f77dc41e767 - languageName: node - linkType: hard - -"@turf/midpoint@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/midpoint@npm:7.4.0" - dependencies: - "@turf/bearing": "npm:7.4.0" - "@turf/destination": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/ec86f5a46c1ab1bc58fa27695be608d9c56ab7eb404172789405a5436d896f6bd2f050c5f75fa441113e2a08ed0471fde0f424335d55857e6cd6c741e76ad86d - languageName: node - linkType: hard - -"@turf/moran-index@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/moran-index@npm:7.4.0" - dependencies: - "@turf/distance-weight": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/8fc5f5a93d833c697fc0cda3bc9dab317004fa3cebe8c0e95e7c1f80920499bd64517181375b8b952475d6ad512b1d5c4b04ab89eed7b937ba4304e7e187b8bc - languageName: node - linkType: hard - -"@turf/nearest-neighbor-analysis@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/nearest-neighbor-analysis@npm:7.4.0" - dependencies: - "@turf/area": "npm:7.4.0" - "@turf/bbox": "npm:7.4.0" - "@turf/bbox-polygon": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/nearest-point": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/c9b775124ca7ffe3d0f66d6f7083ff921812882ac4afcefa5cd1d06fa17e4ac581a7e9ac7effe702b9a19d12f6181d510a334a9c7ba05b6c31434758492ec743 - languageName: node - linkType: hard - -"@turf/nearest-point-on-line@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/nearest-point-on-line@npm:7.4.0" - dependencies: - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e610757bbdc83f74830dc3c130d0e5bd20144a1e2a3183264896e6fec83d571e44fc4f38b18cef4bb4be4627a964420b75c9c8e7e13d9e164b067d6ec18d3c23 - languageName: node - linkType: hard - -"@turf/nearest-point-to-line@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/nearest-point-to-line@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/point-to-line-distance": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e167a3ac7c468bdb1eb1d8f07fe3ff732a787fbd308ff0440e2941bb21629989e9f954b8706d5f35ece511996f0c04304facef4434ebbbb87613dff3696d490d - languageName: node - linkType: hard - -"@turf/nearest-point@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/nearest-point@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/96539e7e2fded0471cadb1b942b0f4521579a293358d104615d6e6ce9b713e1ee519b40de6429d37ca8bcf87308c08251889450a259a97f90b5dba7e066cf252 - languageName: node - linkType: hard - -"@turf/planepoint@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/planepoint@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/80100a6ca94173e08ea6827e619f48fbbdb51d0d8332d429c11482751448ccdfb384f28d993f48243404202f71787a906a19c2960d15957104bafdf8ba4c6102 - languageName: node - linkType: hard - -"@turf/point-grid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/point-grid@npm:7.4.0" - dependencies: - "@turf/boolean-within": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/cef768ac54c5ed29d529b0cfec7caba483290af35e3fc58924a9ae0e2b559482a780c0dae85bf8d3547a964fe3eacbe6423693dca801a5905be86c1ddbc8892e - languageName: node - linkType: hard - -"@turf/point-on-feature@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/point-on-feature@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/center": "npm:7.4.0" - "@turf/explode": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/nearest-point": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/41a785a0c9cdee6d296667c531666c4baa33955ae138971817573d5f9763585918853aa9da9018f4dac89ed333ab78731683ac4c4247bf569499c319e08f0f6f - languageName: node - linkType: hard - -"@turf/point-to-line-distance@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/point-to-line-distance@npm:7.4.0" - dependencies: - "@turf/bearing": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/nearest-point-on-line": "npm:7.4.0" - "@turf/projection": "npm:7.4.0" - "@turf/rhumb-bearing": "npm:7.4.0" - "@turf/rhumb-distance": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/4c6eec9e0fcbe48e313066e51acc98d9c66c4390e5879cedb2c8c24037364d55d09858c13d699861542c147b36e6a358de8e194adca5e9c64ac02156d84cbf04 - languageName: node - linkType: hard - -"@turf/point-to-polygon-distance@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/point-to-polygon-distance@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/point-to-line-distance": "npm:7.4.0" - "@turf/polygon-to-line": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/58d59cb1a7dcb2853d69cc2e3f9d99e934e7abfd6b111a06100cc35bf85bcd1a497ffa624e6b354825438b9746929767e09d34acf007f4ea385a38cbb8c1ed98 - languageName: node - linkType: hard - -"@turf/points-within-polygon@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/points-within-polygon@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/0e215ace627b00b83ea5f41b774e5738ac74aaeb2d8c6db96febdafd59f4b66aaca0ec39978c987955e4ac4d7d0a55e20dac23285a5dd5dee7459499993b4640 - languageName: node - linkType: hard - -"@turf/polygon-smooth@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/polygon-smooth@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/532f4950f6d892951e92fb2193cba56df5fb6dfaefeb8a40648600baa5b70d1f197f789bb346932ca200487734c03b3fbe112bfb382709f7262b975403710372 - languageName: node - linkType: hard - -"@turf/polygon-tangents@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/polygon-tangents@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/boolean-within": "npm:7.4.0" - "@turf/explode": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/nearest-point": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/6ed77d7d8bdba34b86c70a5d5e770fb9973eafa5011b8a8ccf813a7e6baaaf72291c4f733bd548b8c8137bf45aa9137e8c787f6862346e5db103c14482c61ebf - languageName: node - linkType: hard - -"@turf/polygon-to-line@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/polygon-to-line@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/d5b46a30c2a87f3c0422280d04e6a39232774476cc6bca83b1e0a6caa6283bf96b58ca16118392b2dcf23affc26a0206cbffc526fd583eb4e18d88759d5d611e - languageName: node - linkType: hard - -"@turf/polygonize@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/polygonize@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/envelope": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/8c79a2364b964e90fd14932c76951c7dbaf40e81b89d346eb32a58ce1f04084e245b480721232cdb662167bf302a608345ecf44aa2a23350f056c4583c8369f5 - languageName: node - linkType: hard - -"@turf/projection@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/projection@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/f6dd7c33d97dc872181a016581346a9c4bc716405018ecebd0292415398c644058cc72f755b78a8bd7b0d5f89a95b7662b5fd65d91831c3f8f5cdb04cf46118c - languageName: node - linkType: hard - -"@turf/quadrat-analysis@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/quadrat-analysis@npm:7.4.0" - dependencies: - "@turf/area": "npm:7.4.0" - "@turf/bbox": "npm:7.4.0" - "@turf/bbox-polygon": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/point-grid": "npm:7.4.0" - "@turf/random": "npm:7.4.0" - "@turf/square-grid": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/fe8ab866477d57f60aea9789e9c444f07d6cb16b5f20b674c47bc6f195f2faeac45ae0fd58d21e6fce2ca97c104a465c10d11f05b538e70ae996df0076be57f3 - languageName: node - linkType: hard - -"@turf/random@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/random@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/712e4788ab51ce2ff14007bc7511ba56e4fb77d316697fa22b95535c1911d01c410f5fb2609b22ba790cb41d5071aee192a9dd4c3f297393d24d8fcde95924fb - languageName: node - linkType: hard - -"@turf/rectangle-grid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/rectangle-grid@npm:7.4.0" - dependencies: - "@turf/boolean-intersects": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/3408be433a962edb57257616d66777a624044f178def7aa60aa3183d915b886696c5e714ad193c55acf464c4c7071428dee90d01696ed58d8a00af6bd3fef0e3 - languageName: node - linkType: hard - -"@turf/rewind@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/rewind@npm:7.4.0" - dependencies: - "@turf/boolean-clockwise": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/7e0fdfbd6bd353173c3b5845187c261085b95c46d711dc417b831d0ae2fe98c5783eb3d8a8b3af3dfeb33c26e968571e02e0426e38b23d78bd41b4433f324d99 - languageName: node - linkType: hard - -"@turf/rhumb-bearing@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/rhumb-bearing@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/96fa308dd72490637bdb9dc13042faf5efa239740c6fedc3d7f2f0bf4eba0d49c1c5af2d675d0a3dcad18495e41551c8956278b82da5e89f8208a9dc50c9602b - languageName: node - linkType: hard - -"@turf/rhumb-destination@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/rhumb-destination@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/a61bb652283c107c7760bd6a90333e90f99f96c2a3e8fe8910f3ef4fca9723fdf04d89745ff6d89927e09ef6e94f6702215f53f30f064ed03abe468edddca638 - languageName: node - linkType: hard - -"@turf/rhumb-distance@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/rhumb-distance@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/1abfd29a8b0970ee9cf91df5164b9dc8f0b4d2a28349d8eaefa40b56885fcfb2327fd98003716b74cb66acebf954a6508b2cc8f90323309a5562722bc70f4e06 - languageName: node - linkType: hard - -"@turf/sample@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/sample@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/cf781074898945e1ec207f8d92161045e5b43fb607dcaacebe086c3b193a5426a3cf3aea0ea041e03452e1f3572c4fe0b51467a3938d0fdfa407f9037d967257 - languageName: node - linkType: hard - -"@turf/sector@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/sector@npm:7.4.0" - dependencies: - "@turf/circle": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/line-arc": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/50a3fed70849f1ff1893eb87dc5086a7da83f59eaf65798a7671ca3dc525731e7c672d9e6e932269f8c239639e0367646714234180dd444a2aefcd080528516b - languageName: node - linkType: hard - -"@turf/shortest-path@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/shortest-path@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/bbox-polygon": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/clean-coords": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/transform-scale": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/d7444c811a3f4b94085eb521bece14ba3eca4acfa43fbb2b902d9fca838fdd1a9416604ab81dc87d641935accc03a5ec83977a1dce5288a881b6d6081dad8fd1 - languageName: node - linkType: hard - -"@turf/simplify@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/simplify@npm:7.4.0" - dependencies: - "@turf/clean-coords": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/01841ff1aa8043942cf8dc1a72509cd1d64a4286afe5253109aef9ea1564f7848abd487fcccc18f6b9fecd75aa117169d033c901099fdc8523213f636c0190e1 - languageName: node - linkType: hard - -"@turf/square-grid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/square-grid@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/rectangle-grid": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/a77426a28c297a58d50816657912439ba94f702ffa8abbb894ed63a917119e8b5653d3a1b440f1f9c72706d13c38a3ef730b521cc789c01737bf95295b70f40a - languageName: node - linkType: hard - -"@turf/square@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/square@npm:7.4.0" - dependencies: - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e32981e737c78907da41ee6b5fb7b95f32829943450d1ace502f1a1d30c0c9e6402c4fa60d3c3b72fa86410f77e4b386072a2a4e7f626086e830174696da3b68 - languageName: node - linkType: hard - -"@turf/standard-deviational-ellipse@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/standard-deviational-ellipse@npm:7.4.0" - dependencies: - "@turf/center-mean": "npm:7.4.0" - "@turf/ellipse": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/points-within-polygon": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/3ef201309ae876d30f3a4e7ca7e146d95ba73968e550cb5c6d7c3a01df593cf06cdf1dc2cc2397cf4ab075f2e6d9fc2a41dad9e9975207aa067a96e511cf6131 - languageName: node - linkType: hard - -"@turf/tag@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/tag@npm:7.4.0" - dependencies: - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/e7c12815c825d373eb11d5f14e7cb4902ada5c70b3a3331133237236375b8decb16b1fad44cc6e9a5e9c9eb32134f5610bd0987a2ca236e32c4ff414a5142d21 - languageName: node - linkType: hard - -"@turf/tesselate@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/tesselate@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/earcut": "npm:^2.1.4" - "@types/geojson": "npm:^7946.0.10" - earcut: "npm:^2.2.4" - tslib: "npm:^2.8.1" - checksum: 10c0/2c64ae20104cf5e6f7cc9e3d369984a233fe974f91d5517104db7f4d90419908309c9ee3e1a88cbd2ad70e4468f7615fa50ce400ab010e0f8bdfa642f2cd1513 - languageName: node - linkType: hard - -"@turf/tin@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/tin@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/1246275104975bbd26c672d2ff0da48ca3c92d311bfa6e53fd1fa9883c2a952f1b7710269809a069608114a2bb5bff7bc249570161449509a582b7ab41737932 - languageName: node - linkType: hard - -"@turf/transform-rotate@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/transform-rotate@npm:7.4.0" - dependencies: - "@turf/centroid": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/rhumb-bearing": "npm:7.4.0" - "@turf/rhumb-destination": "npm:7.4.0" - "@turf/rhumb-distance": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/51e3a68e8a16af9f1dc130f8d9f79e66e2c23eb6fb08dd5824f954ce3fb5b351d864e23b4ab839229c84dc1dca03d96dd915cc2acdb73e8c37eb7bcec287ba22 - languageName: node - linkType: hard - -"@turf/transform-scale@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/transform-scale@npm:7.4.0" - dependencies: - "@turf/bbox": "npm:7.4.0" - "@turf/center": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/rhumb-bearing": "npm:7.4.0" - "@turf/rhumb-destination": "npm:7.4.0" - "@turf/rhumb-distance": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/dd76eb4824eab4bbfdd8bc305b35d40a28de7d91203476d39e137af6ca0bf5bb0f8956f760d586bff3a08485c0af43cb226aaed6614c2c3bded2206487370e56 - languageName: node - linkType: hard - -"@turf/transform-translate@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/transform-translate@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/rhumb-destination": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/80e8b8b1960ff4a67249fcb1f5ddebcf213158bf9eb04a86b5aa7c9eb0d5ec4ef39f2bb4e2daa0f05099f8a9594e8443b2584bfbf9bf7f5b70af2c19de852834 - languageName: node - linkType: hard - -"@turf/triangle-grid@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/triangle-grid@npm:7.4.0" - dependencies: - "@turf/distance": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/intersect": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/eb631665bdc6cde69161914e9d969d92fb915772e7a047cdae3170c90ecb72447463b2f02813f6458ba7fbf21e4c827a0e1218962145697057d458e1d75f1200 - languageName: node - linkType: hard - -"@turf/truncate@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/truncate@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - tslib: "npm:^2.8.1" - checksum: 10c0/56b87146b0ac7a84ea9df8e43bb7065dbd2ceadbc6e41016a7d8ab1c11136b8db984fd2fe8a4653ae41c304a594d4438f4d0fb8f9928cccd4ae74ca4800da9d9 - languageName: node - linkType: hard - -"@turf/turf@npm:^7.4.0": - version: 7.4.0 - resolution: "@turf/turf@npm:7.4.0" - dependencies: - "@turf/along": "npm:7.4.0" - "@turf/angle": "npm:7.4.0" - "@turf/area": "npm:7.4.0" - "@turf/bbox": "npm:7.4.0" - "@turf/bbox-clip": "npm:7.4.0" - "@turf/bbox-polygon": "npm:7.4.0" - "@turf/bearing": "npm:7.4.0" - "@turf/bezier-spline": "npm:7.4.0" - "@turf/boolean-clockwise": "npm:7.4.0" - "@turf/boolean-concave": "npm:7.4.0" - "@turf/boolean-contains": "npm:7.4.0" - "@turf/boolean-crosses": "npm:7.4.0" - "@turf/boolean-disjoint": "npm:7.4.0" - "@turf/boolean-equal": "npm:7.4.0" - "@turf/boolean-intersects": "npm:7.4.0" - "@turf/boolean-overlap": "npm:7.4.0" - "@turf/boolean-parallel": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/boolean-point-on-line": "npm:7.4.0" - "@turf/boolean-touches": "npm:7.4.0" - "@turf/boolean-valid": "npm:7.4.0" - "@turf/boolean-within": "npm:7.4.0" - "@turf/buffer": "npm:7.4.0" - "@turf/center": "npm:7.4.0" - "@turf/center-mean": "npm:7.4.0" - "@turf/center-median": "npm:7.4.0" - "@turf/center-of-mass": "npm:7.4.0" - "@turf/centroid": "npm:7.4.0" - "@turf/circle": "npm:7.4.0" - "@turf/clean-coords": "npm:7.4.0" - "@turf/clone": "npm:7.4.0" - "@turf/clusters": "npm:7.4.0" - "@turf/clusters-dbscan": "npm:7.4.0" - "@turf/clusters-kmeans": "npm:7.4.0" - "@turf/collect": "npm:7.4.0" - "@turf/combine": "npm:7.4.0" - "@turf/concave": "npm:7.4.0" - "@turf/convex": "npm:7.4.0" - "@turf/destination": "npm:7.4.0" - "@turf/difference": "npm:7.4.0" - "@turf/directional-mean": "npm:7.4.0" - "@turf/dissolve": "npm:7.4.0" - "@turf/distance": "npm:7.4.0" - "@turf/distance-weight": "npm:7.4.0" - "@turf/ellipse": "npm:7.4.0" - "@turf/envelope": "npm:7.4.0" - "@turf/explode": "npm:7.4.0" - "@turf/flatten": "npm:7.4.0" - "@turf/flip": "npm:7.4.0" - "@turf/geojson-rbush": "npm:7.4.0" - "@turf/great-circle": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/hex-grid": "npm:7.4.0" - "@turf/interpolate": "npm:7.4.0" - "@turf/intersect": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@turf/isobands": "npm:7.4.0" - "@turf/isolines": "npm:7.4.0" - "@turf/kinks": "npm:7.4.0" - "@turf/length": "npm:7.4.0" - "@turf/line-arc": "npm:7.4.0" - "@turf/line-chunk": "npm:7.4.0" - "@turf/line-intersect": "npm:7.4.0" - "@turf/line-offset": "npm:7.4.0" - "@turf/line-overlap": "npm:7.4.0" - "@turf/line-segment": "npm:7.4.0" - "@turf/line-slice": "npm:7.4.0" - "@turf/line-slice-along": "npm:7.4.0" - "@turf/line-split": "npm:7.4.0" - "@turf/line-to-polygon": "npm:7.4.0" - "@turf/mask": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@turf/midpoint": "npm:7.4.0" - "@turf/moran-index": "npm:7.4.0" - "@turf/nearest-neighbor-analysis": "npm:7.4.0" - "@turf/nearest-point": "npm:7.4.0" - "@turf/nearest-point-on-line": "npm:7.4.0" - "@turf/nearest-point-to-line": "npm:7.4.0" - "@turf/planepoint": "npm:7.4.0" - "@turf/point-grid": "npm:7.4.0" - "@turf/point-on-feature": "npm:7.4.0" - "@turf/point-to-line-distance": "npm:7.4.0" - "@turf/point-to-polygon-distance": "npm:7.4.0" - "@turf/points-within-polygon": "npm:7.4.0" - "@turf/polygon-smooth": "npm:7.4.0" - "@turf/polygon-tangents": "npm:7.4.0" - "@turf/polygon-to-line": "npm:7.4.0" - "@turf/polygonize": "npm:7.4.0" - "@turf/projection": "npm:7.4.0" - "@turf/quadrat-analysis": "npm:7.4.0" - "@turf/random": "npm:7.4.0" - "@turf/rectangle-grid": "npm:7.4.0" - "@turf/rewind": "npm:7.4.0" - "@turf/rhumb-bearing": "npm:7.4.0" - "@turf/rhumb-destination": "npm:7.4.0" - "@turf/rhumb-distance": "npm:7.4.0" - "@turf/sample": "npm:7.4.0" - "@turf/sector": "npm:7.4.0" - "@turf/shortest-path": "npm:7.4.0" - "@turf/simplify": "npm:7.4.0" - "@turf/square": "npm:7.4.0" - "@turf/square-grid": "npm:7.4.0" - "@turf/standard-deviational-ellipse": "npm:7.4.0" - "@turf/tag": "npm:7.4.0" - "@turf/tesselate": "npm:7.4.0" - "@turf/tin": "npm:7.4.0" - "@turf/transform-rotate": "npm:7.4.0" - "@turf/transform-scale": "npm:7.4.0" - "@turf/transform-translate": "npm:7.4.0" - "@turf/triangle-grid": "npm:7.4.0" - "@turf/truncate": "npm:7.4.0" - "@turf/union": "npm:7.4.0" - "@turf/unkink-polygon": "npm:7.4.0" - "@turf/voronoi": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - "@types/kdbush": "npm:^3.0.5" - tslib: "npm:^2.8.1" - checksum: 10c0/09669238f48d61da0b0220e36fd8141d04a502a35013ad4f5dbbdae84747fa55520bc943ab42c751a736a772ee827231ad9033ef16ce959ae269d27ef487bb73 - languageName: node - linkType: hard - -"@turf/union@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/union@npm:7.4.0" - dependencies: - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - polyclip-ts: "npm:^0.16.8" - tslib: "npm:^2.8.1" - checksum: 10c0/1f30ba610e3913e6b0bdb5283d1858b35873667c31b70dd87658fe033617d8093ad46277f2c5f4a2146780d4699a7e13d822f5fb688ec2a412cae1b2111ec27a - languageName: node - linkType: hard - -"@turf/unkink-polygon@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/unkink-polygon@npm:7.4.0" - dependencies: - "@turf/area": "npm:7.4.0" - "@turf/boolean-point-in-polygon": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/meta": "npm:7.4.0" - "@types/geojson": "npm:^7946.0.10" - rbush: "npm:^3.0.1" - tslib: "npm:^2.8.1" - checksum: 10c0/b684f209d1b1d0e199300af18fdb16db36a2c120e6078818965aff8424306c173fa7845c64c2dcc1345873524a160d019b06734c40dcb00413b8842b80c4d510 - languageName: node - linkType: hard - -"@turf/voronoi@npm:7.4.0": - version: 7.4.0 - resolution: "@turf/voronoi@npm:7.4.0" - dependencies: - "@turf/clone": "npm:7.4.0" - "@turf/helpers": "npm:7.4.0" - "@turf/invariant": "npm:7.4.0" - "@types/d3-voronoi": "npm:^1.1.12" - "@types/geojson": "npm:^7946.0.10" - d3-voronoi: "npm:1.1.2" - tslib: "npm:^2.8.1" - checksum: 10c0/add918728a4d5ff694c8bf3e27bfec78c4b5ccfa869e6eb32267caa51a91a48e2f44370b51021d063214f015c0a6aa565ea4df257ae3012c3e0f247e7cb5a0ea - languageName: node - linkType: hard - -"@types/d3-voronoi@npm:^1.1.12": - version: 1.1.12 - resolution: "@types/d3-voronoi@npm:1.1.12" - checksum: 10c0/9cb1d88400ba442edd27b93a0e80bf6c4e88ab1e6ced4a9761b232e26f565c42753f4aa25ca0f9f773f1d13dae1ed10b3282b48b3fe078f3a7a25706f3a482e1 - languageName: node - linkType: hard - -"@types/earcut@npm:^2.1.4": - version: 2.1.4 - resolution: "@types/earcut@npm:2.1.4" - checksum: 10c0/ab76940f1cc66ac861932f254b8c0344ebdcfed69e356606416d562e17cd112221b08340d52232f73ff1ad08d4dcf9caa5352c73258df4b8a41c9110ba370262 - languageName: node - linkType: hard - -"@types/geojson@npm:^7946.0.10, @types/geojson@npm:^7946.0.14": - version: 7946.0.16 - resolution: "@types/geojson@npm:7946.0.16" - checksum: 10c0/1ff24a288bd5860b766b073ead337d31d73bdc715e5b50a2cee5cb0af57a1ed02cc04ef295f5fa68dc40fe3e4f104dd31282b2b818a5ba3231bc1001ba084e3c - languageName: node - linkType: hard - -"@types/kdbush@npm:^3.0.5": - version: 3.0.5 - resolution: "@types/kdbush@npm:3.0.5" - checksum: 10c0/7506c1098f529194f38b8a2f0b47e4a42d4b1f151e162a4d65ee42bdd956b5ba627575da42e80f7393a4c358a2361a2d67702958da2849601f9bc7a1758057cc - languageName: node - linkType: hard - -"abbrev@npm:^5.0.0": - version: 5.0.0 - resolution: "abbrev@npm:5.0.0" - checksum: 10c0/8e88f5c798ea4562d28c5a3e9ad69e3879890bc5d695d8f2dffb8609be4c890aacc8f80ef4553fdd2c6a62d70c2ce8bc57b38074e383beb7487bdafa9ed42ea5 - languageName: node - linkType: hard - -"accepts@npm:^2.0.0": - version: 2.0.0 - resolution: "accepts@npm:2.0.0" - dependencies: - mime-types: "npm:^3.0.0" - negotiator: "npm:^1.0.0" - checksum: 10c0/98374742097e140891546076215f90c32644feacf652db48412329de4c2a529178a81aa500fbb13dd3e6cbf6e68d829037b123ac037fc9a08bcec4b87b358eef - languageName: node - linkType: hard - -"anymatch@npm:~3.1.2": - version: 3.1.3 - resolution: "anymatch@npm:3.1.3" - dependencies: - normalize-path: "npm:^3.0.0" - picomatch: "npm:^2.0.4" - checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac - languageName: node - linkType: hard - -"arc@npm:^0.2.0": - version: 0.2.0 - resolution: "arc@npm:0.2.0" - checksum: 10c0/16aceadc9797c153f83417cae5b814b999bc58e2ef0349ff14da3cae7206d65e18844ec86e27fbd4bd8524c782bc5f83ee7a254f90891de8235de4cfc5891b12 - languageName: node - linkType: hard - -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 - languageName: node - linkType: hard - -"async-generator-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-generator-function@npm:1.0.0" - checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186 - languageName: node - linkType: hard - -"balanced-match@npm:^4.0.2": - version: 4.0.4 - resolution: "balanced-match@npm:4.0.4" - checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b - languageName: node - linkType: hard - -"bignumber.js@npm:^9.1.0": - version: 9.3.1 - resolution: "bignumber.js@npm:9.3.1" - checksum: 10c0/61342ba5fe1c10887f0ecf5be02ff6709271481aff48631f86b4d37d55a99b87ce441cfd54df3d16d10ee07ceab7e272fc0be430c657ffafbbbf7b7d631efb75 - languageName: node - linkType: hard - -"binary-extensions@npm:^2.0.0": - version: 2.3.0 - resolution: "binary-extensions@npm:2.3.0" - checksum: 10c0/75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 - languageName: node - linkType: hard - -"body-parser@npm:^2.2.1": - version: 2.3.0 - resolution: "body-parser@npm:2.3.0" - dependencies: - bytes: "npm:^3.1.2" - content-type: "npm:^2.0.0" - debug: "npm:^4.4.3" - http-errors: "npm:^2.0.1" - iconv-lite: "npm:^0.7.2" - on-finished: "npm:^2.4.1" - qs: "npm:^6.15.2" - raw-body: "npm:^3.0.2" - type-is: "npm:^2.1.0" - checksum: 10c0/2a8fbbdc471b588338555a3e1a597d1eb0ad0c21cf20fdc3bac5d3f8d9c3a4b19b4163575ab852a43a5dfc0df7770ced5284f979e561f1a24c2f851ce89e695a - languageName: node - linkType: hard - -"brace-expansion@npm:^5.0.8": - version: 5.0.12 - resolution: "brace-expansion@npm:5.0.12" - dependencies: - balanced-match: "npm:^4.0.2" - checksum: 10c0/a40ac64d3bdb5bb222456514d3633c1f627f03b844f509c69e70f98b78be0ce85e21b44bbfecdd0ddd4cc0855ca4242b41ea96ddccf88c7c3c7a84405474bb3a - languageName: node - linkType: hard - -"braces@npm:~3.0.2": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 - languageName: node - linkType: hard - -"bytes@npm:^3.1.2, bytes@npm:~3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e - languageName: node - linkType: hard - -"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind-apply-helpers@npm:1.0.2" - dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 - languageName: node - linkType: hard - -"chokidar@npm:^3.5.2": - version: 3.6.0 - resolution: "chokidar@npm:3.6.0" - dependencies: - anymatch: "npm:~3.1.2" - braces: "npm:~3.0.2" - fsevents: "npm:~2.3.2" - glob-parent: "npm:~5.1.2" - is-binary-path: "npm:~2.1.0" - is-glob: "npm:~4.0.1" - normalize-path: "npm:~3.0.0" - readdirp: "npm:~3.6.0" - dependenciesMeta: - fsevents: - optional: true - checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 - languageName: node - linkType: hard - -"chownr@npm:^3.0.0": - version: 3.0.0 - resolution: "chownr@npm:3.0.0" - checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 - languageName: node - linkType: hard - -"commander@npm:2": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 - languageName: node - linkType: hard - -"concaveman@npm:^1.2.1": - version: 1.2.1 - resolution: "concaveman@npm:1.2.1" - dependencies: - point-in-polygon: "npm:^1.1.0" - rbush: "npm:^3.0.1" - robust-predicates: "npm:^2.0.4" - tinyqueue: "npm:^2.0.3" - checksum: 10c0/7c4cc79c9a77afadf99161fc586be4b05a82bc1fe7239a3893818fb390dfcce0d5cb0876e5f3dfe721e12a1f64d8bc1c768446e281f4b5b44d70e2ca94bf29e6 - languageName: node - linkType: hard - -"content-disposition@npm:^1.0.0": - version: 1.1.0 - resolution: "content-disposition@npm:1.1.0" - checksum: 10c0/94e0aef65873e69330f5f187fbc44ebce593bdcb8013dd8a68b7d0f159ca089bd30db3f8095d829f81c341695b60a6085ee6e15e6d775c4a325b586cc8d91974 - languageName: node - linkType: hard - -"content-type@npm:^1.0.5": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af - languageName: node - linkType: hard - -"content-type@npm:^2.0.0, content-type@npm:^2.1.0": - version: 2.1.0 - resolution: "content-type@npm:2.1.0" - checksum: 10c0/f5d420f55fd0c7a7f7cbae9637777ce67a074aa79b489d8d9fee8599089592b5f8bb194e1d6885741fee20271034baca0d68d5419535b52d070c4f7e39f4b448 - languageName: node - linkType: hard - -"cookie-signature@npm:^1.2.1": - version: 1.2.2 - resolution: "cookie-signature@npm:1.2.2" - checksum: 10c0/54e05df1a293b3ce81589b27dddc445f462f6fa6812147c033350cd3561a42bc14481674e05ed14c7bd0ce1e8bb3dc0e40851bad75415733711294ddce0b7bc6 - languageName: node - linkType: hard - -"cookie@npm:^0.7.1": - version: 0.7.2 - resolution: "cookie@npm:0.7.2" - checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2 - languageName: node - linkType: hard - -"d3-array@npm:^2.5.0": - version: 2.12.1 - resolution: "d3-array@npm:2.12.1" - dependencies: - internmap: "npm:^1.0.0" - checksum: 10c0/7eca10427a9f113a4ca6a0f7301127cab26043fd5e362631ef5a0edd1c4b2dd70c56ed317566700c31e4a6d88b55f3951aaba192291817f243b730cb2352882e - languageName: node - linkType: hard - -"d3-geo@npm:^2.0.2": - version: 2.0.2 - resolution: "d3-geo@npm:2.0.2" - dependencies: - d3-array: "npm:^2.5.0" - checksum: 10c0/6836feb33036f03ec1dc728d64171f3eb40ee2c1c0f2e28232055aa317e5e2d481075294babb9553596e2080496eda119b8a43c51f71c893e6258ccf002bd7f8 - languageName: node - linkType: hard - -"d3-voronoi@npm:1.1.2": - version: 1.1.2 - resolution: "d3-voronoi@npm:1.1.2" - checksum: 10c0/c2dfd76d893cdb78e4aed0f8b64a34147bc7f58a7bbf01581538f8761aefb2a6ee77e818b17c4f85c84ea81447719462f14aa7535eb25ec608d526f486744326 - languageName: node - linkType: hard - -"debug@npm:^4, debug@npm:^4.4.0, debug@npm:^4.4.3": - version: 4.4.3 - resolution: "debug@npm:4.4.3" - dependencies: - ms: "npm:^2.1.3" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 - languageName: node - linkType: hard - -"depd@npm:^2.0.0, depd@npm:~2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c - languageName: node - linkType: hard - -"dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 - languageName: node - linkType: hard - -"earcut@npm:^2.2.4": - version: 2.2.4 - resolution: "earcut@npm:2.2.4" - checksum: 10c0/01ca51830edd2787819f904ae580087d37351f6048b4565e7add4b3da8a86b7bc19262ab2aa7fdc64129ab03af2d9cec8cccee4d230c82275f97ef285c79aafb - languageName: node - linkType: hard - -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 - languageName: node - linkType: hard - -"encodeurl@npm:^2.0.0": - version: 2.0.0 - resolution: "encodeurl@npm:2.0.0" - checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c - languageName: node - linkType: hard - -"es-errors@npm:^1.3.0": - version: 1.3.0 - resolution: "es-errors@npm:1.3.0" - checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 - languageName: node - linkType: hard - -"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.2 - resolution: "es-object-atoms@npm:1.1.2" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10c0/1772861f094f739d6f41b579cfb9a18579daffeb434552a370a5fbef50a32d22227e27b63fdbb757b7ddd429d1b42fe52ccae7966d9302a2ec221b6f1b41bbc4 - languageName: node - linkType: hard - -"escape-html@npm:^1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 - languageName: node - linkType: hard - -"etag@npm:^1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.3 - resolution: "exponential-backoff@npm:3.1.3" - checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 - languageName: node - linkType: hard - -"express@npm:^5.2.1": - version: 5.2.1 - resolution: "express@npm:5.2.1" - dependencies: - accepts: "npm:^2.0.0" - body-parser: "npm:^2.2.1" - content-disposition: "npm:^1.0.0" - content-type: "npm:^1.0.5" - cookie: "npm:^0.7.1" - cookie-signature: "npm:^1.2.1" - debug: "npm:^4.4.0" - depd: "npm:^2.0.0" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - etag: "npm:^1.8.1" - finalhandler: "npm:^2.1.0" - fresh: "npm:^2.0.0" - http-errors: "npm:^2.0.0" - merge-descriptors: "npm:^2.0.0" - mime-types: "npm:^3.0.0" - on-finished: "npm:^2.4.1" - once: "npm:^1.4.0" - parseurl: "npm:^1.3.3" - proxy-addr: "npm:^2.0.7" - qs: "npm:^6.14.0" - range-parser: "npm:^1.2.1" - router: "npm:^2.2.0" - send: "npm:^1.1.0" - serve-static: "npm:^2.2.0" - statuses: "npm:^2.0.1" - type-is: "npm:^2.0.1" - vary: "npm:^1.1.2" - checksum: 10c0/45e8c841ad188a41402ddcd1294901e861ee0819f632fb494f2ed344ef9c43315d294d443fb48d594e6586a3b779785120f43321417adaef8567316a55072949 - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 - languageName: node - linkType: hard - -"fdir@npm:^6.5.0": - version: 6.5.0 - resolution: "fdir@npm:6.5.0" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 - languageName: node - linkType: hard - -"finalhandler@npm:^2.1.0": - version: 2.1.1 - resolution: "finalhandler@npm:2.1.1" - dependencies: - debug: "npm:^4.4.0" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - on-finished: "npm:^2.4.1" - parseurl: "npm:^1.3.3" - statuses: "npm:^2.0.1" - checksum: 10c0/6bd664e21b7b2e79efcaace7d1a427169f61cce048fae68eb56290e6934e676b78e55d89f5998c5508871345bc59a61f47002dc505dc7288be68cceac1b701e2 - languageName: node - linkType: hard - -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: 10c0/9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 - languageName: node - linkType: hard - -"fresh@npm:^2.0.0": - version: 2.0.0 - resolution: "fresh@npm:2.0.0" - checksum: 10c0/0557548194cb9a809a435bf92bcfbc20c89e8b5eb38861b73ced36750437251e39a111fc3a18b98531be9dd91fe1411e4969f229dc579ec0251ce6c5d4900bbc - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 - languageName: node - linkType: hard - -"generator-function@npm:^2.0.0": - version: 2.0.1 - resolution: "generator-function@npm:2.0.1" - checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 - languageName: node - linkType: hard - -"geojson-equality-ts@npm:^1.0.2": - version: 1.0.2 - resolution: "geojson-equality-ts@npm:1.0.2" - dependencies: - "@types/geojson": "npm:^7946.0.14" - checksum: 10c0/f582c6a549673f238b1eb450511e7be222ded8af039924fd21d03ab201de003a5b1769c44b35ca59406533322165520d7aea77e7e1011722259a1485edb30e24 - languageName: node - linkType: hard - -"geojson-polygon-self-intersections@npm:^1.2.1": - version: 1.2.2 - resolution: "geojson-polygon-self-intersections@npm:1.2.2" - dependencies: - rbush: "npm:^2.0.1" - checksum: 10c0/2099cca7466b421f057461f5883535c0c5bd1b14c541f62bb1f7ad81035b92f9983f6c752a97cae8dd93a593d75f5f459bcc3b99c7daf302b331cd6cedd14980 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.3.0": - version: 1.3.1 - resolution: "get-intrinsic@npm:1.3.1" - dependencies: - async-function: "npm:^1.0.0" - async-generator-function: "npm:^1.0.0" - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - function-bind: "npm:^1.1.2" - generator-function: "npm:^2.0.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d - languageName: node - linkType: hard - -"get-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c - languageName: node - linkType: hard - -"glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee - languageName: node - linkType: hard - -"gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 - languageName: node - linkType: hard - -"has-flag@npm:^3.0.0": - version: 3.0.0 - resolution: "has-flag@npm:3.0.0" - checksum: 10c0/1c6c83b14b8b1b3c25b0727b8ba3e3b647f99e9e6e13eb7322107261de07a4c1be56fc0d45678fc376e09772a3a1642ccdaf8fc69bdf123b6c086598397ce473 - languageName: node - linkType: hard - -"has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.4 - resolution: "hasown@npm:2.0.4" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 - languageName: node - linkType: hard - -"http-errors@npm:^2.0.0, http-errors@npm:^2.0.1, http-errors@npm:~2.0.1": - version: 2.0.1 - resolution: "http-errors@npm:2.0.1" - dependencies: - depd: "npm:~2.0.0" - inherits: "npm:~2.0.4" - setprototypeof: "npm:~1.2.0" - statuses: "npm:~2.0.2" - toidentifier: "npm:~1.0.1" - checksum: 10c0/fb38906cef4f5c83952d97661fe14dc156cb59fe54812a42cd448fa57b5c5dfcb38a40a916957737bd6b87aab257c0648d63eb5b6a9ca9f548e105b6072712d4 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.7.2, iconv-lite@npm:~0.7.0": - version: 0.7.3 - resolution: "iconv-lite@npm:0.7.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/be2fd2414f7e94be3a63063fa0ad5919c16bc7b6e00c77eea0765ced6db405739f38dd51016583058fba25cc1d0106ba30b83fbb7a7e32f824d4db76f23d8d33 - languageName: node - linkType: hard - -"ignore-by-default@npm:^1.0.1": - version: 1.0.1 - resolution: "ignore-by-default@npm:1.0.1" - checksum: 10c0/9ab6e70e80f7cc12735def7ecb5527cfa56ab4e1152cd64d294522827f2dcf1f6d85531241537dc3713544e88dd888f65cb3c49c7b2cddb9009087c75274e533 - languageName: node - linkType: hard - -"inherits@npm:~2.0.4": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - -"internmap@npm:^1.0.0": - version: 1.0.1 - resolution: "internmap@npm:1.0.1" - checksum: 10c0/60942be815ca19da643b6d4f23bd0bf4e8c97abbd080fb963fe67583b60bdfb3530448ad4486bae40810e92317bded9995cc31411218acc750d72cd4e8646eee - languageName: node - linkType: hard - -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: 10c0/0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a - languageName: node - linkType: hard - -"is-binary-path@npm:~2.1.0": - version: 2.1.0 - resolution: "is-binary-path@npm:2.1.0" - dependencies: - binary-extensions: "npm:^2.0.0" - checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 - languageName: node - linkType: hard - -"is-glob@npm:^4.0.1, is-glob@npm:~4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 - languageName: node - linkType: hard - -"is-promise@npm:^4.0.0": - version: 4.0.0 - resolution: "is-promise@npm:4.0.0" - checksum: 10c0/ebd5c672d73db781ab33ccb155fb9969d6028e37414d609b115cc534654c91ccd061821d5b987eefaa97cf4c62f0b909bb2f04db88306de26e91bfe8ddc01503 - languageName: node - linkType: hard - -"isexe@npm:^4.0.0": - version: 4.0.0 - resolution: "isexe@npm:4.0.0" - checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce - languageName: node - linkType: hard - -"jsts@npm:2.7.1": - version: 2.7.1 - resolution: "jsts@npm:2.7.1" - checksum: 10c0/57752f181eafef7af3f7e0b374ec0a820288bf0c9dc2d3a854643092331431d6f091a26c7a3947634a92cd64990004f4ddd750b0e95d7f8f6711e1d7bdc8237c - languageName: node - linkType: hard - -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f - languageName: node - linkType: hard - -"media-typer@npm:^1.1.0": - version: 1.1.1 - resolution: "media-typer@npm:1.1.1" - checksum: 10c0/924644de220c3107fc53ec0299b7c1488503470265d32f1492535bd798cc369ba7ceaf9c2a4533361590dcf7208d1cc7b7032dbc1a5918773f5f5d912cab5211 - languageName: node - linkType: hard - -"merge-descriptors@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-descriptors@npm:2.0.0" - checksum: 10c0/95389b7ced3f9b36fbdcf32eb946dc3dd1774c2fdf164609e55b18d03aa499b12bd3aae3a76c1c7185b96279e9803525550d3eb292b5224866060a288f335cb3 - languageName: node - linkType: hard - -"mime-db@npm:^1.54.0": - version: 1.54.0 - resolution: "mime-db@npm:1.54.0" - checksum: 10c0/8d907917bc2a90fa2df842cdf5dfeaf509adc15fe0531e07bb2f6ab15992416479015828d6a74200041c492e42cce3ebf78e5ce714388a0a538ea9c53eece284 - languageName: node - linkType: hard - -"mime-types@npm:^3.0.0, mime-types@npm:^3.0.2": - version: 3.0.2 - resolution: "mime-types@npm:3.0.2" - dependencies: - mime-db: "npm:^1.54.0" - checksum: 10c0/35a0dd1035d14d185664f346efcdb72e93ef7a9b6e9ae808bd1f6358227010267fab52657b37562c80fc888ff76becb2b2938deb5e730818b7983bf8bd359767 - languageName: node - linkType: hard - -"minimatch@npm:^10.2.1": - version: 10.2.6 - resolution: "minimatch@npm:10.2.6" - dependencies: - brace-expansion: "npm:^5.0.8" - checksum: 10c0/4559a836243b98bd4d17ea9f7edae698717c76399eea7be374f3737f33164e4907f19e9726891ddeb122f750a5a7fa80d2ac43e851d6e5984dc4ff42ec127d3a - languageName: node - linkType: hard - -"minipass@npm:^7.0.4, minipass@npm:^7.1.2": - version: 7.1.3 - resolution: "minipass@npm:7.1.3" - checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb - languageName: node - linkType: hard - -"minizlib@npm:^3.1.0": - version: 3.1.0 - resolution: "minizlib@npm:3.1.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec - languageName: node - linkType: hard - -"mock-api@workspace:.": - version: 0.0.0-use.local - resolution: "mock-api@workspace:." - dependencies: - "@faker-js/faker": "npm:^10.6.0" - "@turf/turf": "npm:^7.4.0" - express: "npm:^5.2.1" - nodemon: "npm:^3.1.14" - languageName: unknown - linkType: soft - -"ms@npm:^2.1.3": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 - languageName: node - linkType: hard - -"negotiator@npm:^1.0.0": - version: 1.1.0 - resolution: "negotiator@npm:1.1.0" - dependencies: - content-type: "npm:^2.1.0" - checksum: 10c0/656fa57de02f1a0c4c09f9e17eb78e8182547c07093e810ff8f16249b6ae31f2c546a3d457905e94f3276b25f0e2741ea1a3bc3912192932ed7e493adfea535e - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 13.0.2 - resolution: "node-gyp@npm:13.0.2" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - graceful-fs: "npm:^4.2.6" - nopt: "npm:^10.0.0" - proc-log: "npm:^7.0.0" - semver: "npm:^7.3.5" - tar: "npm:^7.5.4" - tinyglobby: "npm:^0.2.12" - undici: "npm:^8.4.1" - which: "npm:^7.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10c0/29d33ccf47ffeeb5e7af925550b416f698a26a72eb10975c7eb5775c1d0cecacd76d164a4aa45503d3ddcece209db65c712be00423c69381a4cd14e2e6540559 - languageName: node - linkType: hard - -"nodemon@npm:^3.1.14": - version: 3.1.14 - resolution: "nodemon@npm:3.1.14" - dependencies: - chokidar: "npm:^3.5.2" - debug: "npm:^4" - ignore-by-default: "npm:^1.0.1" - minimatch: "npm:^10.2.1" - pstree.remy: "npm:^1.1.8" - semver: "npm:^7.5.3" - simple-update-notifier: "npm:^2.0.0" - supports-color: "npm:^5.5.0" - touch: "npm:^3.1.0" - undefsafe: "npm:^2.0.5" - bin: - nodemon: bin/nodemon.js - checksum: 10c0/074f2056051a148ad11cda0d6c3f905bdef93a878792385f16e1dff0c63dcf07f23ebe1ab3763dca7314d0266e12129f066070545d817a205ee050a22eff50b0 - languageName: node - linkType: hard - -"nopt@npm:^10.0.0": - version: 10.0.1 - resolution: "nopt@npm:10.0.1" - dependencies: - abbrev: "npm:^5.0.0" - bin: - nopt: bin/nopt.js - checksum: 10c0/980d89257f9587f3e1f77877ddbf905d6aa3b738ec33e49a4fa1a059a0dd82eb28063982b150654a7ae9de386f2ead60e56172db7d37cf56de545f7392a2a26a - languageName: node - linkType: hard - -"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 - languageName: node - linkType: hard - -"on-finished@npm:^2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 - languageName: node - linkType: hard - -"once@npm:^1.4.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 - languageName: node - linkType: hard - -"parseurl@npm:^1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 - languageName: node - linkType: hard - -"path-to-regexp@npm:^8.0.0": - version: 8.4.2 - resolution: "path-to-regexp@npm:8.4.2" - checksum: 10c0/05b115c49b47ad252ce05faa32930f643f23769c68b8bcfe78ad833545140c48bbffb3266986d6c8d5db13a64cf12e07e0d72d9882cab830efeefa553533ebaf - languageName: node - linkType: hard - -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1": - version: 2.3.2 - resolution: "picomatch@npm:2.3.2" - checksum: 10c0/a554d1709e59be97d1acb9eaedbbc700a5c03dbd4579807baed95100b00420bc729335440ef15004ae2378984e2487a7c1cebd743cfdb72b6fa9ab69223c0d61 - languageName: node - linkType: hard - -"picomatch@npm:^4.0.4": - version: 4.0.7 - resolution: "picomatch@npm:4.0.7" - checksum: 10c0/beb6ae02c43ae44e84883b90830196d9046b1726ead292adcf7f57945e0bb0d992d68563d87e03b484b6f3c9a5c6defda7523477f047d7f0e663f126cc01787f - languageName: node - linkType: hard - -"point-in-polygon-hao@npm:^1.1.0": - version: 1.2.4 - resolution: "point-in-polygon-hao@npm:1.2.4" - dependencies: - robust-predicates: "npm:^3.0.2" - checksum: 10c0/12badef8b15216acdae7d609a8aca1b916d6a9cac2f53ace2928e3b521bee57224489ea8fba41d001c0c05c50e64152c175e3d6583d8cad6fe7af929f082b49a - languageName: node - linkType: hard - -"point-in-polygon@npm:^1.1.0": - version: 1.1.0 - resolution: "point-in-polygon@npm:1.1.0" - checksum: 10c0/de00419585ee25555d97585b7a23eeb2464a87ef29404264bee55654ca2ecab5a5a99d33e689c07d045faf80091e838f44a1fd130bdd6134493df53114947343 - languageName: node - linkType: hard - -"polyclip-ts@npm:^0.16.8": - version: 0.16.8 - resolution: "polyclip-ts@npm:0.16.8" - dependencies: - bignumber.js: "npm:^9.1.0" - splaytree-ts: "npm:^1.0.2" - checksum: 10c0/8de02c32e566421875c70890fe6d3d7bd55a92fc39867446e65999e042c4632fb27ab1a7e106e96edd12d63b32a643f3a690d9a980aeda655a41ddf4e8750f5d - languageName: node - linkType: hard - -"proc-log@npm:^7.0.0": - version: 7.0.0 - resolution: "proc-log@npm:7.0.0" - checksum: 10c0/b89c2d862604f35fec795477b0c7e376feab3ba0d4f4d291c4e959567442697cf451ac557d0623c1cc38af45a78128b983410f397a10c5d3a67f76c33de4754b - languageName: node - linkType: hard - -"proxy-addr@npm:^2.0.7": - version: 2.0.8 - resolution: "proxy-addr@npm:2.0.8" - dependencies: - forwarded: "npm:0.2.0" - ipaddr.js: "npm:1.9.1" - checksum: 10c0/58398f36e5b1f72b1011ca21844c0c41a9a3b6f2f0d101bcdb19abb3f3dd9626b27a96e53da777ded901eb67faed0304a4bc1d435b235e436f66f8e5e1fe1f5e - languageName: node - linkType: hard - -"pstree.remy@npm:^1.1.8": - version: 1.1.8 - resolution: "pstree.remy@npm:1.1.8" - checksum: 10c0/30f78c88ce6393cb3f7834216cb6e282eb83c92ccb227430d4590298ab2811bc4a4745f850a27c5178e79a8f3e316591de0fec87abc19da648c2b3c6eb766d14 - languageName: node - linkType: hard - -"qs@npm:^6.14.0, qs@npm:^6.15.2": - version: 6.16.0 - resolution: "qs@npm:6.16.0" - dependencies: - es-define-property: "npm:^1.0.1" - side-channel: "npm:^1.1.1" - checksum: 10c0/eb3e31992fbd70e31a1791e571ed817d70975de7d3bfcbbbec93d77d1dd305877e9e8fdbcc62303c228ee5c3606685622cd6231c042dbc4790bb4e7c65fcbe18 - languageName: node - linkType: hard - -"quickselect@npm:^1.0.1": - version: 1.1.1 - resolution: "quickselect@npm:1.1.1" - checksum: 10c0/8890dfe3c42d18e84fb5c18aee04da49b0f5b9d2a7196344c4451cb5660549a2bf770be866704a4a9e6c73d35475c599dd24cf78abcc19886ab54c019a952a37 - languageName: node - linkType: hard - -"quickselect@npm:^2.0.0": - version: 2.0.0 - resolution: "quickselect@npm:2.0.0" - checksum: 10c0/6c8d591bc73beae4c1996b7b7138233a7dbbbdde29b7b6d822a02d08cd220fd27613f47d6e9635989b12e250d42ef9da3448de1ed12ad962974e207ab3c3562c - languageName: node - linkType: hard - -"range-parser@npm:^1.2.1": - version: 1.3.0 - resolution: "range-parser@npm:1.3.0" - checksum: 10c0/295494bb6685f9ab50f41a5f4fa5ce445aeeb9673b491bf178460fcc3a812dcf0d164cf1c83074f13a71a87d91ead5e097afd53e0630bc49a5101ed60f2a7529 - languageName: node - linkType: hard - -"raw-body@npm:^3.0.2": - version: 3.0.2 - resolution: "raw-body@npm:3.0.2" - dependencies: - bytes: "npm:~3.1.2" - http-errors: "npm:~2.0.1" - iconv-lite: "npm:~0.7.0" - unpipe: "npm:~1.0.0" - checksum: 10c0/d266678d08e1e7abea62c0ce5864344e980fa81c64f6b481e9842c5beaed2cdcf975f658a3ccd67ad35fc919c1f6664ccc106067801850286a6cbe101de89f29 - languageName: node - linkType: hard - -"rbush@npm:^2.0.1": - version: 2.0.2 - resolution: "rbush@npm:2.0.2" - dependencies: - quickselect: "npm:^1.0.1" - checksum: 10c0/dfaef8171ff1fb15924e0a84150cc23e31508d67a7821ddb948cd0a5d003f5a20406836866bb1a2dc1f1e2dee06aeb2ce02a1f61a4a8f84ccb792696f43883a7 - languageName: node - linkType: hard - -"rbush@npm:^3.0.1": - version: 3.0.1 - resolution: "rbush@npm:3.0.1" - dependencies: - quickselect: "npm:^2.0.0" - checksum: 10c0/55311586c30cdedaa2220de6f1da45fe1fa806263afbf7b6f4c0078983830c2abc7771187896d68bfc9078cb279079fb4c84971831da4b74384aab2c2c417758 - languageName: node - linkType: hard - -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" - dependencies: - picomatch: "npm:^2.2.1" - checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b - languageName: node - linkType: hard - -"robust-predicates@npm:^2.0.4": - version: 2.0.4 - resolution: "robust-predicates@npm:2.0.4" - checksum: 10c0/3c801ff1ea5ce842c1818da62e2be0cc427ab507dc7a21f3ff2e6278f1d32b5c2f2fc740f8e9c188b4e7a2946228c0173607534432314940e89eae15ded79b5f - languageName: node - linkType: hard - -"robust-predicates@npm:^3.0.2": - version: 3.0.3 - resolution: "robust-predicates@npm:3.0.3" - checksum: 10c0/ae23a0318be809545f091a076818747848f144495491e24e6df5d767f2bad0a1501bbeac34e78b74681d1437ecff0585f593ebfe6c8d49a50e79c5053b962693 - languageName: node - linkType: hard - -"router@npm:^2.2.0": - version: 2.2.0 - resolution: "router@npm:2.2.0" - dependencies: - debug: "npm:^4.4.0" - depd: "npm:^2.0.0" - is-promise: "npm:^4.0.0" - parseurl: "npm:^1.3.3" - path-to-regexp: "npm:^8.0.0" - checksum: 10c0/3279de7450c8eae2f6e095e9edacbdeec0abb5cb7249c6e719faa0db2dba43574b4fff5892d9220631c9abaff52dd3cad648cfea2aaace845e1a071915ac8867 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 - languageName: node - linkType: hard - -"semver@npm:^7.3.5, semver@npm:^7.5.3": - version: 7.8.5 - resolution: "semver@npm:7.8.5" - bin: - semver: bin/semver.js - checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c - languageName: node - linkType: hard - -"send@npm:^1.1.0, send@npm:^1.2.0": - version: 1.2.1 - resolution: "send@npm:1.2.1" - dependencies: - debug: "npm:^4.4.3" - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - etag: "npm:^1.8.1" - fresh: "npm:^2.0.0" - http-errors: "npm:^2.0.1" - mime-types: "npm:^3.0.2" - ms: "npm:^2.1.3" - on-finished: "npm:^2.4.1" - range-parser: "npm:^1.2.1" - statuses: "npm:^2.0.2" - checksum: 10c0/fbbbbdc902a913d65605274be23f3d604065cfc3ee3d78bf9fc8af1dc9fc82667c50d3d657f5e601ac657bac9b396b50ee97bd29cd55436320cf1cddebdcec72 - languageName: node - linkType: hard - -"serve-static@npm:^2.2.0": - version: 2.2.1 - resolution: "serve-static@npm:2.2.1" - dependencies: - encodeurl: "npm:^2.0.0" - escape-html: "npm:^1.0.3" - parseurl: "npm:^1.3.3" - send: "npm:^1.2.0" - checksum: 10c0/37986096e8572e2dfaad35a3925fa8da0c0969f8814fd7788e84d4d388bc068cf0c06d1658509788e55bed942a6b6d040a8a267fa92bb9ffb1179f8bacde5fd7 - languageName: node - linkType: hard - -"setprototypeof@npm:~1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc - languageName: node - linkType: hard - -"side-channel-list@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-list@npm:1.0.1" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.4" - checksum: 10c0/d346c787fd2f9f1c2fdea14f00e8250118db0e7596d85a6cb9faa75f105d31a73a8f7a341c93d7df2a2429098c3d37a77bd3be9e88c37094b8c01807bc77c7a2 - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 - languageName: node - linkType: hard - -"side-channel@npm:^1.1.1": - version: 1.1.1 - resolution: "side-channel@npm:1.1.1" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.4" - side-channel-list: "npm:^1.0.1" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10c0/dc0ab81d67f61bda9247d053ce93f41c3fd8ad2bdcb9cf9d8d2f8540d488f26d87a5e99ebfc07eea49ec025867b2452b705442d974b1478f0395e69f6bfb3270 - languageName: node - linkType: hard - -"simple-update-notifier@npm:^2.0.0": - version: 2.0.0 - resolution: "simple-update-notifier@npm:2.0.0" - dependencies: - semver: "npm:^7.5.3" - checksum: 10c0/2a00bd03bfbcbf8a737c47ab230d7920f8bfb92d1159d421bdd194479f6d01ebc995d13fbe13d45dace23066a78a3dc6642999b4e3b38b847e6664191575b20c - languageName: node - linkType: hard - -"skmeans@npm:0.9.7": - version: 0.9.7 - resolution: "skmeans@npm:0.9.7" - checksum: 10c0/42ee6749bd34a5b5fd969d08a4cd704da119aa9fd3be5d468ba14020ae46372674593dca6f35e728c698ad591ad417cab3177f3ebef8bce16b72a06cb924f7d4 - languageName: node - linkType: hard - -"splaytree-ts@npm:^1.0.2": - version: 1.0.2 - resolution: "splaytree-ts@npm:1.0.2" - checksum: 10c0/4c34573891a749055ffe22381ea841ae03dbf7b55a3ea4a1d7df5013bfbe128e79f6c468579358ec573734cdbdf5f77a97ae7185f155248eb8be58151428c85e - languageName: node - linkType: hard - -"statuses@npm:^2.0.1, statuses@npm:^2.0.2, statuses@npm:~2.0.2": - version: 2.0.2 - resolution: "statuses@npm:2.0.2" - checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f - languageName: node - linkType: hard - -"supports-color@npm:^5.5.0": - version: 5.5.0 - resolution: "supports-color@npm:5.5.0" - dependencies: - has-flag: "npm:^3.0.0" - checksum: 10c0/6ae5ff319bfbb021f8a86da8ea1f8db52fac8bd4d499492e30ec17095b58af11f0c55f8577390a749b1c4dde691b6a0315dab78f5f54c9b3d83f8fb5905c1c05 - languageName: node - linkType: hard - -"tar@npm:^7.5.4": - version: 7.5.22 - resolution: "tar@npm:7.5.22" - dependencies: - "@isaacs/fs-minipass": "npm:^4.0.0" - chownr: "npm:^3.0.0" - minipass: "npm:^7.1.2" - minizlib: "npm:^3.1.0" - yallist: "npm:^5.0.0" - checksum: 10c0/1311f6be85a8157ac4c9147bae43e13923d2a1aae15e4aa1bd5239e4e03d2cf53cfe103dde7f35832fbb4c938b042856bc8e9a0afd29abd05e2d1608788c4fea - languageName: node - linkType: hard - -"tinyglobby@npm:^0.2.12": - version: 0.2.17 - resolution: "tinyglobby@npm:0.2.17" - dependencies: - fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.4" - checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c - languageName: node - linkType: hard - -"tinyqueue@npm:^2.0.3": - version: 2.0.3 - resolution: "tinyqueue@npm:2.0.3" - checksum: 10c0/d7b590088f015a94a17132fa209c2f2a80c45158259af5474901fdf5932e95ea13ff6f034bcc725a6d5f66d3e5b888b048c310229beb25ad5bebb4f0a635abf2 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 - languageName: node - linkType: hard - -"toidentifier@npm:~1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 - languageName: node - linkType: hard - -"topojson-client@npm:3.x": - version: 3.1.0 - resolution: "topojson-client@npm:3.1.0" - dependencies: - commander: "npm:2" - bin: - topo2geo: bin/topo2geo - topomerge: bin/topomerge - topoquantize: bin/topoquantize - checksum: 10c0/da2acba268cbf4d002483d5d81452e0d797b2fff6041fafb1d420e58973fa780a6f42041ce4c2677376ab977e5e1732b89c42a2db3c334a34f6c47f4d94b3eaa - languageName: node - linkType: hard - -"topojson-server@npm:3.x": - version: 3.0.1 - resolution: "topojson-server@npm:3.0.1" - dependencies: - commander: "npm:2" - bin: - geo2topo: bin/geo2topo - checksum: 10c0/fb2ab1137b2082664149fa2346a33fbb1706687b9760ae38f1e8fb9f444226fb0b0e517baf0712f9130244b173ec29a4dcab78f9c0f259770a266481041136ec - languageName: node - linkType: hard - -"touch@npm:^3.1.0": - version: 3.1.1 - resolution: "touch@npm:3.1.1" - bin: - nodetouch: bin/nodetouch.js - checksum: 10c0/d2e4d269a42c846a22a29065b9af0b263de58effc85a1764bb7a2e8fc4b47700e9e2fcbd7eb1f5bffbb7c73d860f93600cef282b93ddac8f0b62321cb498b36e - languageName: node - linkType: hard - -"tslib@npm:^2.8.1": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 - languageName: node - linkType: hard - -"type-is@npm:^2.0.1, type-is@npm:^2.1.0": - version: 2.1.0 - resolution: "type-is@npm:2.1.0" - dependencies: - content-type: "npm:^2.0.0" - media-typer: "npm:^1.1.0" - mime-types: "npm:^3.0.0" - checksum: 10c0/a6018f8f509de48f2c7429305e3a920e73b374fa93127dd0877ae1c2df65a5d33907caac8afb0c37a9b9fc7c49f29e3f55d668963dc845d966930b667c07f50e - languageName: node - linkType: hard - -"undefsafe@npm:^2.0.5": - version: 2.0.5 - resolution: "undefsafe@npm:2.0.5" - checksum: 10c0/96c0466a5fbf395917974a921d5d4eee67bca4b30d3a31ce7e621e0228c479cf893e783a109af6e14329b52fe2f0cb4108665fad2b87b0018c0df6ac771261d5 - languageName: node - linkType: hard - -"undici@npm:^8.4.1": - version: 8.11.2 - resolution: "undici@npm:8.11.2" - checksum: 10c0/106f6991178fb7562fd90cdec7993c5f807a9428682306091f0c4b27fc474ec291f868e29972c6252988bf061ad193df943b3b99e775be157a28d92bbb95699d - languageName: node - linkType: hard - -"unpipe@npm:~1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c - languageName: node - linkType: hard - -"vary@npm:^1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f - languageName: node - linkType: hard - -"which@npm:^7.0.0": - version: 7.0.0 - resolution: "which@npm:7.0.0" - dependencies: - isexe: "npm:^4.0.0" - bin: - node-which: bin/which.js - checksum: 10c0/ca0b54f198f78bbc4b7c02e34bda8d335cb352e0adb4cbca1c37b1a957af3a879a82c4c27ca6525bc942f548d8b64f816ef6528360af9f3de55ffb9b979b620d - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 - languageName: node - linkType: hard - -"yallist@npm:^5.0.0": - version: 5.0.0 - resolution: "yallist@npm:5.0.0" - checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 - languageName: node - linkType: hard diff --git a/nginx/Dockerfile.dev b/nginx/Dockerfile.dev deleted file mode 100644 index 85ae3998b..000000000 --- a/nginx/Dockerfile.dev +++ /dev/null @@ -1,2 +0,0 @@ -FROM nginx -COPY ./default.conf /etc/nginx/conf.d/default.conf \ No newline at end of file diff --git a/nginx/default.conf b/nginx/default.conf deleted file mode 100644 index 851d178dc..000000000 --- a/nginx/default.conf +++ /dev/null @@ -1,27 +0,0 @@ -upstream web { - server web:9000; -} - -# upstream mock_api { -# server mock_api:8080; -# } - -server { - listen 80; - listen 35729; - - # location ~ ^/api/+ { - # proxy_pass http://mock_api; - # } - - location / { - proxy_pass http://web; - } - - location /sockjs-node { - proxy_pass http://web; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - } -} diff --git a/package.json b/package.json index ccfa67618..919007ff0 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,11 @@ "ajv-formats": "^3.0.1", "axios": "1.20.0", "axios-progress-bar": "^1.2.0", - "babel-jest": "^30.5.2", "bootstrap": "5.3.8", "buffer": "^6.0.3", "date-fns": "^4.4.0", "dompurify": "^3.4.16", "epsg-index": "^2.0.0", - "eslint": "^10.11.0", "geodesy": "^2.4.0", "humanize-duration": "^3.35.0", "i18next": "^26.4.2", @@ -35,8 +33,6 @@ "i18next-chained-backend": "^5.0.6", "i18next-http-backend": "^4.0.2", "i18next-localstorage-backend": "^4.3.2", - "jest": "^30.5.2", - "jest-watch-typeahead": "^3.0.1", "localforage": "^1.10.0", "lodash": "^4.18.1", "lodash-es": "^4.18.1", @@ -71,16 +67,14 @@ "suncalc": "^2.0.2", "use-sound": "^5.0.0", "uuid": "^14.0.2", - "web-vitals": "^6.2.2", - "workbox-build": "^7.4.1" + "web-vitals": "^6.2.2" }, "scripts": { "build": "vite build && yarn build-sw", "build-sw": "node ./src/sw-build.js", "check-i18n-files-version": "./scripts/check-i18n-files-version.sh", - "lint": "CI=true eslint src", + "format": "eslint --fix . && stylelint --fix \"**/*.scss\"", "start": "vite", - "stylelint": "stylelint ./src/**/*.scss", "test": "TZ=UTC jest", "test-ci": "TZ=UTC CI=true jest --silent --detectOpenHandles --forceExit" }, @@ -94,13 +88,17 @@ "@testing-library/react": "^16.3.3", "@testing-library/user-event": "^14.6.7", "@vitejs/plugin-react": "^6.1.1", - "dotenv": "^18.0.4", + "babel-jest": "^30.5.2", + "dotenv": "^18.0.5", + "eslint": "^10.11.0", "eslint-plugin-jest": "^29.16.6", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.1.1", "globals": "^17.12.0", + "jest": "^30.5.2", "jest-environment-jsdom": "^30.5.2", "jest-fixed-jsdom": "^0.0.11", + "jest-watch-typeahead": "^3.0.1", "jest-webgl-canvas-mock": "^2.5.3", "msw": "3.0.1", "redux-mock-store": "^1.5.5", @@ -109,10 +107,10 @@ "socket.io-mock": "^1.3.2", "stylelint": "^17.15.0", "stylelint-config-css-modules": "^4.6.0", - "stylelint-config-standard": "^40.0.0", - "stylelint-scss": "^7.3.0", + "stylelint-config-standard-scss": "^17.0.0", "vite": "^8.3.1", - "vite-plugin-svgr": "^5.2.0" + "vite-plugin-svgr": "^5.2.0", + "workbox-build": "^7.4.1" }, "jest": { "moduleNameMapper": { @@ -122,6 +120,9 @@ }, "resetMocks": true, "restoreMocks": true, + "roots": [ + "/src" + ], "setupFilesAfterEnv": [ "/src/setupTests.js" ], diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 000000000..198c1b10c Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 8b83f02ea..9113f28ab 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 000000000..6407e0821 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ + diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 000000000..870754835 Binary files /dev/null and b/public/icon-192.png differ diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 000000000..270c3b893 Binary files /dev/null and b/public/icon-512.png differ diff --git a/public/icon-maskable-512.png b/public/icon-maskable-512.png new file mode 100644 index 000000000..f8d95f024 Binary files /dev/null and b/public/icon-maskable-512.png differ diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 2148363f4..000000000 --- a/public/index.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - EarthRanger - - - - -
- - - - - - \ No newline at end of file diff --git a/public/manifest.json b/public/manifest.json index ad8cf6a3c..24cc4035a 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,15 +1,32 @@ { - "short_name": "EarthRanger", - "name": "EarthRanger Conservation Tool", + "background_color": "#ffffff", + "display": "standalone", "icons": [ { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" + "sizes": "any", + "src": "/favicon.svg", + "type": "image/svg+xml" + }, + { + "sizes": "192x192", + "src": "/icon-192.png", + "type": "image/png" + }, + { + "sizes": "512x512", + "src": "/icon-512.png", + "type": "image/png" + }, + { + "purpose": "maskable", + "sizes": "512x512", + "src": "/icon-maskable-512.png", + "type": "image/png" } ], - "start_url": "./index.html", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" + "id": "/", + "name": "EarthRanger Conservation Tool", + "short_name": "EarthRanger", + "start_url": "/", + "theme_color": "#ffffff" } diff --git a/restart.sh b/restart.sh deleted file mode 100644 index f40b1f142..000000000 --- a/restart.sh +++ /dev/null @@ -1 +0,0 @@ -docker compose kill && docker compose down --remove-orphans && docker compose up --build \ No newline at end of file diff --git a/src/AddAttachmentButton/index.js b/src/AddAttachmentButton/index.js index fab87835f..308efd085 100644 --- a/src/AddAttachmentButton/index.js +++ b/src/AddAttachmentButton/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useRef, useState } from 'react'; +import { memo, useCallback, useContext, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { TrackerContext } from '../utils/analytics'; diff --git a/src/AddAttachmentButton/index.test.js b/src/AddAttachmentButton/index.test.js index dd61013e5..be7800ed6 100644 --- a/src/AddAttachmentButton/index.test.js +++ b/src/AddAttachmentButton/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import userEvent from '@testing-library/user-event'; import { fireEvent, render, screen } from '../test-utils'; diff --git a/src/AddAttachmentButton/styles.module.scss b/src/AddAttachmentButton/styles.module.scss index d257305a0..166b87c6e 100644 --- a/src/AddAttachmentButton/styles.module.scss +++ b/src/AddAttachmentButton/styles.module.scss @@ -1,10 +1,9 @@ @use 'sass:color'; - @use '../common/styles/buttons'; @use '../common/styles/vars/colors'; .addAttachmentButton { - @include buttons.baseButton; + @include buttons.base-button; } .draggingOver { diff --git a/src/AddItemButton/AddItemModal/AddPatrolTab/index.js b/src/AddItemButton/AddItemModal/AddPatrolTab/index.js index 709c906f3..8607848a2 100644 --- a/src/AddItemButton/AddItemModal/AddPatrolTab/index.js +++ b/src/AddItemButton/AddItemModal/AddPatrolTab/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useMemo, useState } from 'react'; +import { memo, useCallback, useContext, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/AddItemButton/AddItemModal/AddPatrolTab/index.test.js b/src/AddItemButton/AddItemModal/AddPatrolTab/index.test.js index 170e8f50f..67cdc23b1 100644 --- a/src/AddItemButton/AddItemModal/AddPatrolTab/index.test.js +++ b/src/AddItemButton/AddItemModal/AddPatrolTab/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/AddItemButton/AddItemModal/AddReportTab/index.js b/src/AddItemButton/AddItemModal/AddReportTab/index.js index 8d55bd412..0b6f2b704 100644 --- a/src/AddItemButton/AddItemModal/AddReportTab/index.js +++ b/src/AddItemButton/AddItemModal/AddReportTab/index.js @@ -1,10 +1,10 @@ -import React, { memo, useCallback, useContext, useRef, useState } from 'react'; +import { memo, useCallback, useContext, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { AddItemContext } from '../..'; import { selectCreatableEventTypesByCategory } from '../../../selectors/event-types'; -import { TAB_KEYS } from '../../../constants'; +import { TAB_KEYS } from '../../../constants'; import { trackEvent } from '../../../utils/analytics'; import useNavigate from '../../../hooks/useNavigate'; import { uuid } from '../../../utils/string'; diff --git a/src/AddItemButton/AddItemModal/AddReportTab/index.test.js b/src/AddItemButton/AddItemModal/AddReportTab/index.test.js index d970038b2..1c1cd7ad6 100644 --- a/src/AddItemButton/AddItemModal/AddReportTab/index.test.js +++ b/src/AddItemButton/AddItemModal/AddReportTab/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/AddItemButton/AddItemModal/TypesList/index.js b/src/AddItemButton/AddItemModal/TypesList/index.js index efdebfae0..98b8c4b2b 100644 --- a/src/AddItemButton/AddItemModal/TypesList/index.js +++ b/src/AddItemButton/AddItemModal/TypesList/index.js @@ -1,5 +1,3 @@ -import React from 'react'; - import EventTypeListItem from '../../../EventTypeListItem'; import * as styles from './styles.module.scss'; diff --git a/src/AddItemButton/AddItemModal/TypesList/index.test.js b/src/AddItemButton/AddItemModal/TypesList/index.test.js index a51d3bed4..e57c651b4 100644 --- a/src/AddItemButton/AddItemModal/TypesList/index.test.js +++ b/src/AddItemButton/AddItemModal/TypesList/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/src/AddItemButton/AddItemModal/TypesList/styles.module.scss b/src/AddItemButton/AddItemModal/TypesList/styles.module.scss index cb6a0755f..07c3c8f27 100644 --- a/src/AddItemButton/AddItemModal/TypesList/styles.module.scss +++ b/src/AddItemButton/AddItemModal/TypesList/styles.module.scss @@ -1,13 +1,13 @@ -@import '../../../common/styles/buttons'; -@import '../../../common/styles/layout'; -@import '../../../common/styles/vars/colors'; +@use '../../../common/styles/buttons'; +@use '../../../common/styles/layout'; +@use '../../../common/styles/vars/colors'; .typesContainer { height: 20rem; overflow-y: auto; .categoryTitle { - background: $light-gray-background; + background: colors.$light-gray-background; line-height: normal; margin: 0; padding: 0.25rem 1rem; @@ -24,7 +24,7 @@ width: 100%; button { - @include unstyledButton; + @include buttons.unstyled-button; flex: 1; font-weight: bold; @@ -40,23 +40,23 @@ &:hover { border: none; - color: $bright-blue; + color: colors.$bright-blue; text-decoration: underline; svg { - fill: $bright-blue; + fill: colors.$bright-blue; } } &[aria-disabled='true'], &[aria-disabled='true']:hover { - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; cursor: not-allowed; opacity: 0.6; text-decoration: none; svg { - fill: $secondary-medium-gray; + fill: colors.$secondary-medium-gray; } } } @@ -71,11 +71,11 @@ } &:first-child { - border-top: thin solid $light-gray-border; + border-top: thin solid colors.$light-gray-border; } .typeListItem { - border: 1px solid $light-gray-border; + border: 1px solid colors.$light-gray-border; display: flex; flex-direction: column; font-size: 0.8rem; @@ -85,7 +85,7 @@ } .typeUnavailableReason { - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; display: block; font-size: 0.7rem; padding: 0 0.25rem 0.25rem; diff --git a/src/AddItemButton/AddItemModal/index.js b/src/AddItemButton/AddItemModal/index.js index 5fd1437c2..2f2b09c8b 100644 --- a/src/AddItemButton/AddItemModal/index.js +++ b/src/AddItemButton/AddItemModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useState } from 'react'; import Modal from 'react-bootstrap/Modal'; import Tab from 'react-bootstrap/Tab'; import Tabs from 'react-bootstrap/Tabs'; @@ -36,6 +36,8 @@ const AddItemModal = ({ onHide, show, ...restProps }) => { && activeTabKey !== ADD_TAB_KEYS.ADD_PATROL && (storedActiveTabKey === ADD_TAB_KEYS.ADD_PATROL || hideAddEventTab); if (shouldSelectEventsTab) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect onTabSelect(ADD_TAB_KEYS.ADD_REPORT); } else if (shouldSelectPatrolsTab) { onTabSelect(ADD_TAB_KEYS.ADD_PATROL); diff --git a/src/AddItemButton/AddItemModal/index.test.js b/src/AddItemButton/AddItemModal/index.test.js index d8d8b9304..2964e1212 100644 --- a/src/AddItemButton/AddItemModal/index.test.js +++ b/src/AddItemButton/AddItemModal/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; @@ -8,7 +7,6 @@ import { eventTypes } from '../../__test-helpers/fixtures/event-types'; import { getStoredTab, storeTab } from './utils'; import { mockStore } from '../../__test-helpers/MockStore'; import patrolTypes from '../../__test-helpers/fixtures/patrol-types'; -import { PERMISSION_KEYS, PERMISSIONS, SYSTEM_CONFIG_FLAGS } from '../../constants'; import { render, screen } from '../../test-utils'; import AddItemModal, { ADD_TAB_KEYS } from './'; diff --git a/src/AddItemButton/AddItemModal/styles.module.scss b/src/AddItemButton/AddItemModal/styles.module.scss index c964dc1b2..f7474819b 100644 --- a/src/AddItemButton/AddItemModal/styles.module.scss +++ b/src/AddItemButton/AddItemModal/styles.module.scss @@ -1,20 +1,20 @@ -@import '../../common/styles/vars/colors'; +@use '../../common/styles/vars/colors'; .modalBody { padding: 0; .tabs { border: 0; - background-color: $light-gray; + background-color: colors.$light-gray; - button[role=tab] { + button[role="tab"] { border: 0; - border-bottom: 3px solid $light-gray; - color: $secondary-medium-gray; + border-bottom: 3px solid colors.$light-gray; + color: colors.$secondary-medium-gray; - &[class*=active] { - border-bottom: 3px solid $bright-blue; - color: $bright-blue; + &[class*="active"] { + border-bottom: 3px solid colors.$bright-blue; + color: colors.$bright-blue; } } } diff --git a/src/AddItemButton/index.js b/src/AddItemButton/index.js index e88da6f96..9b82ac65e 100644 --- a/src/AddItemButton/index.js +++ b/src/AddItemButton/index.js @@ -1,4 +1,4 @@ -import React, { createContext, memo, useCallback, useState } from 'react'; +import { createContext, memo, useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; @@ -82,7 +82,7 @@ const AddItemButton = ({ } - />); + />)).not.toThrow(); cleanup(); }); diff --git a/src/FeedListItem/styles.module.scss b/src/FeedListItem/styles.module.scss index c42830ed3..454c51ffd 100644 --- a/src/FeedListItem/styles.module.scss +++ b/src/FeedListItem/styles.module.scss @@ -1,6 +1,6 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/buttons'; -@import '../common/styles/layout'; +@use '../common/styles/vars/colors'; +@use '../common/styles/buttons'; +@use '../common/styles/layout'; .iconContainer { align-items: center; @@ -10,7 +10,7 @@ position: relative; width: 2.625rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: 3.75rem; } @@ -24,21 +24,21 @@ } .listItem { - --listItemHeight: 3rem; + --list-item-height: 3rem; - @media (min-width: $md-layout-width-min) { - --listItemHeight: 3.85rem; + @media (min-width: layout.$md-layout-width-min) { + --list-item-height: 3.85rem; } align-items: center; - color: $primary-font-color; - height: var(--listItemHeight); + color: colors.$primary-font-color; + height: var(--list-item-height); display: flex; line-height: normal; padding: 0 0.5rem 0 0; + .listItem { - border-top: 1px solid $light-gray-border; + border-top: 1px solid colors.$light-gray-border; } > * { @@ -64,7 +64,7 @@ max-width: 20.5rem; width: 100%; - @media (min-width: $md-layout-width-max) { + @media (min-width: layout.$md-layout-width-max) { overflow: unset; margin-right: 1rem; } diff --git a/src/FilterSettingsControl/index.js b/src/FilterSettingsControl/index.js index bdb59f7f3..d38092dd7 100644 --- a/src/FilterSettingsControl/index.js +++ b/src/FilterSettingsControl/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect } from 'react'; +import { memo, useCallback, useEffect } from 'react'; import Overlay from 'react-bootstrap/Overlay'; import Popover from 'react-bootstrap/Popover'; @@ -14,6 +14,8 @@ const FilterSettingsControl = ({ isOpen, hideFilterSettings, target, container, } }, [hideFilterSettings]); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const handleOutsideClick = useCallback((event) => { event.stopPropagation(); event.preventDefault(); diff --git a/src/FilterSettingsControl/styles.module.scss b/src/FilterSettingsControl/styles.module.scss index 6c58dc916..40f0cce6e 100644 --- a/src/FilterSettingsControl/styles.module.scss +++ b/src/FilterSettingsControl/styles.module.scss @@ -2,10 +2,12 @@ div.popover { position: fixed !important; width: 14.0rem; padding: 0.375rem; - [class*=arrow]::before { + + [class*="arrow"]::before { left: -0.3rem; } - [class*=arrow]::after { + + [class*="arrow"]::after { left: -0.3rem; } } diff --git a/src/FriendlyFilterString/index.js b/src/FriendlyFilterString/index.js index 32c224aaf..5aefa8f3f 100644 --- a/src/FriendlyFilterString/index.js +++ b/src/FriendlyFilterString/index.js @@ -1,4 +1,4 @@ -import React, { memo, useMemo } from 'react'; +import { memo, useMemo } from 'react'; import isEqual from 'react-fast-compare'; import pluralize from 'pluralize'; import { useTranslation } from 'react-i18next'; diff --git a/src/FriendlyFilterString/index.test.js b/src/FriendlyFilterString/index.test.js index 34bff85de..9cb7453cf 100644 --- a/src/FriendlyFilterString/index.test.js +++ b/src/FriendlyFilterString/index.test.js @@ -1,5 +1,3 @@ -import React from 'react'; - import FriendlyFilterString from '.'; import { EVENT_SORT_OPTIONS, SORT_DIRECTION } from '../constants'; import { render, screen } from '../test-utils'; diff --git a/src/GearLayer/index.js b/src/GearLayer/index.js index 6a531be77..e33c78c78 100644 --- a/src/GearLayer/index.js +++ b/src/GearLayer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext, useEffect, useMemo } from 'react'; +import { memo, useContext, useEffect, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { MapContext } from '../MapContext'; @@ -114,7 +114,9 @@ const GearLayer = ({ onGearClick }) => { } return tearDown; - }, [map, shouldRender]); // geojson updates applied in the following effect via setData + // geojson updates are applied by the following effect through setData. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [map, shouldRender]); useEffect(() => { if (!map || !shouldRender) return; diff --git a/src/GearLayer/index.test.js b/src/GearLayer/index.test.js index 31127bc51..7f1b72c8c 100644 --- a/src/GearLayer/index.test.js +++ b/src/GearLayer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render } from '@testing-library/react'; import { useSelector } from 'react-redux'; diff --git a/src/GearPopup/index.test.js b/src/GearPopup/index.test.js index f9ff0ebdb..62b9a50f1 100644 --- a/src/GearPopup/index.test.js +++ b/src/GearPopup/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider, useSelector } from 'react-redux'; import { GPS_FORMATS } from '../utils/location'; diff --git a/src/GearPopup/styles.module.scss b/src/GearPopup/styles.module.scss index 2892f77c8..576b19f19 100644 --- a/src/GearPopup/styles.module.scss +++ b/src/GearPopup/styles.module.scss @@ -1,16 +1,16 @@ -@import '../common/styles/vars/colors'; +@use '../common/styles/vars/colors'; .popup { - [class*=mapboxgl-popup-content] { + [class*="mapboxgl-popup-content"] { width: 16.25rem; } } .header { - background-color: $off-black; + background-color: colors.$off-black; border-radius: 0.5rem 0.5rem 0 0; color: white; - margin: -0.7rem -0.7rem 0.75rem -0.7rem; + margin: -0.7rem -0.7rem 0.75rem; padding: 0.5rem; text-align: left; @@ -40,7 +40,6 @@ .title { margin: 0; overflow-wrap: anywhere; - word-break: break-word; } .body { @@ -66,7 +65,6 @@ max-width: 100%; min-width: 0; overflow-wrap: anywhere; - word-break: break-word; } } diff --git a/src/GeoLocationWatcher/index.test.js b/src/GeoLocationWatcher/index.test.js index e4673c0ba..15ed88541 100644 --- a/src/GeoLocationWatcher/index.test.js +++ b/src/GeoLocationWatcher/index.test.js @@ -1,5 +1,3 @@ -import React from 'react'; - import { Provider } from 'react-redux'; import { toast } from 'react-toastify'; diff --git a/src/GetUserLocationButton/index.js b/src/GetUserLocationButton/index.js index cde2a4e96..dc2cd82fe 100644 --- a/src/GetUserLocationButton/index.js +++ b/src/GetUserLocationButton/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useImperativeHandle, useRef, useState } from 'react'; +import { memo, useEffect, useImperativeHandle, useRef, useState } from 'react'; import { toast } from 'react-toastify'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/GetUserLocationButton/styles.module.scss b/src/GetUserLocationButton/styles.module.scss index b4b11b0b4..eb08d8da6 100644 --- a/src/GetUserLocationButton/styles.module.scss +++ b/src/GetUserLocationButton/styles.module.scss @@ -1,5 +1,4 @@ @use 'sass:color'; - @use '../common/styles/vars/colors'; .loadingOverlay { diff --git a/src/GlobalMenuDrawer/index.js b/src/GlobalMenuDrawer/index.js index 678b8219c..6259cb8b2 100644 --- a/src/GlobalMenuDrawer/index.js +++ b/src/GlobalMenuDrawer/index.js @@ -1,4 +1,4 @@ -import React, { lazy, useCallback, useEffect, useMemo, useRef } from 'react'; +import { lazy, useCallback, useEffect, useMemo, useRef } from 'react'; import { getYear } from 'date-fns'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/GlobalMenuDrawer/index.test.js b/src/GlobalMenuDrawer/index.test.js index bec1a6282..e07e5197a 100644 --- a/src/GlobalMenuDrawer/index.test.js +++ b/src/GlobalMenuDrawer/index.test.js @@ -1,9 +1,8 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; import { addModal } from '../ducks/modals'; -import { createQuerySelectorMockImplementationWithHelpButtonReference } from '../JiraSupportWidget/index.test'; +import { createQuerySelectorMockImplementationWithHelpButtonReference } from '../__test-helpers/jiraSupportWidget'; import { eventTypes } from '../__test-helpers/fixtures/event-types'; import { fetchTableauDashboard } from '../ducks/external-reporting'; import GlobalMenuDrawer from '.'; diff --git a/src/GpsFormatToggle/index.js b/src/GpsFormatToggle/index.js index 5823f38fc..173550e0b 100644 --- a/src/GpsFormatToggle/index.js +++ b/src/GpsFormatToggle/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useId, useImperativeHandle, useRef } from 'react'; +import { memo, useEffect, useId, useImperativeHandle, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/GpsFormatToggle/index.test.js b/src/GpsFormatToggle/index.test.js index c1261dcb5..a7a457841 100644 --- a/src/GpsFormatToggle/index.test.js +++ b/src/GpsFormatToggle/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/GpsFormatToggle/styles.module.scss b/src/GpsFormatToggle/styles.module.scss index 0e580d855..ad638a78f 100644 --- a/src/GpsFormatToggle/styles.module.scss +++ b/src/GpsFormatToggle/styles.module.scss @@ -1,5 +1,4 @@ @use 'sass:color'; - @use '../common/styles/buttons'; @use '../common/styles/layout'; @use '../common/styles/vars/colors'; @@ -12,7 +11,7 @@ .legend, .input { border: 0; - clip: rect(0, 0, 0, 0); + clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden; @@ -85,7 +84,7 @@ } .textCopyButton { - @include buttons.iconButtonSmall; + @include buttons.icon-button-small; flex-shrink: 0; margin: 0; diff --git a/src/GpsFormatTogglePopup/index.js b/src/GpsFormatTogglePopup/index.js index d5b12708d..12d0fe63d 100644 --- a/src/GpsFormatTogglePopup/index.js +++ b/src/GpsFormatTogglePopup/index.js @@ -1,5 +1,3 @@ -import React from 'react'; - import GpsFormatToggle from '../GpsFormatToggle'; const GpsFormatTogglePopup = () => ; diff --git a/src/GpsFormatTogglePopup/styles.module.scss b/src/GpsFormatTogglePopup/styles.module.scss index 66e5d0c1d..2f12e9eb2 100644 --- a/src/GpsFormatTogglePopup/styles.module.scss +++ b/src/GpsFormatTogglePopup/styles.module.scss @@ -1,18 +1,18 @@ .popup { max-width: 22rem !important; - [class*=mapboxgl-popup-tip] { + [class*="mapboxgl-popup-tip"] { border-width: 5px; visibility: hidden; } - [class*=mapboxgl-popup-content] { + [class*="mapboxgl-popup-content"] { background: white; min-width: 16rem; padding: 0.5rem; width: auto; - [class*=gps-format-toggle] { + [class*="gps-format-toggle"] { fieldset { label { font-size: 0.75rem; diff --git a/src/GpsInput/index.js b/src/GpsInput/index.js index 9266fff8a..e02918214 100644 --- a/src/GpsInput/index.js +++ b/src/GpsInput/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useId, useRef, useState } from 'react'; +import { memo, useEffect, useId, useRef, useState } from 'react'; import debounce from 'lodash/debounce'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; @@ -131,7 +131,7 @@ const GpsInput = ({ if (isNewInputValueValid) { onChange(lngLat); } - } catch (error) { + } catch { setIsInputValueValid(false); } } @@ -199,6 +199,8 @@ const GpsInput = ({ // If the text search option is checked, set the input to the content // of the selected place or empty it if there isn't one. const selectedPlace = placesFromSearchText?.[selectedPlaceIndex]; + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setInputValue(selectedPlace ? `${selectedPlace.namePreferred} - ${selectedPlace.placeFormatted}` : ''); } else { // If the text search option is unchecked or the coordinates @@ -239,8 +241,12 @@ const GpsInput = ({ onChange={onInputChange} onKeyDown={onInputKeyDown} placeholder={inputPlaceholder} + // This in-place change is intended. + // eslint-disable-next-line react-hooks/immutability ref={(element) => { if (inputRef) { + // This in-place change is intended. + // eslint-disable-next-line react-hooks/immutability inputRef.current = element; } innerInputRef.current = element; diff --git a/src/GpsInput/index.test.js b/src/GpsInput/index.test.js index 0c0565516..e23adb68e 100644 --- a/src/GpsInput/index.test.js +++ b/src/GpsInput/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/GpsInput/styles.module.scss b/src/GpsInput/styles.module.scss index 1d20ebc66..71c052bde 100644 --- a/src/GpsInput/styles.module.scss +++ b/src/GpsInput/styles.module.scss @@ -1,5 +1,4 @@ @use 'sass:color'; - @use '../common/styles/vars/colors'; .inputWrapper { @@ -34,7 +33,7 @@ &::-webkit-search-cancel-button, &::-webkit-search-results-button, &::-webkit-search-results-decoration { - -webkit-appearance: none; + appearance: none; } } } @@ -65,7 +64,7 @@ background-color: colors.$semi-light-gray; } - &[aria-selected=true] { + &[aria-selected="true"] { background-color: colors.$very-light-blue; padding-left: 0.5rem; diff --git a/src/HamburgerMenuIcon/index.js b/src/HamburgerMenuIcon/index.js index 0bfa8a9d3..038d3d7c2 100644 --- a/src/HamburgerMenuIcon/index.js +++ b/src/HamburgerMenuIcon/index.js @@ -1,5 +1,3 @@ -import React from 'react'; - import * as styles from './styles.module.scss'; const HamburgerMenuIcon = ({ className = '', isOpen = false, ref, ...restProps }) => + {/* Using this ref during render is intended. */} + {/* eslint-disable-next-line react-hooks/refs */} setPopoverOpenState(false)} container={wrapperRef.current} target={wrapperRef.current}>
    diff --git a/src/MapBaseLayerControl/styles.module.scss b/src/MapBaseLayerControl/styles.module.scss index eb9e32775..b51932afc 100644 --- a/src/MapBaseLayerControl/styles.module.scss +++ b/src/MapBaseLayerControl/styles.module.scss @@ -1,13 +1,15 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/buttons'; +@use 'sass:color'; +@use '../common/styles/vars/colors'; +@use '../common/styles/buttons'; .wrapper { position: relative; } .button { - @include mapboxControlButton; + @include buttons.mapbox-control-button; + svg path { fill: #333; } @@ -18,9 +20,11 @@ background: none; border: none; max-width: 26rem; + // overflow: hidden; width: 90vw; - [class*=popover-body] { + + [class*="popover-body"] { padding: 0; } } @@ -31,16 +35,21 @@ flex-wrap: wrap; justify-content: flex-end; margin: 0; + li { align-self: stretch; - border: thin solid $light-gray-border;; - margin: -1px -1px; + border: thin solid colors.$light-gray-border;; + margin: -1px; text-align: center; - width: calc(100%/3); + width: calc(100% / 3); + button { $hover: white; + background: rgba($hover, 0.8) !important; - @include unstyledButton; + + @include buttons.unstyled-button; + align-items: center; display: flex; height: 100%; @@ -53,17 +62,20 @@ padding: 0.5rem; transition: background 0.2s linear; width: 100%; - &[type=button]:first-child { /* the first-child selector is a selector specificity */ + + &[type="button"]:first-child { /* the first-child selector is a selector specificity */ &:hover, &:active { - background: rgba(darken($hover, 2%), 0.925) !important; + background: rgba(color.adjust($hover, $lightness: -2%), 0.925) !important; text-decoration: underline; } + &.active { background: $hover !important; } } } } + img { margin-bottom: 0.25rem; max-height: 2.5rem; diff --git a/src/MapDrawingTools/ContextProvider.js b/src/MapDrawingTools/ContextProvider.js index 868708573..6240cfe3d 100644 --- a/src/MapDrawingTools/ContextProvider.js +++ b/src/MapDrawingTools/ContextProvider.js @@ -1,4 +1,4 @@ -import React, { createContext, useState } from 'react'; +import { createContext, useState } from 'react'; export const MapDrawingToolsContext = createContext(); diff --git a/src/MapDrawingTools/MapLayers.js b/src/MapDrawingTools/MapLayers.js index 8c2e63bb5..2f1fdc61a 100644 --- a/src/MapDrawingTools/MapLayers.js +++ b/src/MapDrawingTools/MapLayers.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useState } from 'react'; import { MapContext } from '../MapContext'; import { useMapEventBinding } from '../hooks'; diff --git a/src/MapDrawingTools/index.js b/src/MapDrawingTools/index.js index 7eaade553..0fb78e605 100644 --- a/src/MapDrawingTools/index.js +++ b/src/MapDrawingTools/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import debounce from 'lodash/debounce'; import noop from 'lodash/noop'; import isEqual from 'react-fast-compare'; @@ -67,7 +67,8 @@ const MapDrawingTools = ({ const showLayer = pointerLocation || points.length; - // eslint-disable-next-line react-hooks/exhaustive-deps + // Memoizing the debounced handler, with these dependencies, is intended. + // eslint-disable-next-line react-hooks/exhaustive-deps, react-hooks/use-memo const onMapClick = useCallback(debounce((event) => { event.preventDefault(); event.originalEvent.stopPropagation(); diff --git a/src/MapDrawingTools/index.test.js b/src/MapDrawingTools/index.test.js index 1f07c4183..028ef46fe 100644 --- a/src/MapDrawingTools/index.test.js +++ b/src/MapDrawingTools/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { createMapMock } from '../__test-helpers/mocks'; import { MapContext } from '../MapContext'; @@ -34,7 +33,7 @@ describe('rendering', () => { let drawing = false; let map = createMapMock(); - render( + expect(() => render( @@ -42,7 +41,7 @@ describe('rendering', () => { - ); + )).not.toThrow(); }); }); @@ -69,13 +68,13 @@ describe('MapDrawingTools', () => { points = []; drawing = true; - render( + expect(() => render( - ); + )).not.toThrow(); }); }); diff --git a/src/MapDrawingTools/styles.module.scss b/src/MapDrawingTools/styles.module.scss index 68d1adb8e..3c5ef7e1c 100644 --- a/src/MapDrawingTools/styles.module.scss +++ b/src/MapDrawingTools/styles.module.scss @@ -1,4 +1,4 @@ -$background: rgba(0,0,0,0.65); +$background: rgb(0 0 0 / 65%); .popup { line-height: normal; @@ -12,16 +12,16 @@ $background: rgba(0,0,0,0.65); } &.notDone { - [class*=mapboxgl-popup-content] { + [class*="mapboxgl-popup-content"] { background: $background; color: white; max-width: 10rem; padding: 0.25rem; } - [class*=mapboxgl-popup-tip] { + [class*="mapboxgl-popup-tip"] { border-right-color: $background; - border-top-color: rgba(0,0,0,0); + border-top-color: rgb(0 0 0 / 0%); } } } \ No newline at end of file diff --git a/src/MapImagesLayer/index.test.js b/src/MapImagesLayer/index.test.js index ccb6d03d6..92aeb9562 100644 --- a/src/MapImagesLayer/index.test.js +++ b/src/MapImagesLayer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { createMapMock } from '../__test-helpers/mocks'; @@ -9,11 +8,11 @@ import { render } from '../test-utils'; import MapImagesLayer from './'; test('rendering without crashing', () => { - render( + expect(() => render( - ); + )).not.toThrow(); }); describe('adding images to the map', () => { diff --git a/src/MapLegend/index.js b/src/MapLegend/index.js index 124f8ce74..bd0cf6363 100644 --- a/src/MapLegend/index.js +++ b/src/MapLegend/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Popover from 'react-bootstrap/Popover'; diff --git a/src/MapLegend/index.test.js b/src/MapLegend/index.test.js index 776d9890d..aacebd96d 100644 --- a/src/MapLegend/index.test.js +++ b/src/MapLegend/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import userEvent from '@testing-library/user-event'; import { render, screen } from '../test-utils'; diff --git a/src/MapLegend/styles.module.scss b/src/MapLegend/styles.module.scss index 2e9eb7812..1739c2238 100644 --- a/src/MapLegend/styles.module.scss +++ b/src/MapLegend/styles.module.scss @@ -1,13 +1,13 @@ -@import '../common/styles/buttons'; -@import '../common//styles//vars/colors'; +@use '../common/styles/buttons'; +@use '../common//styles//vars/colors'; .mapLegend { --close-button-size: 1.75rem; --legend-height: 3.25rem; - background: rgba(255, 255, 255, 0.9); + background: rgb(255 255 255 / 90%); border-radius: 0 var(--close-button-size) var(--close-button-size) 0; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.5); + box-shadow: 0 0 4px rgb(0 0 0 / 50%); display: flex; flex-wrap: wrap; height: var(--legend-height); @@ -42,7 +42,7 @@ } } -@mixin buttonOpacity { +@mixin button-opacity { opacity: 0.75; &:hover { @@ -57,8 +57,8 @@ } .close { - @include unstyledButton; - @include buttonOpacity; + @include buttons.unstyled-button; + @include button-opacity; right: 0.25rem; padding: 0; @@ -75,8 +75,8 @@ .gearButton { --dimensions: 1rem; - @include buttonOpacity; - @include gearButton; + @include button-opacity; + @include buttons.gear-button; height: var(--dimensions); position: absolute; diff --git a/src/MapLocationSelectionOverview/index.js b/src/MapLocationSelectionOverview/index.js index 7b829fe87..e67b2f59e 100644 --- a/src/MapLocationSelectionOverview/index.js +++ b/src/MapLocationSelectionOverview/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useState } from 'react'; +import { memo, useCallback, useContext, useState } from 'react'; import Button from 'react-bootstrap/Button'; import Collapse from 'react-bootstrap/Collapse'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; diff --git a/src/MapLocationSelectionOverview/index.test.js b/src/MapLocationSelectionOverview/index.test.js index fbb1ae5db..e4210bef7 100644 --- a/src/MapLocationSelectionOverview/index.test.js +++ b/src/MapLocationSelectionOverview/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; import cloneDeep from 'lodash/cloneDeep'; @@ -103,7 +102,7 @@ describe('MapLocationSelectionOverview', () => { describe('with a single-point location', () => { test('the title is "Choose report location"', async () => { - await screen.findByText('Choose event location'); + expect(await screen.findByText('Choose event location')).toBeInTheDocument(); }); }); @@ -125,7 +124,7 @@ describe('MapLocationSelectionOverview', () => { }); test('the title is "Create report area"', async () => { - await screen.findByText('Create event area'); + expect(await screen.findByText('Create event area')).toBeInTheDocument(); }); test('renders default values for area and perimeter', async () => { diff --git a/src/MapLocationSelectionOverview/styles.module.scss b/src/MapLocationSelectionOverview/styles.module.scss index 799f8ba39..fd296f8fa 100644 --- a/src/MapLocationSelectionOverview/styles.module.scss +++ b/src/MapLocationSelectionOverview/styles.module.scss @@ -1,9 +1,9 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/animations'; -@import '../common/styles/layout'; +@use '../common/styles/vars/colors'; +@use '../common/styles/animations'; +@use '../common/styles/layout'; .mapLocationSelectionOverview { - @include fade-in; + @include animations.fade-in; background: white; border-radius: 3px; @@ -14,7 +14,7 @@ transition: all 0.3s linear; z-index: 12; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { left: 1rem; top: 2rem; width: auto; @@ -27,7 +27,7 @@ align-items: center; height: 3rem; padding: 0.5rem; - box-shadow: 0px 0.125rem 0.25rem rgba(0, 0, 0, 0.25); + box-shadow: 0 0.125rem 0.25rem rgb(0 0 0 / 25%); cursor: pointer; h2 { @@ -39,7 +39,7 @@ .actions { display: flex; align-items: center; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; svg { width: 1rem; @@ -76,17 +76,17 @@ } .modal { - [class*=modal-dialog] { + [class*="modal-dialog"] { width: 19rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: 29.5rem; } - [class*=modal-content] { + [class*="modal-content"] { width: 19rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: 29.5rem; } } @@ -109,12 +109,12 @@ } .undoButton { - color: $secondary-medium-gray; - background-color: $light-gray-background; + color: colors.$secondary-medium-gray; + background-color: colors.$light-gray-background; margin-right: 0.5rem; } .discardButton { - background-color: rgba(208, 3, 27, 0.05); - color: $bright-red; + background-color: rgb(208 3 27 / 5%); + color: colors.$bright-red; } diff --git a/src/MapMarkerDropper/index.js b/src/MapMarkerDropper/index.js index 1f087b878..a6852e7ca 100644 --- a/src/MapMarkerDropper/index.js +++ b/src/MapMarkerDropper/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext, useState, useEffect, useRef } from 'react'; +import { memo, useContext, useState, useEffect, useRef } from 'react'; import throttle from 'lodash/throttle'; import { addMapImage } from '../utils/map'; diff --git a/src/MapMarkerDropper/styles.module.scss b/src/MapMarkerDropper/styles.module.scss index 78e723cf4..e55a506e4 100644 --- a/src/MapMarkerDropper/styles.module.scss +++ b/src/MapMarkerDropper/styles.module.scss @@ -1,16 +1,19 @@ -@import '../common/styles/buttons'; +@use '../common/styles/buttons'; .mapControl { - @include mapboxControlButton; + @include buttons.mapbox-control-button; + font-size: 0; } .buttons { align-items: center; display: flex; + button { flex-shrink: 0; } + button + button { margin-left: 0.25rem; } diff --git a/src/MapPrintControl/index.js b/src/MapPrintControl/index.js index c8e7ebf40..3046e1ba8 100644 --- a/src/MapPrintControl/index.js +++ b/src/MapPrintControl/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { memo, useCallback, useEffect, useRef, useState } from 'react'; import Button from 'react-bootstrap/Button'; import Overlay from 'react-bootstrap/Overlay'; import Popover from 'react-bootstrap/Popover'; @@ -94,7 +94,11 @@ const MapPrintControl = () => { diff --git a/src/MapPrintControl/styles.module.scss b/src/MapPrintControl/styles.module.scss index f308ef3ff..f28567093 100644 --- a/src/MapPrintControl/styles.module.scss +++ b/src/MapPrintControl/styles.module.scss @@ -1,9 +1,10 @@ -@import '../common/styles/buttons'; -@import '../common/styles/vars/colors'; +@use '../common/styles/buttons'; +@use '../common/styles/vars/colors'; .wrapper { position: relative; - [class*=bs-popover] { + + [class*="bs-popover"] { max-width: unset; } } @@ -16,16 +17,20 @@ position: relative; max-width: 18rem; width: 100vw; + button { width: 6rem; } + label { width: 62.5%; padding-right: 0.5rem; + * { width: 100%; } } + small { font-size: 0.65rem; width: 100%; @@ -33,16 +38,19 @@ } .button { - @include mapboxControlButton; + @include buttons.mapbox-control-button; + &.active svg { path, g, rect, polyline { - fill: $bright-blue; - stroke: $bright-blue; + fill: colors.$bright-blue; + stroke: colors.$bright-blue; } + polyline, polygon { fill: none; } } + /* svg { path, g { fill: #333; diff --git a/src/MapRulerControl/PointPopup.js b/src/MapRulerControl/PointPopup.js index a4ee4e00a..df43ada2e 100644 --- a/src/MapRulerControl/PointPopup.js +++ b/src/MapRulerControl/PointPopup.js @@ -1,4 +1,4 @@ -import React, { useMemo, memo } from 'react'; +import { useMemo, memo } from 'react'; import { length, lineString } from '@turf/turf'; import { useTranslation } from 'react-i18next'; diff --git a/src/MapRulerControl/PointPopup.test.js b/src/MapRulerControl/PointPopup.test.js index 946acb49b..f2ada34c8 100644 --- a/src/MapRulerControl/PointPopup.test.js +++ b/src/MapRulerControl/PointPopup.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { GPS_FORMATS } from '../utils/location'; diff --git a/src/MapRulerControl/index.js b/src/MapRulerControl/index.js index b577bc577..18034e7b0 100644 --- a/src/MapRulerControl/index.js +++ b/src/MapRulerControl/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext, useState, useEffect, useCallback } from 'react'; +import { memo, useContext, useState, useEffect, useCallback } from 'react'; import Button from 'react-bootstrap/Button'; import { connect } from 'react-redux'; import isEqual from 'react-fast-compare'; @@ -87,12 +87,16 @@ const MapRulerControl = ({ setIsPickingLocation }) => { useEffect(() => { if (!drawing && active) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setNextClickResetsState(true); } }, [active, drawing]); useEffect(() => { if (!active || drawing) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setNextClickResetsState(false); } }, [active, drawing]); @@ -132,12 +136,16 @@ const MapRulerControl = ({ setIsPickingLocation }) => { }, []); useEffect(() => { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setPoints([]); setDrawingState(active); }, [active]); useEffect(() => { if (!drawing && points.length > 1) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setSelectedPointIndex(points.length - 1); } }, [drawing, points.length]); diff --git a/src/MapRulerControl/index.test.js b/src/MapRulerControl/index.test.js index 2fcecc050..7b43bdf94 100644 --- a/src/MapRulerControl/index.test.js +++ b/src/MapRulerControl/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/MapRulerControl/styles.module.scss b/src/MapRulerControl/styles.module.scss index 71bdd4cdb..2ac70313f 100644 --- a/src/MapRulerControl/styles.module.scss +++ b/src/MapRulerControl/styles.module.scss @@ -1,11 +1,13 @@ -@import '../common/styles/buttons'; +@use '../common/styles/buttons'; .buttons { align-items: center; display: flex; + button { flex-shrink: 0; } + button + button { margin-left: 0.25rem; } @@ -15,22 +17,26 @@ line-height: normal; margin-top: 2.25rem; position: fixed; + &.unfinished { - [class*=mapboxgl-popup-content] { + [class*="mapboxgl-popup-content"] { width: 7rem; padding: 0.5rem 0; } } + p { margin: 0.75rem 0; } - [class*=addReport] { + + [class*="addReport"] { background: none !important; } } .button { - @include mapboxControlButton; + @include buttons.mapbox-control-button; + svg path { fill: #333; } @@ -43,6 +49,7 @@ display: flex; flex-flow: column; justify-content: center; + svg { height: 2rem; width: 2rem; diff --git a/src/MapTerrain/index.js b/src/MapTerrain/index.js index 681a28435..93f91f436 100644 --- a/src/MapTerrain/index.js +++ b/src/MapTerrain/index.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import { useEffect } from 'react'; import { connect } from 'react-redux'; const DEFAULT_DEM_SOURCE_CONFIG = { diff --git a/src/MapTerrain/index.test.js b/src/MapTerrain/index.test.js index e212525af..38aad38b9 100644 --- a/src/MapTerrain/index.test.js +++ b/src/MapTerrain/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { createMapMock } from '../__test-helpers/mocks'; import { mockStore } from '../__test-helpers/MockStore'; diff --git a/src/MediaModal/index.js b/src/MediaModal/index.js index ad07a1098..0da165c65 100644 --- a/src/MediaModal/index.js +++ b/src/MediaModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { memo, useCallback, useEffect, useRef, useState } from 'react'; import Modal from 'react-bootstrap/Modal'; import { useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/MediaModal/index.test.js b/src/MediaModal/index.test.js index 9e25ed3fe..12bddefcb 100644 --- a/src/MediaModal/index.test.js +++ b/src/MediaModal/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/src/MessageInput/index.js b/src/MessageInput/index.js index caeea14b9..ff9bc3762 100644 --- a/src/MessageInput/index.js +++ b/src/MessageInput/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { memo, useCallback, useEffect, useRef, useState } from 'react'; import Button from 'react-bootstrap/Button'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/MessageInput/styles.module.scss b/src/MessageInput/styles.module.scss index 40c0727dc..90a990735 100644 --- a/src/MessageInput/styles.module.scss +++ b/src/MessageInput/styles.module.scss @@ -6,10 +6,12 @@ flex-wrap: wrap; justify-content: space-between; padding-top: 0.5rem; + input { flex-grow: 1; margin-right: 0.5rem; } + small { text-align: right; width: 100%; diff --git a/src/MessageList/MessageListItem.js b/src/MessageList/MessageListItem.js index 76d5ba75a..bb241b4bf 100644 --- a/src/MessageList/MessageListItem.js +++ b/src/MessageList/MessageListItem.js @@ -1,5 +1,4 @@ - -import React, { memo } from 'react'; +import { memo } from 'react'; import { connect } from 'react-redux'; import uniq from 'lodash/uniq'; diff --git a/src/MessageList/MessageSummaryList.js b/src/MessageList/MessageSummaryList.js index 4711ba4e7..9b5d82a52 100644 --- a/src/MessageList/MessageSummaryList.js +++ b/src/MessageList/MessageSummaryList.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import MoonLoader from 'react-spinners/MoonLoader'; import { useTranslation } from 'react-i18next'; @@ -63,6 +63,8 @@ const MessageSummaryList = (props) => { }, [dispatch, socket]); useEffect(() => { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setLoadState(true); fetchAllMessages({ page_size: 100, recent_message: 1 }) .then((results) => dispatch(fetchMessagesSuccess({ results }))) diff --git a/src/MessageList/MessageSummaryListItem.js b/src/MessageList/MessageSummaryListItem.js index 5e884cc18..3b95b8591 100644 --- a/src/MessageList/MessageSummaryListItem.js +++ b/src/MessageList/MessageSummaryListItem.js @@ -1,5 +1,4 @@ - -import React, { memo } from 'react'; +import { memo } from 'react'; import { connect } from 'react-redux'; import { STATUSES } from '../constants'; diff --git a/src/MessageList/ParamFedMessageList.js b/src/MessageList/ParamFedMessageList.js index 698499b19..11c4a2c31 100644 --- a/src/MessageList/ParamFedMessageList.js +++ b/src/MessageList/ParamFedMessageList.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { @@ -59,6 +59,8 @@ const ParamFedMessageList = ({ isReverse = false, params = null, ...restProps }) useEffect(() => { if (params) { window.clearTimeout(scrollPositionTimeout.current); + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setLoadState(true); isInit.current = false; fetchMessages({ since: FETCH_MESSAGES_SINCE_PARAMETER, ...params }, true) diff --git a/src/MessageList/SenderDetails.js b/src/MessageList/SenderDetails.js index fd4dc70d7..4fd17433c 100644 --- a/src/MessageList/SenderDetails.js +++ b/src/MessageList/SenderDetails.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as UserIcon } from '../common/images/icons/solid-user-icon.svg'; diff --git a/src/MessageList/index.js b/src/MessageList/index.js index 6740fa9ae..15095c733 100644 --- a/src/MessageList/index.js +++ b/src/MessageList/index.js @@ -1,4 +1,4 @@ -import React, { memo, useMemo, useState } from 'react'; +import { memo, useMemo, useState } from 'react'; import { isSameDay, isToday, isYesterday } from 'date-fns'; import { useTranslation } from 'react-i18next'; import InfiniteScroll from 'react-infinite-scroller'; diff --git a/src/MessageList/styles.module.scss b/src/MessageList/styles.module.scss index 0dac9cafc..aa5f85368 100644 --- a/src/MessageList/styles.module.scss +++ b/src/MessageList/styles.module.scss @@ -1,9 +1,10 @@ -@import '../common/styles/vars/colors'; +@use 'sass:color'; +@use '../common/styles/vars/colors'; $icon-size: 1.5em; .dividerTitle { - $divider-color: darken($light-gray-border, 10%); + $divider-color: color.adjust(colors.$light-gray-border, $lightness: -10%); border-top: 1px solid $divider-color; color: $divider-color; @@ -13,11 +14,13 @@ $icon-size: 1.5em; margin: 0.5em 0; text-align: center; text-transform: uppercase; + span { background: white; font-size: 0.75em; padding: 0.25em; } + &.reverse { margin: 0 0 0.5em; } @@ -25,10 +28,11 @@ $icon-size: 1.5em; .senderDetails { align-items: center; - color: $light-font-color; + color: colors.$light-font-color; display: flex; font-size: 0.7em; margin-bottom: 0.5em; + img, svg { margin-right: 0.5em; max-height: $icon-size; @@ -40,20 +44,23 @@ $icon-size: 1.5em; .outgoingMessage { .messageDetails { align-self: flex-end; - background: lighten($light-blue, 35%); - border: 1px solid lighten($light-blue, 25%); + background: color.adjust(colors.$light-blue, $lightness: 35%); + border: 1px solid color.adjust(colors.$light-blue, $lightness: 25%); margin: 0 0 0 0.5rem; } + .senderDetails { justify-content: flex-end; + img, svg { margin-left: 0.5em; } } } + .messageDetails { - background: lighten($light-blue, 25%); - border: 1px solid lighten($light-blue, 15%); + background: color.adjust(colors.$light-blue, $lightness: 25%); + border: 1px solid color.adjust(colors.$light-blue, $lightness: 15%); border-radius: 1em; margin: 0 0.5rem 0 0; width: 85%; @@ -68,19 +75,23 @@ $icon-size: 1.5em; line-height: normal; margin: 0; text-align: left; + ul { display: flex; flex-flow: column; } + li li { display: flex; flex-flow: column; padding: 0.75em 1em; position: relative; - [class*=badge] { + + [class*="badge"] { left: 1rem; position: absolute; } + li { align-items: center; flex-flow: row; @@ -90,6 +101,7 @@ $icon-size: 1.5em; } } } + .messageDetails { align-items: center; display: flex; @@ -124,30 +136,37 @@ $icon-size: 1.5em; .summaryList { $img-size: 2em; - [class*=senderDetails] { + + [class*="senderDetails"] { font-size: 1.05em; font-style: normal; font-weight: 600; margin-bottom: 0; } + li li { cursor: pointer; transition: background 0.15s linear; + &:hover { - background: rgba($light-blue, 0.1); + background: rgba(colors.$light-blue, 0.1); text-decoration: underline; } + &:not(:first-child) { - border-top: 1px solid $light-gray-border; + border-top: 1px solid colors.$light-gray-border; } + img { max-height: $img-size; max-width: $img-size; } } - [class*=messageDetails] { + + [class*="messageDetails"] { padding-top: 0.25em; } + .messageTime { position: absolute; right: 1em; @@ -177,8 +196,10 @@ $icon-size: 1.5em; .messageSubjectName { display: contents; + &.clickable { cursor: pointer; + &:hover { text-decoration: underline; } diff --git a/src/MessagesModal/index.js b/src/MessagesModal/index.js index fdbaac1eb..e857a8d03 100644 --- a/src/MessagesModal/index.js +++ b/src/MessagesModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useMemo, useState } from 'react'; +import { memo, useEffect, useMemo, useState } from 'react'; import Button from 'react-bootstrap/Button'; import Modal from 'react-bootstrap/Modal'; import { useSelector } from 'react-redux'; @@ -44,6 +44,8 @@ const MessagesModal = ({ onSelectSubject, selectedSubject = null }) => { }; useEffect(() => { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setSelectingRecipient(false); }, [params]); diff --git a/src/MessagingSelect/index.js b/src/MessagingSelect/index.js index 45dd4dad8..034c8e54a 100644 --- a/src/MessagingSelect/index.js +++ b/src/MessagingSelect/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useMemo, useRef } from 'react'; +import { memo, useEffect, useMemo, useRef } from 'react'; import { components } from 'react-select'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/ModalRenderer/index.js b/src/ModalRenderer/index.js index 3cd46fd0d..c6c2c0e88 100644 --- a/src/ModalRenderer/index.js +++ b/src/ModalRenderer/index.js @@ -1,4 +1,4 @@ -import React, { memo, Suspense, useContext } from 'react'; +import { memo, Suspense, useContext } from 'react'; import Modal from 'react-bootstrap/Modal'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/src/ModalRenderer/index.test.js b/src/ModalRenderer/index.test.js index 185de2a69..78ca821d5 100644 --- a/src/ModalRenderer/index.test.js +++ b/src/ModalRenderer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/ModalRenderer/styles.module.scss b/src/ModalRenderer/styles.module.scss index c9790e37f..3576867f5 100644 --- a/src/ModalRenderer/styles.module.scss +++ b/src/ModalRenderer/styles.module.scss @@ -4,18 +4,18 @@ } .modalMediaBackground { - background: rgba(0, 0, 0, 0.85) !important; + background: rgb(0 0 0 / 85%) !important; - [class*=modal-dialog] { + [class*="modal-dialog"] { max-width: 100%; max-height: 100%; align-items: flex-start; - [class*=modal-content] { + [class*="modal-content"] { background-color: transparent; border: none; - [class*=modal-body] { + [class*="modal-body"] { height: 80vh; } diff --git a/src/MouseMarkerLayer/index.js b/src/MouseMarkerLayer/index.js index adaef4d9a..18dd0bda8 100644 --- a/src/MouseMarkerLayer/index.js +++ b/src/MouseMarkerLayer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useMemo } from 'react'; +import { memo, useMemo } from 'react'; import { point } from '@turf/turf'; import { SYMBOL_ICON_SIZE_EXPRESSION, LAYER_IDS, SOURCE_IDS } from '../constants'; diff --git a/src/MouseMarkerPopup/index.js b/src/MouseMarkerPopup/index.js index 60fbc0907..1abcdba38 100644 --- a/src/MouseMarkerPopup/index.js +++ b/src/MouseMarkerPopup/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import useStringifyCoordinates from '../hooks/useStringifyCoordinates'; diff --git a/src/MouseMarkerPopup/styles.module.scss b/src/MouseMarkerPopup/styles.module.scss index 3f44ff2e3..de19d36a0 100644 --- a/src/MouseMarkerPopup/styles.module.scss +++ b/src/MouseMarkerPopup/styles.module.scss @@ -1,19 +1,22 @@ -$background: rgba(0,0,0,0.65); +$background: rgb(0 0 0 / 65%); .popup { position: fixed; top: 2.333rem; + p { margin: 0 0 0.25rem; } - [class*=mapboxgl-popup-content] { + + [class*="mapboxgl-popup-content"] { background: $background; color: white; max-width: 10rem; padding: 0.25rem; } - [class*=mapboxgl-popup-tip] { + + [class*="mapboxgl-popup-tip"] { border-left-color: $background; - border-top-color: rgba(0,0,0,0); + border-top-color: rgb(0 0 0 / 0%); } } \ No newline at end of file diff --git a/src/Nav/MessageMenu.js b/src/Nav/MessageMenu.js index b1009ac6d..315d22312 100644 --- a/src/Nav/MessageMenu.js +++ b/src/Nav/MessageMenu.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import Dropdown from 'react-bootstrap/Dropdown'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/Nav/Nav.scss b/src/Nav/Nav.scss index 5f7a4c1bd..41f5c1431 100644 --- a/src/Nav/Nav.scss +++ b/src/Nav/Nav.scss @@ -1,6 +1,6 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/buttons'; -@import '../common/styles/layout'; +@use '../common/styles/vars/colors'; +@use '../common/styles/buttons'; +@use '../common/styles/layout'; .profile-pin-modal { .modal-dialog { @@ -10,8 +10,8 @@ .primary-nav { align-items: center; - background: $title-bar-color; - box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.33); + background: colors.$title-bar-color; + box-shadow: 0 0.25rem 0.25rem 0 rgb(0 0 0 / 33%); color: white; display: flex; height: var(--nav-height); @@ -21,28 +21,31 @@ width: 100vw; z-index: 2; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { padding: 0; } .dropdown-menu { - background: $off-white; - box-shadow: 3px 3px 0.5rem rgba($dark-gray, 0.25); + background: colors.$off-white; + box-shadow: 3px 3px 0.5rem rgba(colors.$dark-gray, 0.25); } + > .btn-primary { background: none; border: none; } + .dropdown-toggle { max-height: var(--nav-height); } + .left-controls { align-items: center; display: flex; justify-content: flex-start; flex: 2; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { padding-left: 1.5rem; } @@ -55,12 +58,12 @@ max-height: 2rem; } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: block; width: 1.25rem; } - @media (min-width: $lg-layout-width-min) { + @media (min-width: layout.$lg-layout-width-min) { width: auto; } } @@ -69,7 +72,7 @@ padding: 1rem; } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { .global-menu-button { margin-right: 1.5rem; opacity: 0.9; @@ -80,6 +83,7 @@ } } } + .center-controls { display: flex; justify-content: center; @@ -92,7 +96,7 @@ text-overflow: ellipsis; } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { flex: 2; h6 { @@ -100,28 +104,30 @@ } } - @media (min-width: $lg-layout-width-min) { + @media (min-width: layout.$lg-layout-width-min) { h6 { max-width: none; } } } + .rightMenus { align-items: center; display: flex; justify-content: flex-end; flex: 2; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { padding-right: 1.5rem; } } + .dropdown.show { max-width: 95vw; } .dropdown-toggle { - @include unstyledDropdown; + @include buttons.unstyled-dropdown; } .dropdown-item { diff --git a/src/Nav/NavHomeItem/index.js b/src/Nav/NavHomeItem/index.js index 59a1dc917..85676853e 100644 --- a/src/Nav/NavHomeItem/index.js +++ b/src/Nav/NavHomeItem/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import { calcUrlForImage } from '../../utils/img'; diff --git a/src/Nav/NavHomeMenu/index.js b/src/Nav/NavHomeMenu/index.js index 0f170bfc9..2295a60b1 100644 --- a/src/Nav/NavHomeMenu/index.js +++ b/src/Nav/NavHomeMenu/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import Dropdown from 'react-bootstrap/Dropdown'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/Nav/NavHomeMenu/styles.module.scss b/src/Nav/NavHomeMenu/styles.module.scss index ab7459712..a9f8bf0ab 100644 --- a/src/Nav/NavHomeMenu/styles.module.scss +++ b/src/Nav/NavHomeMenu/styles.module.scss @@ -1,5 +1,6 @@ -@import '../../common/styles/layout'; -@import '../../common/styles/vars/colors'; +@use 'sass:color'; +@use '../../common/styles/layout'; +@use '../../common/styles/vars/colors'; header { .toggle { @@ -10,7 +11,7 @@ header { +h6 { display: none; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: initial; } } @@ -22,7 +23,7 @@ header { &:hover, &:hover::after { - color: darken(white, 7%); + color: color.adjust(white, $lightness: -7%); } &::after { @@ -46,16 +47,19 @@ header { font-size: 0.9rem; margin: 0; } - &[class*=active] { - background: $light-gray !important; + + &[class*="active"] { + background: colors.$light-gray !important; color: unset !important; font-weight: bold; + &::after { content: "\2713"; display: block; float: right; } } + svg { height: 1rem; width: 1.25rem; diff --git a/src/Nav/index.js b/src/Nav/index.js index 3f034d0d6..88cfebf64 100644 --- a/src/Nav/index.js +++ b/src/Nav/index.js @@ -1,4 +1,4 @@ -import React, { lazy, memo, useCallback, useEffect } from 'react'; +import { lazy, memo, useCallback, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router'; import { useTranslation } from 'react-i18next'; diff --git a/src/Nav/index.test.js b/src/Nav/index.test.js index 02e9bd8fd..ce68abf5e 100644 --- a/src/Nav/index.test.js +++ b/src/Nav/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { http, HttpResponse } from 'msw/http'; import { Provider } from 'react-redux'; import { setupServer } from 'msw/node'; diff --git a/src/Nav/styles.module.scss b/src/Nav/styles.module.scss index 54249a4f3..cccfb0443 100644 --- a/src/Nav/styles.module.scss +++ b/src/Nav/styles.module.scss @@ -1,4 +1,4 @@ -@import '../common/styles/vars/colors'; +@use '../common/styles/vars/colors'; .messageMenu { margin-right: 1rem; @@ -9,11 +9,11 @@ width: 2.5rem; height: 2.5rem; margin: -0.625rem; - background-color: $transparent-dark-gray; + background-color: colors.$transparent-dark-gray; border-radius: 0.125rem; path { - fill: $light-gray; + fill: colors.$light-gray; } } @@ -23,7 +23,7 @@ } } - [class*=dropdown-menu] { + [class*="dropdown-menu"] { border: none; margin-right: -1rem; padding: 0; diff --git a/src/NavigationContextProvider/index.js b/src/NavigationContextProvider/index.js index e457fc5f9..5e75637cb 100644 --- a/src/NavigationContextProvider/index.js +++ b/src/NavigationContextProvider/index.js @@ -1,4 +1,4 @@ -import React, { createContext, useCallback, useEffect, useRef, useState } from 'react'; +import { createContext, useCallback, useEffect, useRef, useState } from 'react'; export const NavigationContext = createContext(); diff --git a/src/NavigationContextProvider/index.test.js b/src/NavigationContextProvider/index.test.js index b3f5df78b..1a0bfe9ff 100644 --- a/src/NavigationContextProvider/index.test.js +++ b/src/NavigationContextProvider/index.test.js @@ -1,4 +1,4 @@ -import React, { useContext, useEffect } from 'react'; +import { useContext, useEffect } from 'react'; import NavigationContextProvider, { BLOCKER_STATES, NavigationContext } from './'; import { act, render, renderHook } from '../test-utils'; diff --git a/src/NavigationPromptModal/index.js b/src/NavigationPromptModal/index.js index 4716ab3f5..8a5408962 100644 --- a/src/NavigationPromptModal/index.js +++ b/src/NavigationPromptModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback } from 'react'; +import { memo, useCallback } from 'react'; import Button from 'react-bootstrap/Button'; import Modal from 'react-bootstrap/Modal'; import { useTranslation } from 'react-i18next'; diff --git a/src/NavigationPromptModal/index.test.js b/src/NavigationPromptModal/index.test.js index aec02e1cf..cdf3556aa 100644 --- a/src/NavigationPromptModal/index.test.js +++ b/src/NavigationPromptModal/index.test.js @@ -1,4 +1,4 @@ -import React, { useContext, useEffect } from 'react'; +import { useContext, useEffect } from 'react'; import userEvent from '@testing-library/user-event'; import NavigationPromptModal from './'; @@ -52,13 +52,13 @@ describe('NavigationPromptModal', () => { renderNavigationPromptModal({ ...initialProps, when: true }, ChildComponent); - await screen.findByText(TITLE_TEXT); + expect(await screen.findByText(TITLE_TEXT)).toBeInTheDocument(); }); test('forces to show the modal even if when is false', async () => { renderNavigationPromptModal({ ...initialProps, when: false, show: true }); - await screen.findByText(TITLE_TEXT); + expect(await screen.findByText(TITLE_TEXT)).toBeInTheDocument(); }); test('triggers onContinue and closes the modal if navigation attempt is continued in the negative', async () => { diff --git a/src/NavigationPromptModal/styles.module.scss b/src/NavigationPromptModal/styles.module.scss index d9650422e..edcc88518 100644 --- a/src/NavigationPromptModal/styles.module.scss +++ b/src/NavigationPromptModal/styles.module.scss @@ -1,11 +1,12 @@ -@import '../common/styles/vars/colors'; +@use '../common/styles/vars/colors'; -@mixin continueButton($background: $bright-red) { +@mixin continue-button($background: colors.$bright-red) { align-items: center; border: none; background-color: $background; display: flex; justify-content: center; + svg { margin-right: 0.25rem; } @@ -17,16 +18,16 @@ .cancelButton { background-color: white; border: none; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; margin-right: 0.5rem; } .negativeContinue { - @include continueButton; + @include continue-button; } .positiveContinue { - @include continueButton($primary-button-color); + @include continue-button(colors.$primary-button-color); } } diff --git a/src/NoteModal/index.js b/src/NoteModal/index.js index 74d6e1ae6..c4c2e3f92 100644 --- a/src/NoteModal/index.js +++ b/src/NoteModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, Fragment, useState, useRef, useEffect } from 'react'; +import { memo, Fragment, useState, useRef, useEffect } from 'react'; import { connect } from 'react-redux'; import Modal from 'react-bootstrap/Modal'; import Button from 'react-bootstrap/Button'; diff --git a/src/NotificationMenu/index.js b/src/NotificationMenu/index.js index faa4a22a1..5f0e68e41 100644 --- a/src/NotificationMenu/index.js +++ b/src/NotificationMenu/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext, useEffect, useRef, useState } from 'react'; +import { memo, useContext, useEffect, useRef, useState } from 'react'; import Button from 'react-bootstrap/Button'; import { differenceInCalendarDays } from 'date-fns'; import Dropdown from 'react-bootstrap/Dropdown'; @@ -43,7 +43,7 @@ const formatUnreadNewsItemsAsNotifications = (news = [], t) => news.map(item => const NotificationItem = ({ item }) => { const { t } = useTranslation('top-bar', { keyPrefix: 'notificationMenu.notificationItem' }); - const isNewsItem = item.hasOwnProperty('read'); + const isNewsItem = Object.hasOwn(item, 'read'); const isUnread = isNewsItem && !item.read; let displayMessage = item.message.replace(/(<([^>]+)>)/ig, '').substring(0, NEWS_ITEM_CHARACTER_LIMIT); @@ -162,6 +162,8 @@ const NotificationMenu = (props) => { }; useEffect(() => { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect fetchNewsForMenu(); }, []); // eslint-disable-line react-hooks/exhaustive-deps @@ -195,6 +197,8 @@ const NotificationMenu = (props) => { id="overlay-example" placement="bottom" role="alert" + // Using this ref during render is intended. + // eslint-disable-next-line react-hooks/refs target={toggleBtnRef.current} > {outdatedNotificationString} diff --git a/src/NotificationMenu/index.test.js b/src/NotificationMenu/index.test.js index 1ae57bb44..92076779b 100644 --- a/src/NotificationMenu/index.test.js +++ b/src/NotificationMenu/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { http, HttpResponse } from 'msw/http'; import { Provider } from 'react-redux'; import { setupServer } from 'msw/node'; @@ -9,7 +8,7 @@ import { NEWS_API_URL } from '../ducks/news'; import { mockStore } from '../__test-helpers/MockStore'; import SocketProvider, { mockedSocket } from '../__test-helpers/MockSocketContext'; import mockNewsData from '../__test-helpers/fixtures/news'; -import { render, waitFor, waitForElementToBeRemoved, screen } from '../test-utils'; +import { render, waitFor, screen } from '../test-utils'; import NotificationMenu from '../NotificationMenu'; @@ -34,11 +33,11 @@ afterAll(() => server.close()); test('rendering without crashing', () => { - render( + expect(() => render( - ); + )).not.toThrow(); }); describe('listing news items', () => { @@ -128,7 +127,10 @@ describe('listing news items', () => { await userEvent.click(toggle); await waitFor(() => { - expect(screen.getAllByRole('listitem')).toHaveLength(4); + const listItemCount = screen.getAllByRole('listitem').length; + if (listItemCount !== 4) { + throw new Error(`Expected 4 list items, found ${listItemCount}.`); + } }); userNotificationListItem = screen.getAllByRole('listitem')[0]; @@ -192,7 +194,7 @@ describe('handling failed news requests', () => { }); test('showing an error message', async () => { - await screen.findByTestId('error-message'); + expect(await screen.findByTestId('error-message')).toBeInTheDocument(); }); test('presenting a retry button which attempts to re-fetch news', async () => { @@ -205,7 +207,7 @@ describe('handling failed news requests', () => { }); describe('reminding users of unread messages', () => { - const unread = mockNewsData.filter(n => n.hasOwnProperty('read') && !n.read); + const unread = mockNewsData.filter(n => Object.hasOwn(n, 'read') && !n.read); let rendered; beforeEach(async () => { diff --git a/src/NotificationMenu/styles.module.scss b/src/NotificationMenu/styles.module.scss index 2c6e99703..3d8d5f17e 100644 --- a/src/NotificationMenu/styles.module.scss +++ b/src/NotificationMenu/styles.module.scss @@ -1,12 +1,12 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/layout'; +@use '../common/styles/vars/colors'; +@use '../common/styles/layout'; .dropdown { margin-right: 1rem; position: relative; &:hover { - [class*=icon] { + [class*="icon"] { opacity: 1; } } @@ -18,7 +18,7 @@ div.menu { padding: 0; width: 20rem; - @media (min-height: $lg-height-min) { + @media (min-height: layout.$lg-height-min) { max-height: 60vh; } } @@ -80,7 +80,7 @@ div.menu { flex-flow: column; + .item { - border-top: 1px solid $light-gray-border; + border-top: 1px solid colors.$light-gray-border; } /* &.unread *:not(button) { @@ -114,7 +114,7 @@ div.menu { position: relative; width: var(--badge-dimensions); - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { --badge-dimensions: 0.95rem; } } @@ -137,7 +137,7 @@ div.menu { } .unreadNotificationsPopover { - color: $primary-font-color; + color: colors.$primary-font-color; left: -9rem; padding: 0.5rem; text-align: center; @@ -145,7 +145,7 @@ div.menu { width: 18rem; position: absolute; - [class*=arrow] { + [class*="arrow"] { display: none; } } diff --git a/src/NumericInput/index.js b/src/NumericInput/index.js index 2005ed91d..57c949d65 100644 --- a/src/NumericInput/index.js +++ b/src/NumericInput/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as ArrowUpSimpleIcon } from '../common/images/icons/arrow-up-simple.svg'; diff --git a/src/NumericInput/index.test.js b/src/NumericInput/index.test.js index 5dfbff0f9..176a11f58 100644 --- a/src/NumericInput/index.test.js +++ b/src/NumericInput/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import userEvent from '@testing-library/user-event'; import { fireEvent } from '@testing-library/react'; diff --git a/src/NumericInput/styles.module.scss b/src/NumericInput/styles.module.scss index 933388133..07180fdfb 100644 --- a/src/NumericInput/styles.module.scss +++ b/src/NumericInput/styles.module.scss @@ -1,5 +1,4 @@ @use 'sass:color'; - @use '../common/styles/inputs'; @use '../common/styles/vars/colors'; @@ -46,7 +45,7 @@ } .controls { - @include inputs.boxedFieldTrailingControl; + @include inputs.boxed-field-trailing-control; button { align-items: center; diff --git a/src/PatrolDetailView/Header/index.js b/src/PatrolDetailView/Header/index.js index b9424de9c..a328f3e7b 100644 --- a/src/PatrolDetailView/Header/index.js +++ b/src/PatrolDetailView/Header/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useMemo, useRef } from 'react'; +import { memo, useCallback, useMemo, useRef } from 'react'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; diff --git a/src/PatrolDetailView/Header/index.test.js b/src/PatrolDetailView/Header/index.test.js index 49ab1db51..642c15d32 100644 --- a/src/PatrolDetailView/Header/index.test.js +++ b/src/PatrolDetailView/Header/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/PatrolDetailView/Header/styles.module.scss b/src/PatrolDetailView/Header/styles.module.scss index 6ea348956..bc7b5a5cd 100644 --- a/src/PatrolDetailView/Header/styles.module.scss +++ b/src/PatrolDetailView/Header/styles.module.scss @@ -1,20 +1,20 @@ -@import '../../common/styles/layout'; -@import '../../common/styles/vars/colors'; -@import '../../common/styles/inputs'; +@use '../../common/styles/layout'; +@use '../../common/styles/vars/colors'; +@use '../../common/styles/inputs'; .header { align-items: center; - background-color: $very-light-gray; - border-bottom: 1px solid $secondary-light-gray; - border-top: 1px solid $secondary-light-gray; - box-shadow: 0 0.25rem 0.75rem -0.125rem rgba(0, 0, 0, 0.25); + background-color: colors.$very-light-gray; + border-bottom: 1px solid colors.$secondary-light-gray; + border-top: 1px solid colors.$secondary-light-gray; + box-shadow: 0 0.25rem 0.75rem -0.125rem rgb(0 0 0 / 25%); display: flex; height: 4rem; position: relative; width: 100%; z-index: 1; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { height: 5rem; } @@ -37,17 +37,17 @@ height: 1.5rem; fill: currentcolor; - &[class*=newPatrol] { - fill: $dark-gray; + &[class*="newPatrol"] { + fill: colors.$dark-gray; } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: 2rem; height: 2rem; } } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { min-width: 4.5rem; width: 4.5rem; } @@ -59,10 +59,10 @@ .serialNumber { font-size: 0.75rem; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; margin: 0 0.5rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { font-size: 1rem; margin: 0 0.75rem; } @@ -73,15 +73,15 @@ flex-direction: column; width: 8rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: 20.25rem; } } .title { - @include editableItemTitle; + @include inputs.editable-item-title; - border-bottom: 1px dashed $secondary-light-gray; + border-bottom: 1px dashed colors.$secondary-light-gray; } .description { @@ -92,7 +92,7 @@ margin-right: 0.5rem; text-align: right; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { font-size: 1rem; margin-right: 1rem; } @@ -104,14 +104,15 @@ .patrolTrackControls { display: none; - --buttonDimensions: 2.5rem; + + --button-dimensions: 2.5rem; button { - height: var(--buttonDimensions); - width: var(--buttonDimensions); + height: var(--button-dimensions); + width: var(--button-dimensions); } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: flex; } @@ -124,11 +125,11 @@ display: none; align-items: center; font-size: 1rem; - background-color: $transparent-dark-gray; + background-color: colors.$transparent-dark-gray; border: none; height: 2rem; border-radius: 4px; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; font-weight: 700; margin-left: 0.5rem; @@ -137,8 +138,8 @@ } &:hover { - background: $hover-button-background; - color: $secondary-medium-gray; + background: colors.$hover-button-background; + color: colors.$secondary-medium-gray; } } @@ -148,14 +149,14 @@ margin-right: 0.5rem; } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: flex; height: 2.75rem; } } .restorePatrolButton { - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: flex; height: 2.75rem; } @@ -166,7 +167,7 @@ } .distanceCovered { - &:before { + &::before { content: ' | '; } } @@ -175,7 +176,7 @@ width: 15rem; font-size: 0.79rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: unset; font-size: unset; } @@ -184,7 +185,7 @@ .scheduledStartTime { font-size: 0.79rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { font-size: unset; } } diff --git a/src/PatrolDetailView/InvalidDatesModal/index.js b/src/PatrolDetailView/InvalidDatesModal/index.js index 9ab12a358..7799ec54c 100644 --- a/src/PatrolDetailView/InvalidDatesModal/index.js +++ b/src/PatrolDetailView/InvalidDatesModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback } from 'react'; +import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import Modal from 'react-bootstrap/Modal'; diff --git a/src/PatrolDetailView/InvalidDatesModal/index.test.js b/src/PatrolDetailView/InvalidDatesModal/index.test.js index ac3951a9a..fa309ffb5 100644 --- a/src/PatrolDetailView/InvalidDatesModal/index.test.js +++ b/src/PatrolDetailView/InvalidDatesModal/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '../../test-utils'; import userEvent from '@testing-library/user-event'; diff --git a/src/PatrolDetailView/PlanSection/index.js b/src/PatrolDetailView/PlanSection/index.js index 16d1e383f..194964b4f 100644 --- a/src/PatrolDetailView/PlanSection/index.js +++ b/src/PatrolDetailView/PlanSection/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import Form from 'react-bootstrap/Form'; import { format, isFuture, isValid, parseISO } from 'date-fns'; import { useDispatch, useSelector } from 'react-redux'; @@ -57,6 +57,8 @@ const PlanSection = ({ const [startDate, setStartDate] = useState(format(displayStartDate ?? new Date(), 'yyyy-MM-dd')); const [startTime, setStartTime] = useState(getHoursAndMinutesString(displayStartDate)); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const handleEndDateChange = useCallback((newEndDate) => { setEndDate(newEndDate); @@ -68,6 +70,8 @@ const PlanSection = ({ } }, [endTime, isAutoEnd, onPatrolEndDateChange]); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const handleStartDateChange = useCallback((newStartDate) => { setStartDate(newStartDate); @@ -79,6 +83,8 @@ const PlanSection = ({ } }, [isAutoStart, onPatrolStartDateChange, startTime]); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const handleEndTimeChange = useCallback((newEndTime) => { setEndTime(newEndTime); diff --git a/src/PatrolDetailView/PlanSection/index.test.js b/src/PatrolDetailView/PlanSection/index.test.js index d77977ad8..5cadddfe3 100644 --- a/src/PatrolDetailView/PlanSection/index.test.js +++ b/src/PatrolDetailView/PlanSection/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; @@ -156,7 +155,7 @@ describe('PatrolDetailView - PlanSection', () => { expect(onPatrolObjectiveChange).toHaveBeenCalled(); }); - test('it should show the field empty for new patrols', async () => { + test('it should show the objective empty for new patrols', async () => { renderPlanSectionWithWrapper(); const objectiveInput = await screen.getByTestId('patrolDetailView-objectiveTextArea'); diff --git a/src/PatrolDetailView/PlanSection/styles.module.scss b/src/PatrolDetailView/PlanSection/styles.module.scss index b28924e3e..58c7d07eb 100644 --- a/src/PatrolDetailView/PlanSection/styles.module.scss +++ b/src/PatrolDetailView/PlanSection/styles.module.scss @@ -1,6 +1,6 @@ -@import '../../common/styles/vars/colors'; -@import '../../common/styles/layout'; -@import '../../common/styles/inputs'; +@use '../../common/styles/vars/colors'; +@use '../../common/styles/layout'; +@use '../../common/styles/inputs'; .sectionHeader { align-items: center; @@ -19,7 +19,7 @@ } svg { - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; margin-right: 0.5rem; width: 1.5rem; } @@ -29,7 +29,7 @@ .row { display: block; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { align-items: flex-end; display: flex; @@ -45,7 +45,7 @@ display: flex; width: 100%; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { width: 50%; } } @@ -54,7 +54,8 @@ margin-top: 1.5rem; width: 100%; position: relative; - @include label-styles; + + @include inputs.label-styles; > div:first-child, > label { diff --git a/src/PatrolDetailView/index.js b/src/PatrolDetailView/index.js index 428f48a0b..cf0903a60 100644 --- a/src/PatrolDetailView/index.js +++ b/src/PatrolDetailView/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import Button from 'react-bootstrap/Button'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation, useSearchParams } from 'react-router'; @@ -125,9 +125,13 @@ const PatrolDetailView = () => { const patrolStartTime = useMemo(() => patrolForm ? actualStartTimeForPatrol(patrolForm) : null, [patrolForm]); const patrolAttachments = useMemo( + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization () => Array.isArray(patrolForm?.files) ? patrolForm.files : [], [patrolForm?.files] ); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const patrolNotes = useMemo(() => Array.isArray(patrolForm?.notes) ? [...patrolForm.notes] : [], [patrolForm?.notes]); const patrolChanges = useMemo(() => { @@ -202,7 +206,7 @@ const PatrolDetailView = () => { } ['start_location', 'end_location'].forEach((prop) => { - if (patrolToSubmit.hasOwnProperty(prop) && !patrolToSubmit[prop]) { + if (Object.hasOwn(patrolToSubmit, prop) && !patrolToSubmit[prop]) { patrolToSubmit[prop] = null; } }); @@ -286,7 +290,7 @@ const PatrolDetailView = () => { leader: selection || null, }; if (isNewPatrol && selection) { - const [patrolSegment] = patrolForm?.patrol_segments; + const [patrolSegment] = patrolForm.patrol_segments; const { start_location, time_range } = patrolSegment; const trackedSubjectLocation = selection?.last_position?.geometry?.coordinates; const trackedSubjectLocationTime = selection?.last_position?.properties?.coordinateProperties?.time; @@ -312,7 +316,7 @@ const PatrolDetailView = () => { ...patrolForm?.patrol_segments[0], ...update, }, - ...patrolForm?.patrol_segments.slice(1), + ...patrolForm.patrol_segments.slice(1), ], }); @@ -458,12 +462,16 @@ const PatrolDetailView = () => { useEffect(() => { if (patrol) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setPatrolForm({ ...patrol }); } }, [leader, patrol]); useEffect(() => { if (isNewPatrol || patrolStore[patrolId]) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setIsLoadingPatrol(false); } }, [isNewPatrol, patrolId, patrolStore]); @@ -483,6 +491,8 @@ const PatrolDetailView = () => { useEffect(() => { if (!isNewPatrol && !patrolStore[patrolId]) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setIsLoadingPatrol(true); dispatch(fetchPatrol(patrolId)) .then(() => setIsLoadingPatrol(false)) diff --git a/src/PatrolDetailView/index.test.js b/src/PatrolDetailView/index.test.js index 1ccd43bf4..94d8a4959 100644 --- a/src/PatrolDetailView/index.test.js +++ b/src/PatrolDetailView/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { http, HttpResponse } from 'msw/http'; import { Provider } from 'react-redux'; import { setupServer } from 'msw/node'; @@ -637,8 +636,8 @@ describe('PatrolDetailView', () => { const cancelButton = await screen.findByText('Cancel'); await userEvent.click(cancelButton); - await screen.findByText('Unsaved Changes'); - await screen.findByText('There are unsaved changes. Would you like to go back, discard the changes, or save and continue?'); + expect(await screen.findByText('Unsaved Changes')).toBeInTheDocument(); + expect(await screen.findByText('There are unsaved changes. Would you like to go back, discard the changes, or save and continue?')).toBeInTheDocument(); }); test('saving unsaved changes', async () => { diff --git a/src/PatrolDetailView/styles.module.scss b/src/PatrolDetailView/styles.module.scss index 33b52a237..5a831462e 100644 --- a/src/PatrolDetailView/styles.module.scss +++ b/src/PatrolDetailView/styles.module.scss @@ -1,5 +1,5 @@ -@import '../common/styles/layout'; -@import '../common/styles/vars/colors'; +@use '../common/styles/layout'; +@use '../common/styles/vars/colors'; .patrolDetailView { display: flex; @@ -7,8 +7,8 @@ height: 100%; background-color: white; - @media (min-width: $md-layout-width-min) { - @include sidebar-width-detail; + @media (min-width: layout.$md-layout-width-min) { + @include layout.sidebar-width-detail; } } @@ -20,14 +20,14 @@ display: flex; height: calc(100% - 3.5rem); - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { height: calc(100% - 5rem); } .navigationBar{ display: none; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: unset; } @@ -42,7 +42,7 @@ flex-direction: column; height: 100%; background-color: white; - border-left: 1px solid $very-light-gray-alt; + border-left: 1px solid colors.$very-light-gray-alt; width: 100%; @media print { @@ -52,8 +52,8 @@ .section { background-color: white; - border-bottom: 1px solid $very-light-gray-alt; - border-top: 1px solid $very-light-gray-alt; + border-bottom: 1px solid colors.$very-light-gray-alt; + border-top: 1px solid colors.$very-light-gray-alt; padding: 1.125rem; } @@ -66,7 +66,7 @@ display: flex; justify-content: space-between; padding: 0.875rem 1rem; - border-top: 1px solid $very-light-gray-alt; + border-top: 1px solid colors.$very-light-gray-alt; } .footerActionButtonsContainer { @@ -77,7 +77,7 @@ .cancelButton { background-color: transparent; border-color: transparent; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; font-weight: bold; margin-right: 0.5rem; } diff --git a/src/PatrolFilter/DateRange.js b/src/PatrolFilter/DateRange.js index ed091dfe2..b25aad75e 100644 --- a/src/PatrolFilter/DateRange.js +++ b/src/PatrolFilter/DateRange.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback } from 'react'; +import { memo, useCallback } from 'react'; import { connect } from 'react-redux'; import { INITIAL_FILTER_STATE } from '../ducks/patrol-filter'; diff --git a/src/PatrolFilter/DateRangePopover/index.js b/src/PatrolFilter/DateRangePopover/index.js index b0c388766..470eca3c2 100644 --- a/src/PatrolFilter/DateRangePopover/index.js +++ b/src/PatrolFilter/DateRangePopover/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback } from 'react'; +import { memo, useCallback } from 'react'; import Button from 'react-bootstrap/Button'; import isEqual from 'react-fast-compare'; import Popover from 'react-bootstrap/Popover'; diff --git a/src/PatrolFilter/DateRangePopover/index.test.js b/src/PatrolFilter/DateRangePopover/index.test.js index 7dace569b..17d6f511a 100644 --- a/src/PatrolFilter/DateRangePopover/index.test.js +++ b/src/PatrolFilter/DateRangePopover/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/PatrolFilter/FiltersPopover/index.js b/src/PatrolFilter/FiltersPopover/index.js index cbfe0594d..8b17e4943 100644 --- a/src/PatrolFilter/FiltersPopover/index.js +++ b/src/PatrolFilter/FiltersPopover/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback } from 'react'; +import { memo, useCallback } from 'react'; import Button from 'react-bootstrap/Button'; import isEqual from 'react-fast-compare'; import Popover from 'react-bootstrap/Popover'; diff --git a/src/PatrolFilter/FiltersPopover/index.test.js b/src/PatrolFilter/FiltersPopover/index.test.js index c608b1a2b..2de2ffddc 100644 --- a/src/PatrolFilter/FiltersPopover/index.test.js +++ b/src/PatrolFilter/FiltersPopover/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; @@ -71,7 +70,7 @@ describe('PatrolFilter', () => { ); - await screen.findByText('Reset All'); + expect(await screen.findByText('Reset All')).toBeInTheDocument(); }); test('does not show the Reset All button if the filters have not been modified', async () => { diff --git a/src/PatrolFilter/FiltersPopover/styles.module.scss b/src/PatrolFilter/FiltersPopover/styles.module.scss index 69b387207..bda23f488 100644 --- a/src/PatrolFilter/FiltersPopover/styles.module.scss +++ b/src/PatrolFilter/FiltersPopover/styles.module.scss @@ -1,9 +1,9 @@ -@import '../../common/styles/vars/colors'; +@use '../../common/styles/vars/colors'; .popover { overflow: auto !important; - [class*=popover-body] { + [class*="popover-body"] { overflow: auto !important; } } @@ -20,17 +20,17 @@ label { font-weight: 500; font-size: 0.75rem; - color: $medium-light-gray; + color: colors.$medium-light-gray; margin-bottom: 0.375rem; } button { - &[class*=hidden] { + &[class*="hidden"] { visibility: hidden; } } - [class*=select] { + [class*="select"] { display: flex; align-items: center; width: 100%; @@ -49,7 +49,7 @@ padding: 0.5rem 1rem; overflow: hidden; - [class*=header] { + [class*="header"] { width: 100%; display: flex; justify-content: space-between; @@ -59,23 +59,23 @@ label { font-weight: 500; font-size: 1rem; - color: $primary-font-color; + color: colors.$primary-font-color; } } button { - &[class*=hidden] { + &[class*="hidden"] { visibility: hidden; } } - [class*=checkboxListContainer] { + [class*="checkboxListContainer"] { width: 100%; } } .statusContainer { - [class*=statusItem] { + [class*="statusItem"] { display: flex; align-items: center; @@ -88,7 +88,7 @@ } .patrolTypeContainer { - [class*=patrolTypeItem] { + [class*="patrolTypeItem"] { display: flex; align-items: center; diff --git a/src/PatrolFilter/PatrolFilterSettings.js b/src/PatrolFilter/PatrolFilterSettings.js index de98ed85a..63b55d148 100644 --- a/src/PatrolFilter/PatrolFilterSettings.js +++ b/src/PatrolFilter/PatrolFilterSettings.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback } from 'react'; +import { memo, useCallback } from 'react'; import { connect } from 'react-redux'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; diff --git a/src/PatrolFilter/index.js b/src/PatrolFilter/index.js index c79459308..a4ac76ab0 100644 --- a/src/PatrolFilter/index.js +++ b/src/PatrolFilter/index.js @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import Button from 'react-bootstrap/Button'; import debounce from 'lodash/debounce'; @@ -86,6 +86,8 @@ const PatrolFilter = ({ className = '' }) => { useEffect(() => { if (!caseInsensitiveCompare(filterText, patrolFilter.filter.text)) { + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setFilterText(patrolFilter.filter.text); } }, [patrolFilter.filter.text]); // eslint-disable-line react-hooks/exhaustive-deps diff --git a/src/PatrolFilter/index.test.js b/src/PatrolFilter/index.test.js index 64c12dcd9..504cce2bd 100644 --- a/src/PatrolFilter/index.test.js +++ b/src/PatrolFilter/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/PatrolFilter/styles.module.scss b/src/PatrolFilter/styles.module.scss index 59d0aefb7..71465f50f 100644 --- a/src/PatrolFilter/styles.module.scss +++ b/src/PatrolFilter/styles.module.scss @@ -1,5 +1,4 @@ @use 'sass:color'; - @use '../common/styles/vars/colors'; .form { @@ -49,11 +48,11 @@ } .filterPopover { - > [class*=arrow]::after { + > [class*="arrow"]::after { border-bottom-color: colors.$popover-header-color; } - [class*=popover-header] { + [class*="popover-header"] { background: colors.$highlight-color; color: white; padding: 1rem; @@ -71,7 +70,7 @@ div.filterPopover { max-width: 29rem; width: 90vw; - [class*=popover-body] { + [class*="popover-body"] { overflow: hidden; padding: 0; } diff --git a/src/PatrolList/index.js b/src/PatrolList/index.js index 7f6ef220f..56271461b 100644 --- a/src/PatrolList/index.js +++ b/src/PatrolList/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext } from 'react'; +import { memo, useCallback, useContext } from 'react'; import { Flipper, Flipped } from 'react-flip-toolkit'; import MoonLoader from 'react-spinners/MoonLoader'; import { useTranslation } from 'react-i18next'; diff --git a/src/PatrolList/styles.module.scss b/src/PatrolList/styles.module.scss index bd3fa3fcf..c90e54f76 100644 --- a/src/PatrolList/styles.module.scss +++ b/src/PatrolList/styles.module.scss @@ -1,12 +1,14 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/buttons'; +@use 'sass:color'; +@use '../common/styles/vars/colors'; +@use '../common/styles/buttons'; .patrolList { background-color: white; justify-content: space-evenly; overflow-y: scroll; height: calc(100% - 6.5rem); - [class*=titleContainer] { + + [class*="titleContainer"] { max-width: 20.5rem; } } @@ -34,7 +36,7 @@ } &.modified { - background: lighten($highlight-color, 15%); + background: color.adjust(colors.$highlight-color, $lightness: 15%); color: white; } } @@ -76,7 +78,7 @@ width: 1.75rem; &:active { - background: rgba(0, 0, 0, 0.17); + background: rgb(0 0 0 / 17%); } } @@ -95,7 +97,7 @@ } .kebab { - --hamburger-menu-color: rgba(0, 0, 0, 0.47); + --hamburger-menu-color: rgb(0 0 0 / 47%); display: flex; position: static; @@ -103,7 +105,7 @@ } .patrolButton { - @include patrolJumpButton; + @include buttons.patrol-jump-button; } .loaderWrapper { diff --git a/src/PatrolListItem/index.js b/src/PatrolListItem/index.js index 5f3a85ed8..cbd3207bb 100644 --- a/src/PatrolListItem/index.js +++ b/src/PatrolListItem/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react'; +import { memo, useCallback, useEffect, useMemo, useRef } from 'react'; import Button from 'react-bootstrap/Button'; import { shallowEqual, useSelector } from 'react-redux'; diff --git a/src/PatrolListItem/index.test.js b/src/PatrolListItem/index.test.js index 234ff2aa8..86d37a13d 100644 --- a/src/PatrolListItem/index.test.js +++ b/src/PatrolListItem/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { bbox, lineString } from '@turf/turf'; import userEvent from '@testing-library/user-event'; @@ -152,7 +151,7 @@ describe('the patrol list item', () => { }); test('showing an icon for the patrol', async () => { - await screen.findByTestId(`patrol-list-item-icon-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-icon-${testPatrol.id}`)).toBeInTheDocument(); }); test('showing the patrol title', async () => { @@ -168,7 +167,7 @@ describe('the patrol list item', () => { }); test('showing a kebab menu for additional actions', async () => { - await screen.findByTestId(`patrol-list-item-kebab-menu-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-kebab-menu-${testPatrol.id}`)).toBeInTheDocument(); }); test('hides menu on outside click to prevent menu overlapping', async () => { @@ -206,7 +205,7 @@ describe('for active patrols', () => { }); test('showing a location jump button if the patrol has any location data', async () => { - await screen.findByTestId(`patrol-list-item-jump-btn-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-jump-btn-${testPatrol.id}`)).toBeInTheDocument(); }); test('toggling a patrol track on when clicking the "jump to location button"', async () => { @@ -234,7 +233,7 @@ describe('for active patrols', () => { }); test('showing a track button if the patrol has track data', async () => { - await screen.findByTestId(`patrol-list-item-track-btn-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-track-btn-${testPatrol.id}`)).toBeInTheDocument(); }); test('showing no distance while nothing has measured the legs of the patrol', async () => { diff --git a/src/PatrolListItem/styles.module.scss b/src/PatrolListItem/styles.module.scss index 0be691b5c..31966cb96 100644 --- a/src/PatrolListItem/styles.module.scss +++ b/src/PatrolListItem/styles.module.scss @@ -1,6 +1,6 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/buttons'; -@import '../common/styles/layout'; +@use '../common/styles/vars/colors'; +@use '../common/styles/buttons'; +@use '../common/styles/layout'; .icon { @@ -16,7 +16,7 @@ height: var(--dimensions); width: var(--dimensions); - &[class*=generic] { + &[class*="generic"] { height: var(--half-size); width: var(--half-size); } @@ -35,24 +35,24 @@ text-overflow: ellipsis; font-size: .875rem; - @media (min-width: $sm-layout-width-max) { + @media (min-width: layout.$sm-layout-width-max) { font-size: unset; padding-right: 1.2rem; } - @media (min-width: $md-layout-width-max) { + @media (min-width: layout.$md-layout-width-max) { padding-right: unset; } } } .titleDetails { - color: $off-black; + color: colors.$off-black; font-size: 0.75rem; } .title, .icon { - @include unstyledButton; + @include buttons.unstyled-button; } .controls { @@ -68,9 +68,9 @@ .serialNumber { display: none; padding-right: 0.5rem; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: flex; } } @@ -84,15 +84,15 @@ } .stateDependantControl { - background: $transparent-dark-gray !important; + background: colors.$transparent-dark-gray !important; border: none; display: none; &:hover{ - background: $hover-button-background !important; + background: colors.$hover-button-background !important; } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: unset; } } diff --git a/src/PatrolMenu/index.js b/src/PatrolMenu/index.js index 966415056..5b71bf04a 100644 --- a/src/PatrolMenu/index.js +++ b/src/PatrolMenu/index.js @@ -1,4 +1,4 @@ -import React, { memo, useMemo, useCallback } from 'react'; +import { memo, useMemo, useCallback } from 'react'; import { useSelector } from 'react-redux'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; diff --git a/src/PatrolMenu/index.test.js b/src/PatrolMenu/index.test.js index e6dd5a310..47e1d017d 100644 --- a/src/PatrolMenu/index.test.js +++ b/src/PatrolMenu/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import PatrolMenu from './index'; import patrols from '../__test-helpers/fixtures/patrols'; import patrolTypes from '../__test-helpers/fixtures/patrol-types'; @@ -98,7 +97,10 @@ describe('PatrolMenu', () => { renderPatrolMenu(); await userEvent.click(screen.getByRole('button')); - testMinimumOptionsMenu(); + expect(screen.getByText('Copy patrol link')).toBeInTheDocument(); + expect(screen.getByTestId('clip-icon')).toBeInTheDocument(); + expect(screen.getByText('Print Patrol')).toBeInTheDocument(); + expect(screen.getByTestId('printer-icon')).toBeInTheDocument(); }); test('reaches the copy button with the keyboard', async () => { diff --git a/src/PatrolStartStopLayer/index.js b/src/PatrolStartStopLayer/index.js index 95948ff88..416e1bb04 100644 --- a/src/PatrolStartStopLayer/index.js +++ b/src/PatrolStartStopLayer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/PatrolStartStopLayer/index.test.js b/src/PatrolStartStopLayer/index.test.js index 80fc953b9..b7117c4e9 100644 --- a/src/PatrolStartStopLayer/index.test.js +++ b/src/PatrolStartStopLayer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { addFeatureCollectionImagesToMap } from '../utils/map'; diff --git a/src/PatrolTrackControls/index.js b/src/PatrolTrackControls/index.js index 5e107bd0f..eef90a839 100644 --- a/src/PatrolTrackControls/index.js +++ b/src/PatrolTrackControls/index.js @@ -1,4 +1,4 @@ -import React, { useCallback, useContext, useRef } from 'react'; +import { useCallback, useContext, useRef } from 'react'; import { PREVIEW_FEATURES } from '../constants'; import { fitMapBoundsForAnalyzer } from '../utils/analyzers'; diff --git a/src/PatrolTrackControls/index.test.js b/src/PatrolTrackControls/index.test.js index 071af7a6a..5752fec88 100644 --- a/src/PatrolTrackControls/index.test.js +++ b/src/PatrolTrackControls/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { bbox, lineString } from '@turf/turf'; import userEvent from '@testing-library/user-event'; @@ -21,11 +20,11 @@ const map = createMapMock({ fitBounds: jest.fn() }); const onLocationClick = jest.fn(); test('rendering without crashing', () => { - render( + expect(() => render( - ); + )).not.toThrow(); }); @@ -83,11 +82,11 @@ describe('patrols with leader, location and track data', () => { }); test('showing a location jump button if the patrol has any location data', async () => { - await screen.findByTestId(`patrol-list-item-jump-btn-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-jump-btn-${testPatrol.id}`)).toBeInTheDocument(); }); test('showing a track button if the patrol has track data', async () => { - await screen.findByTestId(`patrol-list-item-track-btn-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-track-btn-${testPatrol.id}`)).toBeInTheDocument(); }); }); @@ -146,7 +145,7 @@ describe('patrols WITHOUT leader', () => { }); test('showing a location jump button because patrol has location data', async () => { - await screen.findByTestId(`patrol-list-item-jump-btn-${testPatrol.id}`); + expect(await screen.findByTestId(`patrol-list-item-jump-btn-${testPatrol.id}`)).toBeInTheDocument(); }); test('NOT showing a track jump button even if the patrol has track data but there is no leader', () => { diff --git a/src/PatrolTrackControls/styles.module.scss b/src/PatrolTrackControls/styles.module.scss index c21a58ddf..d7140a586 100644 --- a/src/PatrolTrackControls/styles.module.scss +++ b/src/PatrolTrackControls/styles.module.scss @@ -1,4 +1,4 @@ -@import "../common/styles/vars/colors"; +@use '../common/styles/vars/colors'; .patrolTrackControls { display: flex; @@ -6,6 +6,6 @@ button { margin: 0 0.25rem; border-radius: 0.25rem; - background-color: $transparent-dark-gray !important; + background-color: colors.$transparent-dark-gray !important; } } \ No newline at end of file diff --git a/src/PatrolTrackLayer/index.js b/src/PatrolTrackLayer/index.js index e01ab1cde..aa3bdb9dd 100644 --- a/src/PatrolTrackLayer/index.js +++ b/src/PatrolTrackLayer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext } from 'react'; +import { memo, useContext } from 'react'; import { useSelector } from 'react-redux'; import { selectPatrolMapTrackData } from '../selectors/patrols'; diff --git a/src/PatrolTrackLegend/index.js b/src/PatrolTrackLegend/index.js index aa1a4d4d6..5c3e5246c 100644 --- a/src/PatrolTrackLegend/index.js +++ b/src/PatrolTrackLegend/index.js @@ -1,4 +1,4 @@ -import React, { memo, useMemo } from 'react'; +import { memo, useMemo } from 'react'; import { formatDistance, formatDistanceToNow } from 'date-fns'; import omit from 'lodash/omit'; import { useDispatch, useSelector } from 'react-redux'; diff --git a/src/PatrolTrackLegend/index.test.js b/src/PatrolTrackLegend/index.test.js index 8cfc62955..9578d57c4 100644 --- a/src/PatrolTrackLegend/index.test.js +++ b/src/PatrolTrackLegend/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/PatrolTracks/index.js b/src/PatrolTracks/index.js index 17a307ade..5bc8bc253 100644 --- a/src/PatrolTracks/index.js +++ b/src/PatrolTracks/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect } from 'react'; +import { memo, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { fetchTracksIfNecessary } from '../utils/tracks'; diff --git a/src/PickMapLocationButton/index.js b/src/PickMapLocationButton/index.js index 6bf72bf9e..a11d0c890 100644 --- a/src/PickMapLocationButton/index.js +++ b/src/PickMapLocationButton/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/PickMapLocationButton/index.test.js b/src/PickMapLocationButton/index.test.js index 7b08b9758..084291a08 100644 --- a/src/PickMapLocationButton/index.test.js +++ b/src/PickMapLocationButton/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/PickMapLocationButton/styles.module.scss b/src/PickMapLocationButton/styles.module.scss index 0ad9b52f6..af41f1ec1 100644 --- a/src/PickMapLocationButton/styles.module.scss +++ b/src/PickMapLocationButton/styles.module.scss @@ -1,4 +1,4 @@ -$background: rgba(0,0,0,0.65); +$background: rgb(0 0 0 / 65%); .instructionsPopup { align-items: center; @@ -13,15 +13,15 @@ $background: rgba(0,0,0,0.65); margin: 0 0 0.25rem; } - [class*=mapboxgl-popup-content] { + [class*="mapboxgl-popup-content"] { background: $background; color: white; max-width: 10rem; padding: 0.25rem; } - [class*=mapboxgl-popup-tip] { + [class*="mapboxgl-popup-tip"] { border-right-color: $background; - border-top-color: rgba(0,0,0,0); + border-top-color: rgb(0 0 0 / 0%); } } diff --git a/src/Popup/index.js b/src/Popup/index.js index a29d24175..4c23ea492 100644 --- a/src/Popup/index.js +++ b/src/Popup/index.js @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useRef } from 'react'; +import { useContext, useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import mapboxgl from 'mapbox-gl'; import xor from 'lodash/xor'; @@ -79,6 +79,8 @@ const Popup = ({ className = '', trackPointer = false, offset, coordinates, anch return createPortal( <>{children}, + // Using this ref during render is intended. + // eslint-disable-next-line react-hooks/refs popupContainerRef.current ); }; diff --git a/src/Popup/index.test.js b/src/Popup/index.test.js index 1475ef3e1..2e52b406d 100644 --- a/src/Popup/index.test.js +++ b/src/Popup/index.test.js @@ -1,4 +1,4 @@ -import React, { useRef } from 'react'; +import { useRef } from 'react'; import { cleanup, render } from '@testing-library/react'; import { createMapMock } from '../__test-helpers/mocks'; @@ -33,6 +33,8 @@ jest.mock('mapbox-gl', () => ({ const Wrapper = ({ children }) => { const mapRef = useRef(createMapMock()); + // Using this ref during render is intended. + // eslint-disable-next-line react-hooks/refs return {children} ; @@ -56,7 +58,7 @@ describe('the Popup component', () => { }); test('rendering without crashing', () => { - renderWithWrapper(); + expect(() => renderWithWrapper()).not.toThrow(); }); test('setting rendered React components as DOM content', () => { diff --git a/src/Popup/styles.module.scss b/src/Popup/styles.module.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/PopupLayer/index.js b/src/PopupLayer/index.js index 70cdf262f..644721d4f 100644 --- a/src/PopupLayer/index.js +++ b/src/PopupLayer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext, useEffect, useState } from 'react'; +import { memo, useContext, useEffect, useState } from 'react'; import { calculatePopoverPlacement } from '../utils/map'; import { MapContext } from '../MapContext'; diff --git a/src/PrintTitle/index.js b/src/PrintTitle/index.js index e0473e9ff..803e5a12b 100644 --- a/src/PrintTitle/index.js +++ b/src/PrintTitle/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useSelector } from 'react-redux'; import * as styles from './styles.module.scss'; diff --git a/src/PrintTitle/index.test.js b/src/PrintTitle/index.test.js index 0ae06f03d..56635c734 100644 --- a/src/PrintTitle/index.test.js +++ b/src/PrintTitle/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { render, screen } from '@testing-library/react'; import configureStore from 'redux-mock-store'; diff --git a/src/ProfilePINModal/index.js b/src/ProfilePINModal/index.js index 3263ca8ea..95870ea5b 100644 --- a/src/ProfilePINModal/index.js +++ b/src/ProfilePINModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { memo, useCallback, useEffect, useRef, useState } from 'react'; import Form from 'react-bootstrap/Form'; import Modal from 'react-bootstrap/Modal'; import PinField from 'react-pin-field'; @@ -25,6 +25,8 @@ const ProfilePINModal = ({ onSuccess, profile }) => { } }, [error]); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const onComplete = useCallback((pin) => { if (pin !== profile.pin.toString()) { return setError(true); diff --git a/src/ProfilePINModal/index.test.js b/src/ProfilePINModal/index.test.js index 5a55db9de..9dcfbfdf9 100644 --- a/src/ProfilePINModal/index.test.js +++ b/src/ProfilePINModal/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import userEvent from '@testing-library/user-event'; import { render, screen, waitFor } from '../test-utils'; @@ -20,8 +19,8 @@ describe('ProfilePINModal', () => { }); test('the content', async () => { - await screen.findByText('Enter Your PIN'); - await screen.findByText(`User: ${profile.username}`); + expect(await screen.findByText('Enter Your PIN')).toBeInTheDocument(); + expect(await screen.findByText(`User: ${profile.username}`)).toBeInTheDocument(); }); test('entering the correct PIN invokes the onSuccess callback', async () => { diff --git a/src/ProfilePINModal/styles.module.scss b/src/ProfilePINModal/styles.module.scss index 39599e47f..361379385 100644 --- a/src/ProfilePINModal/styles.module.scss +++ b/src/ProfilePINModal/styles.module.scss @@ -1,13 +1,13 @@ -@import '../common/styles/vars/colors'; +@use '../common/styles/vars/colors'; -$profilePinDimensions: 2.5rem; +$profile-pin-dimensions: 2.5rem; .modalBody { min-height: 9.5rem; } .error { - color: $error; + color: colors.$error; margin: 1rem 0 0; } @@ -18,14 +18,14 @@ $profilePinDimensions: 2.5rem; input { border-radius: 0; font-size: 1.5rem; - height: $profilePinDimensions; + height: $profile-pin-dimensions; margin-right: 0.333rem; text-align: center; - width: $profilePinDimensions; + width: $profile-pin-dimensions; &:focus, &:active { - border-color: $highlight-color; + border-color: colors.$highlight-color; } } } diff --git a/src/QuickLinks/index.js b/src/QuickLinks/index.js index adc8d4e36..8e36ab5cd 100644 --- a/src/QuickLinks/index.js +++ b/src/QuickLinks/index.js @@ -1,4 +1,4 @@ -import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import useOnScreen from '../hooks/useOnScreen'; diff --git a/src/QuickLinks/index.test.js b/src/QuickLinks/index.test.js index 4dc3181da..8c2b3be2d 100644 --- a/src/QuickLinks/index.test.js +++ b/src/QuickLinks/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/src/QuickLinks/styles.module.scss b/src/QuickLinks/styles.module.scss index 6095e80c0..2cea1836c 100644 --- a/src/QuickLinks/styles.module.scss +++ b/src/QuickLinks/styles.module.scss @@ -1,5 +1,5 @@ -@import '../common/styles/layout'; -@import '../common/styles/vars/colors'; +@use '../common/styles/layout'; +@use '../common/styles/vars/colors'; .navigationBar { display: flex; @@ -7,7 +7,7 @@ min-width: 3rem; background-color: white; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { min-width: 4.5rem; } @@ -16,27 +16,27 @@ flex-direction: column; justify-content: center; align-items: center; - color: $secondary-light-gray; + color: colors.$secondary-light-gray; font-size: 0.625rem; height: 3rem; padding: 0; cursor: pointer; - border-bottom: 1px solid rgba(177, 179, 179, 0.25); + border-bottom: 1px solid rgb(177 179 179 / 25%); &:hover { - color: $bright-blue !important; - background-color: $very-light-blue !important; + color: colors.$bright-blue !important; + background-color: colors.$very-light-blue !important; font-weight: bold; svg { - color: $bright-blue; + color: colors.$bright-blue; } } svg { - color: $secondary-light-gray; + color: colors.$secondary-light-gray; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { margin-bottom: 0.5rem; } } @@ -44,54 +44,54 @@ span { display: none; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: block; } } - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { height: 5.5rem; } } - [class*=active] { - color: $bright-blue !important; - background-color: $very-light-blue !important; + [class*="active"] { + color: colors.$bright-blue !important; + background-color: colors.$very-light-blue !important; font-weight: bold; svg { - color: $bright-blue; + color: colors.$bright-blue; } } - [class*=active] ~ [class*=active] { - color: $secondary-light-gray !important; + [class*="active"] ~ [class*="active"] { + color: colors.$secondary-light-gray !important; background-color: white !important; font-weight: normal; &:hover { - color: $bright-blue !important; - background-color: $very-light-blue !important; + color: colors.$bright-blue !important; + background-color: colors.$very-light-blue !important; font-weight: bold; svg { - color: $bright-blue; + color: colors.$bright-blue; } } svg { - color: $secondary-light-gray; + color: colors.$secondary-light-gray; } } } .sectionsWrapper { - background-color: $very-light-gray; + background-color: colors.$very-light-gray; overflow-x: hidden; width: 100%; height: 100%; - &[class*=readonly] { + &[class*="readonly"] { cursor: not-allowed; } } diff --git a/src/ReportFormSummary/V1SchemaFormSummary/index.js b/src/ReportFormSummary/V1SchemaFormSummary/index.js index aa8efe4b0..ea6858b74 100644 --- a/src/ReportFormSummary/V1SchemaFormSummary/index.js +++ b/src/ReportFormSummary/V1SchemaFormSummary/index.js @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; import Form from '@rjsf/react-bootstrap'; import { formValidator } from '../../utils/events'; diff --git a/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss b/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss index 4524b4b4a..1d822fbf9 100644 --- a/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss +++ b/src/ReportFormSummary/V1SchemaFormSummary/styles.module.scss @@ -1,7 +1,7 @@ @use '../../common/styles/vars/colors'; .form { - [class*=react-datepicker-wrapper] { + [class*="react-datepicker-wrapper"] { div { border: none; padding: 0; @@ -10,7 +10,7 @@ } } - [class*=row] { + [class*="row"] { padding: 0; > * { @@ -18,7 +18,7 @@ } } - [class*=col-] { + [class*="col-"] { padding: 0; } @@ -30,7 +30,7 @@ button, input, - [class*=control] { + [class*="control"] { background-color: transparent !important; border: transparent; font-size: 1rem; @@ -39,18 +39,18 @@ padding: 0; } - [class*=control] { + [class*="control"] { min-height: 1.5rem; } - [class*=selectWidget] { + [class*="selectWidget"] { div { height: 1.5rem; display: block; padding: 0; } - [class*=singleValue] { + [class*="singleValue"] { color: black; margin: 0; } @@ -71,21 +71,21 @@ margin-bottom: 0; } - button[class*=moveButton], - button[type=submit], + button[class*="moveButton"], + button[type="submit"], svg, - [class*=addButton], - [class*=triangle], - [class*=IndicatorsContainer] { + [class*="addButton"], + [class*="triangle"], + [class*="IndicatorsContainer"] { display: none !important; } - [class*=checkboxesWidget] { + [class*="checkboxesWidget"] { border: none; max-height: none; overflow-y: hidden; - [class*=checkbox] { + [class*="checkbox"] { margin-bottom: 0; padding-left: 0; @@ -95,7 +95,7 @@ margin: 0; opacity: 1; - &:before { + &::before { content: "\002D"; margin-right: 0.25rem; } diff --git a/src/ReportFormSummary/index.js b/src/ReportFormSummary/index.js index ac4d6f456..1e4b08b0f 100644 --- a/src/ReportFormSummary/index.js +++ b/src/ReportFormSummary/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect } from 'react'; +import { memo, useEffect } from 'react'; import MoonLoader from 'react-spinners/MoonLoader'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/ReportFormSummary/index.test.js b/src/ReportFormSummary/index.test.js index 72d25e196..d81886dbf 100644 --- a/src/ReportFormSummary/index.test.js +++ b/src/ReportFormSummary/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { http, HttpResponse } from 'msw/http'; import { setupServer } from 'msw/node'; diff --git a/src/ReportGeometryDrawer/CancelationConfirmationModal/index.js b/src/ReportGeometryDrawer/CancelationConfirmationModal/index.js index adcc5185d..b36ed9907 100644 --- a/src/ReportGeometryDrawer/CancelationConfirmationModal/index.js +++ b/src/ReportGeometryDrawer/CancelationConfirmationModal/index.js @@ -1,4 +1,4 @@ -import React, { memo, useContext } from 'react'; +import { memo, useContext } from 'react'; import Button from 'react-bootstrap/Button'; import Modal from 'react-bootstrap/Modal'; import { useDispatch } from 'react-redux'; diff --git a/src/ReportGeometryDrawer/CancelationConfirmationModal/index.test.js b/src/ReportGeometryDrawer/CancelationConfirmationModal/index.test.js index 506215a76..02c441fc2 100644 --- a/src/ReportGeometryDrawer/CancelationConfirmationModal/index.test.js +++ b/src/ReportGeometryDrawer/CancelationConfirmationModal/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/ReportGeometryDrawer/CancelationConfirmationModal/styles.module.scss b/src/ReportGeometryDrawer/CancelationConfirmationModal/styles.module.scss index 493107009..08f94d657 100644 --- a/src/ReportGeometryDrawer/CancelationConfirmationModal/styles.module.scss +++ b/src/ReportGeometryDrawer/CancelationConfirmationModal/styles.module.scss @@ -1,8 +1,8 @@ -@import '../../common/styles/vars/colors'; +@use '../../common/styles/vars/colors'; .message { font-size: 1.125 rem; - color: $off-black; + color: colors.$off-black; } .buttons { @@ -12,12 +12,12 @@ .continueEditingButton { background-color: white; border: none; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; margin-right: 0.5rem; } .discardButton { - background-color: $bright-red; + background-color: colors.$bright-red; border: none; } } diff --git a/src/ReportGeometryDrawer/Footer/index.js b/src/ReportGeometryDrawer/Footer/index.js index e5ec126cc..b752e6472 100644 --- a/src/ReportGeometryDrawer/Footer/index.js +++ b/src/ReportGeometryDrawer/Footer/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import Button from 'react-bootstrap/Button'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; diff --git a/src/ReportGeometryDrawer/Footer/index.test.js b/src/ReportGeometryDrawer/Footer/index.test.js index 9eb6dc773..628af0511 100644 --- a/src/ReportGeometryDrawer/Footer/index.test.js +++ b/src/ReportGeometryDrawer/Footer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import userEvent from '@testing-library/user-event'; import Footer from './'; diff --git a/src/ReportGeometryDrawer/Footer/styles.module.scss b/src/ReportGeometryDrawer/Footer/styles.module.scss index 42ff3c99a..12ccc88b7 100644 --- a/src/ReportGeometryDrawer/Footer/styles.module.scss +++ b/src/ReportGeometryDrawer/Footer/styles.module.scss @@ -1,4 +1,4 @@ -@import '../../common/styles/vars/colors'; +@use '../../common/styles/vars/colors'; .footer { z-index: 12; @@ -7,7 +7,7 @@ left: 0; width: 100%; height: 4rem; - background: linear-gradient(180deg, #FFFFFF 0%, rgba(255, 255, 255, 0.65) 100%); + background: linear-gradient(180deg, #FFF 0%, rgb(255 255 255 / 65%) 100%); backdrop-filter: blur(8px); display: flex; justify-content: flex-end; @@ -17,7 +17,7 @@ .cancelButton { background: transparent; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; font-weight: bold; border: none; margin-right: 1rem; diff --git a/src/ReportGeometryDrawer/InformationModal/index.js b/src/ReportGeometryDrawer/InformationModal/index.js index 9d7759db7..df88500a3 100644 --- a/src/ReportGeometryDrawer/InformationModal/index.js +++ b/src/ReportGeometryDrawer/InformationModal/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import Modal from 'react-bootstrap/Modal'; import { useTranslation } from 'react-i18next'; diff --git a/src/ReportGeometryDrawer/index.js b/src/ReportGeometryDrawer/index.js index b2b8ef6ea..a87ccec38 100644 --- a/src/ReportGeometryDrawer/index.js +++ b/src/ReportGeometryDrawer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useContext, useEffect, useReducer, useState } from 'react'; +import { memo, useCallback, useContext, useEffect, useReducer, useState } from 'react'; import { bbox } from '@turf/turf'; import isEqual from 'react-fast-compare'; import { useDispatch, useSelector } from 'react-redux'; @@ -63,6 +63,8 @@ const ReportGeometryDrawer = () => { } }, [canUndo, isDrawing, points.length, reportGeometry.past]); + // Only the React Compiler needs these dependencies to line up. + // eslint-disable-next-line react-hooks/preserve-manual-memoization const onCancel = useCallback(() => { let originalPoints = []; if (event?.geometry) { @@ -152,6 +154,8 @@ const ReportGeometryDrawer = () => { dispatchReportGeometry(setGeometryPoints(eventPolygon.geometry.coordinates[0].slice(0, -1))); setTimeout(() => dispatchReportGeometry(reset())); + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setIsDrawing(false); } }, [event?.geometry, map]); diff --git a/src/ReportGeometryDrawer/index.test.js b/src/ReportGeometryDrawer/index.test.js index 719e52222..d27e4fd97 100644 --- a/src/ReportGeometryDrawer/index.test.js +++ b/src/ReportGeometryDrawer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/ReportListItem/index.js b/src/ReportListItem/index.js index f3624e3ce..83f4ecc7d 100644 --- a/src/ReportListItem/index.js +++ b/src/ReportListItem/index.js @@ -1,4 +1,4 @@ -import React, { memo, useCallback, useRef } from 'react'; +import { memo, useCallback, useRef } from 'react'; import { useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/ReportListItem/index.test.js b/src/ReportListItem/index.test.js index bb378f222..7db2db2e6 100644 --- a/src/ReportListItem/index.test.js +++ b/src/ReportListItem/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { mockStore } from '../__test-helpers/MockStore'; diff --git a/src/ReportListItem/styles.module.scss b/src/ReportListItem/styles.module.scss index 97ccb329f..7261bb1a2 100644 --- a/src/ReportListItem/styles.module.scss +++ b/src/ReportListItem/styles.module.scss @@ -1,6 +1,6 @@ -@import '../common/styles/vars/colors'; -@import '../common/styles/buttons'; -@import '../common/styles/layout'; +@use '../common/styles/vars/colors'; +@use '../common/styles/buttons'; +@use '../common/styles/layout'; .icon { color: white; @@ -10,7 +10,7 @@ svg { --dimensions: 1.75rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { --dimensions: 2rem; } @@ -20,7 +20,7 @@ height: var(--dimensions); width: var(--dimensions); - &[class*=generic] { + &[class*="generic"] { height: var(--half-size); width: var(--half-size); } @@ -28,7 +28,7 @@ .patrolIndicator { align-items: center; - background: rgba(0, 0, 0, 0.25); + background: rgb(0 0 0 / 25%); color: white; display: flex; font-size: 0.75rem; @@ -46,17 +46,17 @@ .title, .icon { - @include unstyledButton; + @include buttons.unstyled-button; } .serialNumber { display: none; padding-left: 0.5rem; padding-right: 0.5rem; - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; min-width: 1.25rem; - @media (min-width: $md-layout-width-min) { + @media (min-width: layout.$md-layout-width-min) { display: flex; } } @@ -89,33 +89,40 @@ .noPriority { &:hover { - background-color: $no-priority-bg-hover !important; + background-color: colors.$no-priority-bg-hover !important; + div[role='img'] { - background-color: $no-priority-base-hover !important; + background-color: colors.$no-priority-base-hover !important; } } } + .lowPriority { &:hover { - background-color: $low-priority-bg-hover !important; + background-color: colors.$low-priority-bg-hover !important; + div[role='img'] { - background-color: $low-priority-base-hover !important; + background-color: colors.$low-priority-base-hover !important; } } } + .mediumPriority { &:hover { - background-color: $medium-priority-bg-hover !important; + background-color: colors.$medium-priority-bg-hover !important; + div[role='img'] { - background-color: $medium-priority-base-hover !important; + background-color: colors.$medium-priority-base-hover !important; } } } + .highPriority { &:hover { - background-color: $high-priority-bg-hover !important; + background-color: colors.$high-priority-bg-hover !important; + div[role='img'] { - background-color: $high-priority-base-hover !important; + background-color: colors.$high-priority-base-hover !important; } } } diff --git a/src/ReportedBySelect/index.js b/src/ReportedBySelect/index.js index bbab3c45d..d011a7243 100644 --- a/src/ReportedBySelect/index.js +++ b/src/ReportedBySelect/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useMemo, useRef } from 'react'; +import { memo, useEffect, useMemo, useRef } from 'react'; import { components } from 'react-select'; import { List } from 'react-window'; import { useSelector } from 'react-redux'; diff --git a/src/ReportedBySelect/index.test.js b/src/ReportedBySelect/index.test.js index c7b5dfcd6..df0a98790 100644 --- a/src/ReportedBySelect/index.test.js +++ b/src/ReportedBySelect/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; @@ -29,7 +28,7 @@ describe('ReportedBySelect', () => { test('displaying the current selection', async () => { renderWithWrapper(); - await screen.findByText('Informant'); + expect(await screen.findByText('Informant')).toBeInTheDocument(); }); test('listing reporters', async () => { diff --git a/src/ReportedBySelect/styles.module.scss b/src/ReportedBySelect/styles.module.scss index 722e43675..24188810f 100644 --- a/src/ReportedBySelect/styles.module.scss +++ b/src/ReportedBySelect/styles.module.scss @@ -1,4 +1,4 @@ -@import '../common/styles/vars/colors'; +@use '../common/styles/vars/colors'; .option { @@ -18,24 +18,28 @@ &:active, &:hover { cursor: pointer; + div { - background-color: rgba($bright-blue, 0.3); + background-color: rgba(colors.$bright-blue, 0.3); color: white; } } &.hidden { - color: $light-font-color; + color: colors.$light-font-color; font-style: italic; } + &.optionLabel { pointer-events: none; + * { - color: $secondary-medium-gray; + color: colors.$secondary-medium-gray; font-size: 0.75rem; text-transform: uppercase; } } + &:hover, &:focus, &:active { background-color: initial; color: initial; @@ -83,7 +87,7 @@ .timeAgo { - color: $light-font-color; + color: colors.$light-font-color; flex-grow: 1; font-size: 0.7rem; font-style: italic; diff --git a/src/ReporterSelect/index.js b/src/ReporterSelect/index.js index 6fdd6cf30..46bd81b2e 100644 --- a/src/ReporterSelect/index.js +++ b/src/ReporterSelect/index.js @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; diff --git a/src/ReporterSelect/index.test.js b/src/ReporterSelect/index.test.js index 2518af8bc..aefe76afb 100644 --- a/src/ReporterSelect/index.test.js +++ b/src/ReporterSelect/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; diff --git a/src/ReportsHeatLayer/index.js b/src/ReportsHeatLayer/index.js index b2ce504ce..1ebc3b8e0 100644 --- a/src/ReportsHeatLayer/index.js +++ b/src/ReportsHeatLayer/index.js @@ -1,4 +1,4 @@ -import React, { memo, useMemo } from 'react'; +import { memo, useMemo } from 'react'; import { featureCollection } from '@turf/turf'; import { useSelector } from 'react-redux'; diff --git a/src/ReportsHeatLayer/index.test.js b/src/ReportsHeatLayer/index.test.js index 597422ed7..5f320f68a 100644 --- a/src/ReportsHeatLayer/index.test.js +++ b/src/ReportsHeatLayer/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { featureCollection, point } from '@turf/turf'; import { render } from '@testing-library/react'; import { useSelector } from 'react-redux'; diff --git a/src/ReportsHeatmapLegend/index.js b/src/ReportsHeatmapLegend/index.js index 5824759bd..0e1cd5ae5 100644 --- a/src/ReportsHeatmapLegend/index.js +++ b/src/ReportsHeatmapLegend/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import { memo } from 'react'; import { differenceInCalendarDays } from 'date-fns'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; @@ -8,7 +8,7 @@ import { getMapEventSymbolPointsWithVirtualDate } from '../selectors/events'; import HeatmapLegend from '../HeatmapLegend'; const ReportsHeatmapLegend = ({ onClose }) => { - const { t } = useTranslation('heatmap', { keyPrefix: 'reportsHeatmapLegend' }); + const { t } = useTranslation('heatmap', { keyPrefix: 'reportsHeatmapLegend' }); const eventFilter = useSelector((state) => state.data.eventFilter); const reports = useSelector(getMapEventSymbolPointsWithVirtualDate); diff --git a/src/RequireAccessToken/index.js b/src/RequireAccessToken/index.js index de5d1ae5a..b5350315e 100644 --- a/src/RequireAccessToken/index.js +++ b/src/RequireAccessToken/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect } from 'react'; +import { memo, useEffect } from 'react'; import { connect } from 'react-redux'; import { Navigate, useLocation } from 'react-router'; import { useAuth0 } from '@auth0/auth0-react'; diff --git a/src/RequireAccessToken/index.test.js b/src/RequireAccessToken/index.test.js index 73c7c666a..e73354c99 100644 --- a/src/RequireAccessToken/index.test.js +++ b/src/RequireAccessToken/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; import { useAuth0 } from '@auth0/auth0-react'; diff --git a/src/RequireEulaConfirmation/index.js b/src/RequireEulaConfirmation/index.js index 8faa5b0e8..57cbeafc7 100644 --- a/src/RequireEulaConfirmation/index.js +++ b/src/RequireEulaConfirmation/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useState } from 'react'; +import { memo, useEffect, useState } from 'react'; import { Navigate, useLocation } from 'react-router'; import { useDispatch, useSelector } from 'react-redux'; @@ -28,9 +28,11 @@ const RequireEulaConfirmation = ({ children }) => { useEffect(() => { // null check to distinguish from eulaEnabled = false if (user.id && eulaEnabled !== null) { - const accepted = user.hasOwnProperty('accepted_eula') ? user.accepted_eula : true; + const accepted = Object.hasOwn(user, 'accepted_eula') ? user.accepted_eula : true; const ignoreEula = eulaEnabled === false; + // Updating state from this effect is intended. + // eslint-disable-next-line react-hooks/set-state-in-effect setEulaAccepted(accepted || ignoreEula); } }, [eulaEnabled, user]); diff --git a/src/RequireEulaConfirmation/index.test.js b/src/RequireEulaConfirmation/index.test.js index ebf539d05..9ec2d1351 100644 --- a/src/RequireEulaConfirmation/index.test.js +++ b/src/RequireEulaConfirmation/index.test.js @@ -1,4 +1,3 @@ -import React from 'react'; import { Provider } from 'react-redux'; import { render, waitFor } from '@testing-library/react'; diff --git a/src/RightClickMarkerDropper/index.test.js b/src/RightClickMarkerDropper/index.test.js index a16ed6458..3b0c50606 100644 --- a/src/RightClickMarkerDropper/index.test.js +++ b/src/RightClickMarkerDropper/index.test.js @@ -1,6 +1,3 @@ - - -import React from 'react'; import { Provider } from 'react-redux'; @@ -22,12 +19,12 @@ beforeEach(() => { }); test('rendering without crashing', () => { - render( + expect(() => render( - ); + )).not.toThrow(); }); test('showing a popup on map right click', () => { diff --git a/src/SchemaFields/index.js b/src/SchemaFields/index.js index 9c5fbc601..a89188574 100644 --- a/src/SchemaFields/index.js +++ b/src/SchemaFields/index.js @@ -1,4 +1,4 @@ -import React, { useCallback, useRef, useState } from 'react'; +import { useCallback, useRef, useState } from 'react'; import Button from 'react-bootstrap/Button'; import { canExpand, getInputProps, getTemplate, getUiOptions } from '@rjsf/utils'; import Form from 'react-bootstrap/Form'; @@ -94,6 +94,8 @@ export const ArrayFieldTemplate = ({ const descriptionToRender = uiOptions.description?.trim() || schema.description?.trim(); return
    + {/* Creating this component during render is intended. */} + {/* eslint-disable-next-line react-hooks/static-components */} {titleToRender && } + {/* Creating this component during render is intended. */} + {/* eslint-disable-next-line react-hooks/static-components */} {descriptionToRender && { const descriptionToRender = uiOptions.description?.trim() || description?.trim(); return <> + {/* Creating this component during render is intended. */} + {/* eslint-disable-next-line react-hooks/static-components */} {titleToRender && { uiSchema={uiSchema} />} + {/* Creating this component during render is intended. */} + {/* eslint-disable-next-line react-hooks/static-components */} {descriptionToRender &&